diff --git a/coolstore-partner-common/src/main/java/com/cool/store/constants/RedisConstant.java b/coolstore-partner-common/src/main/java/com/cool/store/constants/RedisConstant.java index 29f07024f..7dbe943e4 100644 --- a/coolstore-partner-common/src/main/java/com/cool/store/constants/RedisConstant.java +++ b/coolstore-partner-common/src/main/java/com/cool/store/constants/RedisConstant.java @@ -283,4 +283,10 @@ public class RedisConstant { public static final String SUBMIT_BUILD_KEY = "submit_build_key_"; public static final String GET_AI_MODULE = "get_ai_module_"; + + public static final String HUOMA_STORE_DEVICE_RESOURCE_KEY = "huoma_store_device_resource"; + + public static final String HUO_MA_STORE_ID = "huo_ma_store_id"; + + public static final String HUO_MA_TOKEN= "huo_ma_token:{0}"; } 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 cbbb7cdd3..f98a853da 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 @@ -310,9 +310,11 @@ public enum ErrorCodeEnum { MESSAGE_NOT_HANDLED(1610008,"当前消息无需处理,请确认消息处理类型!",null), MESSAGE_PUBLISH(1610009,"您选择通知任务正在发布中,请稍后重试!",null), - NOT_FLAGSHIP_STORE(16100005,"非直营店,无法跳过缴费阶段!",null), - NOT_FLAGSHIP_STORE_NOT_EXIST(16100006,"当前阶段加盟类型不能变更!",null), - JOIN_MODE_NOT_ALLOW_OPERATE(16100007,"加盟部人员只能新建加盟店或联营店,请确认!",null), + NOT_FLAGSHIP_STORE(1610010,"非直营店,无法跳过缴费阶段!",null), + NOT_FLAGSHIP_STORE_NOT_EXIST(1610011,"当前阶段加盟类型不能变更!",null), + JOIN_MODE_NOT_ALLOW_OPERATE(1610012,"加盟部人员只能新建加盟店或联营店,请确认!",null), + STORE_NOT_FIND(1610013,"门店不存在",null), + ; diff --git a/coolstore-partner-common/src/main/java/com/cool/store/enums/SpecialTagEnum.java b/coolstore-partner-common/src/main/java/com/cool/store/enums/SpecialTagEnum.java new file mode 100644 index 000000000..d022a0728 --- /dev/null +++ b/coolstore-partner-common/src/main/java/com/cool/store/enums/SpecialTagEnum.java @@ -0,0 +1,58 @@ +package com.cool.store.enums; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @Author suzhuhong + * @Date 2025/11/5 16:03 + * @Version 1.0 + */ +public enum SpecialTagEnum { + + ELECTRONIC_PRICE_LIST("电子价目牌"), + ACTIVITY_CAROUSEL("活动轮播"), + ACTIVITY_PACKAGE("活动套餐"), + PROMOTIONAL_VIDEO("宣传视频"); + + private final String tagName; + + SpecialTagEnum(String tagName) { + this.tagName = tagName; + } + + public String getTagName() { + return tagName; + } + + /** + * 根据标签名称获取枚举值 + */ + public static SpecialTagEnum fromTagName(String tagName) { + for (SpecialTagEnum tag : values()) { + if (tag.getTagName().equals(tagName)) { + return tag; + } + } + return null; + } + + /** + * 获取所有标签名称列表 + */ + public static List getAllTagNames() { + return Arrays.stream(values()) + .map(SpecialTagEnum::getTagName) + .collect(Collectors.toList()); + } + + /** + * 获取电子价目牌标签名称 + * @return + */ + public static List getElectronicPriceTagName() { + return Arrays.asList(ELECTRONIC_PRICE_LIST.getTagName()); + } + +} diff --git a/coolstore-partner-common/src/main/java/com/cool/store/enums/StoreStatusEnum.java b/coolstore-partner-common/src/main/java/com/cool/store/enums/StoreStatusEnum.java new file mode 100644 index 000000000..6ae889d05 --- /dev/null +++ b/coolstore-partner-common/src/main/java/com/cool/store/enums/StoreStatusEnum.java @@ -0,0 +1,77 @@ +package com.cool.store.enums; + +/** + * Created by Administrator on 2020/1/20. + */ +public enum StoreStatusEnum { + + //营业 + OPEN("open","在营"), + //闭店 + CLOSED("closed","闭店解约"), + //未开业 + NOT_OPEN("not_open","未开业"), + //迁址 + CHANGE_ADDRESS("change_address","迁址"), + //退单 + CHARGEBACK("chargeback","退单"), + //暂停营业 + CLOSE_UP("close_up","暂停营业"); + ; + + + private final String value; + + private final String name; + + StoreStatusEnum(String value, String name) { + this.value = value; + this.name = name; + } + + public String getValue() { + return value; + } + + public String getName() { + return name; + } + + public static StoreStatusEnum parse(String value) { + for (StoreStatusEnum storeStatusEnum : StoreStatusEnum.values()) { + if (storeStatusEnum.getValue().equals(value)) { + return storeStatusEnum; + } + } + return null; + } + + public static String getName(String value) { + for (StoreStatusEnum storeStatusEnum : StoreStatusEnum.values()) { + if (storeStatusEnum.getValue().equals(value)) { + return storeStatusEnum.name; + } + } + return null; + } + + public static String getCode(String flag) { + switch (flag) { + case "营业": + case "在营": + return "open"; + case "闭店": + case "闭店解约": + return "closed"; + case "未开业": + return "not_open"; + case "迁址": + return "change_address"; + case "退单": + return "chargeback"; + case "暂停营业": + return "close_up"; + } + return "open"; + } +} diff --git a/coolstore-partner-common/src/main/java/com/cool/store/enums/wechat/WechatTemplateDetailEnum.java b/coolstore-partner-common/src/main/java/com/cool/store/enums/wechat/WechatTemplateDetailEnum.java new file mode 100644 index 000000000..1e8484d73 --- /dev/null +++ b/coolstore-partner-common/src/main/java/com/cool/store/enums/wechat/WechatTemplateDetailEnum.java @@ -0,0 +1,53 @@ +package com.cool.store.enums.wechat; + +/** + * @Author suzhuhong + * @Date 2025/10/16 15:19 + * @Version 1.0 + */ +public enum WechatTemplateDetailEnum { + + CHARACTER_STRING2("编号","character_string2"), + THING10("项目名称","thing10"), + TIME14("完成时间","time14"), + THING25("客户名称","thing25"), + THING60("位置","thing60"), + + + THING6("工单标题","thing6"), + TIME33("创建时间","time33"), + CHARACTER_STRING14("工单编号","character_string14"), + + + ; + + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + private String name; + + private String code; + + WechatTemplateDetailEnum(String name, String code) { + this.name = name; + this.code = code; + } + + + + +} diff --git a/coolstore-partner-common/src/main/java/com/cool/store/enums/wechat/WechatTemplateEnum.java b/coolstore-partner-common/src/main/java/com/cool/store/enums/wechat/WechatTemplateEnum.java new file mode 100644 index 000000000..2ce643e36 --- /dev/null +++ b/coolstore-partner-common/src/main/java/com/cool/store/enums/wechat/WechatTemplateEnum.java @@ -0,0 +1,79 @@ +package com.cool.store.enums.wechat; + +import com.fasterxml.jackson.annotation.JsonValue; + +import java.lang.reflect.Array; +import java.util.Arrays; +import java.util.List; + +import static com.cool.store.enums.wechat.WechatTemplateDetailEnum.*; + +/** + * @Author suzhuhong + * @Date 2025/10/10 14:39 + * @Version 1.0 + */ +public enum WechatTemplateEnum { + + QUESTION_NOTICE("QUESTION_NOTICE", "T3sp5gBItHKD8oCeEiQMjn7JXpngFiz3dDcaArk84xY", "收到工单通知", + Arrays.asList(CHARACTER_STRING2,THING10,TIME14,THING25,THING60)), + + NEW_QUESTION_NOTICE("new_question_notice", "35rmoQ5wEHvUgCgSIJ2CpOb1DOJgWOiy8J7DXT_e4_Y", "新工单提醒", + Arrays.asList(THING6,TIME33,CHARACTER_STRING14)), + + ; + + + private final String code; + private final String templateId; + private final String title; + private final List contentList; + + WechatTemplateEnum(String code, String templateId, String title, List contentList) { + this.code = code; + this.templateId = templateId; + this.title = title; + this.contentList = contentList; + } + + @JsonValue + public String getCode() { + return code; + } + + public String getTemplateId() { + return templateId; + } + + public String getTitle() { + return title; + } + + public List getContentList() { + return contentList; + } + + /** + * 根据code获取枚举 + */ + public static WechatTemplateEnum getByCode(String code) { + for (WechatTemplateEnum template : values()) { + if (template.getCode().equals(code)) { + return template; + } + } + return null; + } + + /** + * 根据模板ID获取枚举 + */ + public static WechatTemplateEnum getByTemplateId(String templateId) { + for (WechatTemplateEnum template : values()) { + if (template.getTemplateId().equals(templateId)) { + return template; + } + } + return null; + } +} diff --git a/coolstore-partner-common/src/main/java/com/cool/store/utils/BeanUtil.java b/coolstore-partner-common/src/main/java/com/cool/store/utils/BeanUtil.java index 7838c1fd5..4d6936f79 100644 --- a/coolstore-partner-common/src/main/java/com/cool/store/utils/BeanUtil.java +++ b/coolstore-partner-common/src/main/java/com/cool/store/utils/BeanUtil.java @@ -1,5 +1,6 @@ package com.cool.store.utils; +import cn.hutool.core.bean.copier.CopyOptions; import com.github.pagehelper.PageInfo; import java.util.ArrayList; @@ -28,6 +29,18 @@ public class BeanUtil extends cn.hutool.core.bean.BeanUtil { return result; } + public static List toList(List list, Class clazz, CopyOptions copyOptions) { + if (list == null || list.isEmpty()) { + return Collections.emptyList(); + } + List result = new ArrayList<>(list.size()); + for (T t : list) { + R r = toBean(t, clazz, copyOptions); + result.add(r); + } + return result; + } + public static PageInfo toPage(PageInfo page, Class clazz) { PageInfo newPage = new PageInfo<>(); newPage.setPages(page.getPages()); diff --git a/coolstore-partner-common/src/main/java/com/cool/store/utils/BrowserVersionUtils.java b/coolstore-partner-common/src/main/java/com/cool/store/utils/BrowserVersionUtils.java new file mode 100644 index 000000000..663a1cd9a --- /dev/null +++ b/coolstore-partner-common/src/main/java/com/cool/store/utils/BrowserVersionUtils.java @@ -0,0 +1,62 @@ +package com.cool.store.utils; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @Author suzhuhong + * @Date 2025/11/4 17:34 + * @Version 1.0 + */ +public class BrowserVersionUtils { + + + /** + * 检测是否为旧版Chrome浏览器(版本小于60) + * @param userAgent 浏览器User-Agent字符串 + * @return true-是旧版Chrome,false-不是旧版Chrome + */ + public static boolean isOldChromeBrowser(String userAgent) { + if (userAgent == null || userAgent.isEmpty()) { + return false; + } + + // 检查是否是Chrome浏览器 + if (!userAgent.contains("Chrome")) { + return false; // 不是Chrome浏览器 + } + + // 提取Chrome版本号 + Integer chromeVersion = extractChromeVersion(userAgent); + + if (chromeVersion == null) { + return false; // 无法提取版本号 + } + + // 判断版本是否小于60 + return chromeVersion < 60; + } + + /** + * 从User-Agent中提取Chrome主版本号 + * @param userAgent 浏览器User-Agent字符串 + * @return Chrome主版本号,如果无法提取返回null + */ + public static Integer extractChromeVersion(String userAgent) { + // 正则表达式匹配 Chrome/版本号 模式 + Pattern pattern = Pattern.compile("Chrome/(\\d+)"); + Matcher matcher = pattern.matcher(userAgent); + + if (matcher.find()) { + try { + return Integer.parseInt(matcher.group(1)); + } catch (NumberFormatException e) { + System.err.println("版本号格式错误: " + matcher.group(1)); + return null; + } + } + + return null; + } + +} diff --git a/coolstore-partner-common/src/main/java/com/cool/store/utils/OkHttpUtil.java b/coolstore-partner-common/src/main/java/com/cool/store/utils/OkHttpUtil.java new file mode 100644 index 000000000..a39959958 --- /dev/null +++ b/coolstore-partner-common/src/main/java/com/cool/store/utils/OkHttpUtil.java @@ -0,0 +1,197 @@ +package com.cool.store.utils; +import com.cool.store.enums.ErrorCodeEnum; +import com.cool.store.exception.ServiceException; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import okhttp3.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import java.io.IOException; +import java.util.Map; + +/** + * @Author suzhuhong + * @Date 2025/10/10 14:21 + * @Version 1.0 + * OkHttp工具类 + */ +@Slf4j +@Component +public class OkHttpUtil { + + @Autowired + private OkHttpClient okHttpClient; + + @Autowired + private ObjectMapper objectMapper; + + private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); + + /** + * GET请求 + */ + public String doGet(String url) throws IOException { + return doGet(url, null); + } + + /** + * GET请求 - 带请求头 + */ + public String doGet(String url, Map headers) throws IOException { + Request.Builder builder = new Request.Builder().url(url); + + // 添加请求头 + if (headers != null && !headers.isEmpty()) { + headers.forEach(builder::addHeader); + } + + Request request = builder.build(); + + try (Response response = okHttpClient.newCall(request).execute()) { + if (!response.isSuccessful()) { + throw new IOException("Unexpected code: " + response); + } + ResponseBody body = response.body(); + return body != null ? body.string() : null; + } + } + + /** + * POST请求 - JSON数据 + */ + public String doPostJson(String url, Object data) throws IOException { + return doPostJson(url, data, null); + } + + /** + * POST请求 - JSON数据,带请求头 + */ + public String doPostJson(String url, Object data, Map headers) throws IOException { + //打印日志 + logRequest(url, data); + + String json = objectMapper.writeValueAsString(data); + RequestBody requestBody = RequestBody.create( JSON,json); + Request.Builder builder = new Request.Builder() + .url(url) + .post(requestBody); + + // 添加请求头 + if (headers != null && !headers.isEmpty()) { + headers.forEach(builder::addHeader); + } + + Request request = builder.build(); + + try (Response response = okHttpClient.newCall(request).execute()) { + if (!response.isSuccessful()) { + throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR, + "HTTP请求失败,状态码: " + response.code()); + } + ResponseBody body = response.body(); + + String responseBody = body != null ? body.string() : null; + + logResponse(url, response.code(), responseBody); + return responseBody; + } + } + + /** + * 异步GET请求 + */ + public void doGetAsync(String url, Callback callback) { + doGetAsync(url, null, callback); + } + + /** + * 异步GET请求 - 带请求头 + */ + public void doGetAsync(String url, Map headers, Callback callback) { + Request.Builder builder = new Request.Builder().url(url); + + if (headers != null && !headers.isEmpty()) { + headers.forEach(builder::addHeader); + } + + Request request = builder.build(); + okHttpClient.newCall(request).enqueue(callback); + } + + /** + * 异步POST请求 + */ + public void doPostAsync(String url, Object data, Callback callback) { + doPostAsync(url, data, null, callback); + } + + /** + * 异步POST请求 - 带请求头 + */ + public void doPostAsync(String url, Object data, Map headers, Callback callback) { + try { + String json = objectMapper.writeValueAsString(data); + RequestBody requestBody = RequestBody.create( JSON,json); + + Request.Builder builder = new Request.Builder() + .url(url) + .post(requestBody); + + if (headers != null && !headers.isEmpty()) { + headers.forEach(builder::addHeader); + } + + Request request = builder.build(); + okHttpClient.newCall(request).enqueue(callback); + } catch (IOException e) { + callback.onFailure(null, e); + } + } + + private void logRequest(String url, Object requestBody) { + if (log.isInfoEnabled()) { + try { + log.info("\n======= 请求开始 =======\n" + + "API地址: {}\n" + + "请求参数: {}\n" + + "======= 请求结束 =======", + url, + objectMapper.writerWithDefaultPrettyPrinter() + .writeValueAsString(requestBody)); + } catch (JsonProcessingException e) { + log.warn("日志JSON序列化失败", e); + } + } + } + + private void logResponse(String url, int statusCode, String responseBody) { + if (log.isInfoEnabled()) { + try { + // 尝试美化JSON输出 + Object json = objectMapper.readValue(responseBody, Object.class); + String prettyResponse = objectMapper.writerWithDefaultPrettyPrinter() + .writeValueAsString(json); + + log.info("\n======= 响应开始 =======\n" + + "API地址: {}\n" + + "HTTP状态码: {}\n" + + "响应内容: {}\n" + + "======= 响应结束 =======", + url, + statusCode, + prettyResponse); + } catch (Exception e) { + // 非JSON响应或解析失败时直接输出原始内容 + log.info("\n======= 响应开始 =======\n" + + "API地址: {}\n" + + "HTTP状态码: {}\n" + + "原始响应: {}\n" + + "======= 响应结束 =======", + url, + statusCode, + responseBody); + } + } + } +} diff --git a/coolstore-partner-dao/src/main/java/com/cool/store/dao/HyPartnerUserInfoDAO.java b/coolstore-partner-dao/src/main/java/com/cool/store/dao/HyPartnerUserInfoDAO.java index f54825b8c..5dd700af4 100644 --- a/coolstore-partner-dao/src/main/java/com/cool/store/dao/HyPartnerUserInfoDAO.java +++ b/coolstore-partner-dao/src/main/java/com/cool/store/dao/HyPartnerUserInfoDAO.java @@ -1,5 +1,6 @@ package com.cool.store.dao; +import com.cool.store.dto.wechat.ServiceAccountOpenIdDTO; import com.cool.store.entity.HyPartnerUserInfoDO; import com.cool.store.mapper.HyPartnerUserInfoMapper; import com.google.common.collect.Lists; @@ -112,4 +113,11 @@ public class HyPartnerUserInfoDAO { return hyPartnerUserInfoMapper.selectPasswordIsNull(); } + + public List selectLastBindRecord(List mobileList){ + if (CollectionUtils.isEmpty(mobileList)){ + return Lists.newArrayList(); + } + return hyPartnerUserInfoMapper.selectLastBindRecord(mobileList); + } } diff --git a/coolstore-partner-dao/src/main/java/com/cool/store/dao/OldShopDAO.java b/coolstore-partner-dao/src/main/java/com/cool/store/dao/OldShopDAO.java index 27a6dc3eb..facb70050 100644 --- a/coolstore-partner-dao/src/main/java/com/cool/store/dao/OldShopDAO.java +++ b/coolstore-partner-dao/src/main/java/com/cool/store/dao/OldShopDAO.java @@ -40,4 +40,8 @@ public class OldShopDAO { List list = oldShopMapper.selectByExample(example); return list.isEmpty() ? null : list.get(0); } + + public void insertSelective(OldShopDO oldShopDO) { + oldShopMapper.insertSelective(oldShopDO); + } } diff --git a/coolstore-partner-dao/src/main/java/com/cool/store/dao/PartnerUserWechatBindDAO.java b/coolstore-partner-dao/src/main/java/com/cool/store/dao/PartnerUserWechatBindDAO.java index 388e59e80..9134b3efb 100644 --- a/coolstore-partner-dao/src/main/java/com/cool/store/dao/PartnerUserWechatBindDAO.java +++ b/coolstore-partner-dao/src/main/java/com/cool/store/dao/PartnerUserWechatBindDAO.java @@ -31,6 +31,27 @@ public class PartnerUserWechatBindDAO { return partnerUserWechatBindMapper.insert(partnerUserWechatBindDO); } + /** + * 更新 + * @param partnerUserWechatBindDO + * @return + */ + public Integer update(PartnerUserWechatBindDO partnerUserWechatBindDO) { + if (partnerUserWechatBindDO == null) { + return 0; + } + return partnerUserWechatBindMapper.update(partnerUserWechatBindDO); + } + + /** + * 更新所有的unionId对应的服务号ID + * @param unionId 开发平台的用户ID + * @param serviceAccountOpenId 服务号ID + * @return + */ + public Integer updateByUnionId(String unionId,String serviceAccountOpenId) { + return partnerUserWechatBindMapper.updateByUnionId(unionId,serviceAccountOpenId); + } public PartnerUserWechatBindDO getByOpenIdAndPartnerId(String partnerId, String openId) { if (StringUtil.isEmpty(partnerId)|| StringUtil.isEmpty(openId)){ diff --git a/coolstore-partner-dao/src/main/java/com/cool/store/mapper/HyPartnerUserInfoMapper.java b/coolstore-partner-dao/src/main/java/com/cool/store/mapper/HyPartnerUserInfoMapper.java index 4ac2fcb53..c25bedbdb 100644 --- a/coolstore-partner-dao/src/main/java/com/cool/store/mapper/HyPartnerUserInfoMapper.java +++ b/coolstore-partner-dao/src/main/java/com/cool/store/mapper/HyPartnerUserInfoMapper.java @@ -1,5 +1,6 @@ package com.cool.store.mapper; +import com.cool.store.dto.wechat.ServiceAccountOpenIdDTO; import com.cool.store.entity.HyPartnerUserInfoDO; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; @@ -55,4 +56,6 @@ public interface HyPartnerUserInfoMapper extends tk.mybatis.mapper.common.Mappe List selectPasswordIsNull(); + List selectLastBindRecord(@Param("mobileList") List mobileList); + } \ No newline at end of file diff --git a/coolstore-partner-dao/src/main/java/com/cool/store/mapper/PartnerUserWechatBindMapper.java b/coolstore-partner-dao/src/main/java/com/cool/store/mapper/PartnerUserWechatBindMapper.java index a94d56629..d69cb7fba 100644 --- a/coolstore-partner-dao/src/main/java/com/cool/store/mapper/PartnerUserWechatBindMapper.java +++ b/coolstore-partner-dao/src/main/java/com/cool/store/mapper/PartnerUserWechatBindMapper.java @@ -18,6 +18,22 @@ public interface PartnerUserWechatBindMapper { */ Integer insert(PartnerUserWechatBindDO partnerUserWechatBindDO); + /** + * 更新数据 + * @param partnerUserWechatBindDO + * @return + */ + Integer update(PartnerUserWechatBindDO partnerUserWechatBindDO); + + + /** + * 更新所有的unionId对应的服务号ID + * @param unionId 开发平台的用户ID + * @param serviceAccountOpenId 服务号ID + * @return + */ + Integer updateByUnionId(String unionId,String serviceAccountOpenId); + /** * 根据partnerId与openId查询 * @param partnerId diff --git a/coolstore-partner-dao/src/main/resources/mapper/HyPartnerUserInfoMapper.xml b/coolstore-partner-dao/src/main/resources/mapper/HyPartnerUserInfoMapper.xml index 7f7b18652..6b4606782 100644 --- a/coolstore-partner-dao/src/main/resources/mapper/HyPartnerUserInfoMapper.xml +++ b/coolstore-partner-dao/src/main/resources/mapper/HyPartnerUserInfoMapper.xml @@ -195,4 +195,23 @@ + + \ No newline at end of file diff --git a/coolstore-partner-dao/src/main/resources/mapper/PartnerUserWechatBindMapper.xml b/coolstore-partner-dao/src/main/resources/mapper/PartnerUserWechatBindMapper.xml index c638c9338..b77174957 100644 --- a/coolstore-partner-dao/src/main/resources/mapper/PartnerUserWechatBindMapper.xml +++ b/coolstore-partner-dao/src/main/resources/mapper/PartnerUserWechatBindMapper.xml @@ -8,6 +8,8 @@ + + @@ -17,15 +19,33 @@ open_id, bind_time, partner_id, + union_id, create_time ) VALUES ( #{openId, jdbcType=VARCHAR}, #{bindTime, jdbcType=TIMESTAMP}, #{partnerId, jdbcType=VARCHAR}, + #{unionId, jdbcType=VARCHAR}, #{createTime, jdbcType=TIMESTAMP} ) + + UPDATE xfsg_partner_user_wechat_bind + + + union_id = #{unionId, jdbcType=VARCHAR}, + + + where id = #{id} + + + + UPDATE xfsg_partner_user_wechat_bind + set service_account_open_id = #{serviceAccountOpenId} + where union_id = #{unionId} + + diff --git a/coolstore-partner-model/src/main/java/com/cool/store/dto/StoreDTO.java b/coolstore-partner-model/src/main/java/com/cool/store/dto/StoreDTO.java index 3937ea797..84b2efe1d 100644 --- a/coolstore-partner-model/src/main/java/com/cool/store/dto/StoreDTO.java +++ b/coolstore-partner-model/src/main/java/com/cool/store/dto/StoreDTO.java @@ -56,4 +56,7 @@ public class StoreDTO { private String managerSupervisionName; @ApiModelProperty("所属大区/分部") private String branchName; + + @ApiModelProperty("门店状态") + private String status; } diff --git a/coolstore-partner-model/src/main/java/com/cool/store/dto/huoma/AccountTagDTO.java b/coolstore-partner-model/src/main/java/com/cool/store/dto/huoma/AccountTagDTO.java new file mode 100644 index 000000000..8e4c0a21a --- /dev/null +++ b/coolstore-partner-model/src/main/java/com/cool/store/dto/huoma/AccountTagDTO.java @@ -0,0 +1,20 @@ +package com.cool.store.dto.huoma; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @Author suzhuhong + * @Date 2025/11/6 11:09 + * @Version 1.0 + */ +@Data +public class AccountTagDTO { + + @ApiModelProperty("门店编码") + private String storeNum; + + @ApiModelProperty("设备名称") + private String deviceName; + +} diff --git a/coolstore-partner-model/src/main/java/com/cool/store/dto/huoma/HuoMaAccountDTO.java b/coolstore-partner-model/src/main/java/com/cool/store/dto/huoma/HuoMaAccountDTO.java new file mode 100644 index 000000000..4ccaccdf9 --- /dev/null +++ b/coolstore-partner-model/src/main/java/com/cool/store/dto/huoma/HuoMaAccountDTO.java @@ -0,0 +1,39 @@ +package com.cool.store.dto.huoma; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + *

+ * 火码账号DTO + *

+ * + * @author wangff + * @since 2025/9/23 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class HuoMaAccountDTO { + /** + * 账号 + */ + private String account; + + /** + * 密码 + */ + private String password; + + /** + * 是否已查询 + */ + private Boolean isQuery; + + public HuoMaAccountDTO(String account, String password) { + this.account = account; + this.password = password; + this.isQuery = false; + } +} diff --git a/coolstore-partner-model/src/main/java/com/cool/store/dto/huoma/ProgramReqDTO.java b/coolstore-partner-model/src/main/java/com/cool/store/dto/huoma/ProgramReqDTO.java new file mode 100644 index 000000000..3983d99cb --- /dev/null +++ b/coolstore-partner-model/src/main/java/com/cool/store/dto/huoma/ProgramReqDTO.java @@ -0,0 +1,40 @@ +package com.cool.store.dto.huoma; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import java.util.List; + +/** + * @Author suzhuhong + * @Date 2025/11/5 14:43 + * @Version 1.0 + */ +@Data +public class ProgramReqDTO { + + @ApiModelProperty(name = "门店编码",required = true) + private String storeCode; + + @ApiModelProperty(name = "设备名称",required = true) + @NotEmpty(message = "设备名称不能为空") + private String deviceName; + + @ApiModelProperty(name = "第几页,",required = true) + private Integer index; + + @ApiModelProperty(name ="每页数量",required = true) + private Integer size; + + @ApiModelProperty(name = "时间",hidden = true) + private String date; + + @ApiModelProperty(name = "排序",hidden = true) + private String sort; + + @ApiModelProperty("标签id列表") + private List tagIds; + +} diff --git a/coolstore-partner-model/src/main/java/com/cool/store/dto/huoma/ProgramResponseDTO.java b/coolstore-partner-model/src/main/java/com/cool/store/dto/huoma/ProgramResponseDTO.java new file mode 100644 index 000000000..3922c7ba9 --- /dev/null +++ b/coolstore-partner-model/src/main/java/com/cool/store/dto/huoma/ProgramResponseDTO.java @@ -0,0 +1,25 @@ +package com.cool.store.dto.huoma; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @Author suzhuhong + * @Date 2025/11/5 14:44 + * @Version 1.0 + */ +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class ProgramResponseDTO { + + @ApiModelProperty("节目ID") + private Long id; + + @ApiModelProperty("节目名称") + private String name; + + @ApiModelProperty("节目缩略图") + private String thumbnail; + +} diff --git a/coolstore-partner-model/src/main/java/com/cool/store/dto/huoma/PublishDTO.java b/coolstore-partner-model/src/main/java/com/cool/store/dto/huoma/PublishDTO.java new file mode 100644 index 000000000..6453c8c8c --- /dev/null +++ b/coolstore-partner-model/src/main/java/com/cool/store/dto/huoma/PublishDTO.java @@ -0,0 +1,27 @@ +package com.cool.store.dto.huoma; + +import com.alibaba.fastjson.annotation.JSONField; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import java.util.List; + +/** + * @Author suzhuhong + * @Date 2025/11/5 17:06 + * @Version 1.0 + */ +@Data +public class PublishDTO { + + @ApiModelProperty(name = "门店编号",required = true) + @NotEmpty(message = "门店编码不能为空") + private String storeCode; + @ApiModelProperty(name = "设备ID列表",required = true) + @NotEmpty(message = "设备ID列表不能为空") + @JSONField(name = "terminals") + private List deviceIdList; + @ApiModelProperty("节目id") + private Long programId; +} diff --git a/coolstore-partner-model/src/main/java/com/cool/store/dto/huoma/StoreEquipmentDTO.java b/coolstore-partner-model/src/main/java/com/cool/store/dto/huoma/StoreEquipmentDTO.java new file mode 100644 index 000000000..cfae3c530 --- /dev/null +++ b/coolstore-partner-model/src/main/java/com/cool/store/dto/huoma/StoreEquipmentDTO.java @@ -0,0 +1,59 @@ +package com.cool.store.dto.huoma; + +import com.cool.store.utils.BrowserVersionUtils; +import lombok.Data; + +import java.util.Objects; + +/** + * @Author: WangShuo + * @Date: 2025/08/13/16:24 + * @Version 1.0 + * @注释: + */ +@Data +public class StoreEquipmentDTO { + /** + * 已授权登录数 + */ + private Integer activeCount; + + /** + * 总设备 + */ + private Integer terminalCount; + + /** + * 网点ID + */ + private Integer pointId; + + /** + * 网点号 + */ + private String pointCode; + + /** + * 签到数 + */ + private Integer signCount; + + /** + * 在线 + */ + + private Integer connectCount; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + StoreEquipmentDTO that = (StoreEquipmentDTO) o; + return Objects.equals(pointCode, that.pointCode); + } + + @Override + public int hashCode() { + return Objects.hashCode(pointCode); + } +} diff --git a/coolstore-partner-model/src/main/java/com/cool/store/dto/huoma/StoreRequestDTO.java b/coolstore-partner-model/src/main/java/com/cool/store/dto/huoma/StoreRequestDTO.java new file mode 100644 index 000000000..5a22c8095 --- /dev/null +++ b/coolstore-partner-model/src/main/java/com/cool/store/dto/huoma/StoreRequestDTO.java @@ -0,0 +1,40 @@ +package com.cool.store.dto.huoma; + +import lombok.Data; + +/** + * @Author suzhuhong + * @Date 2025/8/18 16:00 + * @Version 1.0 + */ +@Data +public class StoreRequestDTO { + + private String reportCode; + + private Integer index; + + private Integer size; + + private Params params; + + public StoreRequestDTO(String reportCode, Integer index, Integer size, String shopCode) { + this.reportCode = reportCode; + this.index = index; + this.size = size; + this.params = new Params(shopCode); + } + + @Data + static class Params{ + private String inputText_2; + + public Params(String inputText_2) { + this.inputText_2 = inputText_2; + } + } + + + + +} diff --git a/coolstore-partner-model/src/main/java/com/cool/store/dto/huoma/StoreXinFaDetailRequestDTO.java b/coolstore-partner-model/src/main/java/com/cool/store/dto/huoma/StoreXinFaDetailRequestDTO.java new file mode 100644 index 000000000..4e30a38ef --- /dev/null +++ b/coolstore-partner-model/src/main/java/com/cool/store/dto/huoma/StoreXinFaDetailRequestDTO.java @@ -0,0 +1,24 @@ +package com.cool.store.dto.huoma; + +import lombok.Data; + +/** + * @Author suzhuhong + * @Date 2025/8/18 16:38 + * @Version 1.0 + */ +@Data +public class StoreXinFaDetailRequestDTO { + + private Integer index; + + private Integer size; + + private Integer pointId; + + public StoreXinFaDetailRequestDTO(Integer index, Integer size, Integer pointId) { + this.index = index; + this.size = size; + this.pointId = pointId; + } +} diff --git a/coolstore-partner-model/src/main/java/com/cool/store/dto/huoma/StoreXinFaDeviceDetail.java b/coolstore-partner-model/src/main/java/com/cool/store/dto/huoma/StoreXinFaDeviceDetail.java new file mode 100644 index 000000000..7ebf36201 --- /dev/null +++ b/coolstore-partner-model/src/main/java/com/cool/store/dto/huoma/StoreXinFaDeviceDetail.java @@ -0,0 +1,81 @@ +package com.cool.store.dto.huoma; + +import com.alibaba.fastjson.parser.DefaultJSONParser; +import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer; +import com.cool.store.utils.BrowserVersionUtils; +import com.cool.store.utils.StringUtil; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.lang.reflect.Type; + +/** + * @Author suzhuhong + * @Date 2025/8/18 16:27 + * @Version 1.0 + */ +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class StoreXinFaDeviceDetail { + + /** + * 设备ID + */ + @ApiModelProperty(value = "设备ID") + private String id; + + @ApiModelProperty("设备id") + private String deviceId; + + /** + * 设备名称 + */ + @ApiModelProperty(value = "设备名称") + private String name; + + /** + * 设备连接状态 0:未连接 1:已连接 + */ + @ApiModelProperty(value = "设备连接状态 false:未连接 true:已连接") + private Boolean isConnect; + + /** + * 设备总内存 + */ + @ApiModelProperty(value = "设备总内存") + private String totalRam; + + /** + * 设备可用内存 + */ + @ApiModelProperty(value = "设备可用内存") + private String availRam; + + /** + * 设备浏览器信息 + */ + @ApiModelProperty(value = "设备浏览器信息") + private String userAgent; + + /** + * 内用内存小于300M 或者 浏览器版本小于60 + */ + @ApiModelProperty(value = "内用内存小于300M 或者 浏览器版本小于60") + private Boolean flag; + + public boolean getFlag() { + if (StringUtil.isEmpty(availRam)||StringUtil.isEmpty(userAgent)){ + return false; + } + try { + Boolean isOldChromeBrowser = BrowserVersionUtils.isOldChromeBrowser(userAgent); + long availableMemoryMB = Long.parseLong(availRam) / (1024 * 1024); + return availableMemoryMB < 300 || isOldChromeBrowser; + } catch (NumberFormatException e) { + return false; + } + } + +} diff --git a/coolstore-partner-model/src/main/java/com/cool/store/dto/huoma/TagDTO.java b/coolstore-partner-model/src/main/java/com/cool/store/dto/huoma/TagDTO.java new file mode 100644 index 000000000..6752e601a --- /dev/null +++ b/coolstore-partner-model/src/main/java/com/cool/store/dto/huoma/TagDTO.java @@ -0,0 +1,29 @@ +package com.cool.store.dto.huoma; + +import io.swagger.models.auth.In; +import lombok.Data; + +/** + * @Author suzhuhong + * @Date 2025/11/5 9:33 + * @Version 1.0 + */ +@Data +public class TagDTO { + + private String channelType; + + private Integer index; + + private Integer size; + + private String type; + + public TagDTO(String channelType, Integer index, Integer size, String type) { + this.channelType = channelType; + this.index = index; + this.size = size; + this.type = type; + } + +} diff --git a/coolstore-partner-model/src/main/java/com/cool/store/dto/huoma/TagDetailDTO.java b/coolstore-partner-model/src/main/java/com/cool/store/dto/huoma/TagDetailDTO.java new file mode 100644 index 000000000..5274fb05d --- /dev/null +++ b/coolstore-partner-model/src/main/java/com/cool/store/dto/huoma/TagDetailDTO.java @@ -0,0 +1,22 @@ +package com.cool.store.dto.huoma; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @Author suzhuhong + * @Date 2025/11/5 9:41 + * @Version 1.0 + */ +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class TagDetailDTO { + + @ApiModelProperty("标签Id") + private Integer id; + + @ApiModelProperty("标签名称") + private String name; + +} diff --git a/coolstore-partner-model/src/main/java/com/cool/store/dto/recipe/LaunchDataDTO.java b/coolstore-partner-model/src/main/java/com/cool/store/dto/recipe/LaunchDataDTO.java new file mode 100644 index 000000000..90eb0e210 --- /dev/null +++ b/coolstore-partner-model/src/main/java/com/cool/store/dto/recipe/LaunchDataDTO.java @@ -0,0 +1,21 @@ +package com.cool.store.dto.recipe; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + *

+ * 服务包菜品数据 + *

+ * + * @author wangff + * @since 2025/10/30 + */ +@Data +public class LaunchDataDTO { + @ApiModelProperty("名称") + private String spName; + + @ApiModelProperty("上新时间,yyyy-MM-dd") + private String upSaleDate; +} diff --git a/coolstore-partner-model/src/main/java/com/cool/store/dto/recipe/RecipeLaunchDTO.java b/coolstore-partner-model/src/main/java/com/cool/store/dto/recipe/RecipeLaunchDTO.java new file mode 100644 index 000000000..47a0179ba --- /dev/null +++ b/coolstore-partner-model/src/main/java/com/cool/store/dto/recipe/RecipeLaunchDTO.java @@ -0,0 +1,34 @@ +package com.cool.store.dto.recipe; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + *

+ * 菜品上新DTO + *

+ * + * @author wangff + * @since 2025/11/3 + */ +@Data +public class RecipeLaunchDTO { + @ApiModelProperty("商品编码") + private String goodsCode; + + @ApiModelProperty("商品图片") + private String goodsImageUrl; + + @ApiModelProperty("商品名称") + private String goodsName; + + @ApiModelProperty("上新时间") + private String launchTime; + + @ApiModelProperty("单日最高销量") + private Integer maxQty; + + @ApiModelProperty("销量总计") + private Integer sumQty; + +} diff --git a/coolstore-partner-model/src/main/java/com/cool/store/dto/recipe/RecipeSpLaunchDTO.java b/coolstore-partner-model/src/main/java/com/cool/store/dto/recipe/RecipeSpLaunchDTO.java new file mode 100644 index 000000000..ffec16435 --- /dev/null +++ b/coolstore-partner-model/src/main/java/com/cool/store/dto/recipe/RecipeSpLaunchDTO.java @@ -0,0 +1,23 @@ +package com.cool.store.dto.recipe; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +/** + *

+ * 服务包菜品上新DTO + *

+ * + * @author wangff + * @since 2025/11/3 + */ +@Data +public class RecipeSpLaunchDTO { + @ApiModelProperty("菜品上新记录") + private List recipeRecordList; + + @ApiModelProperty("服务包执行记录") + private List spRecordList; +} diff --git a/coolstore-partner-model/src/main/java/com/cool/store/dto/recipe/RevenueDataDTO.java b/coolstore-partner-model/src/main/java/com/cool/store/dto/recipe/RevenueDataDTO.java new file mode 100644 index 000000000..e4b6e66a0 --- /dev/null +++ b/coolstore-partner-model/src/main/java/com/cool/store/dto/recipe/RevenueDataDTO.java @@ -0,0 +1,38 @@ +package com.cool.store.dto.recipe; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.List; + +/** + *

+ * 营收数据 + *

+ * + * @author wangff + * @since 2025/10/30 + */ +@Data +public class RevenueDataDTO { + @ApiModelProperty("门店编码") + private String storeCode; + + @ApiModelProperty("营业额") + private BigDecimal amt; + + @ApiModelProperty("实收") + private BigDecimal receivedAmt; + + @ApiModelProperty("营业时间,yyyy-MM-dd") + private String businessDate; + + @ApiModelProperty("服务包列表") + private List otherLaunchDates; + + @ApiModelProperty("菜品列表") + private List otherRecipeLaunchDates; + + +} diff --git a/coolstore-partner-model/src/main/java/com/cool/store/dto/recipe/RevenueDataQueryDTO.java b/coolstore-partner-model/src/main/java/com/cool/store/dto/recipe/RevenueDataQueryDTO.java new file mode 100644 index 000000000..56587568c --- /dev/null +++ b/coolstore-partner-model/src/main/java/com/cool/store/dto/recipe/RevenueDataQueryDTO.java @@ -0,0 +1,28 @@ +package com.cool.store.dto.recipe; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + *

+ * 营收数据查询DTO + *

+ * + * @author wangff + * @since 2025/10/30 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class RevenueDataQueryDTO { + @ApiModelProperty("门店编码") + private String storeCode; + + @ApiModelProperty("业务时间开始") + private String businessDateFrom; + + @ApiModelProperty("业务时间结束") + private String businessDateTo; +} diff --git a/coolstore-partner-model/src/main/java/com/cool/store/dto/recipe/ServicePackageExecuteDTO.java b/coolstore-partner-model/src/main/java/com/cool/store/dto/recipe/ServicePackageExecuteDTO.java new file mode 100644 index 000000000..b80308180 --- /dev/null +++ b/coolstore-partner-model/src/main/java/com/cool/store/dto/recipe/ServicePackageExecuteDTO.java @@ -0,0 +1,30 @@ +package com.cool.store.dto.recipe; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + *

+ * 服务包执行DTO + *

+ * + * @author wangff + * @since 2025/11/3 + */ +@Data +public class ServicePackageExecuteDTO { + @ApiModelProperty("服务包执行时间") + private String executeTime; + + @ApiModelProperty("服务包图片") + private String spImage; + + @ApiModelProperty("服务包名称") + private String spName; + + @ApiModelProperty("服务包id") + @JsonSerialize(using = ToStringSerializer.class) + private Long spId; +} diff --git a/coolstore-partner-model/src/main/java/com/cool/store/dto/wechat/AccessTokenDTO.java b/coolstore-partner-model/src/main/java/com/cool/store/dto/wechat/AccessTokenDTO.java new file mode 100644 index 000000000..2b046715e --- /dev/null +++ b/coolstore-partner-model/src/main/java/com/cool/store/dto/wechat/AccessTokenDTO.java @@ -0,0 +1,17 @@ +package com.cool.store.dto.wechat; + +import lombok.Data; + +/** + * @Author suzhuhong + * @Date 2025/10/10 15:01 + * @Version 1.0 + */ +@Data +public class AccessTokenDTO { + + private String access_token; + + private Integer expires_in; + +} diff --git a/coolstore-partner-model/src/main/java/com/cool/store/dto/wechat/CallbackMessageDTO.java b/coolstore-partner-model/src/main/java/com/cool/store/dto/wechat/CallbackMessageDTO.java new file mode 100644 index 000000000..1bb7755dd --- /dev/null +++ b/coolstore-partner-model/src/main/java/com/cool/store/dto/wechat/CallbackMessageDTO.java @@ -0,0 +1,26 @@ +package com.cool.store.dto.wechat; + +import lombok.Data; + +/** + * @Author suzhuhong + * @Date 2025/10/14 14:39 + * @Version 1.0 + */ +@Data +public class CallbackMessageDTO { + + private String toUserName; + + private String fromUserName; + + private Long createTime; + + private String msgType; + + private String event; + + private String eventKey; + + +} diff --git a/coolstore-partner-model/src/main/java/com/cool/store/dto/wechat/ServiceAccountOpenIdDTO.java b/coolstore-partner-model/src/main/java/com/cool/store/dto/wechat/ServiceAccountOpenIdDTO.java new file mode 100644 index 000000000..425ba9021 --- /dev/null +++ b/coolstore-partner-model/src/main/java/com/cool/store/dto/wechat/ServiceAccountOpenIdDTO.java @@ -0,0 +1,23 @@ +package com.cool.store.dto.wechat; + +import lombok.Data; + +import java.util.Date; + +/** + * @Author suzhuhong + * @Date 2025/10/16 14:13 + * @Version 1.0 + */ +@Data +public class ServiceAccountOpenIdDTO { + + private String partnerId; + + private String unionId; + + private String serviceAccountOpenId; + + private Date lastUpdateTime; + +} diff --git a/coolstore-partner-model/src/main/java/com/cool/store/dto/wechat/WechatTemplateMessageDTO.java b/coolstore-partner-model/src/main/java/com/cool/store/dto/wechat/WechatTemplateMessageDTO.java new file mode 100644 index 000000000..33f7a681a --- /dev/null +++ b/coolstore-partner-model/src/main/java/com/cool/store/dto/wechat/WechatTemplateMessageDTO.java @@ -0,0 +1,90 @@ +package com.cool.store.dto.wechat; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.Map; + +/** + * @Author suzhuhong + * @Date 2025/10/10 14:36 + * @Version 1.0 + */ +@Data +public class WechatTemplateMessageDTO { + + /** + * 接收者openid + */ + @JsonProperty("touser") + private String toUser; + + /** + * 模板ID + */ + @JsonProperty("template_id") + private String templateId; + + /** + * 模板跳转链接(非必须) + */ + private String url; + + /** + * 跳小程序所需数据,不需跳小程序可不用传该数据 + */ + private MiniprogramDTO miniprogram; + + /** + * 模板数据 + */ + private Map data; + + /** + * 小程序跳转DTO + */ + @Data + public static class MiniprogramDTO { + + /** + * 所需跳转到的小程序appid + */ + private String appid; + + /** + * 所需跳转到小程序的具体页面路径,支持带参数 + */ + private String pagepath; + } + + /** + * 模板数据项DTO + */ + @Data + public static class TemplateDataItemDTO { + + /** + * 模板内容 + */ + private String value; + + /** + * 模板内容字体颜色,不填默认为黑色 + */ + private String color; + + public TemplateDataItemDTO() { + } + + public TemplateDataItemDTO(String value) { + this.value = value; + this.color = "#333333"; + } + + public TemplateDataItemDTO(String value, String color) { + this.value = value; + this.color = color; + } + } + +} diff --git a/coolstore-partner-model/src/main/java/com/cool/store/dto/wechat/WechatUserInfoDTO.java b/coolstore-partner-model/src/main/java/com/cool/store/dto/wechat/WechatUserInfoDTO.java new file mode 100644 index 000000000..573ef562e --- /dev/null +++ b/coolstore-partner-model/src/main/java/com/cool/store/dto/wechat/WechatUserInfoDTO.java @@ -0,0 +1,115 @@ +package com.cool.store.dto.wechat; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.List; + +/** + * @Author suzhuhong + * @Date 2025/10/15 9:56 + * @Version 1.0 + */ +@Data +public class WechatUserInfoDTO { + /** + * 用户是否订阅该公众号标识 + * 0代表未关注,1代表关注 + */ + private Integer subscribe; + + /** + * 用户的标识,对当前公众号唯一 + */ + private String openid; + + /** + * 用户的昵称 + */ + private String nickname; + + /** + * 用户的性别 + * 1为男性,2为女性,0为未知 + */ + private Integer sex; + + /** + * 用户所在城市 + */ + private String city; + + /** + * 用户所在国家 + */ + private String country; + + /** + * 用户所在省份 + */ + private String province; + + /** + * 用户的语言 + * 简体中文为zh_CN + */ + private String language; + + /** + * 用户头像 + */ + private String headimgurl; + + /** + * 用户关注时间,为时间戳 + */ + @JsonProperty("subscribe_time") + private Long subscribeTime; + + /** + * 只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段 + */ + private String unionid; + + /** + * 公众号运营者对粉丝的备注 + */ + private String remark; + + /** + * 用户所在的分组ID(兼容旧的用户分组接口) + */ + private Integer groupid; + + /** + * 用户被打上的标签ID列表 + */ + @JsonProperty("tagid_list") + private List tagidList; + + /** + * 返回用户关注的渠道来源 + */ + @JsonProperty("subscribe_scene") + private String subscribeScene; + + /** + * 二维码扫码场景(开发者自定义) + */ + @JsonProperty("qr_scene") + private Long qrScene; + + /** + * 二维码扫码场景描述(开发者自定义) + */ + @JsonProperty("qr_scene_str") + private String qrSceneStr; + + /** + * 是否已关注 + */ + public boolean isSubscribed() { + return subscribe != null && subscribe == 1; + } + +} diff --git a/coolstore-partner-model/src/main/java/com/cool/store/entity/OldShopDO.java b/coolstore-partner-model/src/main/java/com/cool/store/entity/OldShopDO.java index ed7fcc93b..17aca56b2 100644 --- a/coolstore-partner-model/src/main/java/com/cool/store/entity/OldShopDO.java +++ b/coolstore-partner-model/src/main/java/com/cool/store/entity/OldShopDO.java @@ -1,13 +1,19 @@ package com.cool.store.entity; import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; import javax.persistence.*; import java.util.Date; @Data @Table(name = "xfsg_old_shop") +@AllArgsConstructor +@NoArgsConstructor +@Builder public class OldShopDO { /** diff --git a/coolstore-partner-model/src/main/java/com/cool/store/entity/PartnerUserWechatBindDO.java b/coolstore-partner-model/src/main/java/com/cool/store/entity/PartnerUserWechatBindDO.java index f3496136a..79eabd0c4 100644 --- a/coolstore-partner-model/src/main/java/com/cool/store/entity/PartnerUserWechatBindDO.java +++ b/coolstore-partner-model/src/main/java/com/cool/store/entity/PartnerUserWechatBindDO.java @@ -36,6 +36,10 @@ public class PartnerUserWechatBindDO implements Serializable { */ private String partnerId; + private String unionId; + + private String serviceAccountOpenId; + /** * 创建时间 */ diff --git a/coolstore-partner-model/src/main/java/com/cool/store/request/recipe/RevenueDataRequest.java b/coolstore-partner-model/src/main/java/com/cool/store/request/recipe/RevenueDataRequest.java new file mode 100644 index 000000000..e2795fabf --- /dev/null +++ b/coolstore-partner-model/src/main/java/com/cool/store/request/recipe/RevenueDataRequest.java @@ -0,0 +1,29 @@ +package com.cool.store.request.recipe; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/** + *

+ * 营收数据Request + *

+ * + * @author wangff + * @since 2025/10/30 + */ +@Data +public class RevenueDataRequest { + @ApiModelProperty("门店id") + @NotBlank(message = "门店id不能为空") + private String storeId; + + @ApiModelProperty("业务时间开始,yyyy-MM-dd") + @NotBlank(message = "业务时间开始不能为空") + private String businessDateFrom; + + @ApiModelProperty("业务时间结束,yyyy-MM-dd") + @NotBlank(message = "业务时间结束不能为空") + private String businessDateTo; +} diff --git a/coolstore-partner-model/src/main/java/com/cool/store/vo/recipe/LaunchDataVO.java b/coolstore-partner-model/src/main/java/com/cool/store/vo/recipe/LaunchDataVO.java new file mode 100644 index 000000000..0b9fc81de --- /dev/null +++ b/coolstore-partner-model/src/main/java/com/cool/store/vo/recipe/LaunchDataVO.java @@ -0,0 +1,21 @@ +package com.cool.store.vo.recipe; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + *

+ * 服务包菜品数据 + *

+ * + * @author wangff + * @since 2025/10/30 + */ +@Data +public class LaunchDataVO { + @ApiModelProperty("名称") + private String spName; + + @ApiModelProperty("上新时间,yyyy-MM-dd") + private String upSaleDate; +} diff --git a/coolstore-partner-model/src/main/java/com/cool/store/vo/recipe/RevenueDataVO.java b/coolstore-partner-model/src/main/java/com/cool/store/vo/recipe/RevenueDataVO.java new file mode 100644 index 000000000..f25ca5110 --- /dev/null +++ b/coolstore-partner-model/src/main/java/com/cool/store/vo/recipe/RevenueDataVO.java @@ -0,0 +1,38 @@ +package com.cool.store.vo.recipe; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.List; + +/** + *

+ * 营收数据VO + *

+ * + * @author wangff + * @since 2025/10/30 + */ +@Data +public class RevenueDataVO { + @ApiModelProperty("门店编码") + private String storeNum; + + @ApiModelProperty("营业额") + private BigDecimal amt; + + @ApiModelProperty("实收") + private BigDecimal receivedAmt; + + @ApiModelProperty("营业时间,yyyy-MM-dd") + private String businessDate; + + @ApiModelProperty("服务包列表") + private List otherLaunchDates; + + @ApiModelProperty("菜品列表") + private List otherRecipeLaunchDates; + + +} diff --git a/coolstore-partner-service/src/main/java/com/cool/store/builder/TemplateMessageBuilder.java b/coolstore-partner-service/src/main/java/com/cool/store/builder/TemplateMessageBuilder.java new file mode 100644 index 000000000..9881c7cb3 --- /dev/null +++ b/coolstore-partner-service/src/main/java/com/cool/store/builder/TemplateMessageBuilder.java @@ -0,0 +1,126 @@ +package com.cool.store.builder; + +import com.cool.store.config.weixin.WechatMiniappProperties; +import com.cool.store.dto.wechat.WechatTemplateMessageDTO; +import com.cool.store.enums.wechat.WechatTemplateEnum; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import java.util.HashMap; +import java.util.Map; + +/** + * @Author suzhuhong + * @Date 2025/10/10 14:34 + * @Version 1.0 + */ +@Component +public class TemplateMessageBuilder { + + @Autowired + private WechatMiniappProperties wechatMiniappProperties; + + /** + * 构建普通模板消息 + */ + public WechatTemplateMessageDTO buildNormalTemplate(String openId, + WechatTemplateEnum template, + Map data) { + WechatTemplateMessageDTO messageDTO = new WechatTemplateMessageDTO(); + messageDTO.setToUser(openId); + messageDTO.setTemplateId(template.getTemplateId()); + + // 设置URL(如果data中包含url) + if (data.containsKey("url")) { + messageDTO.setUrl((String) data.get("url")); + } + + // 构建模板数据 + messageDTO.setData(buildTemplateData(data)); + + return messageDTO; + } + + /** + * 构建小程序跳转模板消息 + */ + public WechatTemplateMessageDTO buildMiniappTemplate(String openId, + WechatTemplateEnum template, + Map data, + String miniAppPagePath) { + WechatTemplateMessageDTO messageDTO = new WechatTemplateMessageDTO(); + messageDTO.setToUser(openId); + messageDTO.setTemplateId(template.getTemplateId()); + + // 设置小程序跳转 + WechatTemplateMessageDTO.MiniprogramDTO miniProgram = new WechatTemplateMessageDTO.MiniprogramDTO(); + miniProgram.setAppid(wechatMiniappProperties.getAppId()); + miniProgram.setPagepath(miniAppPagePath != null ? miniAppPagePath : wechatMiniappProperties.getDefaultPagePath()); + messageDTO.setMiniprogram(miniProgram); + + // 设置备用URL(如果data中包含url) + if (data.containsKey("url")) { + messageDTO.setUrl((String) data.get("url")); + } + + // 构建模板数据 + messageDTO.setData(buildTemplateData(data)); + + return messageDTO; + } + + /** + * 构建小程序跳转模板消息(带备用URL) + */ + public WechatTemplateMessageDTO buildMiniAppTemplateWithUrl(String openId, + WechatTemplateEnum template, + Map data, + String miniAppPagePath, + String backupUrl) { + WechatTemplateMessageDTO messageDTO = buildMiniappTemplate(openId, template, data, miniAppPagePath); + + // 设置备用URL + if (backupUrl != null && !backupUrl.trim().isEmpty()) { + messageDTO.setUrl(backupUrl); + } + + return messageDTO; + } + + /** + * 构建模板数据 + */ + private Map buildTemplateData(Map data) { + Map templateData = new HashMap<>(); + + data.forEach((key, value) -> { + if (!"url".equals(key) && value != null) { + WechatTemplateMessageDTO.TemplateDataItemDTO item = + new WechatTemplateMessageDTO.TemplateDataItemDTO( + value.toString(), + getColorByField(key) + ); + templateData.put(key, item); + } + }); + + return templateData; + } + + /** + * 根据字段名获取颜色 + */ + private String getColorByField(String fieldName) { + switch (fieldName) { + case "amount": + case "refundAmount": + case "couponValue": + case "character_string2": + return "#FF0000"; // 金额类字段用红色 + case "orderNo": + case "expressNo": + return "#173177"; // 编号类字段用蓝色 + default: + return "#333333"; // 默认用深灰色 + } + } +} diff --git a/coolstore-partner-service/src/main/java/com/cool/store/config/weixin/WechatMiniappProperties.java b/coolstore-partner-service/src/main/java/com/cool/store/config/weixin/WechatMiniappProperties.java new file mode 100644 index 000000000..b1be5c0f6 --- /dev/null +++ b/coolstore-partner-service/src/main/java/com/cool/store/config/weixin/WechatMiniappProperties.java @@ -0,0 +1,32 @@ +package com.cool.store.config.weixin; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * @Author suzhuhong + * @Date 2025/10/10 14:41 + * @Version 1.0 + */ +@Data +@Configuration +@ConfigurationProperties(prefix = "wechat.miniapp") +public class WechatMiniappProperties { + + /** + * 小程序appId + */ + private String appId; + + /** + * 小程序页面路径 + */ + private String defaultPagePath ; + + /** + * 是否使用小程序跳转 + */ + private boolean enabled = false; + +} diff --git a/coolstore-partner-service/src/main/java/com/cool/store/config/weixin/WechatMpProperties.java b/coolstore-partner-service/src/main/java/com/cool/store/config/weixin/WechatMpProperties.java new file mode 100644 index 000000000..10acc5f25 --- /dev/null +++ b/coolstore-partner-service/src/main/java/com/cool/store/config/weixin/WechatMpProperties.java @@ -0,0 +1,37 @@ +package com.cool.store.config.weixin; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * @Author suzhuhong + * @Date 2025/10/10 14:29 + * @Version 1.0 + * 微信服务号配置 + */ +@Data +@Configuration +@ConfigurationProperties(prefix = "wechat.mp") +public class WechatMpProperties { + + /** + * 公众号appId + */ + private String appId; + + /** + * 公众号appSecret + */ + private String appSecret; + + /** + * 获取access_token的URL + */ + private String accessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token"; + + /** + * 发送模板消息的URL + */ + private String sendTemplateMessageUrl = "https://api.weixin.qq.com/cgi-bin/message/template/send"; +} diff --git a/coolstore-partner-service/src/main/java/com/cool/store/handler/WeChatHandler.java b/coolstore-partner-service/src/main/java/com/cool/store/handler/WeChatHandler.java new file mode 100644 index 000000000..95c461dd7 --- /dev/null +++ b/coolstore-partner-service/src/main/java/com/cool/store/handler/WeChatHandler.java @@ -0,0 +1,157 @@ +package com.cool.store.handler; + +import com.alibaba.fastjson.JSONObject; +import com.cool.store.dao.PartnerUserWechatBindDAO; +import com.cool.store.dto.wechat.WechatUserInfoDTO; +import com.cool.store.service.wechat.WechatTemplateService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; + +import javax.annotation.Resource; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import java.io.StringReader; +import java.util.HashMap; +import java.util.Map; + +/** + * @Author suzhuhong + * @Date 2025/10/14 14:56 + * @Version 1.0 + */ +@Component +@Slf4j +public class WeChatHandler { + + @Resource + PartnerUserWechatBindDAO partnerUserWechatBindDAO; + @Resource + WechatTemplateService wechatTemplateService; + + public Map parseXmlToMap(String xmlContent) throws Exception { + Map result = new HashMap<>(); + + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + + DocumentBuilder builder = factory.newDocumentBuilder(); + Document document = builder.parse(new InputSource(new StringReader(xmlContent))); + + NodeList nodes = document.getDocumentElement().getChildNodes(); + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + if (node.getNodeType() == Node.ELEMENT_NODE) { + String tagName = node.getNodeName(); + String textContent = node.getTextContent(); + result.put(tagName, textContent); + } + } + + return result; + } + + + public String processMessage(Map messageMap) { + String msgType = (String) messageMap.get("MsgType"); + String event = (String) messageMap.get("Event"); + + switch (msgType) { + case "event": + return handleEvent(messageMap); + +// case "text": +// return handleTextMessage(message); +// +// case "image": +// return handleImageMessage(message); + + default: + // 其他类型的消息直接回复success + return "success"; + } + } + + private String handleEvent(Map messageMap) { + String event = (String) messageMap.get("Event"); + String fromUserName = (String) messageMap.get("FromUserName"); + String toUserName = (String) messageMap.get("ToUserName"); + + switch (event) { + case "subscribe": + // 关注事件 - 绑定用户 + return handleSubscribeEvent(fromUserName,toUserName); + + case "unsubscribe": + // 取消关注事件 - 解绑用户 + return handleUnsubscribeEvent(fromUserName,toUserName); + + default: + return buildWelcomeReply(fromUserName, toUserName); + } + } + + private String handleSubscribeEvent(String fromUserName,String toUserName) { + try { + + //根据openId 获取用户信息 + WechatUserInfoDTO userInfo = wechatTemplateService.getUserInfo(fromUserName, null); + + log.info("handleSubscribeEvent: {}", JSONObject.toJSONString(userInfo)); + + //根据unionId 更新服务号ID + if (userInfo != null) { + partnerUserWechatBindDAO.updateByUnionId(userInfo.getUnionid(),fromUserName); + } + + // 立即回复欢迎消息 + return buildWelcomeReply(fromUserName, toUserName); + + } catch (Exception e) { + // 即使处理失败也要返回success + return buildWelcomeReply(fromUserName, toUserName); + } + } + + /** + * 处理取消关注事件 + */ + private String handleUnsubscribeEvent(String fromUserName,String toUserName) { + + // 异步处理用户解绑 + //userBindingService.unbindOfficialAccountUser(openId); + + return "success"; + } + + private String buildSuccessReply(String fromUser, String toUser) { + return String.format( + "" + + "" + + "" + + "%d" + + "" + + "" + + "", + fromUser, toUser, System.currentTimeMillis() / 1000 + ); + } + + + private String buildWelcomeReply(String fromUser, String toUser) { + return String.format( + "" + + "" + + "" + + "%d" + + "" + + "" + + "", + fromUser, toUser, System.currentTimeMillis() / 1000 + ); + } + +} diff --git a/coolstore-partner-service/src/main/java/com/cool/store/service/ThirdFoodService.java b/coolstore-partner-service/src/main/java/com/cool/store/service/ThirdFoodService.java index 919cd6d69..88045070d 100644 --- a/coolstore-partner-service/src/main/java/com/cool/store/service/ThirdFoodService.java +++ b/coolstore-partner-service/src/main/java/com/cool/store/service/ThirdFoodService.java @@ -1,10 +1,11 @@ package com.cool.store.service; import com.cool.store.dto.FoodTokenDTO; -import com.cool.store.dto.GetAccessTokenDTO; -import com.cool.store.dto.store.StoreUserPositionDTO; +import com.cool.store.dto.recipe.RecipeSpLaunchDTO; import com.cool.store.dto.store.StoreUserUpdateDTO; +import com.cool.store.request.recipe.RevenueDataRequest; import com.cool.store.response.caipin.StoreUserResponse; +import com.cool.store.vo.recipe.RevenueDataVO; import java.util.List; @@ -31,4 +32,17 @@ public interface ThirdFoodService { */ StoreUserResponse pushStoreUser(List storeUserUpdateDTOList); + /** + * 查询门店营收实收数据 + * @param request 营收数据Request + * @return 营收数据VO列表 + */ + List getRevenueData(RevenueDataRequest request); + + /** + * 查询菜品服务包上新数据 + * @param request 请求request + * @return 服务包菜品上新DTO + */ + RecipeSpLaunchDTO getRecipeServiceLaunch(RevenueDataRequest request); } diff --git a/coolstore-partner-service/src/main/java/com/cool/store/service/impl/MessageTemplateServiceImpl.java b/coolstore-partner-service/src/main/java/com/cool/store/service/impl/MessageTemplateServiceImpl.java index 0ee448fe7..fb98026cd 100644 --- a/coolstore-partner-service/src/main/java/com/cool/store/service/impl/MessageTemplateServiceImpl.java +++ b/coolstore-partner-service/src/main/java/com/cool/store/service/impl/MessageTemplateServiceImpl.java @@ -9,9 +9,12 @@ import com.cool.store.dto.notice.MessageTemplateCountDTO; import com.cool.store.dto.notice.NoticeDTO; import com.cool.store.dto.store.AuthStoreUserDTO; import com.cool.store.dto.store.StoreAreaDTO; +import com.cool.store.dto.wechat.ServiceAccountOpenIdDTO; import com.cool.store.entity.*; import com.cool.store.enums.ErrorCodeEnum; import com.cool.store.enums.notice.*; +import com.cool.store.enums.wechat.WechatTemplateDetailEnum; +import com.cool.store.enums.wechat.WechatTemplateEnum; import com.cool.store.exception.ServiceException; import com.cool.store.mapper.StoreGroupMappingMapper; import com.cool.store.mapper.StoreMapper; @@ -19,12 +22,16 @@ import com.cool.store.request.notice.*; import com.cool.store.response.bigdata.ApiResponse; import com.cool.store.service.MessageTemplateService; import com.cool.store.service.StoreService; +import com.cool.store.service.wechat.WechatTemplateService; import com.cool.store.utils.CoolDateUtils; import com.cool.store.utils.RedisUtilPool; +import com.cool.store.utils.poi.DateUtils; import com.cool.store.vo.PartnerUserInfoVO; import com.cool.store.vo.notice.*; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; +import com.google.common.collect.Lists; +import com.google.gson.JsonObject; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -67,10 +74,14 @@ public class MessageTemplateServiceImpl implements MessageTemplateService { @Resource MatterConfigDAO matterConfigDAO; @Resource + WechatTemplateService wechatTemplateService; + @Resource RedisUtilPool redisUtilPool; @Resource TaskExecutor noticeThreadPool; @Resource + HyPartnerUserInfoDAO hyPartnerUserInfoDAO; + @Resource MessageIssueService messageIssueService; @@ -210,10 +221,38 @@ public class MessageTemplateServiceImpl implements MessageTemplateService { JSONObject.toJSONString(request.getStoreInfoList()), JSONObject.toJSONString(request.getUserInfoList()), userId); + + //发送通知 + Set userIds = authUser.values().stream().flatMap(Collection::stream).collect(Collectors.toSet()); + + //分批 查询用户信息 + List openIdList = new ArrayList<>(); + Lists.partition(new ArrayList<>(userIds), 100).forEach(x->{ + List userInfoByUserIds = enterpriseUserDAO.getUserInfoByUserIds(x); + //取出用户的手机号,过滤掉空的手机号 + List mobileList = userInfoByUserIds.stream().filter(user -> StringUtils.isNotBlank(user.getMobile())).map(EnterpriseUserDO::getMobile).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(mobileList)){ + List serviceAccountOpenIdDTOS = hyPartnerUserInfoDAO.selectLastBindRecord(mobileList); + if (CollectionUtils.isNotEmpty(serviceAccountOpenIdDTOS)){ + //服务号ID + openIdList.addAll(serviceAccountOpenIdDTOS.stream().map(ServiceAccountOpenIdDTO::getServiceAccountOpenId).collect(Collectors.toList())); + } + + } + }); + + MessageTemplateDO messageTemplateDO = list.get(0); + Map data = new HashMap<>(); + data.put(WechatTemplateDetailEnum.THING6.getCode(), messageTemplateDO.getMessageTitle()); + data.put(WechatTemplateDetailEnum.TIME33.getCode(), DateUtils.parseDateToStr(DateUtils.SPECIAL_DATE_START, new Date())); + data.put(WechatTemplateDetailEnum.CHARACTER_STRING14.getCode(), messageTemplateDO.getMessageCode()); + openIdList.forEach(x->{ + wechatTemplateService.sendMiniAppTemplate(x, WechatTemplateEnum.NEW_QUESTION_NOTICE,data,"pages/notification/index"); + }); // 即时消息下发 messageIssueService.issueMessage(realtimeMessageList); } catch (Exception e) { - log.info("发布流程异常,已取消发布"); + log.info("发布流程异常 e:{}",e.getMessage()); } finally { releaseLocks(lockKeys); log.info("发布流程结束,已释放Redis锁"); diff --git a/coolstore-partner-service/src/main/java/com/cool/store/service/impl/ShopAccountServiceImpl.java b/coolstore-partner-service/src/main/java/com/cool/store/service/impl/ShopAccountServiceImpl.java index 1c71d6202..7dc3b069f 100644 --- a/coolstore-partner-service/src/main/java/com/cool/store/service/impl/ShopAccountServiceImpl.java +++ b/coolstore-partner-service/src/main/java/com/cool/store/service/impl/ShopAccountServiceImpl.java @@ -59,6 +59,8 @@ public class ShopAccountServiceImpl implements ShopAccountService { ThirdXinGuanJiaService thirdXinGuanJiaService; @Resource private LineInfoDAO lineInfoDAO; + @Resource + private StoreDao storeDao; @Override public List getShopAccountByShopId(Long shopId) { @@ -311,7 +313,17 @@ public class ShopAccountServiceImpl implements ShopAccountService { //查询老店关联表数据 OldShopDO oldShopDO = oldShopDAO.getByCode(shopCode); if (Objects.isNull(oldShopDO)) { - throw new ServiceException(ErrorCodeEnum.GET_YLS_CODE_FAIL); + StoreDO storeDO = storeDao.getByStoreNum(shopCode); + if (Objects.isNull(storeDO)) { + throw new ServiceException(ErrorCodeEnum.GET_YLS_CODE_FAIL); + } + oldShopDO = OldShopDO.builder() + .shopCode(shopCode) + .shopName(storeDO.getStoreName()) + .mobile(storeDO.getTelephone()) + .ylsShopCode("ZXA8_" + shopCode) + .build(); + oldShopDAO.insertSelective(oldShopDO); } return oldShopDO.getYlsShopCode(); } diff --git a/coolstore-partner-service/src/main/java/com/cool/store/service/impl/StoreServiceImpl.java b/coolstore-partner-service/src/main/java/com/cool/store/service/impl/StoreServiceImpl.java index ce45189ae..4cc73fea3 100644 --- a/coolstore-partner-service/src/main/java/com/cool/store/service/impl/StoreServiceImpl.java +++ b/coolstore-partner-service/src/main/java/com/cool/store/service/impl/StoreServiceImpl.java @@ -399,6 +399,7 @@ public class StoreServiceImpl implements StoreService { dto.setJoinMode(JoinModeEnum.getByCode(store.getJoinModel())); dto.setBrand(FranchiseBrandEnum.getDescByCode(store.getJoinBrand())); dto.setOrderMiniProgramName(store.getMiniProgramOrderStoreName()); + dto.setStatus(StoreStatusEnum.getName(store.getStoreStatus())); if (store.getRegionId() != null){ dto.setManagerSupervisionName(regionMap.get(store.getRegionId())); } diff --git a/coolstore-partner-service/src/main/java/com/cool/store/service/impl/ThirdFoodServiceImpl.java b/coolstore-partner-service/src/main/java/com/cool/store/service/impl/ThirdFoodServiceImpl.java index c19bcf2c5..4fddb48d1 100644 --- a/coolstore-partner-service/src/main/java/com/cool/store/service/impl/ThirdFoodServiceImpl.java +++ b/coolstore-partner-service/src/main/java/com/cool/store/service/impl/ThirdFoodServiceImpl.java @@ -1,17 +1,23 @@ package com.cool.store.service.impl; +import cn.hutool.core.bean.copier.CopyOptions; import cn.hutool.core.util.RandomUtil; -import com.alibaba.fastjson.JSONObject; +import com.cool.store.dao.StoreDao; import com.cool.store.dto.FoodTokenDTO; -import com.cool.store.dto.GetAccessTokenDTO; -import com.cool.store.dto.store.StoreUserPositionDTO; +import com.cool.store.dto.recipe.RecipeSpLaunchDTO; +import com.cool.store.dto.recipe.RevenueDataDTO; +import com.cool.store.dto.recipe.RevenueDataQueryDTO; import com.cool.store.dto.store.StoreUserUpdateDTO; +import com.cool.store.entity.StoreDO; import com.cool.store.enums.ErrorCodeEnum; import com.cool.store.exception.ServiceException; +import com.cool.store.request.recipe.RevenueDataRequest; import com.cool.store.response.caipin.StoreUserResponse; import com.cool.store.response.oppty.OpportunityApiResponse; import com.cool.store.service.ThirdFoodService; +import com.cool.store.utils.BeanUtil; import com.cool.store.utils.SignatureUtils; +import com.cool.store.vo.recipe.RevenueDataVO; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.ObjectMapper; @@ -24,9 +30,9 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import javax.annotation.Resource; -import java.net.URI; +import java.util.Collections; import java.util.List; -import java.util.Map; +import java.util.Objects; /** * @Author suzhuhong @@ -45,6 +51,8 @@ public class ThirdFoodServiceImpl implements ThirdFoodService { OkHttpClient okHttpClient; @Resource ObjectMapper objectMapper; + @Resource + private StoreDao storeDao; @Override @@ -60,6 +68,29 @@ public class ThirdFoodServiceImpl implements ThirdFoodService { return executeApiCall(url, dto, StoreUserResponse.class); } + @Override + public List getRevenueData(RevenueDataRequest request) { + StoreDO storeDO = storeDao.getByStoreId(request.getStoreId()); + if (Objects.isNull(storeDO)) { + throw new ServiceException(ErrorCodeEnum.STORE_NOT_FIND); + } + RevenueDataQueryDTO queryDTO = new RevenueDataQueryDTO(storeDO.getStoreNum(), request.getBusinessDateFrom(), request.getBusinessDateTo()); + String url = "/v1/store/business"; + List list = executeApiCall(url, queryDTO, List.class); + return BeanUtil.toList(list, RevenueDataVO.class, CopyOptions.create().setFieldMapping(Collections.singletonMap("storeCode", "storeNum"))); + } + + @Override + public RecipeSpLaunchDTO getRecipeServiceLaunch(RevenueDataRequest request) { + StoreDO storeDO = storeDao.getByStoreId(request.getStoreId()); + if (Objects.isNull(storeDO)) { + throw new ServiceException(ErrorCodeEnum.STORE_NOT_FIND); + } + RevenueDataQueryDTO queryDTO = new RevenueDataQueryDTO(storeDO.getStoreNum(), request.getBusinessDateFrom(), request.getBusinessDateTo()); + String url = "/v1/store/business/spRecipeList"; + return executeApiCall(url, queryDTO, RecipeSpLaunchDTO.class); + } + private T executeApiCall(String url, Object requestBody, Class responseType) { // 1. 打印请求前日志 diff --git a/coolstore-partner-service/src/main/java/com/cool/store/service/impl/WechatMiniAppServiceImpl.java b/coolstore-partner-service/src/main/java/com/cool/store/service/impl/WechatMiniAppServiceImpl.java index 169b77771..bf6ddb727 100644 --- a/coolstore-partner-service/src/main/java/com/cool/store/service/impl/WechatMiniAppServiceImpl.java +++ b/coolstore-partner-service/src/main/java/com/cool/store/service/impl/WechatMiniAppServiceImpl.java @@ -111,9 +111,16 @@ public class WechatMiniAppServiceImpl implements WechatMiniAppService { PartnerUserWechatBindDO bindDO = new PartnerUserWechatBindDO(); bindDO.setBindTime(new Date()); bindDO.setOpenId(openid); + bindDO.setUnionId(unionId); bindDO.setPartnerId(hyPartnerUserInfoDO.getPartnerId()); bindDO.setCreateTime(new Date()); partnerUserWechatBindDAO.insertSelective(bindDO); + }else { + //维护unionId 针对老数据没有unionId + if (zlPartnerUserBindDO.getUnionId()==null){ + zlPartnerUserBindDO.setUnionId(unionId); + partnerUserWechatBindDAO.update(zlPartnerUserBindDO); + } } BeanUtil.copyProperties(hyPartnerUserInfoDO, userInfoVO); fillLineInfo(userInfoVO, hyPartnerUserInfoDO.getPartnerId()); diff --git a/coolstore-partner-service/src/main/java/com/cool/store/service/impl/xinfa/XinFaBusinessServiceImpl.java b/coolstore-partner-service/src/main/java/com/cool/store/service/impl/xinfa/XinFaBusinessServiceImpl.java new file mode 100644 index 000000000..b00e6b0dc --- /dev/null +++ b/coolstore-partner-service/src/main/java/com/cool/store/service/impl/xinfa/XinFaBusinessServiceImpl.java @@ -0,0 +1,67 @@ +package com.cool.store.service.impl.xinfa; + +import com.cool.store.dto.huoma.*; +import com.cool.store.enums.SpecialTagEnum; +import com.cool.store.response.ResponseResult; +import com.cool.store.service.xinfa.XinFaBusinessService; +import com.cool.store.service.xinfa.XinFaDeviceService; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @Author suzhuhong + * @Date 2025/11/5 16:17 + * @Version 1.0 + */ +@Service +public class XinFaBusinessServiceImpl implements XinFaBusinessService { + @Resource + XinFaDeviceService xinFaDeviceService; + + @Override + public List getStoreXinFaDeviceDetail(String storeNum) { + return xinFaDeviceService.getStoreXinFaDeviceDetail(storeNum); + } + + @Override + public List getAccountAllTags(String storeNum,String deviceName) { + //如果是广告机,不需要展示标签 + if (deviceName.contains("广告机")){ + return new ArrayList<>(); + } + List accountAllTags = xinFaDeviceService.getAccountAllTags(storeNum); + if (accountAllTags != null){ + return accountAllTags.stream() + .filter(tag -> tag.getName() != null && + SpecialTagEnum.getAllTagNames().contains(tag.getName())) + .sorted(Comparator.comparing(tag -> SpecialTagEnum.getAllTagNames().indexOf(tag.getName()))) + .collect(Collectors.toList()); + } + return null; + } + + @Override + public List getProgramList(ProgramReqDTO programReqDTO) { + //如果没传tag 查所有 根据更新时间倒序排 + programReqDTO.setSort("desc"); + programReqDTO.setDate("updateTime"); + if (CollectionUtils.isEmpty(programReqDTO.getTagIds())){ + //设备名称包含 广告机 只查询电子价目表 + programReqDTO.setTagIds(xinFaDeviceService.getAccountSpecialTagIds(programReqDTO.getStoreCode(), SpecialTagEnum.getElectronicPriceTagName())); + } + List programList = xinFaDeviceService.getProgramList(programReqDTO); + return programList; + } + + @Override + public Boolean publishProgram(PublishDTO publishDTO) { + return xinFaDeviceService.publish(publishDTO); + } +} diff --git a/coolstore-partner-service/src/main/java/com/cool/store/service/wechat/WechatTemplateService.java b/coolstore-partner-service/src/main/java/com/cool/store/service/wechat/WechatTemplateService.java new file mode 100644 index 000000000..eb40fbde8 --- /dev/null +++ b/coolstore-partner-service/src/main/java/com/cool/store/service/wechat/WechatTemplateService.java @@ -0,0 +1,149 @@ +package com.cool.store.service.wechat; + +import com.cool.store.builder.TemplateMessageBuilder; +import com.cool.store.config.weixin.WechatMpProperties; +import com.cool.store.dto.wechat.AccessTokenDTO; +import com.cool.store.dto.wechat.WechatTemplateMessageDTO; +import com.cool.store.dto.wechat.WechatUserInfoDTO; +import com.cool.store.enums.wechat.WechatTemplateEnum; +import com.cool.store.utils.OkHttpUtil; +import com.cool.store.utils.RedisUtilPool; +import com.cool.store.utils.poi.StringUtils; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.io.IOException; +import java.util.Map; + +/** + * @Author suzhuhong + * @Date 2025/10/10 14:15 + * @Version 1.0 + */ +@Slf4j +@Service +public class WechatTemplateService { + + + private static final String ACCESS_TOKEN_KEY = "wechat_service_account_access_token"; + + @Autowired + private WechatMpProperties wechatMpProperties; + + @Autowired + private TemplateMessageBuilder templateMessageBuilder; + + @Autowired + private OkHttpUtil okHttpUtil; + @Autowired + private ObjectMapper objectMapper; + @Resource + private RedisUtilPool redisUtilPool; + + + public String getAccessToken() { + String cachedToken = redisUtilPool.getString(ACCESS_TOKEN_KEY); + if (StringUtils.isNotEmpty(cachedToken)) { + log.info("从 Redis 获取 access_token: {}", cachedToken); + return cachedToken; + } + String url = String.format("%s?grant_type=client_credential&appid=%s&secret=%s", + wechatMpProperties.getAccessTokenUrl(), + wechatMpProperties.getAppId(), + wechatMpProperties.getAppSecret()); + try { + String result = okHttpUtil.doGet(url); + log.info("获取access_token响应: {}", result); + + if (StringUtils.isNotEmpty( result)){ + AccessTokenDTO responseDTO = objectMapper.readValue(result, AccessTokenDTO.class); + String accessToken = responseDTO.getAccess_token(); + + // 将获取到的 token 存入 Redis,设置过期时间(微信 token 有效期 7200 秒,这里设置 7000 秒) + if (StringUtils.isNotEmpty(accessToken)) { + redisUtilPool.setString(ACCESS_TOKEN_KEY, accessToken, 7000); + log.info("将 access_token 存入 Redis: {}", accessToken); + } + return accessToken; + } + return null; + } catch (IOException e) { + log.error("获取access_token失败", e); + } catch (Exception e) { + log.error("解析access_token响应失败", e); + } + return null; + } + + public WechatUserInfoDTO getUserInfo(String openId, String lang) { + String accessToken = getAccessToken(); + //默认中国 + lang = StringUtils.isEmpty(lang)?"zh_CN":lang; + if (accessToken == null) { + log.error("获取access_token失败"); + return null; + } + String url = String.format("https://api.weixin.qq.com/cgi-bin/user/info?access_token=%s&openid=%s", + accessToken, openId); + + if (lang != null && !lang.trim().isEmpty()) { + url += "&lang=" + lang; + } + try { + String result = okHttpUtil.doGet(url); + log.debug("获取用户信息响应: {}", result); + WechatUserInfoDTO userInfo = objectMapper.readValue(result, WechatUserInfoDTO.class); + return userInfo; + } catch (IOException e) { + log.error("获取用户信息失败", e); + return null; + } catch (Exception e) { + log.error("解析用户信息响应失败", e); + return null; + } + } + + public boolean sendNormalTemplate(String openId, WechatTemplateEnum template, Map data) { + WechatTemplateMessageDTO messageDTO = templateMessageBuilder.buildNormalTemplate(openId, template, data); + return sendTemplateMessage(messageDTO); + } + + public boolean sendMiniAppTemplate(String openId, WechatTemplateEnum template, + Map data, String miniAppPagePath) { + WechatTemplateMessageDTO messageDTO = templateMessageBuilder.buildMiniappTemplate( + openId, template, data, miniAppPagePath); + return sendTemplateMessage(messageDTO); + } + + public boolean sendMiniAppTemplateWithUrl(String openId, WechatTemplateEnum template, + Map data, String miniAppPagePath, String backupUrl) { + WechatTemplateMessageDTO messageDTO = templateMessageBuilder.buildMiniAppTemplateWithUrl( + openId, template, data, miniAppPagePath, backupUrl); + return sendTemplateMessage(messageDTO); + } + + private boolean sendTemplateMessage(WechatTemplateMessageDTO messageDTO) { + String accessToken = getAccessToken(); + if (accessToken == null) { + log.error("获取access_token失败,无法发送模板消息"); + return false; + } + + String url = String.format("%s?access_token=%s", + wechatMpProperties.getSendTemplateMessageUrl(), accessToken); + + log.info("发送模板消息: {}", messageDTO); + try { + String result = okHttpUtil.doPostJson(url, messageDTO); + log.info("发送模板消息响应: {}", result); + + return Boolean.TRUE; + } catch (Exception e) { + log.error("解析模板消息响应失败", e); + return false; + } + } +} diff --git a/coolstore-partner-service/src/main/java/com/cool/store/service/xinfa/XinFaBusinessService.java b/coolstore-partner-service/src/main/java/com/cool/store/service/xinfa/XinFaBusinessService.java new file mode 100644 index 000000000..8ff1c2fd6 --- /dev/null +++ b/coolstore-partner-service/src/main/java/com/cool/store/service/xinfa/XinFaBusinessService.java @@ -0,0 +1,48 @@ +package com.cool.store.service.xinfa; + +import com.cool.store.dto.huoma.*; +import com.cool.store.response.ResponseResult; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.List; + +/** + * @Author suzhuhong + * @Date 2025/11/5 16:15 + * @Version 1.0 + */ +public interface XinFaBusinessService { + + + /** + * 获取门店信发设备列表 + * @param storeNum + * @return + */ + List getStoreXinFaDeviceDetail(String storeNum); + + /** + * 获取账号下有哪些标签 + * @param storeNum + * @return + */ + List getAccountAllTags(String storeNum,String deviceName); + + /** + * 获取账号下有哪些节目、 + * 通过门店在哪个账号下 确定账号 + * @param programReqDTO + * @return + */ + List getProgramList(ProgramReqDTO programReqDTO); + + /** + * 发布信发设备 + * @param publishDTO + * @return + */ + Boolean publishProgram(PublishDTO publishDTO); + + + +} diff --git a/coolstore-partner-service/src/main/java/com/cool/store/service/xinfa/XinFaDeviceService.java b/coolstore-partner-service/src/main/java/com/cool/store/service/xinfa/XinFaDeviceService.java new file mode 100644 index 000000000..fd1eb065e --- /dev/null +++ b/coolstore-partner-service/src/main/java/com/cool/store/service/xinfa/XinFaDeviceService.java @@ -0,0 +1,491 @@ +package com.cool.store.service.xinfa; + +import com.alibaba.fastjson.JSONObject; +import com.cool.store.constants.RedisConstant; +import com.cool.store.dto.huoma.*; +import com.cool.store.enums.ErrorCodeEnum; +import com.cool.store.enums.SpecialTagEnum; +import com.cool.store.exception.ServiceException; +import com.cool.store.response.ResponseResult; +import com.cool.store.utils.RedisUtilPool; +import com.cool.store.utils.poi.constant.Constants; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import okhttp3.*; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.jetbrains.annotations.NotNull; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.web.bind.annotation.RequestParam; + +import javax.annotation.PostConstruct; +import javax.annotation.Resource; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.*; +import java.util.stream.Collectors; + +/** + * @Author suzhuhong + * @Date 2025/11/4 15:47 + * @Version 1.0 + */ +@Service +@Slf4j +public class XinFaDeviceService { + + @Value("${huoMa.direct.stores.account}") + private String huoMaDirectStoresAccount; + @Value("${huoMa.direct.stores.password}") + private String huoMaDirectStoresPassword; + @Value("${huoMa.franchise.stores.account}") + private String huoMaFranchiseStoresAccount; + @Value("${huoMa.franchise.stores.password}") + private String huoMaFranchiseStoresPassword; + @Value("${huoMa.restaurant.stores.account}") + private String huoMaRestaurantStoresAccount; + @Value("${huoMa.restaurant.stores.password}") + private String huoMaRestaurantStoresPassword; + @Resource + RedisUtilPool redisUtilPool; + @Value("${huoMa.token.url}") + private String huoMaTokenUrl; + @Value("${huoMa.get.point.terminal.url}") + private String huoMaGetPointTerminalUrl; + @Value("${huoMa.id.url}") + private String huoMaGetStoreIdUrl; + @Value("${huoMa.store.device.detail.url}") + private String huoMaGetStoreXinFaDeviceDetailUrl ; + @Value("${huoMa.get.tag.url}") + private String huoMaGetTagUrl; + @Value("${huoMa.get.program.url}") + private String huoMaGetProgramUrl; + @Value("${huoMa.get.publish.url}") + private String huoMaGetPublishUrl; + + + private final Map accountMap = new HashMap<>(); + + @PostConstruct + public void initAccountMap() { + accountMap.put("restaurant", new HuoMaAccountDTO(huoMaRestaurantStoresAccount, huoMaRestaurantStoresPassword)); + accountMap.put("direct", new HuoMaAccountDTO(huoMaDirectStoresAccount, huoMaDirectStoresPassword)); + accountMap.put("franchise", new HuoMaAccountDTO(huoMaFranchiseStoresAccount, huoMaFranchiseStoresPassword)); + } + + public String getStoreToken(String account, String password) { + String key = MessageFormat.format(RedisConstant.HUO_MA_TOKEN, account); + String accessToken = redisUtilPool.getString(key); + if (accessToken != null) { + return accessToken; + } + Map requestBody = new HashMap<>(); + requestBody.put("account", account); + requestBody.put("password", password); + String responseBody = sendPostRequest(JSONObject.toJSONString(requestBody), huoMaTokenUrl); + try{ + ObjectMapper mapper = new ObjectMapper(); + JsonNode rootNode = mapper.readTree(responseBody); + String token = rootNode.path("data").path("token").asText(); + //缓存60秒 + redisUtilPool.setString(key, token,60*60); + return token; + }catch (Exception e){ + log.error("解析获取token失败,url:{},responseBody:{}",huoMaTokenUrl, responseBody); + } + return null; + } + + + public List getStoreEquipmentDataByStoreNumList(List storeNumList, String token) { + Map> requestBody = new HashMap<>(); + requestBody.put("codeList", storeNumList); + String responseBody = sendPostRequestByToken(JSONObject.toJSONString(requestBody), huoMaGetPointTerminalUrl,token); + try{ + ObjectMapper mapper = new ObjectMapper(); + JsonNode rootNode = mapper.readTree(responseBody); + return mapper.convertValue(rootNode.get("data"), + mapper.getTypeFactory().constructCollectionType(List.class, StoreEquipmentDTO.class)); + }catch (Exception e){ + log.error("解析获取data失败,url:{},responseBody:{}",huoMaTokenUrl, responseBody); + } + return Collections.emptyList(); + } + + + + public Integer getStoreIdByStoreNum(String storeNum, String token) { + String houMaStoreId = redisUtilPool.hashGet(RedisConstant.HUO_MA_STORE_ID, storeNum); + if (houMaStoreId != null) { + try { + return Integer.valueOf(houMaStoreId); + } catch (NumberFormatException e) { + // 如果缓存中的数据格式不正确,继续执行正常逻辑 + log.warn("Redis缓存中的门店ID格式不正确,storeNum: {}", storeNum); + } + } + StoreRequestDTO requestBody = new StoreRequestDTO("point_report", 0, 10, storeNum); + String responseBody = sendPostRequestByToken(JSONObject.toJSONString(requestBody), huoMaGetStoreIdUrl,token); + try{ + Integer storeId = extractIdsFromResponse(responseBody); + redisUtilPool.hashSet(RedisConstant.HUO_MA_STORE_ID, storeNum, storeId.toString()); + return storeId; + }catch (Exception e){ + log.error("解析获取data失败,url:{},responseBody:{}",huoMaTokenUrl, responseBody); + } + return null; + } + + + public List getStoreXinFaDeviceDetail(String storeNum) { + String source = redisUtilPool.hashGet(RedisConstant.HUOMA_STORE_DEVICE_RESOURCE_KEY, storeNum); + if (StringUtils.isNotBlank(source)) { + HuoMaAccountDTO huoMaAccountDTO = accountMap.get(source); + if (Objects.nonNull(huoMaAccountDTO)) { + String token = getStoreToken(huoMaAccountDTO.getAccount(), huoMaAccountDTO.getPassword()); + List deviceDetailDetail = getStoreXinFaDeviceDetailDetail(storeNum, token); + if (CollectionUtils.isNotEmpty(deviceDetailDetail)) { + return deviceDetailDetail; + } + } + } + for (Map.Entry entry : accountMap.entrySet()) { + HuoMaAccountDTO huoMaAccountDTO = entry.getValue(); + if (!huoMaAccountDTO.getIsQuery()) { + String token = getStoreToken(huoMaAccountDTO.getAccount(), huoMaAccountDTO.getPassword()); + List deviceDetailDetail = getStoreXinFaDeviceDetailDetail(storeNum, token); + if (CollectionUtils.isNotEmpty(deviceDetailDetail)) { + redisUtilPool.hashSet(RedisConstant.HUOMA_STORE_DEVICE_RESOURCE_KEY, storeNum, entry.getKey(), Constants.REFRESH_TOKEN_EXPIRE); + return deviceDetailDetail; + } + } + } + return Collections.emptyList(); + } + + + public List getStoreXinFaDeviceDetailDetail(String storeNum, String token) { + Integer storeIdByStoreNum = getStoreIdByStoreNum(storeNum, token); + return getStoreXinFaDeviceDetailByPointId(storeIdByStoreNum, token); + } + + + public List getAccountAllTags(String storeNum){ + String source = redisUtilPool.hashGet(RedisConstant.HUOMA_STORE_DEVICE_RESOURCE_KEY, storeNum); + //获取标签 必须要知道门店属于哪个账号下 获取对应账号下的标签 如果获取不到 直接返回空 + if (StringUtils.isEmpty(source)){ + log.info("门店没有找到对应的账号,storeNum: {}", storeNum); + return new ArrayList<>(); + } + HuoMaAccountDTO huoMaAccountDTO = accountMap.get(source); + if (Objects.nonNull(huoMaAccountDTO)){ + huoMaAccountDTO.setIsQuery(true); + String token = getStoreToken(huoMaAccountDTO.getAccount(), huoMaAccountDTO.getPassword()); + TagDTO tagDTO = new TagDTO("DEFAULT", 0, 30,"program"); + String responseBody = null; + try{ + responseBody = sendPostRequestByToken(JSONObject.toJSONString(tagDTO), huoMaGetTagUrl,token); + ObjectMapper mapper = new ObjectMapper(); + JsonNode rootNode = mapper.readTree(responseBody); + + // 直接转换整个数组 + return mapper.convertValue( + rootNode.path("data").path("content"), + mapper.getTypeFactory().constructCollectionType(List.class, TagDetailDTO.class) + ); + }catch (Exception e){ + log.error("getAccountAllTags解析获取data失败,url:{},responseBody:{}",huoMaTokenUrl, responseBody); + } + } + return new ArrayList<>(); + } + + + /** + * 获取账号下指定标签的id 只需要一下四个 + * @param storeNum + * @return + */ + public List getAccountSpecialTagIds( String storeNum,List tagList) { + List accountAllTags = getAccountAllTags(storeNum); + if (accountAllTags != null) { + return accountAllTags.stream() + .filter(tag -> tag.getName() != null && + tagList.contains(tag.getName())) + .map(TagDetailDTO::getId) + .collect(Collectors.toList()); + } + return new ArrayList<>(); + } + + + public List getProgramList(ProgramReqDTO programReqDTO) { + if (StringUtils.isEmpty(programReqDTO.getStoreCode())){ + log.info("门店没有找到对应的账号,storeNum: {}", programReqDTO.getStoreCode()); + return new ArrayList<>(); + } + //先查询门店是属于哪个账号下 + String source = redisUtilPool.hashGet(RedisConstant.HUOMA_STORE_DEVICE_RESOURCE_KEY, programReqDTO.getStoreCode()); + //获取标签 必须要知道门店属于哪个账号下 获取对应账号下的标签 如果获取不到 直接返回空 + if (StringUtils.isEmpty(source)){ + log.info("门店没有找到对应的账号,storeNum: {}", programReqDTO.getStoreCode()); + return new ArrayList<>(); + } + HuoMaAccountDTO huoMaAccountDTO = accountMap.get(source); + if (huoMaAccountDTO!=null){ + String token = getStoreToken(huoMaAccountDTO.getAccount(), huoMaAccountDTO.getPassword()); + String responseBody = null; + try{ + responseBody = sendPostRequestByToken(JSONObject.toJSONString(programReqDTO), huoMaGetProgramUrl,token); + ObjectMapper mapper = new ObjectMapper(); + JsonNode rootNode = mapper.readTree(responseBody); + + // 直接转换整个数组 + return mapper.convertValue( + rootNode.path("data").path("content"), + mapper.getTypeFactory().constructCollectionType(List.class, ProgramResponseDTO.class) + ); + }catch (Exception e){ + log.error("getProgramList 解析获取data失败,url:{},responseBody:{}",huoMaTokenUrl, responseBody); + } + } + return new ArrayList<>(); + } + + public Boolean publish(PublishDTO publishDTO){ + if (StringUtils.isEmpty(publishDTO.getStoreCode())){ + log.info("门店没有找到对应的账号,发布失败,storeNum: {}", publishDTO.getStoreCode()); + return Boolean.FALSE; + } + String source = redisUtilPool.hashGet(RedisConstant.HUOMA_STORE_DEVICE_RESOURCE_KEY, publishDTO.getStoreCode()); + //获取标签 必须要知道门店属于哪个账号下 获取对应账号下的标签 如果获取不到 直接返回空 + if (StringUtils.isEmpty(source)){ + log.info("门店没有找到对应的账号,storeNum: {}", publishDTO.getStoreCode()); + return Boolean.FALSE; + } + HuoMaAccountDTO huoMaAccountDTO = accountMap.get(source); + if (huoMaAccountDTO!=null){ + String token = getStoreToken(huoMaAccountDTO.getAccount(), huoMaAccountDTO.getPassword()); + String responseBody = null; + try{ + responseBody = sendPostRequestByToken(JSONObject.toJSONString(publishDTO), huoMaGetPublishUrl,token); + ObjectMapper mapper = new ObjectMapper(); + JsonNode rootNode = mapper.readTree(responseBody); + int code = rootNode.get("code").asInt(); + if (code != 0) { + throw new RuntimeException("发布失败"); + } + // 直接转换整个数组 + log.info("发布成功 deviceId:{},storeCode:{}",JSONObject.toJSONString(publishDTO.getDeviceIdList()), publishDTO.getStoreCode() ); + return Boolean.TRUE; + }catch (Exception e){ + log.error("发布失败, url:{}, responseBody:{}", huoMaTokenUrl, responseBody); + } + } + return Boolean.FALSE; + } + + + + public List getStoreXinFaDeviceDetailByPointId(Integer pointId, String token) { + if (pointId != null){ + StoreXinFaDetailRequestDTO storeXinFaDetailRequestDTO = new StoreXinFaDetailRequestDTO(0, 10, pointId); + String responseBody = null; + try{ + responseBody = sendPostRequestByToken(JSONObject.toJSONString(storeXinFaDetailRequestDTO), huoMaGetStoreXinFaDeviceDetailUrl,token); + ObjectMapper mapper = new ObjectMapper(); + JsonNode rootNode = mapper.readTree(responseBody); + + // 直接转换整个数组 + return mapper.convertValue( + rootNode.path("data").path("content"), + mapper.getTypeFactory().constructCollectionType(List.class, StoreXinFaDeviceDetail.class) + ); + }catch (Exception e){ + log.error("getStoreXinFaDeviceDetailByPointId解析获取data失败,url:{},responseBody:{}",huoMaTokenUrl, responseBody); + } + return null; + } + return null; + } + + private Integer extractIdsFromResponse(String jsonResponse) throws IOException { + ObjectMapper mapper = new ObjectMapper(); + JsonNode rootNode = mapper.readTree(jsonResponse); + // 遍历dataList数组提取ID + JsonNode dataList = rootNode.path("data").path("dataList"); + for (JsonNode item : dataList) { + if (item.has("ID")) { + //取出第一个id + return item.get("ID").asInt(); + } + } + return null; + } + + private String sendPostRequest(String requestBody, String requestUrl) { + log.info("开始发送请求,url:{},requestBody:{}", requestUrl, requestBody); + + int maxRetries = 3; + for (int i = 0; i < maxRetries; i++) { + try { + Request request = new Request.Builder() + .url(requestUrl) + .post(RequestBody.create(MediaType.parse("application/json"), requestBody)) + .build(); + + return sendPost(requestUrl, request); + } catch (Exception e) { + log.warn("请求失败,第{}次重试,错误: {}", i + 1, e.getMessage()); + if (i == maxRetries - 1) { + throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR, "请求重试失败: " + e.getMessage()); + } + // 重试前等待 + try { + Thread.sleep(1000 * (i + 1)); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR, "重试被中断"); + } + } + } + throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR, "请求重试失败"); + } + + private String sendPostRequestByToken(String requestBody, String requestUrl, String token) { + log.info("开始发送请求,url:{},requestBody:{}", requestUrl, requestBody); + + int maxRetries = 3; + for (int i = 0; i < maxRetries; i++) { + try { + Request request = new Request.Builder() + .url(requestUrl) + .post(RequestBody.create(MediaType.parse("application/json"), requestBody)) + .addHeader("token", token) + .build(); + + String result = sendPost(requestUrl, request); + + // 检查是否token失效 + if (isTokenExpired(result)) { + log.warn("Token已失效,正在清除缓存并重试,第{}次", i + 1); + // 直接清除对应账号的token缓存 + token = clearAccountTokenCacheForToken(token); + + // 抛出异常触发重试 + throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR, "Token失效,需要重试"); + } + + return result; + } catch (ServiceException e) { + log.warn("请求失败,第{}次重试,错误: {}", i + 1, e.getMessage()); + if (i == maxRetries - 1) { + throw e; + } + try { + Thread.sleep(1000 * (i + 1)); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR, "重试被中断"); + } + } catch (Exception e) { + log.warn("请求异常,第{}次重试,错误: {}", i + 1, e.getMessage()); + if (i == maxRetries - 1) { + throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR, "请求重试失败: " + e.getMessage()); + } + try { + Thread.sleep(1000 * (20*i + 1)); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR, "重试被中断"); + } + } + } + throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR, "请求重试失败"); + } + + private boolean isTokenExpired(String responseBody) { + try { + ObjectMapper mapper = new ObjectMapper(); + JsonNode rootNode = mapper.readTree(responseBody); + int code = rootNode.path("code").asInt(-1); + String msg = rootNode.path("msg").asText(""); + + return code == 501; + } catch (Exception e) { + log.error("检查token失效状态时发生错误: {}", e.getMessage()); + return false; + } + } + + private String clearAccountTokenCacheForToken(String token) { + try { + // 遍历可能的账号,找到对应的缓存并删除 + String[] accounts = { + huoMaDirectStoresAccount, + huoMaFranchiseStoresAccount, + huoMaRestaurantStoresAccount + }; + + for (String account : accounts) { + if (account != null) { + String key = MessageFormat.format(RedisConstant.HUO_MA_TOKEN, account); + String cachedToken = redisUtilPool.getString(key); + if (token.equals(cachedToken)) { + redisUtilPool.delKey(key); + log.info("已清除账号 {} 的token缓存", account); + + // 根据账号类型获取对应的密码并重新获取token + String password = getPasswordForAccount(account); + if (password != null) { + String newToken = getStoreToken(account, password); + if (newToken != null) { + log.info("已为账号 {} 重新获取新的token", account); + return newToken; + } + } + break; + } + } + } + } catch (Exception e) { + log.error("清除token缓存或重新获取token失败: {}", e.getMessage()); + } + return null; + } + + + private String getPasswordForAccount(String account) { + if (account.equals(huoMaDirectStoresAccount)) { + return huoMaDirectStoresPassword; + } else if (account.equals(huoMaFranchiseStoresAccount)) { + return huoMaFranchiseStoresPassword; + } else if (account.equals(huoMaRestaurantStoresAccount)) { + return huoMaRestaurantStoresPassword; + } + return null; + } + + @NotNull + private static String sendPost(String requestUrl, Request request) { + try (Response response = new OkHttpClient().newCall(request).execute()) { + log.info("发起请求 time:{}", System.currentTimeMillis()); + if (!response.isSuccessful()) { + log.info("HTTP请求失败,msg: " + response.message()); + throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR, + "HTTP请求失败,状态码: " + response.code()); + } + String responseBody = response.body().string(); + log.info("请求成功responseBody:{}", JSONObject.toJSONString(responseBody)); + return responseBody; + } catch (ServiceException e) { + throw e; + } catch (Exception e) { + log.error("API调用异常 - URL: {}, 错误: {}", requestUrl, e.getMessage(), e); + throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR, "接口调用异常: " + e.getMessage()); + } + } + +} diff --git a/coolstore-partner-service/src/main/java/com/cool/store/utils/poi/constant/Constants.java b/coolstore-partner-service/src/main/java/com/cool/store/utils/poi/constant/Constants.java index b08d231e6..7c5cdc771 100644 --- a/coolstore-partner-service/src/main/java/com/cool/store/utils/poi/constant/Constants.java +++ b/coolstore-partner-service/src/main/java/com/cool/store/utils/poi/constant/Constants.java @@ -220,4 +220,6 @@ public class Constants public static final String WANG_LEI_JOB_NUMBER = "19060164"; + public static final int REFRESH_TOKEN_EXPIRE = 60*60*24*30; + } diff --git a/coolstore-partner-web/src/main/java/com/cool/store/config/OpenApiValidateFilter.java b/coolstore-partner-web/src/main/java/com/cool/store/config/OpenApiValidateFilter.java index 1eb0558b3..682af5c52 100644 --- a/coolstore-partner-web/src/main/java/com/cool/store/config/OpenApiValidateFilter.java +++ b/coolstore-partner-web/src/main/java/com/cool/store/config/OpenApiValidateFilter.java @@ -42,6 +42,11 @@ public class OpenApiValidateFilter implements Filter { private String coolAppKey; @Value("${cool.api.secret}") private String coolAppSecret; + private static final Set WHITELIST_URIS = new HashSet<>(Arrays.asList( + "/zxjp/open/v1/statusRefresh", + "/zxjp/open/v1/getStoreUser", + "/zxjp/open/v1/callback" + )); private static final List oldUrlMapping = new ArrayList<>(Arrays.asList( "/zxjp/open/v1/statusRefresh","/zxjp/open/v1/changePaymentStatus", "/zxjp/open/v1/getYlsToken", "/zxjp/open/v1/getStoreList", @@ -61,7 +66,7 @@ public class OpenApiValidateFilter implements Filter { } MDC.put(CommonConstants.REQUEST_ID, UUIDUtils.get32UUID()); //statusRefresh 放开不需要验签 - if (uri.startsWith("/zxjp/open/v1/statusRefresh") || uri.startsWith("/zxjp/open/v1/getStoreUser")) { + if (isWhitelistUri(uri)) { filterChain.doFilter(servletRequest, response); return; } @@ -174,6 +179,9 @@ public class OpenApiValidateFilter implements Filter { return OpenSignatureUtil.generateOldSign(params, coolAppSecret); } + private boolean isWhitelistUri(String uri) { + return WHITELIST_URIS.stream().anyMatch(uri::startsWith); + } @Override public void destroy() { } diff --git a/coolstore-partner-web/src/main/java/com/cool/store/controller/webb/DataBoardController.java b/coolstore-partner-web/src/main/java/com/cool/store/controller/webb/DataBoardController.java new file mode 100644 index 000000000..4e69892b7 --- /dev/null +++ b/coolstore-partner-web/src/main/java/com/cool/store/controller/webb/DataBoardController.java @@ -0,0 +1,37 @@ +package com.cool.store.controller.webb; + +import com.cool.store.request.recipe.RevenueDataRequest; +import com.cool.store.response.ResponseResult; +import com.cool.store.service.ThirdFoodService; +import com.cool.store.vo.recipe.RevenueDataVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; + +/** + *

+ * 数据看板 前端控制器 + *

+ * + * @author wangff + * @since 2025/10/30 + */ +@RestController +@RequestMapping("/pc/databoard") +@Api(tags = "数据看板") +@Slf4j +@RequiredArgsConstructor +public class DataBoardController { + private final ThirdFoodService thirdFoodService; + + @ApiOperation("门店营收") + @PostMapping("/revenueData") + public ResponseResult> getStoreRevenueData(@RequestBody @Valid RevenueDataRequest request) { + return ResponseResult.success(thirdFoodService.getRevenueData(request)); + } +} diff --git a/coolstore-partner-web/src/main/java/com/cool/store/controller/webb/OpenApiController.java b/coolstore-partner-web/src/main/java/com/cool/store/controller/webb/OpenApiController.java index 583927355..c44825039 100644 --- a/coolstore-partner-web/src/main/java/com/cool/store/controller/webb/OpenApiController.java +++ b/coolstore-partner-web/src/main/java/com/cool/store/controller/webb/OpenApiController.java @@ -5,6 +5,7 @@ import com.cool.store.context.PartnerUserHolder; import com.cool.store.dto.*; import com.cool.store.dto.store.StoreUserPositionDTO; import com.cool.store.dto.wx.MiniProgramFreeLoginDTO; +import com.cool.store.handler.WeChatHandler; import com.cool.store.request.OpenApiStoreRequest; import com.cool.store.request.StoreCodeDTO; import com.cool.store.request.*; @@ -15,10 +16,12 @@ import com.cool.store.request.xgj.ReceiptCallBackRequest; import com.cool.store.response.ResponseResult; import com.cool.store.response.bigdata.ApiResponse; import com.cool.store.service.*; +import com.cool.store.utils.poi.StringUtils; import com.github.pagehelper.PageInfo; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -52,6 +55,8 @@ public class OpenApiController { MessageTemplateService messageTemplateService; @Resource WechatMiniAppService wechatMiniAppService; + @Autowired + WeChatHandler weChatHandler; @PostMapping("/statusRefresh") public ApiResponse statusRefresh(@RequestBody StatusRefreshDTO statusRefreshDTO){ @@ -185,4 +190,28 @@ public class OpenApiController { public ApiResponse getTokenByMobile(@RequestBody @Validated MiniProgramFreeLoginDTO param) { return ApiResponse.success(wechatMiniAppService.getShortTermTokenByMobile(param)); } + + @RequestMapping(value = "/callback", produces = "application/xml;charset=UTF-8") + @ApiOperation("callback") + public String handleWechatMessage( + @RequestParam("signature") String signature, + @RequestParam("timestamp") String timestamp, + @RequestParam("nonce") String nonce, + @RequestParam(value = "echostr", required = false) String echostr, + @RequestBody(required = false) String requestBody) { + + log.info("url:{}","/open/v1/"); + log.info("callback_signature:{},timestamp:{},nonce:{}",signature,timestamp,nonce); + log.info("requestBody:{}",requestBody); + + if (StringUtils.isNotEmpty(requestBody)) { + try { + return weChatHandler.processMessage(weChatHandler.parseXmlToMap(requestBody)); + } catch (Exception e) { + log.info("回调处理失败 e:{}",e); + return "success"; + } + } + return echostr; + } } diff --git a/coolstore-partner-web/src/main/java/com/cool/store/controller/webb/PCTestController.java b/coolstore-partner-web/src/main/java/com/cool/store/controller/webb/PCTestController.java index 64c87bda8..ce2e5c02e 100644 --- a/coolstore-partner-web/src/main/java/com/cool/store/controller/webb/PCTestController.java +++ b/coolstore-partner-web/src/main/java/com/cool/store/controller/webb/PCTestController.java @@ -8,11 +8,16 @@ import com.cool.store.dto.FoodTokenDTO; import com.cool.store.dto.GetAccessTokenDTO; import com.cool.store.dto.HqtTokenDTO; import com.cool.store.dto.ModifyPasswordDTO; +import com.cool.store.dto.huoma.*; +import com.cool.store.dto.wechat.CallbackMessageDTO; +import com.cool.store.dto.wechat.WechatTemplateMessageDTO; import com.cool.store.entity.*; import com.cool.store.enums.DownSystemTypeEnum; import com.cool.store.enums.MessageEnum; import com.cool.store.enums.SMSMsgEnum; import com.cool.store.enums.point.ShopSubStageStatusEnum; +import com.cool.store.enums.wechat.WechatTemplateEnum; +import com.cool.store.handler.WeChatHandler; import com.cool.store.job.XxlJobHandler; import com.cool.store.mapper.FranchiseFeeMapper; import com.cool.store.mapper.LineInfoMapper; @@ -36,10 +41,14 @@ import com.cool.store.service.*; import com.cool.store.service.impl.CommonService; import com.cool.store.service.impl.OrderSysInfoServiceImpl; import com.cool.store.service.impl.UserAuthMappingServiceImpl; +import com.cool.store.service.wechat.WechatTemplateService; +import com.cool.store.service.xinfa.XinFaBusinessService; +import com.cool.store.service.xinfa.XinFaDeviceService; import com.cool.store.utils.CoolDateUtils; import com.cool.store.utils.RedisConstantUtil; import com.cool.store.utils.RedisUtilPool; import com.cool.store.utils.poi.StringUtils; +import com.fasterxml.jackson.core.JsonProcessingException; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -92,14 +101,16 @@ public class PCTestController { private HttpRestTemplateService httpRestTemplateService; @Resource FranchiseFeeMapper franchiseFeeMapper; - + @Resource + WechatTemplateService wechatTemplateService; @Resource ShopInfoMapper shopInfoMapper; @Resource LinePayService linePayService; @Resource LinePayDAO linePayDAO; - + @Autowired + WeChatHandler weChatHandler; @GetMapping("/syncStore") public ResponseResult syncStore(@RequestParam("shopId")Long shopId){ syncMainSysServer.syncStore(shopId); @@ -556,4 +567,75 @@ public class PCTestController { return request; } + + @RequestMapping(value = "/testWxNotice", produces = "application/xml;charset=UTF-8") + @ApiOperation("testWxNotice") + public String handleWechatMessage( + @RequestParam("signature") String signature, + @RequestParam("timestamp") String timestamp, + @RequestParam("nonce") String nonce, + @RequestParam(value = "echostr", required = false) String echostr, + @RequestBody(required = false) String requestBody) { + + System.out.println("收到微信消息:"); + System.out.println("signature: " + signature); + System.out.println("timestamp: " + timestamp); + System.out.println("nonce: " + nonce); + System.out.println("echostr: " + echostr); + System.out.println("requestBody: " + requestBody); + + if (StringUtils.isNotEmpty(requestBody)) { + try { + return weChatHandler.processMessage(weChatHandler.parseXmlToMap(requestBody)); + } catch (Exception e) { + log.info("回调处理失败 e:{}",e.getMessage()); + return "success"; + } + } + return nonce; + } + + @ApiOperation("测试小程序模板消息") + @PostMapping("/testMiniAppTemplate") + public ApiResponse testMiniAppTemplate() { + Map data = new HashMap<>(); + data.put("character_string2", "ceshi002"); + data.put("thing10", "测试通知功能"); + data.put("time14", "2025-10-01 12:00:00"); + data.put("thing25", "正新管理有限公司"); + data.put("thing60", "上海市-松江区"); + wechatTemplateService.sendNormalTemplate("o9_unvpJy1SGdnkeun7igRBSLuB0", WechatTemplateEnum.QUESTION_NOTICE, data); + return ApiResponse.success(true); + } + + @Resource + XinFaBusinessService xinFaBusinessService; + @ApiOperation("测试门店设备信息") + @GetMapping("/getStoreXinFaDeviceDetail") + public ResponseResult> getStoreXinFaDeviceDetail(@RequestParam("storeNum")String storeNum) { + return ResponseResult.success(xinFaBusinessService.getStoreXinFaDeviceDetail(storeNum)); + } + + @ApiOperation("测试标签信息") + @GetMapping("/getAccountAllTags") + public ResponseResult> getAccountAllTags(@RequestParam("storeNum")String storeNum, + @RequestParam("deviceName")String deviceName) { + List accountAllTags = xinFaBusinessService.getAccountAllTags(storeNum,deviceName); + return ResponseResult.success(accountAllTags); + } + + @ApiOperation("获取节目列表") + @PostMapping("/getProgramList") + public ResponseResult> getProgramList(@RequestBody ProgramReqDTO programReqDTO) { + List accountAllTags = xinFaBusinessService.getProgramList(programReqDTO); + return ResponseResult.success(accountAllTags); + } + + @ApiOperation("发布/上架") + @PostMapping("/publishProgram") + public ResponseResult publishProgram(@RequestBody PublishDTO publishDTO) { + Boolean publishStatus = xinFaBusinessService.publishProgram(publishDTO); + return ResponseResult.success(publishStatus); + } + } diff --git a/coolstore-partner-web/src/main/java/com/cool/store/controller/webc/MiniDataBoardController.java b/coolstore-partner-web/src/main/java/com/cool/store/controller/webc/MiniDataBoardController.java new file mode 100644 index 000000000..e471872c4 --- /dev/null +++ b/coolstore-partner-web/src/main/java/com/cool/store/controller/webc/MiniDataBoardController.java @@ -0,0 +1,47 @@ +package com.cool.store.controller.webc; + +import com.cool.store.dto.recipe.RecipeSpLaunchDTO; +import com.cool.store.request.recipe.RevenueDataRequest; +import com.cool.store.response.ResponseResult; +import com.cool.store.service.ThirdFoodService; +import com.cool.store.vo.recipe.RevenueDataVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.Valid; +import java.util.List; + +/** + *

+ * 数据看板 前端控制器 + *

+ * + * @author wangff + * @since 2025/10/30 + */ +@RestController +@RequestMapping("/mini/databoard") +@Api(tags = "Mini数据看板") +@Slf4j +@RequiredArgsConstructor +public class MiniDataBoardController { + private final ThirdFoodService thirdFoodService; + + @ApiOperation("门店营收") + @PostMapping("/revenueData") + public ResponseResult> getStoreRevenueData(@RequestBody @Valid RevenueDataRequest request) { + return ResponseResult.success(thirdFoodService.getRevenueData(request)); + } + + @ApiOperation("查询菜品服务包上新数据") + @PostMapping("/recipeSpLaunch") + public ResponseResult getRecipeSpLaunchData(@RequestBody @Valid RevenueDataRequest request) { + return ResponseResult.success(thirdFoodService.getRecipeServiceLaunch(request)); + } +} diff --git a/coolstore-partner-web/src/main/java/com/cool/store/controller/webc/MiniXinFaController.java b/coolstore-partner-web/src/main/java/com/cool/store/controller/webc/MiniXinFaController.java new file mode 100644 index 000000000..a9cc9a5b7 --- /dev/null +++ b/coolstore-partner-web/src/main/java/com/cool/store/controller/webc/MiniXinFaController.java @@ -0,0 +1,54 @@ +package com.cool.store.controller.webc; + +import com.cool.store.dto.huoma.*; +import com.cool.store.response.ResponseResult; +import com.cool.store.service.xinfa.XinFaBusinessService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * @Author suzhuhong + * @Date 2025/11/5 17:49 + * @Version 1.0 + */ +@RestController +@RequestMapping("/mini/xinfa") +@Api(tags = "小程序-信发") +@Slf4j +public class MiniXinFaController { + + @Resource + XinFaBusinessService xinFaBusinessService; + @ApiOperation("测试门店设备信息") + @GetMapping("/getStoreXinFaDeviceDetail") + public ResponseResult> getStoreXinFaDeviceDetail(@RequestParam("storeNum")String storeNum) { + return ResponseResult.success(xinFaBusinessService.getStoreXinFaDeviceDetail(storeNum)); + } + + @ApiOperation("测试标签信息") + @PostMapping("/getAccountAllTags") + public ResponseResult> getAccountAllTags(@RequestBody AccountTagDTO tagDTO) { + List accountAllTags = xinFaBusinessService.getAccountAllTags(tagDTO.getStoreNum(), tagDTO.getDeviceName()); + return ResponseResult.success(accountAllTags); + } + + @ApiOperation("获取节目列表") + @PostMapping("/getProgramList") + public ResponseResult> getProgramList(@RequestBody ProgramReqDTO programReqDTO) { + List accountAllTags = xinFaBusinessService.getProgramList(programReqDTO); + return ResponseResult.success(accountAllTags); + } + + @ApiOperation("发布/上架") + @PostMapping("/publishProgram") + public ResponseResult publishProgram(@RequestBody PublishDTO publishDTO) { + Boolean publishStatus = xinFaBusinessService.publishProgram(publishDTO); + return ResponseResult.success(publishStatus); + } + +} diff --git a/coolstore-partner-web/src/main/resources/application-ab.properties b/coolstore-partner-web/src/main/resources/application-ab.properties index 242f7308a..02d7bbe98 100644 --- a/coolstore-partner-web/src/main/resources/application-ab.properties +++ b/coolstore-partner-web/src/main/resources/application-ab.properties @@ -137,3 +137,22 @@ hqt.token.grant_type=client_credentials hqt.token.client.id=WrPffdGpcWkcPsbN hqt.token.client.secret=rYe9Cwug5LwQNIBJAiW0a7weF9CAhYCD +#fuwuhao appId +wechat.mp.appId=wx4a18ef8bb41aa55c +wechat.mp.appSecret=793904b58f4ecdead3bbe4312c5f5c45 +#xiaochengxu appid +wechat.miniapp.appId=wxd77a2761c1911ee1 + +huoMa.token.url = https://www.huoMayunping.com/api/SAASLogin/merchant +huoMa.id.url = https://www.huomayunping.com/api/reportCenter/executeSql +huoMa.store.device.detail.url = https://www.huomayunping.com/api/terminal/search +huoMa.get.point.terminal.url = https://www.huoMayunping.com/api/terminal/getPointTerminalInfos +huoMa.get.tag.url = https://www.huomayunping.com/api/tag/search +huoMa.get.program.url = https://www.huomayunping.com/api/program/search +huoMa.get.publish.url = https://www.huomayunping.com/api/channelPublish/target/v2/quick-publish +huoMa.direct.stores.account = 15370309163 +huoMa.direct.stores.password = Zx@123456. +huoMa.franchise.stores.account = 13563273279 +huoMa.franchise.stores.password = Zx@123456. +huoMa.restaurant.stores.account = 18656552865 +huoMa.restaurant.stores.password = ZX123456 diff --git a/coolstore-partner-web/src/main/resources/application-online.properties b/coolstore-partner-web/src/main/resources/application-online.properties index b9c73dda2..bb4f1e31f 100644 --- a/coolstore-partner-web/src/main/resources/application-online.properties +++ b/coolstore-partner-web/src/main/resources/application-online.properties @@ -138,4 +138,24 @@ hqt.token.url=https://tc.cloud.hecom.cn hqt.token.username=18161486722 hqt.token.grant_type=client_credentials hqt.token.client.id=WrPffdGpcWkcPsbN -hqt.token.client.secret=rYe9Cwug5LwQNIBJAiW0a7weF9CAhYCD \ No newline at end of file +hqt.token.client.secret=rYe9Cwug5LwQNIBJAiW0a7weF9CAhYCD + +#fuwuhao appId +wechat.mp.appId=wx4a18ef8bb41aa55c +wechat.mp.appSecret=793904b58f4ecdead3bbe4312c5f5c45 +#xiaochengxu appid +wechat.miniapp.appId=wxd77a2761c1911ee1 + +huoMa.token.url = https://www.huoMayunping.com/api/SAASLogin/merchant +huoMa.id.url = https://www.huomayunping.com/api/reportCenter/executeSql +huoMa.store.device.detail.url = https://www.huomayunping.com/api/terminal/search +huoMa.get.point.terminal.url = https://www.huoMayunping.com/api/terminal/getPointTerminalInfos +huoMa.get.tag.url = https://www.huomayunping.com/api/tag/search +huoMa.get.program.url = https://www.huomayunping.com/api/program/search +huoMa.get.publish.url = https://www.huomayunping.com/api/channelPublish/target/v2/quick-publish +huoMa.direct.stores.account = 15370309163 +huoMa.direct.stores.password = Zx@123456. +huoMa.franchise.stores.account = 13563273279 +huoMa.franchise.stores.password = Zx@123456. +huoMa.restaurant.stores.account = 18656552865 +huoMa.restaurant.stores.password = ZX123456 \ No newline at end of file diff --git a/coolstore-partner-web/src/main/resources/application-test.properties b/coolstore-partner-web/src/main/resources/application-test.properties index eea16e79c..b9182bd10 100644 --- a/coolstore-partner-web/src/main/resources/application-test.properties +++ b/coolstore-partner-web/src/main/resources/application-test.properties @@ -145,3 +145,27 @@ hqt.token.grant_type=client_credentials hqt.token.client.id=WrPffdGpcWkcPsbN hqt.token.client.secret=rYe9Cwug5LwQNIBJAiW0a7weF9CAhYCD + +#fuwuhao appId +wechat.mp.appId=wx4a18ef8bb41aa55c +wechat.mp.appSecret=793904b58f4ecdead3bbe4312c5f5c45 +#xiaochengxu appid +wechat.miniapp.appId=wxd77a2761c1911ee1 + +zx.iot.appId=p-ts3PhNyf +zx.iot.appSecret=X4cVmfxM+ + + +huoMa.token.url = https://www.huoMayunping.com/api/SAASLogin/merchant +huoMa.id.url = https://www.huomayunping.com/api/reportCenter/executeSql +huoMa.store.device.detail.url = https://www.huomayunping.com/api/terminal/search +huoMa.get.point.terminal.url = https://www.huoMayunping.com/api/terminal/getPointTerminalInfos +huoMa.get.tag.url = https://www.huomayunping.com/api/tag/search +huoMa.get.program.url = https://www.huomayunping.com/api/program/search +huoMa.get.publish.url = https://www.huomayunping.com/api/channelPublish/target/v2/quick-publish +huoMa.direct.stores.account = 15370309163 +huoMa.direct.stores.password = Zx@123456. +huoMa.franchise.stores.account = 13563273279 +huoMa.franchise.stores.password = Zx@123456. +huoMa.restaurant.stores.account = 18656552865 +huoMa.restaurant.stores.password = ZX123456 diff --git a/pom.xml b/pom.xml index b4d687d85..f3901d5b8 100644 --- a/pom.xml +++ b/pom.xml @@ -232,6 +232,7 @@ alibabacloud-dysmsapi20170525 2.0.24 +