feat(订单): 添加商品封面图片和审批图片字段
feat(查询): 增加按货柜ID查询订单动态功能 feat(企业微信): 新增手动同步企业微信数据接口
This commit is contained in:
parent
5a826a7777
commit
ca7a4b53ab
|
|
@ -0,0 +1,333 @@
|
|||
package com.agileboot.admin.controller.qywx;
|
||||
|
||||
import com.agileboot.admin.customize.service.QywxScheduleJob;
|
||||
import com.agileboot.common.core.dto.ResponseDTO;
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import com.agileboot.domain.qywx.authCorpInfo.AuthCorpInfoApplicationService;
|
||||
import com.agileboot.domain.qywx.authCorpInfo.db.QyAuthCorpInfoEntity;
|
||||
import com.agileboot.domain.qywx.template.TemplateApplicationService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 企业微信手动同步控制器
|
||||
* 用于手动触发企业微信定时任务,方便调试和即时同步
|
||||
* 该接口无需权限验证,路径为 /qywx/** 已在SecurityConfig中配置为permitAll
|
||||
*/
|
||||
@Tag(name = "企业微信手动同步API", description = "手动触发企业微信定时任务")
|
||||
@RestController
|
||||
@RequestMapping("/qywx/manual")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class QywxManualSyncController {
|
||||
|
||||
private final QywxScheduleJob qywxScheduleJob;
|
||||
private final TemplateApplicationService templateApplicationService;
|
||||
private final AuthCorpInfoApplicationService authCorpInfoApplicationService;
|
||||
|
||||
/**
|
||||
* 手动获取套件访问令牌(suite_access_token)
|
||||
* 对应定时任务:@Scheduled(cron = "0 10 * * * *")
|
||||
*/
|
||||
@Operation(summary = "手动获取套件访问令牌", description = "获取企业微信应用凭证(suite_access_token)")
|
||||
@PostMapping("/suite-access-token")
|
||||
public ResponseDTO<String> getSuiteAccessToken(
|
||||
@Parameter(description = "应用ID,不传则执行所有应用")
|
||||
@RequestParam(required = false) String appid) {
|
||||
try {
|
||||
if (appid != null && !appid.isEmpty()) {
|
||||
// 执行单个应用
|
||||
qywxScheduleJob.getSuiteAccessToken(appid);
|
||||
return ResponseDTO.ok("成功获取应用 " + appid + " 的suite_access_token");
|
||||
} else {
|
||||
// 执行所有应用
|
||||
qywxScheduleJob.getSuiteAccessTokenTask();
|
||||
return ResponseDTO.ok("成功获取所有应用的suite_access_token");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("手动获取suite_access_token失败", e);
|
||||
return ResponseDTO.fail(new ApiException(ErrorCode.Internal.INTERNAL_ERROR, "获取suite_access_token失败:" + e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 手动获取访问令牌(access_token)
|
||||
* 对应定时任务:@Scheduled(cron = "0 20 * * * *")
|
||||
*/
|
||||
@Operation(summary = "手动获取访问令牌", description = "获取企业微信访问令牌(access_token)")
|
||||
@PostMapping("/access-token")
|
||||
public ResponseDTO<String> getAccessToken(
|
||||
@Parameter(description = "应用ID,不传则执行所有应用")
|
||||
@RequestParam(required = false) String appid) {
|
||||
try {
|
||||
if (appid != null && !appid.isEmpty()) {
|
||||
// 执行单个应用
|
||||
qywxScheduleJob.getAccessToken(appid);
|
||||
return ResponseDTO.ok("成功获取应用 " + appid + " 的access_token");
|
||||
} else {
|
||||
// 执行所有应用
|
||||
qywxScheduleJob.getAccessTokenTask();
|
||||
return ResponseDTO.ok("成功获取所有应用的access_token");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("手动获取access_token失败", e);
|
||||
return ResponseDTO.fail(new ApiException(ErrorCode.Internal.INTERNAL_ERROR, "获取access_token失败:" + e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 手动同步部门信息
|
||||
* 对应定时任务:@Scheduled(cron = "0 30 * * * *")
|
||||
*/
|
||||
@Operation(summary = "手动同步部门信息", description = "从企业微信同步组织架构信息到本地数据库")
|
||||
@PostMapping("/sync-department")
|
||||
public ResponseDTO<String> syncDepartment(
|
||||
@Parameter(description = "应用ID,不传则执行所有应用")
|
||||
@RequestParam(required = false) String appid,
|
||||
@Parameter(description = "企业ID,不传则执行该应用下所有企业")
|
||||
@RequestParam(required = false) String corpid) {
|
||||
try {
|
||||
if (appid != null && !appid.isEmpty() && corpid != null && !corpid.isEmpty()) {
|
||||
// 执行指定应用和企业
|
||||
QyAuthCorpInfoEntity authCorpInfo = authCorpInfoApplicationService.selectByAppidAndCorpid(appid, corpid);
|
||||
if (authCorpInfo != null) {
|
||||
qywxScheduleJob.syncDepartmentInfo(appid, authCorpInfo);
|
||||
return ResponseDTO.ok("成功同步应用 " + appid + " 企业 " + corpid + " 的部门信息");
|
||||
} else {
|
||||
return ResponseDTO.fail(new ApiException(ErrorCode.Internal.INTERNAL_ERROR, "未找到对应的授权企业信息"));
|
||||
}
|
||||
} else if (appid != null && !appid.isEmpty()) {
|
||||
// 执行指定应用下的所有企业
|
||||
List<QyAuthCorpInfoEntity> authCorpInfoList = authCorpInfoApplicationService.getByAppid(appid);
|
||||
if (authCorpInfoList != null && !authCorpInfoList.isEmpty()) {
|
||||
for (QyAuthCorpInfoEntity authCorpInfo : authCorpInfoList) {
|
||||
qywxScheduleJob.syncDepartmentInfo(appid, authCorpInfo);
|
||||
}
|
||||
return ResponseDTO.ok("成功同步应用 " + appid + " 下所有企业的部门信息");
|
||||
} else {
|
||||
return ResponseDTO.fail(new ApiException(ErrorCode.Internal.INTERNAL_ERROR, "该应用下未找到授权企业"));
|
||||
}
|
||||
} else {
|
||||
// 执行所有应用
|
||||
qywxScheduleJob.syncDepartmentInfoTask();
|
||||
return ResponseDTO.ok("成功同步所有应用的部门信息");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("手动同步部门信息失败", e);
|
||||
return ResponseDTO.fail(new ApiException(ErrorCode.Internal.INTERNAL_ERROR, "同步部门信息失败:" + e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 手动同步用户信息
|
||||
* 对应定时任务:@Scheduled(cron = "0 40 * * * *")
|
||||
*/
|
||||
@Operation(summary = "手动同步用户信息", description = "从企业微信同步用户信息到本地数据库")
|
||||
@PostMapping("/sync-user")
|
||||
public ResponseDTO<String> syncUser(
|
||||
@Parameter(description = "应用ID,不传则执行所有应用")
|
||||
@RequestParam(required = false) String appid,
|
||||
@Parameter(description = "企业ID,不传则执行该应用下所有企业")
|
||||
@RequestParam(required = false) String corpid) {
|
||||
try {
|
||||
if (appid != null && !appid.isEmpty() && corpid != null && !corpid.isEmpty()) {
|
||||
// 执行指定应用和企业
|
||||
QyAuthCorpInfoEntity authCorpInfo = authCorpInfoApplicationService.selectByAppidAndCorpid(appid, corpid);
|
||||
if (authCorpInfo != null) {
|
||||
qywxScheduleJob.syncUserInfo(appid, authCorpInfo);
|
||||
return ResponseDTO.ok("成功同步应用 " + appid + " 企业 " + corpid + " 的用户信息");
|
||||
} else {
|
||||
return ResponseDTO.fail(new ApiException(ErrorCode.Internal.INTERNAL_ERROR, "未找到对应的授权企业信息"));
|
||||
}
|
||||
} else if (appid != null && !appid.isEmpty()) {
|
||||
// 执行指定应用下的所有企业
|
||||
List<QyAuthCorpInfoEntity> authCorpInfoList = authCorpInfoApplicationService.getByAppid(appid);
|
||||
if (authCorpInfoList != null && !authCorpInfoList.isEmpty()) {
|
||||
for (QyAuthCorpInfoEntity authCorpInfo : authCorpInfoList) {
|
||||
qywxScheduleJob.syncUserInfo(appid, authCorpInfo);
|
||||
}
|
||||
return ResponseDTO.ok("成功同步应用 " + appid + " 下所有企业的用户信息");
|
||||
} else {
|
||||
return ResponseDTO.fail(new ApiException(ErrorCode.Internal.INTERNAL_ERROR, "该应用下未找到授权企业"));
|
||||
}
|
||||
} else {
|
||||
// 执行所有应用
|
||||
qywxScheduleJob.syncUserInfoTask();
|
||||
return ResponseDTO.ok("成功同步所有应用的用户信息");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("手动同步用户信息失败", e);
|
||||
return ResponseDTO.fail(new ApiException(ErrorCode.Internal.INTERNAL_ERROR, "同步用户信息失败:" + e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 手动获取授权信息
|
||||
* 对应定时任务:@Scheduled(cron = "0 45 * * * *")
|
||||
*/
|
||||
@Operation(summary = "手动获取授权信息", description = "获取企业授权信息并更新到本地数据库")
|
||||
@PostMapping("/auth-info")
|
||||
public ResponseDTO<String> getAuthInfo(
|
||||
@Parameter(description = "应用ID,不传则执行所有应用")
|
||||
@RequestParam(required = false) String appid) {
|
||||
try {
|
||||
if (appid != null && !appid.isEmpty()) {
|
||||
// 执行单个应用
|
||||
qywxScheduleJob.getAuthInfo(appid);
|
||||
return ResponseDTO.ok("成功获取应用 " + appid + " 的授权信息");
|
||||
} else {
|
||||
// 执行所有应用
|
||||
qywxScheduleJob.getAuthInfoTask();
|
||||
return ResponseDTO.ok("成功获取所有应用的授权信息");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("手动获取授权信息失败", e);
|
||||
return ResponseDTO.fail(new ApiException(ErrorCode.Internal.INTERNAL_ERROR, "获取授权信息失败:" + e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 手动同步用户绑定关系
|
||||
* 对应定时任务:@Scheduled(cron = "0 50 * * * *")
|
||||
*/
|
||||
@Operation(summary = "手动同步用户绑定关系", description = "同步企业微信用户与系统用户的绑定关系")
|
||||
@PostMapping("/sync-user-bindings")
|
||||
public ResponseDTO<String> syncUserBindings() {
|
||||
try {
|
||||
qywxScheduleJob.syncUserBindings();
|
||||
return ResponseDTO.ok("成功同步用户绑定关系");
|
||||
} catch (Exception e) {
|
||||
log.error("手动同步用户绑定关系失败", e);
|
||||
return ResponseDTO.fail(new ApiException(ErrorCode.Internal.INTERNAL_ERROR, "同步用户绑定关系失败:" + e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行完整同步流程
|
||||
* 按顺序执行:获取suite_access_token -> 获取access_token -> 同步部门 -> 同步用户 -> 获取授权信息 -> 同步绑定关系
|
||||
*/
|
||||
@Operation(summary = "执行完整同步流程", description = "按顺序执行所有同步任务(推荐用于初始化或全量同步)")
|
||||
@PostMapping("/sync-all")
|
||||
public ResponseDTO<String> syncAll(
|
||||
@Parameter(description = "应用ID,不传则执行所有应用")
|
||||
@RequestParam(required = false) String appid) {
|
||||
try {
|
||||
StringBuilder result = new StringBuilder();
|
||||
|
||||
// 1. 获取suite_access_token
|
||||
if (appid != null && !appid.isEmpty()) {
|
||||
qywxScheduleJob.getSuiteAccessToken(appid);
|
||||
result.append("1. 已获取应用 ").append(appid).append(" 的suite_access_token\n");
|
||||
} else {
|
||||
qywxScheduleJob.getSuiteAccessTokenTask();
|
||||
result.append("1. 已获取所有应用的suite_access_token\n");
|
||||
}
|
||||
|
||||
// 等待一小段时间确保token生效
|
||||
Thread.sleep(1000);
|
||||
|
||||
// 2. 获取access_token
|
||||
if (appid != null && !appid.isEmpty()) {
|
||||
qywxScheduleJob.getAccessToken(appid);
|
||||
result.append("2. 已获取应用 ").append(appid).append(" 的access_token\n");
|
||||
} else {
|
||||
qywxScheduleJob.getAccessTokenTask();
|
||||
result.append("2. 已获取所有应用的access_token\n");
|
||||
}
|
||||
|
||||
Thread.sleep(1000);
|
||||
|
||||
// 3. 同步部门信息
|
||||
if (appid != null && !appid.isEmpty()) {
|
||||
List<QyAuthCorpInfoEntity> authCorpInfoList = authCorpInfoApplicationService.getByAppid(appid);
|
||||
if (authCorpInfoList != null && !authCorpInfoList.isEmpty()) {
|
||||
for (QyAuthCorpInfoEntity authCorpInfo : authCorpInfoList) {
|
||||
qywxScheduleJob.syncDepartmentInfo(appid, authCorpInfo);
|
||||
}
|
||||
}
|
||||
result.append("3. 已同步应用 ").append(appid).append(" 的部门信息\n");
|
||||
} else {
|
||||
qywxScheduleJob.syncDepartmentInfoTask();
|
||||
result.append("3. 已同步所有应用的部门信息\n");
|
||||
}
|
||||
|
||||
Thread.sleep(1000);
|
||||
|
||||
// 4. 同步用户信息
|
||||
if (appid != null && !appid.isEmpty()) {
|
||||
List<QyAuthCorpInfoEntity> authCorpInfoList = authCorpInfoApplicationService.getByAppid(appid);
|
||||
if (authCorpInfoList != null && !authCorpInfoList.isEmpty()) {
|
||||
for (QyAuthCorpInfoEntity authCorpInfo : authCorpInfoList) {
|
||||
qywxScheduleJob.syncUserInfo(appid, authCorpInfo);
|
||||
}
|
||||
}
|
||||
result.append("4. 已同步应用 ").append(appid).append(" 的用户信息\n");
|
||||
} else {
|
||||
qywxScheduleJob.syncUserInfoTask();
|
||||
result.append("4. 已同步所有应用的用户信息\n");
|
||||
}
|
||||
|
||||
Thread.sleep(1000);
|
||||
|
||||
// 5. 获取授权信息
|
||||
if (appid != null && !appid.isEmpty()) {
|
||||
qywxScheduleJob.getAuthInfo(appid);
|
||||
result.append("5. 已获取应用 ").append(appid).append(" 的授权信息\n");
|
||||
} else {
|
||||
qywxScheduleJob.getAuthInfoTask();
|
||||
result.append("5. 已获取所有应用的授权信息\n");
|
||||
}
|
||||
|
||||
Thread.sleep(1000);
|
||||
|
||||
// 6. 同步用户绑定关系
|
||||
qywxScheduleJob.syncUserBindings();
|
||||
result.append("6. 已同步用户绑定关系\n");
|
||||
|
||||
result.append("\n✅ 完整同步流程执行成功!");
|
||||
return ResponseDTO.ok(result.toString());
|
||||
} catch (Exception e) {
|
||||
log.error("执行完整同步流程失败", e);
|
||||
return ResponseDTO.fail(new ApiException(ErrorCode.Internal.INTERNAL_ERROR, "执行完整同步流程失败:" + e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有可用的应用ID列表
|
||||
*/
|
||||
@Operation(summary = "获取应用ID列表", description = "获取系统中所有已配置的企业微信应用ID")
|
||||
@GetMapping("/appid-list")
|
||||
public ResponseDTO<List<String>> getAppidList() {
|
||||
try {
|
||||
List<String> appidList = templateApplicationService.getTemplateAppidList();
|
||||
return ResponseDTO.ok(appidList);
|
||||
} catch (Exception e) {
|
||||
log.error("获取应用ID列表失败", e);
|
||||
return ResponseDTO.fail(new ApiException(ErrorCode.Internal.INTERNAL_ERROR, "获取应用ID列表失败:" + e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定应用下的所有企业列表
|
||||
*/
|
||||
@Operation(summary = "获取企业列表", description = "获取指定应用下所有已授权的企业")
|
||||
@GetMapping("/corp-list")
|
||||
public ResponseDTO<List<QyAuthCorpInfoEntity>> getCorpList(
|
||||
@Parameter(description = "应用ID", required = true)
|
||||
@RequestParam String appid) {
|
||||
try {
|
||||
List<QyAuthCorpInfoEntity> corpList = authCorpInfoApplicationService.getByAppid(appid);
|
||||
return ResponseDTO.ok(corpList);
|
||||
} catch (Exception e) {
|
||||
log.error("获取企业列表失败", e);
|
||||
return ResponseDTO.fail(new ApiException(ErrorCode.Internal.INTERNAL_ERROR, "获取企业列表失败:" + e.getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -86,6 +86,7 @@ public interface ShopOrderMapper extends BaseMapper<ShopOrderEntity> {
|
|||
"sog.goods_name as goodsName, " +
|
||||
"sog.price as goodsPrice, " +
|
||||
"sog.quantity as quantity, " +
|
||||
"sog.cover_img as coverImg, " +
|
||||
"so.payment_method as paymentMethod, " +
|
||||
"so.name as orderName, " +
|
||||
"so.mobile as orderMobile, " +
|
||||
|
|
@ -99,6 +100,7 @@ public interface ShopOrderMapper extends BaseMapper<ShopOrderEntity> {
|
|||
"null as auditName, " +
|
||||
"null as auditRemark, " +
|
||||
"null as images, " +
|
||||
"null as auditImages, " +
|
||||
"so.create_time as dynamic_time " +
|
||||
"FROM shop_order so " +
|
||||
"INNER JOIN shop_order_goods sog ON so.order_id = sog.order_id AND sog.deleted = 0 " +
|
||||
|
|
@ -115,6 +117,7 @@ public interface ShopOrderMapper extends BaseMapper<ShopOrderEntity> {
|
|||
"sog.goods_name as goodsName, " +
|
||||
"sog.price as goodsPrice, " +
|
||||
"sog.quantity as quantity, " +
|
||||
"sog.cover_img as coverImg, " +
|
||||
"so.payment_method as paymentMethod, " +
|
||||
"so.name as orderName, " +
|
||||
"so.mobile as orderMobile, " +
|
||||
|
|
@ -128,6 +131,7 @@ public interface ShopOrderMapper extends BaseMapper<ShopOrderEntity> {
|
|||
"ra.audit_name as auditName, " +
|
||||
"ra.audit_remark as auditRemark, " +
|
||||
"ra.return_images as images, " +
|
||||
"ra.audit_images as auditImages, " +
|
||||
"COALESCE(ra.approval_time, ra.create_time) as dynamic_time " +
|
||||
"FROM shop_order so " +
|
||||
"INNER JOIN shop_order_goods sog ON so.order_id = sog.order_id AND sog.deleted = 0 " +
|
||||
|
|
|
|||
|
|
@ -36,6 +36,9 @@ public class BorrowReturnDynamicDTO {
|
|||
@ApiModelProperty("数量")
|
||||
private Integer quantity;
|
||||
|
||||
@ApiModelProperty("商品封面图片")
|
||||
private String coverImg;
|
||||
|
||||
@ApiModelProperty("支付方式")
|
||||
private String paymentMethod;
|
||||
|
||||
|
|
@ -78,6 +81,9 @@ public class BorrowReturnDynamicDTO {
|
|||
@ApiModelProperty("归还图片(归还记录时有效)")
|
||||
private String images;
|
||||
|
||||
@ApiModelProperty("审批图片(归还记录时有效)")
|
||||
private String auditImages;
|
||||
|
||||
public String getDynamicTypeStr() {
|
||||
if (dynamicType == null) return "-";
|
||||
switch (dynamicType) {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import lombok.EqualsAndHashCode;
|
|||
public class SearchBorrowReturnDynamicQuery<T> extends AbstractPageQuery<T> {
|
||||
|
||||
private Long goodsId;
|
||||
private Long cellId;
|
||||
private Integer status;
|
||||
private Integer dynamicType; // 动态类型:0-借出 1-归还
|
||||
|
||||
|
|
@ -53,6 +54,10 @@ public class SearchBorrowReturnDynamicQuery<T> extends AbstractPageQuery<T> {
|
|||
queryWrapper.eq("sog.goods_id", goodsId);
|
||||
}
|
||||
|
||||
if (cellId != null) {
|
||||
queryWrapper.eq("sog.cell_id", cellId);
|
||||
}
|
||||
|
||||
queryWrapper.eq("so.deleted", 0)
|
||||
.eq("sog.deleted", 0)
|
||||
.eq("so.pay_status", 2);
|
||||
|
|
|
|||
Loading…
Reference in New Issue