zoujiajian 2 年 前
コミット
12e80976d3

+ 10 - 0
netflix-common/src/main/java/com/cyksj/common/constant/Constant.java

@@ -149,4 +149,14 @@ public interface Constant {
 	 * 渠道专属优惠码
 	 */
 	Long DISTRIBUTE_POPULARIZE_COUPON_ID = 56l;
+
+	/**
+	 * AI 车票额外座位数
+	 */
+	Integer AI_EXTRACT_NUM = 5;
+
+	/**
+	 * GPT Plus规格 新车队规格限制上车数
+	 */
+	List<Long> GPT_PLUS_PARKING_SKU_IDS = List.of(161l, 178l);
 }

+ 13 - 0
netflix-dao/src/main/java/com/cyksj/mapper/GroupsRelationAlertMapper.java

@@ -0,0 +1,13 @@
+package com.cyksj.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.GroupsRelationAlert;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: GroupsRelationAlertMapper
+ * 创建者: JavaZou
+ * 创建时间:2023/10/26 15:14
+ */
+public interface GroupsRelationAlertMapper extends BaseMapper<GroupsRelationAlert> {
+}

+ 8 - 0
netflix-dao/src/main/java/com/cyksj/mapper/GroupsRelationMapper.java

@@ -59,4 +59,12 @@ public interface GroupsRelationMapper extends BaseMapper<GroupsRelation> {
 	GroupsRelationBackView getGroupRelationAccountView(Long relationId);
 
 	List<RenewalView> getUserHasPayGoods(@Param("list") List<Long> userIds, @Param("now") DateTime now);
+
+	Integer selectAvailableRelation(@Param("skuId") Long skuId, @Param("skuNum") Integer skuNum);
+
+	Integer selectSpecialGroupsRelationAvailable(@Param("skuId") Long skuId, @Param("maxNum") Integer maxNum, @Param("skuNum") Integer skuNum, @Param("extractNum") Integer extractNum, @Param("tenExpiry") DateTime tenExpiry);
+
+	Integer selectLimitAvailableNum(@Param("skuId") Long skuId, @Param("maxNum") Integer maxNum);
+
+	Integer selectNumWaitingGroups(Long skuId);
 }

+ 45 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/GroupsRelationAlert.java

@@ -0,0 +1,45 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: GroupsRelationAlert
+ * 创建者: JavaZou
+ * 创建时间:2023/10/26 15:13
+ */
+@Getter
+@Setter
+public class GroupsRelationAlert extends BaseEntity{
+
+	/**
+	 * 针对库存
+	 */
+	@NotNull
+	private Long skuId;
+
+	/**
+	 * 预警数量
+	 */
+	@NotNull(message = "预警数量不为空")
+	private Integer num;
+
+	/**
+	 * 手机号
+	 */
+	@NotNull(message = "手机号不为空")
+	private String phoneStr;
+
+	/**
+	 * 预警开发
+	 */
+	private Boolean isOpen;
+
+	/**
+	 * 是否重置 根据新增对应规格账号 重置该预警记录
+	 */
+	private Boolean isReset;
+}

+ 60 - 0
netflix-dao/src/main/resources/mapper/GroupRelationMapper.xml

@@ -265,4 +265,64 @@
         group by g.id,g.title,g.logo
         order by goods_id
     </select>
+
+    <select id="selectAvailableRelation" resultType="java.lang.Integer">
+        select count(gr.id)
+        from account a
+                 inner join `groups_trips` gt on gt.account_id = a.id
+            and gt.`status` = 'validity'
+            and gt.sku_id = #{skuId}
+                 inner join groups_relation gr on gr.groups_id = gt.id
+            and gr.status in ('none', 'locking')
+            and gt.available_parking_num = 0
+            and gr.num &lt;= #{skuNum}
+    </select>
+
+    <select id="selectSpecialGroupsRelationAvailable" resultType="java.lang.Integer">
+        select ifnull(sum(a1 + (#{extractNum} - t1)), 0)
+        from (select gt.id,
+                     (select count(*)
+                      from groups_relation gr2
+                      where gr2.groups_id = gt.id
+                        and num > #{skuNum}
+                        and num &lt;= #{maxNum})                         t1,
+                     (select count(*)
+                      from groups_relation gr2
+                      where gr2.groups_id = gt.id
+                        and num > #{skuNum}
+                        and num &lt;= #{maxNum}
+                        and (gr2.user_id = 0 or gr2.status = 'locking')) a1
+              from account a
+                       inner join `groups_trips` gt on gt.account_id = a.id
+                  and gt.`status` = 'validity'
+                  and gt.available_parking_num = 0
+                  and gt.sku_id = #{skuId}
+                  and a.expiry_time >= #{tenExpiry}) s
+        where (t1 = #{extractNum} and a1 = 0) = 0
+    </select>
+
+    <select id="selectLimitAvailableNum" resultType="java.lang.Integer">
+        select sum(s1 - s2)
+        from (select available_parking_num          as s1,
+                     (select count(*)
+                      from groups_relation gr
+                      where gr.groups_id = gt.id
+                        and gr.status in ('validity', 'outside')
+                        and gr.num &lt;= #{maxNum}) as s2
+              from groups_trips gt
+              where gt.sku_id = #{skuId}
+                and gt.status = 'validity'
+                and gt.available_parking_num != 0) t
+        where t.s1 >= s2
+    </select>
+
+    <select id="selectNumWaitingGroups" resultType="java.lang.Integer">
+        select count(gr.id)
+        from `groups_trips` gt
+                 inner join groups_relation gr on gr.groups_id = gt.id
+            and gt.`status` = 'waiting'
+            and gt.sku_id = #{skuId}
+            and gr.user_id != 0
+            and gr.status in ('validity','outside')
+    </select>
 </mapper>

+ 2 - 0
netflix-service/src/main/java/com/cyksj/service/mange/CmsGroupService.java

@@ -19,4 +19,6 @@ public interface CmsGroupService extends IService<GroupsTrips> {
     void replaceTripsAccount(ReplaceTripsAccountReq req);
 
 	void sendChangeAccountMsg(Long groupsId, Long goodsId, String account);
+
+	Integer getAvailableRelation(Long goodsId, Long skuId);
 }

+ 72 - 0
netflix-service/src/main/java/com/cyksj/service/mange/group/CmsGroupServiceImpl.java

@@ -17,6 +17,7 @@ import com.cyksj.mapper.manage.DelGroupsTripsRecordMapper;
 import com.cyksj.mapper.manage.GroupsTripsAccountReplaceRecordMapper;
 import com.cyksj.mapper.manage.cms.CmsUserMapper;
 import com.cyksj.model.entity.*;
+import com.cyksj.model.manage.views.AccountView;
 import com.cyksj.model.manage.views.GroupsRelationView;
 import com.cyksj.model.request.ReplaceTripsAccountReq;
 import com.cyksj.model.views.GroupsAccountView;
@@ -25,6 +26,7 @@ import com.cyksj.service.mange.CmsGroupService;
 import com.cyksj.service.sms.SmsService;
 import com.ejlchina.searcher.BeanSearcher;
 import com.ejlchina.searcher.param.Operator;
+import com.ejlchina.searcher.util.MapBuilder;
 import com.ejlchina.searcher.util.MapUtils;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -374,4 +376,74 @@ public class CmsGroupServiceImpl extends ServiceImpl<GroupsMapper,GroupsTrips> i
             }
         });
     }
+
+    @Override
+    public Integer getAvailableRelation(Long goodsId, Long skuId) {
+        //chatGPT
+        GoodsDonSku sku = skuMapper.selectById(skuId);
+        goodsId = sku.getGoodsId();
+        Integer skuNum = sku.getNum();
+        if (Constant.AI_goodsIds.contains(sku.getGoodsId()) && sku.getNum() > 1) {
+            Integer extraNum = Constant.AI_EXTRACT_NUM;
+            //GPT 4个月付
+            if (skuId == 178l) {
+                extraNum = 2;
+            }
+            Integer maxNum = skuNum + extraNum;
+            //主账号有效时间
+            DateTime time = DateUtil.offsetDay(DateUtil.beginOfDay(DateTime.now()), 25);
+            Integer available = relationMapper.selectAvailableRelation(skuId, skuNum);
+            //额外硬塞
+            Integer special_available = relationMapper.selectSpecialGroupsRelationAvailable(skuId, maxNum, skuNum, extraNum, time);
+            available += special_available;
+            //GPT Plus 10人月付规格 4人月付
+            if (Constant.GPT_PLUS_PARKING_SKU_IDS.contains(skuId)) {
+                //上面已排除限制车队
+                //限制车队可用车数位
+                Integer limitAvailable = Optional.ofNullable(relationMapper.selectLimitAvailableNum(skuId, maxNum)).orElse(0);
+                if (limitAvailable < 0) {
+                    limitAvailable = 0;
+                }
+                available += limitAvailable;
+
+                //新车队预备上车 最大可用数
+                if (Constant.GPT_PLUS_PARKING_SKU_IDS.get(0).equals(skuId)) {
+                    maxNum = 10;
+                }else {
+                    maxNum = 4;
+                }
+            }
+            available = getAvailableAfterPreAccount(available, skuId, maxNum, goodsId);
+            //待发车已有人员成功上车
+            Integer waitingNum = relationMapper.selectNumWaitingGroups(skuId);
+            available -= waitingNum;
+            return available;
+        }
+
+        Integer available = relationMapper.selectAvailableRelation(skuId, skuNum);
+        available = getAvailableAfterPreAccount(available, skuId, skuNum, goodsId);
+        //待发车已有人员成功上车
+        Integer waitingNum = relationMapper.selectNumWaitingGroups(skuId);
+        available -= waitingNum;
+        return available;
+    }
+
+    public Integer getAvailableAfterPreAccount(Integer available, Long skuId, Integer maxNum, Long goodsId) {
+        MapBuilder builder = MapUtils.builder();
+        if (goodsId == 26) {
+            //是否在预备规格集合中
+            String extra_sql = String.format("FIND_IN_SET(%s,a.pre_sku_ids) > 0", skuId);
+            builder.put("extra_sql", extra_sql);
+        }
+        Number preAccount = beanSearcher.searchCount(AccountView.class, builder
+                .field(AccountView::getGoodsId, goodsId)
+                .field(AccountView::getAccountType, 2)
+                .field(AccountView::getGroupsId).op(Operator.IsNull)
+                .build());
+        //计算上预发布账号车位数
+        if (preAccount.intValue() > 0) {
+            available += preAccount.intValue() * maxNum;
+        }
+        return available;
+    }
 }

+ 60 - 1
netflix-web/src/main/java/com/cyksj/web/controller/manage/group/CmsGroupController.java

@@ -1,22 +1,26 @@
 package com.cyksj.web.controller.manage.group;
 
-import com.cyksj.web.util.StpAbroadUtil;
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.date.DateTime;
+import cn.hutool.core.lang.Validator;
 import cn.hutool.core.thread.ThreadUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.json.JSONObject;
+import com.baomidou.mybatisplus.core.toolkit.Assert;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.cyksj.common.annotation.Log;
 import com.cyksj.common.annotation.NoSubmit;
 import com.cyksj.common.exception.BusinessRuntimeException;
 import com.cyksj.common.util.GoogleGenerator;
+import com.cyksj.common.util.Jsons;
 import com.cyksj.dto.Result;
 import com.cyksj.enums.BusinessType;
 import com.cyksj.enums.GatewayResponse;
+import com.cyksj.mapper.GroupsRelationAlertMapper;
 import com.cyksj.mapper.GroupsRelationMapper;
 import com.cyksj.mapper.UserMapper;
 import com.cyksj.model.entity.Account;
+import com.cyksj.model.entity.GroupsRelationAlert;
 import com.cyksj.model.entity.GroupsTrips;
 import com.cyksj.model.entity.GroupsTripsAccountReplaceRecord;
 import com.cyksj.model.request.AccountGroupsReq;
@@ -26,6 +30,7 @@ import com.cyksj.model.views.GoodsDonSkuView;
 import com.cyksj.model.views.GroupsTripsWaitingView;
 import com.cyksj.service.mange.CmsAccountService;
 import com.cyksj.service.mange.CmsGroupService;
+import com.cyksj.web.util.StpAbroadUtil;
 import com.ejlchina.searcher.BeanSearcher;
 import com.ejlchina.searcher.SearchResult;
 import com.ejlchina.searcher.param.Operator;
@@ -34,6 +39,7 @@ import com.ejlchina.searcher.util.MapUtils;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
+import org.springframework.dao.DuplicateKeyException;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
@@ -63,6 +69,8 @@ public class CmsGroupController {
 
     private final UserMapper userMapper;
 
+    private final GroupsRelationAlertMapper alertMapper;
+
     @GetMapping("/get")
     public Result<SearchResult<GroupsTrips>> get(String account, Long userId, String showId, String nickName, String submitAccount, Boolean isEmpty) {
         MapBuilder mapBuilder = MapUtils.flatBuilder(request.getParameterMap());
@@ -296,4 +304,55 @@ public class CmsGroupController {
         re.putOpt("time", time);
         return GatewayResponse.SUCCESS.newBuilder().toResult(re.toString());
     }
+
+    /**
+     * 获取该规格下可用车位数
+     */
+    @GetMapping("/get/available/relation")
+    public Result<Integer> getAvailableRelation(Long goodsId, Long skuId) {
+        Integer available = groupService.getAvailableRelation(goodsId, skuId);
+        return GatewayResponse.SUCCESS.newBuilder().toResult(available);
+    }
+
+    /**
+     * 设置库存预警通知
+     */
+    @PutMapping("/set/relation/alert")
+    public Result<String> setGroupsRelationAlert(@RequestBody @Validated GroupsRelationAlert groupsRelationAlert) throws Exception {
+        if (groupsRelationAlert.getId() == null) {
+            try {
+                alertMapper.insert(groupsRelationAlert);
+            } catch (DuplicateKeyException e) {
+            }
+            return GatewayResponse.SUCCESS.newBuilder().toResult();
+        }
+        Long id = groupsRelationAlert.getId();
+        Assert.notNull(id, "预警id不存在");
+        GroupsRelationAlert dbAlert = alertMapper.selectById(id);
+        Assert.notNull(dbAlert, "预警不存在");
+        String phoneStr = groupsRelationAlert.getPhoneStr();
+        List<String> phoneList = Jsons.parseList(phoneStr, String.class);
+        phoneList.forEach(phone -> {
+            if (!Validator.isMobile(phone)) {
+                throw BusinessRuntimeException.getInstance("请输入正确的手机格式");
+            }
+        });
+        Integer dbNum = dbAlert.getNum();
+        Integer num = groupsRelationAlert.getNum();
+        if (dbNum != num) {
+            groupsRelationAlert.setIsReset(true);
+        }
+        alertMapper.updateById(groupsRelationAlert);
+        return GatewayResponse.SUCCESS.newBuilder().toResult();
+    }
+
+    /**
+     * 库存预警通知
+     */
+    @GetMapping("/get/relation/alert")
+    public Result<GroupsRelationAlert> getGroupsRelationAlert(@RequestParam(required = true) Long skuId) {
+        GroupsRelationAlert groupsRelationAlert = alertMapper.selectOne(Wrappers.lambdaQuery(GroupsRelationAlert.class)
+                .eq(GroupsRelationAlert::getSkuId, skuId).last("limit 1"));
+        return GatewayResponse.SUCCESS.newBuilder().toResult(groupsRelationAlert);
+    }
 }