diff --git a/coolstore-partner-common/src/main/java/com/cool/store/enums/ErrorCodeEnum.java b/coolstore-partner-common/src/main/java/com/cool/store/enums/ErrorCodeEnum.java
index c1c4b0772..d4c44ec88 100644
--- a/coolstore-partner-common/src/main/java/com/cool/store/enums/ErrorCodeEnum.java
+++ b/coolstore-partner-common/src/main/java/com/cool/store/enums/ErrorCodeEnum.java
@@ -373,6 +373,11 @@ public enum ErrorCodeEnum {
TP_EXIST_PENDING_IMPORT_TASK(1810012, "存在导入中的任务,请稍后再试", null),
TP_NOT_EXIST_FORM_TYPE(1810013, "不存在该表单类型", null),
+ VISIT_RECORD_NOT_EXIST(1820001, "拜访记录不存在", null),
+ VISIT_RECORD_NOT_COMPLETE_EDIT(1820002, "未编辑拜访信息,无法签退", null),
+ VISIT_RECORD_INVALID(1820003, "拜访记录已失效", null),
+ VISIT_RECORD_NOT_YOUR_OWN(1820004, "非拜访人,无法操作", null),
+ VISIT_RECORD_COMPLETE(1820005, "已完成拜访", null),
CITY_PLANNING_EXISTS(1820001, "同年份同季度同省市已存在规划,不能重复添加", null),
;
diff --git a/coolstore-partner-common/src/main/java/com/cool/store/enums/RocketMqGroupEnum.java b/coolstore-partner-common/src/main/java/com/cool/store/enums/RocketMqGroupEnum.java
index 73b600d3f..576928f44 100644
--- a/coolstore-partner-common/src/main/java/com/cool/store/enums/RocketMqGroupEnum.java
+++ b/coolstore-partner-common/src/main/java/com/cool/store/enums/RocketMqGroupEnum.java
@@ -37,7 +37,7 @@ public enum RocketMqGroupEnum {
SHOP_DECORATION_ASSIGN("shop_decoration_assign", new ArrayList<>(Arrays.asList(RocketMqTagEnum.DELAY_SHOP_DECORATION_ASSIGN))),
STORE_MASTER_ISSUE("store_master_issue", new ArrayList<>(Arrays.asList(RocketMqTagEnum.STORE_MASTER_ISSUE))),
-
+ VISIT_RECORD_INVALID("visit_record_invalid", new ArrayList<>(Arrays.asList(RocketMqTagEnum.VISIT_RECORD_INVALID))),
;
private final String group;
diff --git a/coolstore-partner-common/src/main/java/com/cool/store/enums/RocketMqTagEnum.java b/coolstore-partner-common/src/main/java/com/cool/store/enums/RocketMqTagEnum.java
index f630aebb8..90a73f27e 100644
--- a/coolstore-partner-common/src/main/java/com/cool/store/enums/RocketMqTagEnum.java
+++ b/coolstore-partner-common/src/main/java/com/cool/store/enums/RocketMqTagEnum.java
@@ -21,6 +21,7 @@ public enum RocketMqTagEnum {
STORE_USER_UPDATE("store_user_update", "门店信息人员变更同步菜品"),
DELAY_SHOP_DECORATION_ASSIGN("shop_decoration_assign","门店装修分配"),
STORE_MASTER_ISSUE("store_master_issue","门店主数据下发"),
+ VISIT_RECORD_INVALID("visit_record_invalid", "拜访记录失效"),
;
diff --git a/coolstore-partner-common/src/main/java/com/cool/store/enums/visit/VisitStatusEnum.java b/coolstore-partner-common/src/main/java/com/cool/store/enums/visit/VisitStatusEnum.java
new file mode 100644
index 000000000..75731139b
--- /dev/null
+++ b/coolstore-partner-common/src/main/java/com/cool/store/enums/visit/VisitStatusEnum.java
@@ -0,0 +1,39 @@
+package com.cool.store.enums.visit;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ *
+ * 拜访记录状态枚举类
+ *
+ *
+ * @author wangff
+ * @since 2025/12/8
+ */
+@Getter
+@AllArgsConstructor
+public enum VisitStatusEnum {
+
+ N_SIGN_IN(0, "待签到"),
+
+ N_SIGN_OUT(1, "待签退"),
+
+ COMPLETE(2, "已完成"),
+
+ INVALID(3, "已失效"),
+ ;
+
+ private final Integer status;
+
+ private final String desc;
+
+ public static String getDescByStatus(Integer status) {
+ for (VisitStatusEnum value : values()) {
+ if (value.status.equals(status)) {
+ return value.desc;
+ }
+ }
+ return null;
+ }
+}
diff --git a/coolstore-partner-dao/src/main/java/com/cool/store/dao/store/StoreMasterSignerInfoDAO.java b/coolstore-partner-dao/src/main/java/com/cool/store/dao/store/StoreMasterSignerInfoDAO.java
index b23f6492b..fb687e777 100644
--- a/coolstore-partner-dao/src/main/java/com/cool/store/dao/store/StoreMasterSignerInfoDAO.java
+++ b/coolstore-partner-dao/src/main/java/com/cool/store/dao/store/StoreMasterSignerInfoDAO.java
@@ -6,7 +6,9 @@ import com.cool.store.mapper.store.StoreMasterSignerInfoMapper;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Repository;
+import tk.mybatis.mapper.entity.Example;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -41,4 +43,15 @@ public class StoreMasterSignerInfoDAO {
public StoreMasterSignerInfoDO getByStoreId(String storeId) {
return storeMasterSignerInfoMapper.selectOne(StoreMasterSignerInfoDO.builder().storeId(storeId).build());
}
+
+ public List getListByIdCard(Collection idCards) {
+ if (CollectionUtils.isEmpty(idCards)) {
+ return Collections.emptyList();
+ }
+ Example example = new Example(StoreMasterSignerInfoDO.class);
+ example.createCriteria()
+ .orIn("signer1IdCardNo", idCards)
+ .orIn("signer2IdCardNo", idCards);
+ return storeMasterSignerInfoMapper.selectByExample(example);
+ }
}
diff --git a/coolstore-partner-dao/src/main/java/com/cool/store/dao/visit/VisitRecordDAO.java b/coolstore-partner-dao/src/main/java/com/cool/store/dao/visit/VisitRecordDAO.java
new file mode 100644
index 000000000..f8f0ff9f7
--- /dev/null
+++ b/coolstore-partner-dao/src/main/java/com/cool/store/dao/visit/VisitRecordDAO.java
@@ -0,0 +1,126 @@
+package com.cool.store.dao.visit;
+
+import com.alibaba.excel.util.CollectionUtils;
+import com.cool.store.entity.visit.VisitRecordDO;
+import com.cool.store.enums.visit.VisitStatusEnum;
+import com.cool.store.mapper.visit.VisitRecordMapper;
+import com.cool.store.request.visit.VisitRecordQueryRequest;
+import com.cool.store.vo.visit.VisitPartnerListVO;
+import com.cool.store.vo.visit.VisitRecordListVO;
+import com.cool.store.vo.visit.VisitRecordStatusStatisticsVO;
+import lombok.AllArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
+import tk.mybatis.mapper.entity.Example;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+/**
+ *
+ * 拜访记录DAO
+ *
+ *
+ * @author wangff
+ * @since 2025/12/8
+ */
+@Repository
+@AllArgsConstructor
+public class VisitRecordDAO {
+ private final VisitRecordMapper visitRecordMapper;
+
+ public Boolean insertSelective(VisitRecordDO visitRecordDO) {
+ return visitRecordMapper.insertSelective(visitRecordDO) > 0;
+ }
+
+ public Boolean updateSelective(VisitRecordDO visitRecordDO) {
+ return visitRecordMapper.updateByPrimaryKeySelective(visitRecordDO) > 0;
+ }
+
+ public VisitRecordDO getById(Long id) {
+ return visitRecordMapper.selectByPrimaryKey(id);
+ }
+
+ /**
+ * 查询拜访加盟商
+ * @param regionIds 加盟商所属大区id
+ * @param keyword 加盟商姓名或手机号
+ * @return 拜访加盟商列表VO
+ */
+ public List getPartnerList(List regionIds, String keyword, String userId) {
+ return visitRecordMapper.getPartnerList(regionIds, keyword, userId);
+ }
+
+ /**
+ * 查询拜访加盟商线索id
+ * @param regionIds 加盟商所属大区id
+ * @param keyword 加盟商姓名或手机号
+ * @param userId 拜访用户id
+ * @return 线索id列表
+ */
+ public List getPartnerLineId(List regionIds, String keyword, String userId) {
+ return visitRecordMapper.getPartnerLineId(regionIds, keyword, userId);
+ }
+
+ /**
+ * 根据线索id查询拜访记录列表
+ * @param lineIds 线索id
+ * @return 拜访记录列表VO列表
+ */
+ public List getVisitRecordListByLineIds(List lineIds, String userId) {
+ if (CollectionUtils.isEmpty(lineIds)) {
+ return Collections.emptyList();
+ }
+ return visitRecordMapper.getVisitRecordListByLineIds(lineIds, userId);
+ }
+
+ /**
+ * 根据线索查询
+ * @param lineId 线索id
+ * @param startDate 开始日期
+ * @param endDate 结束日期
+ * @return 拜访记录列表
+ */
+ public List getByLineId(Long lineId, Date startDate, Date endDate, String userId) {
+ Example example = new Example(VisitRecordDO.class);
+ Example.Criteria criteria = example.createCriteria().andEqualTo("lineId", lineId)
+ .andGreaterThanOrEqualTo("visitDate", startDate)
+ .andLessThanOrEqualTo("visitDate", endDate);
+ if (StringUtils.isNotBlank(userId)) {
+ criteria.andEqualTo("userId", userId);
+ }
+ example.setOrderByClause("create_time DESC");
+ return visitRecordMapper.selectByExample(example);
+ }
+
+ public Boolean deleteById(Long id) {
+ return visitRecordMapper.deleteByPrimaryKey(id) > 0;
+ }
+
+ /**
+ * 拜访记录列表
+ * @param request 拜访记录查询Request
+ * @return 拜访记录列表VO列表
+ */
+ public List getVisitRecordList(VisitRecordQueryRequest request) {
+ return visitRecordMapper.getVisitRecordList(request);
+ }
+
+ /**
+ * 根据线索id查询已完成拜访数量
+ * @param lineId 线索id
+ * @return 数量
+ */
+ public Integer getCompleteVisitNum(Long lineId) {
+ return visitRecordMapper.selectCount(VisitRecordDO.builder().lineId(lineId).status(VisitStatusEnum.COMPLETE.getStatus()).build());
+ }
+
+ /**
+ * 统计
+ */
+ public VisitRecordStatusStatisticsVO countStatusStatistics(VisitRecordQueryRequest request) {
+ return visitRecordMapper.countStatusStatistics(request);
+ }
+}
diff --git a/coolstore-partner-dao/src/main/java/com/cool/store/mapper/RegionMapper.java b/coolstore-partner-dao/src/main/java/com/cool/store/mapper/RegionMapper.java
index 29cb18e1d..df82b169b 100644
--- a/coolstore-partner-dao/src/main/java/com/cool/store/mapper/RegionMapper.java
+++ b/coolstore-partner-dao/src/main/java/com/cool/store/mapper/RegionMapper.java
@@ -87,6 +87,8 @@ public interface RegionMapper {
List getSubRegionIdsByRegionIds( @Param("regionIds")List regionIds);
+ List getSubRegionIdsExcludeStore(@Param("regionIds")List regionIds);
+
List getSubRegionIdsByRegionIdList( @Param("regionIds")List regionIds);
List getStoreIdsByRegionIds( @Param("regionIds")List regionIds);
diff --git a/coolstore-partner-dao/src/main/java/com/cool/store/mapper/oplog/SysLogMapper.java b/coolstore-partner-dao/src/main/java/com/cool/store/mapper/oplog/SysLogMapper.java
new file mode 100644
index 000000000..264b647a9
--- /dev/null
+++ b/coolstore-partner-dao/src/main/java/com/cool/store/mapper/oplog/SysLogMapper.java
@@ -0,0 +1,7 @@
+package com.cool.store.mapper.oplog;
+
+import com.cool.store.entity.oplog.SysLogDO;
+import tk.mybatis.mapper.common.Mapper;
+
+public interface SysLogMapper extends Mapper {
+}
\ No newline at end of file
diff --git a/coolstore-partner-dao/src/main/java/com/cool/store/mapper/visit/VisitRecordMapper.java b/coolstore-partner-dao/src/main/java/com/cool/store/mapper/visit/VisitRecordMapper.java
new file mode 100644
index 000000000..f63426cfb
--- /dev/null
+++ b/coolstore-partner-dao/src/main/java/com/cool/store/mapper/visit/VisitRecordMapper.java
@@ -0,0 +1,57 @@
+package com.cool.store.mapper.visit;
+
+import com.cool.store.entity.visit.VisitRecordDO;
+import com.cool.store.request.visit.VisitRecordQueryRequest;
+import com.cool.store.vo.visit.VisitPartnerListVO;
+import com.cool.store.vo.visit.VisitRecordListVO;
+import com.cool.store.vo.visit.VisitRecordStatusStatisticsVO;
+import org.apache.ibatis.annotations.Param;
+import tk.mybatis.mapper.common.Mapper;
+
+import java.util.List;
+
+public interface VisitRecordMapper extends Mapper {
+
+ /**
+ * 查询拜访加盟商
+ * @param regionIds 加盟商所属大区id
+ * @param keyword 加盟商姓名或手机号
+ * @return 拜访加盟商列表VO
+ */
+ List getPartnerList(@Param("regionIds") List regionIds,
+ @Param("keyword") String keyword,
+ @Param("userId") String userId);
+
+ /**
+ * 拜访记录列表
+ * @param request 拜访记录查询Request
+ * @return 拜访记录列表VO列表
+ */
+ List getVisitRecordList(@Param("request") VisitRecordQueryRequest request);
+
+ /**
+ * 查询拜访加盟商线索id
+ * @param regionIds 加盟商所属大区id
+ * @param keyword 加盟商姓名或手机号
+ * @param userId 拜访用户id
+ * @return 线索id列表
+ */
+ List getPartnerLineId(@Param("regionIds") List regionIds,
+ @Param("keyword") String keyword,
+ @Param("userId") String userId);
+
+ /**
+ * 根据线索id查询拜访记录列表
+ * @param lineIds 线索id
+ * @return 拜访记录列表VO列表
+ */
+ List getVisitRecordListByLineIds(@Param("lineIds") List lineIds, @Param("userId") String userId);
+
+ /**
+ * 统计:本月已完成数量、全部已完成数量、全部未完成数量、全部已失效数量
+ * - 本月口径:按 visit_date 在本月范围内且 status=2
+ * - 全部口径:不限制月份
+ */
+ VisitRecordStatusStatisticsVO countStatusStatistics(@Param("request") VisitRecordQueryRequest request);
+
+}
\ No newline at end of file
diff --git a/coolstore-partner-dao/src/main/resources/mapper/RegionMapper.xml b/coolstore-partner-dao/src/main/resources/mapper/RegionMapper.xml
index f7aea2ac8..92c0973c7 100644
--- a/coolstore-partner-dao/src/main/resources/mapper/RegionMapper.xml
+++ b/coolstore-partner-dao/src/main/resources/mapper/RegionMapper.xml
@@ -285,6 +285,17 @@
region_path like concat("%/", #{region}, "/%")
+
+