提交 e1059dbb authored 作者: douxy's avatar douxy

CP计划小程序改造,新增模板改造,导出飞书文件改造

上级 e5ea8462
package com.wangxiaolu.promotion.controller.activity.temporary; package com.wangxiaolu.promotion.controller.activity.temporary;
import com.wangxiaolu.promotion.controller.user.tem.TemporaryInfoQueryController;
import com.wangxiaolu.promotion.domain.user.dao.TemporaryInfoDao; import com.wangxiaolu.promotion.domain.user.dao.TemporaryInfoDao;
import com.wangxiaolu.promotion.enums.activity.TemActApproveStatus; import com.wangxiaolu.promotion.enums.activity.TemActApproveStatus;
import com.wangxiaolu.promotion.exception.DataException; import com.wangxiaolu.promotion.exception.DataException;
...@@ -14,6 +15,7 @@ import com.wangxiaolu.promotion.service.activity.temporary.TemporaryActivityCloc ...@@ -14,6 +15,7 @@ import com.wangxiaolu.promotion.service.activity.temporary.TemporaryActivityCloc
import com.wangxiaolu.promotion.service.activity.temporary.TemporaryActivityClockQueryService; import com.wangxiaolu.promotion.service.activity.temporary.TemporaryActivityClockQueryService;
import com.wangxiaolu.promotion.service.activity.temporary.TemporaryActivityCoreService; import com.wangxiaolu.promotion.service.activity.temporary.TemporaryActivityCoreService;
import com.wangxiaolu.promotion.service.activity.temporary.TemporaryActivityQueryService; import com.wangxiaolu.promotion.service.activity.temporary.TemporaryActivityQueryService;
import com.wangxiaolu.promotion.service.wechat.WeChatUserQueryService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
...@@ -41,6 +43,9 @@ public class TemporaryActivityCoreController { ...@@ -41,6 +43,9 @@ public class TemporaryActivityCoreController {
@Autowired @Autowired
private TemporaryActivityClockCoreService tempActivityClockCoreService; private TemporaryActivityClockCoreService tempActivityClockCoreService;
@Autowired
private WeChatUserQueryService weChatUserQueryService;
/** /**
* 促销员[今日活动]数据保存 * 促销员[今日活动]数据保存
* 返回活动生成id * 返回活动生成id
...@@ -54,6 +59,11 @@ public class TemporaryActivityCoreController { ...@@ -54,6 +59,11 @@ public class TemporaryActivityCoreController {
TemporaryActivityReportedDto temActDto = new TemporaryActivityReportedDto(); TemporaryActivityReportedDto temActDto = new TemporaryActivityReportedDto();
BeanUtils.copyProperties(activityVo, temActDto); BeanUtils.copyProperties(activityVo, temActDto);
temActDto.setId(activityVo.getActivityReportedId()); temActDto.setId(activityVo.getActivityReportedId());
//保存促销员电话号码
String temporaryPhone = weChatUserQueryService.findUserPhoneByID(activityVo.getTemporaryId());
temActDto.setTemporaryPhone(temporaryPhone);
/** /**
* 已有id,修改任务 * 已有id,修改任务
*/ */
...@@ -78,7 +88,8 @@ public class TemporaryActivityCoreController { ...@@ -78,7 +88,8 @@ public class TemporaryActivityCoreController {
.setActivityPatternId(clockDto.getActivityPatternId()) .setActivityPatternId(clockDto.getActivityPatternId())
.setActivityPattern(clockDto.getActivityPattern()) .setActivityPattern(clockDto.getActivityPattern())
.setProvince(clockDto.getClockProvince()) .setProvince(clockDto.getClockProvince())
.setCity(clockDto.getClockCity()); .setCity(clockDto.getClockCity()).setTemporaryPhone(clockDto.getPhone())
;
long reportedId = tempActivityCoreService.activityDataReportedSave(temActDto); long reportedId = tempActivityCoreService.activityDataReportedSave(temActDto);
......
...@@ -17,6 +17,7 @@ import lombok.extern.slf4j.Slf4j; ...@@ -17,6 +17,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.io.File;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.YearMonth; import java.time.YearMonth;
......
package com.wangxiaolu.promotion.controller.user.location;
import com.wangxiaolu.promotion.result.basedata.R;
import com.wangxiaolu.promotion.service.user.TencentLocationQueryService;
import com.wangxiaolu.promotion.utils.TencentMapUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* @Author: DouXinYu
* @Date: 2026-01-12 11:10
* @Description:
*/
@RestController
@RequestMapping("/user/location/query")
public class TencentLocationController {
@Autowired
TencentLocationQueryService tencentLocationQueryService;
@GetMapping("/reverse")
public R getDefaultLocation(@RequestParam("lng") double lng, @RequestParam("lat") double lat){
TencentMapUtil.AddressInfo addressByLngLat = tencentLocationQueryService.getAddressByLngLat(lng, lat);
return R.success(addressByLngLat);
}
@GetMapping("/list")
public R getProvinceDistinctList(){
return R.success(tencentLocationQueryService.getAddressList());
}
}
...@@ -77,4 +77,5 @@ public class ActivityPlanInfoVo { ...@@ -77,4 +77,5 @@ public class ActivityPlanInfoVo {
private String lineName; private String lineName;
} }
...@@ -158,14 +158,24 @@ public class ActivityPlanInfoDto implements Serializable { ...@@ -158,14 +158,24 @@ public class ActivityPlanInfoDto implements Serializable {
*/ */
// private BigDecimal incidentals; // private BigDecimal incidentals;
/** /**
* 是否有试吃台 * 门店是否已配试吃台
*/ */
private String temWlSct; private String temWlSct;
/** /**
* 活动品项:老品/黑鸭/散称 * 活动品项:老品/黑鸭/散称/礼盒
*/ */
private String prdClass; private String prdClass;
/**
* 活动执行方式:经销商/第三方
*/
private String planExecuteMode;
/**
* 门店是否允许使用试吃台
*/
private String isCanUseTasteCounter;
/** /**
* 是否执行:1:执行;0:未执行; * 是否执行:1:执行;0:未执行;
*/ */
......
...@@ -80,12 +80,21 @@ public class ActivityPlanOperVo { ...@@ -80,12 +80,21 @@ public class ActivityPlanOperVo {
private LocalDateTime noonClockInTime; private LocalDateTime noonClockInTime;
/** /**
* 是否有试吃台 * 门店是否可用试吃台
*/
private String isCanUseTasteCounter;
/**
* 门店是否配有试吃台
*/ */
private String temWlSct; private String temWlSct;
/** /**
* 活动品项:老品/黑鸭/散称 * 活动品项:老品/黑鸭/散称/礼盒
*/ */
private String prdClass; private String prdClass;
/**
* 执行方式
*/
private String planExecuteMode;
private List<Long> planIds; private List<Long> planIds;
} }
...@@ -18,6 +18,7 @@ import com.wangxiaolu.promotion.pojo.activity.planv2.dto.ActivityPlanInfoDto; ...@@ -18,6 +18,7 @@ import com.wangxiaolu.promotion.pojo.activity.planv2.dto.ActivityPlanInfoDto;
import com.wangxiaolu.promotion.pojo.activity.temporary.dto.TemporaryActivityMarketCellDto; import com.wangxiaolu.promotion.pojo.activity.temporary.dto.TemporaryActivityMarketCellDto;
import com.wangxiaolu.promotion.pojo.activity.temporary.dto.TemporaryActivityReportedDto; import com.wangxiaolu.promotion.pojo.activity.temporary.dto.TemporaryActivityReportedDto;
import com.wangxiaolu.promotion.pojo.activity.temporary.vo.TemporaryActivityMarketCellVo; import com.wangxiaolu.promotion.pojo.activity.temporary.vo.TemporaryActivityMarketCellVo;
import com.wangxiaolu.promotion.pojo.user.dto.WxTemporaryInfoDto;
import com.wangxiaolu.promotion.result.basedata.RCode; import com.wangxiaolu.promotion.result.basedata.RCode;
import com.wangxiaolu.promotion.service.activity.temporary.TemporaryActivityClockQueryService; import com.wangxiaolu.promotion.service.activity.temporary.TemporaryActivityClockQueryService;
import com.wangxiaolu.promotion.service.activity.temporary.TemporaryActivityCoreService; import com.wangxiaolu.promotion.service.activity.temporary.TemporaryActivityCoreService;
...@@ -88,6 +89,7 @@ public class TemporaryActivityCoreServiceImpl implements TemporaryActivityCoreSe ...@@ -88,6 +89,7 @@ public class TemporaryActivityCoreServiceImpl implements TemporaryActivityCoreSe
// 保存图片 // 保存图片
saveActivityPhotoV2(temActDto); saveActivityPhotoV2(temActDto);
// 售卖单元新增保存 // 售卖单元新增保存
// String key = temMarketCellRedisKey(temActDto.getTemporaryId()); // String key = temMarketCellRedisKey(temActDto.getTemporaryId());
// temporaryActivityMarketCellDao.saveList(reportedId,redisCache.getToJsonArray(key)); // temporaryActivityMarketCellDao.saveList(reportedId,redisCache.getToJsonArray(key));
...@@ -113,6 +115,8 @@ public class TemporaryActivityCoreServiceImpl implements TemporaryActivityCoreSe ...@@ -113,6 +115,8 @@ public class TemporaryActivityCoreServiceImpl implements TemporaryActivityCoreSe
}else { }else {
temActDto.setApproveStatus(TemActApproveStatus.SUBMITTED); temActDto.setApproveStatus(TemActApproveStatus.SUBMITTED);
} }
WxTemporaryInfoDto wxTemporaryInfoDto = temporaryInfoDao.selectOneById(temActDto.getTemporaryId());
temActDto.setTemporaryPhone(wxTemporaryInfoDto.getPhone());
temporaryActivityReportedDao.updateById(temActDto); temporaryActivityReportedDao.updateById(temActDto);
// 售卖单元新增保存 // 售卖单元新增保存
......
...@@ -91,7 +91,7 @@ public class PromPlanCoreServiceImpl implements PromPlanCoreService { ...@@ -91,7 +91,7 @@ public class PromPlanCoreServiceImpl implements PromPlanCoreService {
String[] headers = readExcelUtils.readTitle(); String[] headers = readExcelUtils.readTitle();
Map<Integer, List<Object>> rows = readExcelUtils.readContent(); Map<Integer, List<Object>> rows = readExcelUtils.readContent();
if (headers.length != 12) { if (headers.length != 14) {
throw new DataException(RCode.ACTIVITY_PLAN_TEM_ERROR); throw new DataException(RCode.ACTIVITY_PLAN_TEM_ERROR);
} }
if (CollectionUtil.isEmpty(rows)) { if (CollectionUtil.isEmpty(rows)) {
...@@ -102,7 +102,7 @@ public class PromPlanCoreServiceImpl implements PromPlanCoreService { ...@@ -102,7 +102,7 @@ public class PromPlanCoreServiceImpl implements PromPlanCoreService {
for (Map.Entry<Integer, List<Object>> row : rows.entrySet()) { for (Map.Entry<Integer, List<Object>> row : rows.entrySet()) {
List<Object> cells = row.getValue(); List<Object> cells = row.getValue();
// 判断当前行是否有任一数据为空,如果有则报错,不进行解析 // 判断当前行是否有任一数据为空,如果有则报错,不进行解析
boolean isEmpty = (cells.size() != 12) || cells.stream().anyMatch(cell -> ObjectUtil.isNull(cell) || StringUtils.isBlank(cell.toString())); boolean isEmpty = (cells.size() != 14) || cells.stream().anyMatch(cell -> ObjectUtil.isNull(cell) || StringUtils.isBlank(cell.toString()));
if (isEmpty) { if (isEmpty) {
indexList.add(row.getKey() + 1); indexList.add(row.getKey() + 1);
} }
...@@ -171,7 +171,7 @@ public class PromPlanCoreServiceImpl implements PromPlanCoreService { ...@@ -171,7 +171,7 @@ public class PromPlanCoreServiceImpl implements PromPlanCoreService {
dto.setErrorMsg("门店编码错误;"); dto.setErrorMsg("门店编码错误;");
} else { } else {
if (StringUtils.isAnyBlank(storeDto.getDealersName(), storeDto.getDealerId())) { if (StringUtils.isAnyBlank(storeDto.getDealersName(), storeDto.getDealerId())) {
dto.setErrorMsg("门店「经销商」为空,请到勤策中充;"); dto.setErrorMsg("门店「经销商」为空,请到勤策中充;");
} }
dto.setLineName(storeDto.getLineName()); dto.setLineName(storeDto.getLineName());
dto.setStoreCode(sc); dto.setStoreCode(sc);
...@@ -188,10 +188,10 @@ public class PromPlanCoreServiceImpl implements PromPlanCoreService { ...@@ -188,10 +188,10 @@ public class PromPlanCoreServiceImpl implements PromPlanCoreService {
* 3:活动模式 * 3:活动模式
*/ */
String pattern = row.get(3).toString(); String pattern = row.get(3).toString();
if ("单点CP,常规MINI秀,校园活动".contains(pattern)) { if ("大区KA,重客KA,大区零食,重客零食,场景营销".contains(pattern)) {
dto.setPattern(pattern); dto.setPattern(pattern);
} else { } else {
dto.setErrorMsg("活动模式分为:单点CP、常规MINI秀、校园活动;"); dto.setErrorMsg("活动模式分为:大区KA、重客KA、大区零食、重客零食、场景营销;");
} }
/** /**
...@@ -248,24 +248,43 @@ public class PromPlanCoreServiceImpl implements PromPlanCoreService { ...@@ -248,24 +248,43 @@ public class PromPlanCoreServiceImpl implements PromPlanCoreService {
/** /**
* 10:是否有促销台/试吃台 * 10:门店是否可用试吃台
*/ */
String temWlSct = row.get(10).toString(); String isCanUseTasteCounter = row.get(10).toString();
if ("有,无".contains(temWlSct)) { if ("是,否".contains(isCanUseTasteCounter)) {
dto.setTemWlSct(temWlSct); dto.setIsCanUseTasteCounter(isCanUseTasteCounter);
} else { } else {
dto.setErrorMsg("是否有促销台请填写:有、无;"); dto.setErrorMsg("门店是否可用试吃台请填写:是、否;");
} }
/**
* 11:门店是否已配试吃台
*/
String temWlSct = row.get(11).toString();
if ("是,否".contains(temWlSct)) {
dto.setTemWlSct(temWlSct);
} else {
dto.setErrorMsg("门店是否已配试吃台请填写:是、否;");
}
/** /**
* 11:活动品项 * 12:活动品项
*/ */
String prdClass = row.get(11).toString(); String prdClass = row.get(12).toString();
if ("黑鸭,散称,老品".contains(prdClass)) { if ("黑鸭,散称,老品,礼盒".contains(prdClass)) {
dto.setPrdClass(prdClass); dto.setPrdClass(prdClass);
} else { } else {
dto.setErrorMsg("活动品项请填写:黑鸭、散称、老品;"); dto.setErrorMsg("活动品项请填写:黑鸭、散称、老品、礼盒;");
}
/**
* 13:活动执行模式
*/
String planExecuteMode = row.get(13).toString();
if ("第三方,经销商".contains(planExecuteMode)) {
dto.setPlanExecuteMode(planExecuteMode);
}else {
dto.setErrorMsg("活动执行模式请填写:第三方、经销商;");
} }
// 作废:工资 // 作废:工资
...@@ -325,7 +344,7 @@ public class PromPlanCoreServiceImpl implements PromPlanCoreService { ...@@ -325,7 +344,7 @@ public class PromPlanCoreServiceImpl implements PromPlanCoreService {
String[] headers = readExcelUtils.readTitle(); String[] headers = readExcelUtils.readTitle();
Map<Integer, List<Object>> rows = readExcelUtils.readContent(); Map<Integer, List<Object>> rows = readExcelUtils.readContent();
if (headers.length != 12) { if (headers.length != 14) {
throw new DataException(RCode.ACTIVITY_PLAN_TEM_ERROR); throw new DataException(RCode.ACTIVITY_PLAN_TEM_ERROR);
} }
if (CollectionUtil.isEmpty(rows)) { if (CollectionUtil.isEmpty(rows)) {
...@@ -336,7 +355,7 @@ public class PromPlanCoreServiceImpl implements PromPlanCoreService { ...@@ -336,7 +355,7 @@ public class PromPlanCoreServiceImpl implements PromPlanCoreService {
for (Map.Entry<Integer, List<Object>> row : rows.entrySet()) { for (Map.Entry<Integer, List<Object>> row : rows.entrySet()) {
List<Object> cells = row.getValue(); List<Object> cells = row.getValue();
// 判断当前行是否有任一数据为空,如果有则报错,不进行解析 // 判断当前行是否有任一数据为空,如果有则报错,不进行解析
boolean isEmpty = (cells.size() != 12) || cells.stream().anyMatch(cell -> ObjectUtil.isNull(cell) || StringUtils.isBlank(cell.toString())); boolean isEmpty = (cells.size() != 14) || cells.stream().anyMatch(cell -> ObjectUtil.isNull(cell) || StringUtils.isBlank(cell.toString()));
if (isEmpty) { if (isEmpty) {
indexList.add(row.getKey() + 1); indexList.add(row.getKey() + 1);
} }
...@@ -409,7 +428,7 @@ public class PromPlanCoreServiceImpl implements PromPlanCoreService { ...@@ -409,7 +428,7 @@ public class PromPlanCoreServiceImpl implements PromPlanCoreService {
dto.setErrorMsg("门店编码错误;"); dto.setErrorMsg("门店编码错误;");
} else { } else {
if (StringUtils.isAnyBlank(storeDto.getDealersName(), storeDto.getDealerId())) { if (StringUtils.isAnyBlank(storeDto.getDealersName(), storeDto.getDealerId())) {
dto.setErrorMsg("门店「经销商」为空,请到勤策中充;"); dto.setErrorMsg("门店「经销商」为空,请到勤策中充;");
} }
dto.setLineName(storeDto.getLineName()); dto.setLineName(storeDto.getLineName());
dto.setStoreCode(sc); dto.setStoreCode(sc);
...@@ -426,10 +445,10 @@ public class PromPlanCoreServiceImpl implements PromPlanCoreService { ...@@ -426,10 +445,10 @@ public class PromPlanCoreServiceImpl implements PromPlanCoreService {
* 3:活动模式 * 3:活动模式
*/ */
String pattern = row.get(3).toString(); String pattern = row.get(3).toString();
if ("单点CP,常规MINI秀,校园活动".contains(pattern)) { if ("大区KA,重客KA,大区零食,重客零食,场景营销".contains(pattern)) {
dto.setPattern(pattern); dto.setPattern(pattern);
} else { } else {
dto.setErrorMsg("活动模式分为:单点CP、常规MINI秀、校园活动;"); dto.setErrorMsg("活动模式分为:大区KA、重客KA、大区零食、重客零食、场景营销;");
} }
/** /**
...@@ -482,23 +501,43 @@ public class PromPlanCoreServiceImpl implements PromPlanCoreService { ...@@ -482,23 +501,43 @@ public class PromPlanCoreServiceImpl implements PromPlanCoreService {
} }
/** /**
* 10:是否有促销台/试吃台 * 10:门店是否可用试吃台
*/
String isCanUseTasteCounter = row.get(10).toString();
if ("是,否".contains(isCanUseTasteCounter)) {
dto.setIsCanUseTasteCounter(isCanUseTasteCounter);
} else {
dto.setErrorMsg("门店是否可用试吃台请填写:是、否;");
}
/**
* 11:门店是否已配试吃台
*/ */
String temWlSct = row.get(10).toString(); String temWlSct = row.get(11).toString();
if ("有,无".contains(temWlSct)) { if ("是,否".contains(temWlSct)) {
dto.setTemWlSct(temWlSct); dto.setTemWlSct(temWlSct);
} else { } else {
dto.setErrorMsg("是否有促销台请填写:有、无;"); dto.setErrorMsg("门店是否已配试吃台请填写:是、否;");
} }
/** /**
* 11:活动品项 * 12:活动品项
*/ */
String prdClass = row.get(11).toString(); String prdClass = row.get(12).toString();
if ("黑鸭,散称,老品".contains(prdClass)) { if ("黑鸭,散称,老品,礼盒".contains(prdClass)) {
dto.setPrdClass(prdClass); dto.setPrdClass(prdClass);
} else { } else {
dto.setErrorMsg("活动品项请填写:黑鸭、散称、老品;"); dto.setErrorMsg("活动品项请填写:黑鸭、散称、老品、礼盒;");
}
/**
* 13:活动执行模式
*/
String planExecuteMode = row.get(13).toString();
if ("第三方,经销商".contains(planExecuteMode)) {
dto.setPlanExecuteMode(planExecuteMode);
}else {
dto.setErrorMsg("活动执行模式请填写:第三方、经销商;");
} }
// 8:工资 // 8:工资
...@@ -605,8 +644,10 @@ public class PromPlanCoreServiceImpl implements PromPlanCoreService { ...@@ -605,8 +644,10 @@ public class PromPlanCoreServiceImpl implements PromPlanCoreService {
.setClockOutTime(operVo.getClockOutTime()) .setClockOutTime(operVo.getClockOutTime())
.setNoonClockOutTime(operVo.getNoonClockOutTime()) .setNoonClockOutTime(operVo.getNoonClockOutTime())
.setNoonClockInTime(operVo.getNoonClockInTime()) .setNoonClockInTime(operVo.getNoonClockInTime())
.setIsCanUseTasteCounter(operVo.getIsCanUseTasteCounter())
.setTemWlSct(operVo.getTemWlSct()) .setTemWlSct(operVo.getTemWlSct())
.setPrdClass(operVo.getPrdClass()) .setPrdClass(operVo.getPrdClass())
.setPlanExecuteMode(operVo.getPlanExecuteMode())
.setModifyBy(operVo.getOperName()); .setModifyBy(operVo.getOperName());
activityPlanInfoDao.updateById(planDto); activityPlanInfoDao.updateById(planDto);
} }
...@@ -641,8 +682,10 @@ public class PromPlanCoreServiceImpl implements PromPlanCoreService { ...@@ -641,8 +682,10 @@ public class PromPlanCoreServiceImpl implements PromPlanCoreService {
.setClockOutTime(operVo.getClockOutTime()) .setClockOutTime(operVo.getClockOutTime())
.setNoonClockOutTime(operVo.getNoonClockOutTime()) .setNoonClockOutTime(operVo.getNoonClockOutTime())
.setNoonClockInTime(operVo.getNoonClockInTime()) .setNoonClockInTime(operVo.getNoonClockInTime())
.setIsCanUseTasteCounter(operVo.getIsCanUseTasteCounter())
.setTemWlSct(operVo.getTemWlSct()) .setTemWlSct(operVo.getTemWlSct())
.setPrdClass(operVo.getPrdClass()) .setPrdClass(operVo.getPrdClass())
.setPlanExecuteMode(operVo.getPlanExecuteMode())
.setCreateBy(operVo.getOperName()); .setCreateBy(operVo.getOperName());
activityPlanInfoDao.save(planDto); activityPlanInfoDao.save(planDto);
} }
...@@ -673,7 +716,7 @@ public class PromPlanCoreServiceImpl implements PromPlanCoreService { ...@@ -673,7 +716,7 @@ public class PromPlanCoreServiceImpl implements PromPlanCoreService {
String[] headers = readExcelUtils.readTitle(); String[] headers = readExcelUtils.readTitle();
Map<Integer, List<Object>> rows = readExcelUtils.readContent(); Map<Integer, List<Object>> rows = readExcelUtils.readContent();
if (headers.length != 12) { if (headers.length != 14) {
throw new DataException(RCode.ACTIVITY_PLAN_TEM_ERROR); throw new DataException(RCode.ACTIVITY_PLAN_TEM_ERROR);
} }
if (CollectionUtil.isEmpty(rows)) { if (CollectionUtil.isEmpty(rows)) {
...@@ -684,7 +727,7 @@ public class PromPlanCoreServiceImpl implements PromPlanCoreService { ...@@ -684,7 +727,7 @@ public class PromPlanCoreServiceImpl implements PromPlanCoreService {
for (Map.Entry<Integer, List<Object>> row : rows.entrySet()) { for (Map.Entry<Integer, List<Object>> row : rows.entrySet()) {
List<Object> cells = row.getValue(); List<Object> cells = row.getValue();
// 判断当前行是否有任一数据为空,如果有则报错,不进行解析 // 判断当前行是否有任一数据为空,如果有则报错,不进行解析
boolean isEmpty = (cells.size() != 12) || cells.stream().anyMatch(cell -> ObjectUtil.isNull(cell) || StringUtils.isBlank(cell.toString())); boolean isEmpty = (cells.size() != 14) || cells.stream().anyMatch(cell -> ObjectUtil.isNull(cell) || StringUtils.isBlank(cell.toString()));
if (isEmpty) { if (isEmpty) {
indexList.add(row.getKey() + 1); indexList.add(row.getKey() + 1);
} }
...@@ -747,7 +790,7 @@ public class PromPlanCoreServiceImpl implements PromPlanCoreService { ...@@ -747,7 +790,7 @@ public class PromPlanCoreServiceImpl implements PromPlanCoreService {
dto.setErrorMsg("门店编码错误;"); dto.setErrorMsg("门店编码错误;");
} else { } else {
if (StringUtils.isAnyBlank(storeDto.getDealersName(), storeDto.getDealerId())) { if (StringUtils.isAnyBlank(storeDto.getDealersName(), storeDto.getDealerId())) {
dto.setErrorMsg("门店「经销商」为空,请到勤策中充;"); dto.setErrorMsg("门店「经销商」为空,请到勤策中充;");
} }
dto.setStoreCode(sc); dto.setStoreCode(sc);
dto.setStoreName(storeDto.getStoreName()); dto.setStoreName(storeDto.getStoreName());
...@@ -813,32 +856,50 @@ public class PromPlanCoreServiceImpl implements PromPlanCoreService { ...@@ -813,32 +856,50 @@ public class PromPlanCoreServiceImpl implements PromPlanCoreService {
* 3:活动模式 * 3:活动模式
*/ */
String pattern = row.get(3).toString(); String pattern = row.get(3).toString();
if ("单点CP,常规MINI秀,校园活动".contains(pattern)) { if ("大区KA,重客KA,大区零食,重客零食,场景营销".contains(pattern)) {
dto.setPattern(pattern); dto.setPattern(pattern);
} else { } else {
dto.setErrorMsg("活动模式分为:单点CP、常规MINI秀、校园活动;"); dto.setErrorMsg("活动模式分为:大区KA、重客KA、大区零食、重客零食、场景营销;");
}
/**
* 10:门店是否可用试吃台
*/
String isCanUseTasteCounter = row.get(10).toString();
if ("是,否".contains(isCanUseTasteCounter)) {
dto.setIsCanUseTasteCounter(isCanUseTasteCounter);
} else {
dto.setErrorMsg("门店是否可用试吃台请填写:是、否;");
} }
/** /**
* 10:是否有促销台/试吃台 * 11:门店是否已配试吃台
*/ */
String temWlSct = row.get(10).toString(); String temWlSct = row.get(11).toString();
if ("有,无".contains(temWlSct)) { if ("是,否".contains(temWlSct)) {
dto.setTemWlSct(temWlSct); dto.setTemWlSct(temWlSct);
} else { } else {
dto.setErrorMsg("是否有促销台请填写:有、无;"); dto.setErrorMsg("门店是否已配试吃台请填写:是、否;");
} }
/** /**
* 11:活动品项 * 12:活动品项
*/ */
String prdClass = row.get(11).toString(); String prdClass = row.get(12).toString();
if ("黑鸭,散称,老品".contains(prdClass)) { if ("黑鸭,散称,老品,礼盒".contains(prdClass)) {
dto.setPrdClass(prdClass); dto.setPrdClass(prdClass);
} else { } else {
dto.setErrorMsg("活动品项请填写:黑鸭、散称、老品;"); dto.setErrorMsg("活动品项请填写:黑鸭、散称、老品、礼盒;");
} }
/**
* 13:活动执行模式
*/
String planExecuteMode = row.get(13).toString();
if ("第三方,经销商".contains(planExecuteMode)) {
dto.setPlanExecuteMode(planExecuteMode);
}else {
dto.setErrorMsg("活动执行模式请填写:第三方、经销商;");
}
// 8:工资 // 8:工资
// dto.setSalary(new BigDecimal(row.get(8).toString())); // dto.setSalary(new BigDecimal(row.get(8).toString()));
// 9:杂费 // 9:杂费
......
package com.wangxiaolu.promotion.service.user;
import com.wangxiaolu.promotion.utils.TencentMapUtil;
import java.util.List;
/**
* @Author: DouXinYu
* @Date: 2026-01-12 11:17
* @Description:
*/
public interface TencentLocationQueryService {
TencentMapUtil.AddressInfo getAddressByLngLat(double lng, double lat);
List<TencentMapUtil.RegionNode> getAddressList();
}
package com.wangxiaolu.promotion.service.user.impl;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.wangxiaolu.promotion.service.user.TencentLocationQueryService;
import com.wangxiaolu.promotion.utils.TencentMapUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import java.lang.reflect.Type;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* @Author: DouXinYu
* @Date: 2026-01-12 11:16
* @Description: 腾讯位置查询服务实现类
*/
@Service
public class TencentLocationQueryServiceImpl implements TencentLocationQueryService {
private static final String TRIPLE_REGION_CACHE_KEY = "promotion:district:triple_level";
private static final long CACHE_EXPIRE = 86400L;
private static final Type REGION_NODE_TYPE = new TypeToken<List<TencentMapUtil.RegionNode>>() {}.getType();
private static final Gson GSON = new Gson();
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Autowired
TencentMapUtil tencentMapUtil;
@Override
public TencentMapUtil.AddressInfo getAddressByLngLat(double lng, double lat) {
return tencentMapUtil.getAddressByLngLat(lng, lat);
}
@Override
public List<TencentMapUtil.RegionNode> getAddressList() {
String cacheJson = stringRedisTemplate.opsForValue().get(TRIPLE_REGION_CACHE_KEY);
if (cacheJson != null && !cacheJson.isEmpty()) {
return GSON.fromJson(cacheJson, REGION_NODE_TYPE);
}
List<TencentMapUtil.RegionNode> regionList = tencentMapUtil.getTripleLevelRegion();
if (!regionList.isEmpty()) {
stringRedisTemplate.opsForValue().set(TRIPLE_REGION_CACHE_KEY, GSON.toJson(regionList), CACHE_EXPIRE, TimeUnit.SECONDS);
}
return regionList;
}
}
...@@ -18,4 +18,11 @@ public interface WeChatUserQueryService { ...@@ -18,4 +18,11 @@ public interface WeChatUserQueryService {
LoginVo temporaryLoginByPhone(String phone); LoginVo temporaryLoginByPhone(String phone);
List<Map<String, String>> findStoreList(TemporaryRegisterVo temporaryRegisterVo); List<Map<String, String>> findStoreList(TemporaryRegisterVo temporaryRegisterVo);
/**
* 根据临时ID查询手机号
* @param temporaryId 临时ID
* @return 手机号
*/
String findUserPhoneByID(Long temporaryId);
} }
...@@ -94,4 +94,9 @@ public class WeChatUserQueryServiceImpl implements WeChatUserQueryService { ...@@ -94,4 +94,9 @@ public class WeChatUserQueryServiceImpl implements WeChatUserQueryService {
public List<Map<String, String>> findStoreList(TemporaryRegisterVo temporaryRegisterVo) { public List<Map<String, String>> findStoreList(TemporaryRegisterVo temporaryRegisterVo) {
return activityPlanInfoDao.findThisMonthStoreListByLocation(temporaryRegisterVo); return activityPlanInfoDao.findThisMonthStoreListByLocation(temporaryRegisterVo);
} }
@Override
public String findUserPhoneByID(Long temporaryId) {
return temporaryInfoDao.selectOneById(temporaryId).getPhone();
}
} }
package com.wangxiaolu.promotion.utils;
import com.google.gson.Gson;
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* 腾讯地图工具类(整合:逆地理编码 + 省市区三级嵌套列表)
*/
@Component
public class TencentMapUtil {
// 你的腾讯API Key
private static final String API_KEY = "UTEBZ-UJ3KG-OORQO-QT3PT-JDWU7-YRBZA";
// 1. 逆地理编码接口
private static final String GEOCODER_URL = "https://apis.map.qq.com/ws/geocoder/v1/?location=%f,%f&key=%s&get_poi=0";
// 2. 省市区三级嵌套接口(新版结构)
private static final String DISTRICT_TRIPLE_URL = "https://apis.map.qq.com/ws/district/v1/list?key=%s&struct_type=1";
// OkHttp客户端
private static final OkHttpClient OK_HTTP_CLIENT = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.connectionPool(new ConnectionPool(10, 30, TimeUnit.SECONDS))
.retryOnConnectionFailure(true)
.build();
private static final Gson GSON = new Gson();
@Autowired
private StringRedisTemplate stringRedisTemplate;
// ==================== 1. 逆地理编码实体(保留原有) ====================
public static class AddressInfo {
private String province; // 省份
private String city; // 城市
private String district; // 区县
private String street; // 街道
private String streetNumber;// 门牌号
private String fullAddress; // 完整地址
private double lng; // 经度
private double lat; // 纬度
// Getter & Setter
public String getProvince() { return province; }
public void setProvince(String province) { this.province = province; }
public String getCity() { return city; }
public void setCity(String city) { this.city = city; }
public String getDistrict() { return district; }
public void setDistrict(String district) { this.district = district; }
public String getStreet() { return street; }
public void setStreet(String street) { this.street = street; }
public String getStreetNumber() { return streetNumber; }
public void setStreetNumber(String streetNumber) { this.streetNumber = streetNumber; }
public String getFullAddress() { return fullAddress; }
public void setFullAddress(String fullAddress) { this.fullAddress = fullAddress; }
public double getLng() { return lng; }
public void setLng(double lng) { this.lng = lng; }
public double getLat() { return lat; }
public void setLat(double lat) { this.lat = lat; }
}
// ==================== 2. 三级嵌套列表实体(匹配前端) ====================
public static class RegionNode {
private String text; // 全称(如“北京市”)
private String value; // adcode(如“110000”)
private List<RegionNode> children; // 下级节点
public RegionNode() {
this.children = new ArrayList<>();
}
public RegionNode(String text, String value) {
this.text = text;
this.value = value;
this.children = new ArrayList<>();
}
// Getter & Setter
public String getText() { return text; }
public void setText(String text) { this.text = text; }
public String getValue() { return value; }
public void setValue(String value) { this.value = value; }
public List<RegionNode> getChildren() { return children; }
public void setChildren(List<RegionNode> children) { this.children = children; }
}
// ==================== 腾讯API内部解析实体 ====================
// 逆地理编码响应
private static class GeoResponse {
private int status;
private String message;
private GeoResult result;
// Getter & Setter
public int getStatus() { return status; }
public void setStatus(int status) { this.status = status; }
public String getMessage() { return message; }
public void setMessage(String message) { this.message = message; }
public GeoResult getResult() { return result; }
public void setResult(GeoResult result) { this.result = result; }
}
private static class GeoResult {
private String formatted_address;
private AddressComponent address_component;
// Getter & Setter
public String getFormatted_address() { return formatted_address; }
public void setFormatted_address(String formatted_address) { this.formatted_address = formatted_address; }
public AddressComponent getAddress_component() { return address_component; }
public void setAddress_component(AddressComponent address_component) { this.address_component = address_component; }
}
private static class AddressComponent {
private String province;
private String city;
private String district;
private String street;
private String street_number;
// Getter & Setter
public String getProvince() { return province; }
public void setProvince(String province) { this.province = province; }
public String getCity() { return city; }
public void setCity(String city) { this.city = city; }
public String getDistrict() { return district; }
public void setDistrict(String district) { this.district = district; }
public String getStreet() { return street; }
public void setStreet(String street) { this.street = street; }
public String getStreet_number() { return street_number; }
public void setStreet_number(String street_number) { this.street_number = street_number; }
}
// 三级嵌套响应
private static class DistrictResponse {
private int status;
private String message;
private List<ProvinceItem> result;
// Getter & Setter
public int getStatus() { return status; }
public void setStatus(int status) { this.status = status; }
public String getMessage() { return message; }
public void setMessage(String message) { this.message = message; }
public List<ProvinceItem> getResult() { return result; }
public void setResult(List<ProvinceItem> result) { this.result = result; }
}
private static class ProvinceItem {
private String id;
private String fullname;
private List<CityItem> districts;
// Getter & Setter
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getFullname() { return fullname; }
public void setFullname(String fullname) { this.fullname = fullname; }
public List<CityItem> getDistricts() { return districts; }
public void setDistricts(List<CityItem> districts) { this.districts = districts; }
}
private static class CityItem {
private String id;
private String fullname;
private List<DistrictItem> districts;
// Getter & Setter
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getFullname() { return fullname; }
public void setFullname(String fullname) { this.fullname = fullname; }
public List<DistrictItem> getDistricts() { return districts; }
public void setDistricts(List<DistrictItem> districts) { this.districts = districts; }
}
private static class DistrictItem {
private String id;
private String fullname;
// Getter & Setter
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getFullname() { return fullname; }
public void setFullname(String fullname) { this.fullname = fullname; }
}
// ==================== 核心功能方法 ====================
/**
* 1. 逆地理编码:经纬度转地址(保留原有功能)
*/
public AddressInfo getAddressByLngLat(double lng, double lat) {
AddressInfo addressInfo = new AddressInfo();
try {
// 拼接请求地址(注意:腾讯接口是 lat,lng 顺序)
String requestUrl = String.format(GEOCODER_URL, lat, lng, API_KEY);
Request request = new Request.Builder().url(requestUrl).get().build();
try (Response response = OK_HTTP_CLIENT.newCall(request).execute()) {
if (!response.isSuccessful()) {
throw new IOException("逆地理编码请求失败,响应码:" + response.code());
}
GeoResponse resp = GSON.fromJson(response.body().string(), GeoResponse.class);
if (resp.getStatus() != 0) {
throw new IOException("逆地理编码API失败:" + resp.getMessage());
}
// 解析地址信息
GeoResult result = resp.getResult();
AddressComponent component = result.getAddress_component();
addressInfo.setProvince(component.getProvince());
addressInfo.setCity(component.getCity());
addressInfo.setDistrict(component.getDistrict());
addressInfo.setStreet(component.getStreet());
addressInfo.setStreetNumber(component.getStreet_number());
addressInfo.setFullAddress(result.getFormatted_address());
addressInfo.setLng(lng);
addressInfo.setLat(lat);
}
} catch (Exception e) {
System.err.println("逆地理编码失败:" + e.getMessage());
e.printStackTrace();
}
return addressInfo;
}
/**
* 2. 获取省→市→区三级嵌套列表(匹配前端)
*/
public List<RegionNode> getTripleLevelRegion() {
List<RegionNode> regionList = new ArrayList<>();
try {
String requestUrl = String.format(DISTRICT_TRIPLE_URL, API_KEY);
Request request = new Request.Builder().url(requestUrl).get().build();
try (Response response = OK_HTTP_CLIENT.newCall(request).execute()) {
if (!response.isSuccessful()) {
throw new IOException("三级区划请求失败,响应码:" + response.code());
}
DistrictResponse resp = GSON.fromJson(response.body().string(), DistrictResponse.class);
if (resp.getStatus() != 0) {
throw new IOException("三级区划API失败:" + resp.getMessage());
}
// 转换为前端结构
if (resp.getResult() != null && !resp.getResult().isEmpty()) {
for (ProvinceItem province : resp.getResult()) {
RegionNode provinceNode = new RegionNode(province.getFullname(), province.getId());
if (province.getDistricts() != null && !province.getDistricts().isEmpty()) {
for (CityItem city : province.getDistricts()) {
RegionNode cityNode = new RegionNode(city.getFullname(), city.getId());
if (city.getDistricts() != null && !city.getDistricts().isEmpty()) {
for (DistrictItem district : city.getDistricts()) {
cityNode.getChildren().add(new RegionNode(district.getFullname(), district.getId()));
}
}
provinceNode.getChildren().add(cityNode);
}
}
regionList.add(provinceNode);
}
}
}
} catch (Exception e) {
System.err.println("生成三级区划失败:" + e.getMessage());
e.printStackTrace();
}
return regionList;
}
// ==================== 缓存预热 ====================
@PostConstruct
public void preloadCache() {
// 预热三级区划缓存
new Thread(() -> {
try {
List<RegionNode> regionList = getTripleLevelRegion();
if (!regionList.isEmpty()) {
stringRedisTemplate.opsForValue().set(
"promotion:district:triple_level",
GSON.toJson(regionList),
86400L,
TimeUnit.SECONDS
);
}
} catch (Exception e) {
System.err.println("三级区划缓存预热失败:" + e.getMessage());
}
}).start();
}
}
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论