feat:浦江优化

This commit is contained in:
dzc committed 2026-09-29 19:55:51 +08:00
1 parent da549b19aa
commit 7ae8d3e14b
7 files changed
+77 -8

No files matched your search

+21
View File
@@ -0,0 +1,21 @@
-- wallet_code_use 补二级索引(饭点卡顿波次 2026-09-14 诊断配套,PolarDB 分布式版 MySQL8 兼容模式)
-- 背景:该表此前仅有主键,慢日志实测 UPDATE 全表扫描并锁定全部扫描行:
-- UPDATE wallet_code_use SET del_flag = '1'
-- WHERE del_flag = '0' AND user_id = ? AND biz_type = '5' AND biz_id = ?
-- 扫描 14,653 行、单次耗时最长达 11 秒(波次期间),锁面放大拥堵。
-- 索引设计说明:biz_type 为 tinytext 无法进入普通二级索引;user_id + biz_id 组合
-- 已可把扫描范围缩到该用户名下几行,biz_type 在索引外过滤,无需进索引。
-- idx_wcu_biz 单列索引服务 WalletCodeUseServiceImpl.getInfoByShortCode 按 biz_id 查询。
-- 执行前请确认同名索引不存在:SHOW INDEX FROM pjcloudx_wallet.wallet_code_use;
-- 表仅约 1.5 万行,Online DDL 秒级完成,无锁风险;本文件只包含索引 DDL。
ALTER TABLE pjcloudx_wallet.wallet_code_use
ADD INDEX idx_wcu_user_biz (user_id, biz_id),
ADD INDEX idx_wcu_biz (biz_id);
-- 说明:
-- 1) 全量建库脚本 db/800pjcloudx_wallet.sql 已同步补上这两个索引,新建环境无需再执行本文件。
-- 2) 两条索引合并在一条 ALTER 中执行,只做一次表重建;如需拆开单独执行(参考
-- hard_order verification_time 加列时的生产执行惯例),可改为两条独立的 CREATE INDEX 语句:
-- CREATE INDEX idx_wcu_user_biz ON pjcloudx_wallet.wallet_code_use (user_id, biz_id);
-- CREATE INDEX idx_wcu_biz ON pjcloudx_wallet.wallet_code_use (biz_id);
+3 -1
View File
@@ -540,7 +540,9 @@ CREATE TABLE wallet_code_use
update_time datetime DEFAULT NULL COMMENT '修改时间',
del_flag char(1) COLLATE utf8mb4_general_ci DEFAULT '0' COMMENT '删除标记',
tenant_id bigint DEFAULT NULL COMMENT '租户ID',
PRIMARY KEY (id)
PRIMARY KEY (id),
INDEX idx_wcu_user_biz (user_id, biz_id),
INDEX idx_wcu_biz (biz_id)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4 COMMENT ='二维码使用表';
@@ -149,7 +149,7 @@ public class HardApiController {
@PostMapping("/create-order")
@Operation(summary = "创建订单")
@Idempotent(expireTime = 10, info = "正在创建订单中,请勿重复操作")
@Idempotent(expireTime = 60, delKey = true, info = "正在创建订单中,请勿重复操作")
public R<Long> createOrder(@Valid @RequestBody HardCreateOrderDto dto) {
// 处理商品类型
if (ObjectUtil.isNotEmpty(dto.getList())) {
@@ -167,7 +167,7 @@ public class HardApiController {
@PostMapping("/create-hard-qr-code-order")
@Operation(summary = "创建设备二维码扫一扫订单")
@Idempotent(expireTime = 10, info = "正在创建订单中,请勿重复操作")
@Idempotent(expireTime = 60, delKey = true, info = "正在创建订单中,请勿重复操作")
public R<HardCreateHardQrCodeScanOrderVo> createHardQrCodeScanOrder(@Valid @RequestBody HardCreateOrderDto dto) {
// 处理商品类型
if (ObjectUtil.isNotEmpty(dto.getList())) {
@@ -186,7 +186,7 @@ public class HardApiController {
@PostMapping("/done-hard-qr-code-order")
@Operation(summary = "用户确认设备二维码扫一扫订单")
@Idempotent(expireTime = 10, info = "订单支付中,请勿重复操作")
@Idempotent(expireTime = 60, delKey = true, info = "订单支付中,请勿重复操作")
public R<Long> doneHardQrCodeScanOrder(@Validated @RequestBody HardDoneHardQrCodeScanOrderDto body) {
PjcloudUser user = SecurityUtils.getUser();
hardwareOrderService.doneHardQrCodeScanOrder(body, user);
@@ -225,7 +225,7 @@ public class HardOrderController {
@Operation(summary = "app创建订单扫一扫", description = "app创建订单扫一扫")
@PostMapping("/app/create-order-scan-qrcode")
@Idempotent(expireTime = 5, info = "正在创建订单中,请勿重复操作")
@Idempotent(expireTime = 60, delKey = true, info = "正在创建订单中,请勿重复操作")
public R<Long> appCreateOrderScancode(@Validated @RequestBody HardAppCreateOrderScancode body) {
PjcloudUser user = SecurityUtils.getUser();
HardAppCreateOrderDto dto = HardAppCreateOrderDto.builder()
@@ -147,15 +147,33 @@ public class SysUserFaceServiceImpl extends ServiceImpl<SysUserFaceMapper, SysUs
return sysUserFace.getId();
}
/**
* 修改指定人脸图片;落库新图片地址与修改时间并清空质量检测结果,
* 让终端差异同步按版本时间感知换图并重新提取、重新上报质量。
*
* @param sysUserFace 仅使用记录主键和新图片地址,用户与虹软编号保持数据库原值
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void edit(SysUserFaceEntity sysUserFace) {
SysUserFaceEntity userFace = baseMapper.selectById(sysUserFace.getId());
if (userFace == null) {
throw new CheckedException("人脸样本表不存在");
}
baseMapper.selectById(userFace.getUserId());
int updatedRows = baseMapper.update(null, new LambdaUpdateWrapper<SysUserFaceEntity>()
.set(SysUserFaceEntity::getFaceImg, sysUserFace.getFaceImg())
.set(SysUserFaceEntity::getUpdateTime, LocalDateTime.now())
.set(SysUserFaceEntity::getQualityScore, null)
.set(SysUserFaceEntity::getQualityStatus, null)
.set(SysUserFaceEntity::getQualityCheckedAt, null)
.set(SysUserFaceEntity::getQualityErrorCode, null)
.set(SysUserFaceEntity::getQualityDeviceId, null)
.eq(SysUserFaceEntity::getId, userFace.getId()));
if (updatedRows <= 0) {
throw new RuntimeException("人脸样本修改失败,请刷新后重试");
}
// 发送mq
sendFaceMq(List.of(sysUserFace.getUserId()), null);
sendFaceMq(List.of(userFace.getUserId()), null);
}
@Override
@@ -158,7 +158,8 @@ public class MchManageController {
@Operation(summary = "app查询合作商家的分店", description = "app查询合作商家的分店")
@GetMapping("/app/children-page-join")
@Inner(value = false)
// 不再 @Inner(value = false) 匿名放行:未登录/token 过期时返回 424,
// 与 page-join 行为一致,避免匿名上下文下静默查空导致前端显示"暂无分店"
public R<Page<MchManageVo>> appParentPageJoin(@ParameterObject Page page, @ParameterObject MchManageDto dto) {
dto.setVisibleMobile(YesNoEnum.YES.getCode());
dto.setTypes(MerchantTypeEnum.SUPERMARKET.getType());
@@ -6,6 +6,7 @@ import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bsd.pjcloud.admin.api.dto.UserInfo;
@@ -16,6 +17,7 @@ import com.bsd.pjcloud.admin.api.feign.RemoteUserService;
import com.bsd.pjcloud.admin.api.utils.DataUtil;
import com.bsd.pjcloud.common.core.constant.CacheConstants;
import com.bsd.pjcloud.common.core.constant.enums.MerchantTypeEnum;
import com.bsd.pjcloud.common.core.constant.enums.YesNoEnum;
import com.bsd.pjcloud.common.core.util.BeanUtils;
import com.bsd.pjcloud.common.core.util.CollectionUtils;
import com.bsd.pjcloud.common.core.util.QRCodeImageGenerator;
@@ -59,8 +61,10 @@ import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayInputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
/**
@@ -202,10 +206,33 @@ public class MchManageServiceImpl extends ServiceImpl<MchManageMapper, MchManage
DataUtil.convertDeptList(list.getRecords(), deptList.getData());
}
}
// 主店列表:实时统计可见分店数覆盖冗余字段 mchCount,保证与 children-page-join 查询口径一致
if (Boolean.TRUE.equals(dto.getParentIsNull())) {
fillMchCount(list.getRecords());
}
}
return list;
}
/**
* 按 parent_id 实时统计各主店可见分店数(visible_mobile=1,逻辑删除自动过滤),
* 覆盖 mch_manage.mch_count 冗余计数,避免分店增删/隐藏后计数与实际不一致
*/
private void fillMchCount(List<MchManageVo> records) {
List<Long> ids = records.stream().map(MchManageVo::getId).filter(Objects::nonNull).toList();
if (ObjectUtil.isEmpty(ids)) return;
QueryWrapper<MchManageEntity> wrapper = new QueryWrapper<>();
wrapper.select("parent_id", "count(*) as cnt")
.in("parent_id", ids)
.eq("visible_mobile", YesNoEnum.YES.getCode())
.groupBy("parent_id");
Map<Long, Long> countMap = new HashMap<>();
for (Map<String, Object> row : baseMapper.selectMaps(wrapper)) {
countMap.put(Long.valueOf(String.valueOf(row.get("parent_id"))), Long.valueOf(String.valueOf(row.get("cnt"))));
}
records.forEach(v -> v.setMchCount(countMap.getOrDefault(v.getId(), 0L)));
}
/**
* 分页级联
*/