价格配置

This commit is contained in:
Jerry Yan 2025-02-25 15:03:06 +08:00
parent 9dc5708d04
commit 95747a2a71
13 changed files with 434 additions and 8 deletions

View File

@ -0,0 +1,7 @@
package com.ycwl.basic.biz;
import org.springframework.stereotype.Component;
@Component
public class PriceBiz {
}

View File

@ -25,11 +25,6 @@ public class WechatConfig {
*/ */
private String appSecret; private String appSecret;
/**
* 公众号推送模板
*/
@Value("${wx.push.templateId}")
private String templateId;
/** /**
* 小程序的AppId * 小程序的AppId

View File

@ -0,0 +1,74 @@
package com.ycwl.basic.controller.pc;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ycwl.basic.model.pc.price.entity.PriceConfigEntity;
import com.ycwl.basic.model.pc.price.req.PriceConfigListReq;
import com.ycwl.basic.model.pc.price.resp.GoodsListRespVO;
import com.ycwl.basic.model.pc.price.resp.PriceConfigRespVO;
import com.ycwl.basic.model.pc.template.resp.TemplateRespVO;
import com.ycwl.basic.repository.PriceRepository;
import com.ycwl.basic.repository.TemplateRepository;
import com.ycwl.basic.service.PriceConfigService;
import com.ycwl.basic.utils.ApiResponse;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequestMapping("/api/priceConfig/v1")
public class PriceConfigController {
@Autowired
private PriceConfigService priceConfigService;
@Autowired
private PriceRepository priceRepository;
@GetMapping("/goodsList")
public ApiResponse<List<GoodsListRespVO>> goodsList(@RequestParam Long scenicId) {
return ApiResponse.success(priceConfigService.listGoodsByScenic(scenicId));
}
@PostMapping("/add")
public ApiResponse<PriceConfigEntity> addPriceConfig(@RequestBody PriceConfigEntity priceConfig) {
priceConfig.setId(null);
priceConfigService.save(priceConfig);
return ApiResponse.success(priceConfig);
}
@PostMapping("/update")
public ApiResponse<PriceConfigEntity> updatePriceConfig(@RequestBody PriceConfigEntity priceConfig) {
priceRepository.clearPriceCache(priceConfig.getId());
priceConfigService.updateById(priceConfig);
priceRepository.clearPriceCache(priceConfig.getId());
return ApiResponse.success(priceConfig);
}
@DeleteMapping("/delete/{id}")
public ApiResponse<Boolean> deletePriceConfig(@PathVariable Integer id) {
priceRepository.clearPriceCache(id);
priceConfigService.removeById(id);
return ApiResponse.success(true);
}
@GetMapping("/{id}")
public ApiResponse<PriceConfigRespVO> getPriceConfigById(@PathVariable Integer id) {
PriceConfigRespVO config = priceConfigService.findById(id);
priceConfigService.fillGoodsName(config);
return ApiResponse.success(config);
}
@GetMapping("/list")
public ApiResponse<PageInfo<PriceConfigRespVO>> list(@RequestParam(defaultValue = "1") int pageNum,
@RequestParam(defaultValue = "10") int pageSize,
@ModelAttribute PriceConfigListReq req) {
PageHelper.startPage(pageNum, pageSize);
List<PriceConfigRespVO> result = priceConfigService.listByCondition(req);
priceConfigService.fillGoodsName(result);
PageInfo<PriceConfigRespVO> pageInfo = new PageInfo<>(result);
return ApiResponse.success(pageInfo);
}
}

View File

@ -0,0 +1,20 @@
package com.ycwl.basic.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ycwl.basic.model.pc.price.entity.PriceConfigEntity;
import com.ycwl.basic.model.pc.price.req.PriceConfigListReq;
import com.ycwl.basic.model.pc.price.resp.PriceConfigRespVO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@Mapper
public interface PriceConfigMapper extends BaseMapper<PriceConfigEntity> {
PriceConfigRespVO getById(@Param("id") Integer id);
List<PriceConfigRespVO> listByCondition(@Param("req") PriceConfigListReq req);
PriceConfigEntity getPriceByScenicTypeGoods(Long scenicId, Integer type, String goodsId);
}

View File

@ -0,0 +1,38 @@
package com.ycwl.basic.model.pc.price.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
@Data
@TableName("price_config")
public class PriceConfigEntity {
@TableId(type = IdType.AUTO)
private Integer id;
/**
* 景区ID
*/
private Long scenicId;
/**
* 类型-1一口价0单个定价1打包定价
*/
private Integer type;
/**
* 商品ID多个用逗号隔开
*/
private String goodsIds;
/**
* 价格
*/
private BigDecimal price;
/**
* 划线价格
*/
private BigDecimal slashPrice;
private Date createTime;
private Date updateTime;
}

View File

@ -0,0 +1,10 @@
package com.ycwl.basic.model.pc.price.req;
import lombok.Data;
@Data
public class PriceConfigListReq {
private Long scenicId;
private Integer type;
private Long goodsId;
}

View File

@ -0,0 +1,13 @@
package com.ycwl.basic.model.pc.price.resp;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
@Data
public class GoodsListRespVO {
private Long goodsId;
private String goodsName;
}

View File

@ -0,0 +1,34 @@
package com.ycwl.basic.model.pc.price.resp;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
@Data
public class PriceConfigRespVO {
private Integer id;
private String scenicName;
/**
* 景区ID
*/
private Long scenicId;
/**
* 类型-1一口价0单个定价1打包定价
*/
private Integer type;
/**
* 商品ID多个用逗号隔开
*/
private String goodsIds;
private String goodsNames;
/**
* 价格
*/
private BigDecimal price;
/**
* 划线价格
*/
private BigDecimal slashPrice;
private Date createTime;
}

View File

@ -0,0 +1,60 @@
package com.ycwl.basic.repository;
import com.alibaba.fastjson.JSON;
import com.ycwl.basic.mapper.PriceConfigMapper;
import com.ycwl.basic.model.pc.price.entity.PriceConfigEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
@Component
public class PriceRepository {
@Autowired
private PriceConfigMapper mapper;
@Autowired
private RedisTemplate<String, String> redisTemplate;
public static final String PRICE_SCENIC_TYPE_GOODS_CACHE = "price:s%s:t%s:g%s";
public static final String PRICE_ID_CACHE = "price:%s";
public PriceConfigEntity getPriceConfigByScenicTypeGoods(Long scenicId, Integer type, String goodsId) {
String cacheKey = String.format(PRICE_SCENIC_TYPE_GOODS_CACHE, scenicId, type, goodsId);
PriceConfigEntity priceConfigEntity = null;
if (redisTemplate.hasKey(cacheKey)) {
priceConfigEntity = JSON.parseObject(redisTemplate.opsForValue().get(cacheKey), PriceConfigEntity.class);
}
if (priceConfigEntity == null) {
PriceConfigEntity priceConfig = mapper.getPriceByScenicTypeGoods(scenicId, type, goodsId);
if (priceConfig != null) {
redisTemplate.opsForValue().set(cacheKey, JSON.toJSONString(priceConfig));
redisTemplate.opsForValue().set(String.format(PRICE_ID_CACHE, priceConfig.getId()), JSON.toJSONString(priceConfig));
}
}
return priceConfigEntity;
}
public PriceConfigEntity getPriceConfig(Integer id) {
String cacheKey = String.format(PRICE_ID_CACHE, id);
PriceConfigEntity priceConfigEntity = null;
if (redisTemplate.hasKey(cacheKey)) {
priceConfigEntity = JSON.parseObject(redisTemplate.opsForValue().get(cacheKey), PriceConfigEntity.class);
}
return priceConfigEntity;
}
public void clearPriceCache(Integer id) {
if (redisTemplate.hasKey(String.format(PRICE_ID_CACHE, id))) {
PriceConfigEntity priceConfig = getPriceConfig(id);
if (priceConfig != null) {
clearPriceCache(priceConfig.getScenicId(), priceConfig.getType(), priceConfig.getGoodsIds());
}
}
redisTemplate.delete(String.format(PRICE_ID_CACHE, id));
}
public void clearPriceCache(Long scenicId, Integer type, String goodsId) {
String cacheKey = String.format(PRICE_SCENIC_TYPE_GOODS_CACHE, scenicId, type, goodsId);
redisTemplate.delete(cacheKey);
}
}

View File

@ -0,0 +1,22 @@
package com.ycwl.basic.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ycwl.basic.model.pc.price.entity.PriceConfigEntity;
import com.ycwl.basic.model.pc.price.req.PriceConfigListReq;
import com.ycwl.basic.model.pc.price.resp.GoodsListRespVO;
import com.ycwl.basic.model.pc.price.resp.PriceConfigRespVO;
import java.util.List;
public interface PriceConfigService extends IService<PriceConfigEntity> {
List<PriceConfigRespVO> listByCondition(PriceConfigListReq req);
PriceConfigRespVO findById(Integer id);
List<GoodsListRespVO> listGoodsByScenic(Long scenicId);
void fillGoodsName(List<PriceConfigRespVO> result);
void fillGoodsName(PriceConfigRespVO config);
}

View File

@ -0,0 +1,97 @@
package com.ycwl.basic.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ycwl.basic.mapper.PriceConfigMapper;
import com.ycwl.basic.model.pc.price.entity.PriceConfigEntity;
import com.ycwl.basic.model.pc.price.req.PriceConfigListReq;
import com.ycwl.basic.model.pc.price.resp.GoodsListRespVO;
import com.ycwl.basic.model.pc.price.resp.PriceConfigRespVO;
import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
import com.ycwl.basic.model.pc.template.resp.TemplateRespVO;
import com.ycwl.basic.repository.ScenicRepository;
import com.ycwl.basic.repository.TemplateRepository;
import com.ycwl.basic.service.PriceConfigService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@Service
public class PriceConfigServiceImpl extends ServiceImpl<PriceConfigMapper, PriceConfigEntity> implements PriceConfigService {
@Autowired
private TemplateRepository templateRepository;
@Autowired
private ScenicRepository scenicRepository;
@Override
public List<PriceConfigRespVO> listByCondition(PriceConfigListReq req) {
return baseMapper.listByCondition(req);
}
@Override
public PriceConfigRespVO findById(Integer id) {
return baseMapper.getById(id);
}
@Override
public List<GoodsListRespVO> listGoodsByScenic(Long scenicId) {
List<GoodsListRespVO> goodsList = new ArrayList<>();
// 景区视频
List<TemplateRespVO> templateList = templateRepository.getTemplateListByScenicId(scenicId);
templateList.stream().map(template -> {
GoodsListRespVO goods = new GoodsListRespVO();
goods.setGoodsId(template.getId());
goods.setGoodsName(template.getName());
return goods;
}).forEach(goodsList::add);
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(scenicId);
if (scenicConfig != null) {
if (!Integer.valueOf(1).equals(scenicConfig.getDisableSourceVideo())) {
goodsList.add(new GoodsListRespVO(1L, "原片集"));
}
if (!Integer.valueOf(1).equals(scenicConfig.getDisableSourceImage())) {
goodsList.add(new GoodsListRespVO(2L, "照片集"));
}
}
return goodsList;
}
@Override
public void fillGoodsName(List<PriceConfigRespVO> result) {
for (PriceConfigRespVO item : result) {
fillGoodsName(item);
}
}
@Override
public void fillGoodsName(PriceConfigRespVO item) {
if (Integer.valueOf(-1).equals(item.getType())) {
item.setGoodsNames("景区内所有售卖商品");
} else if (StringUtils.isNotBlank(item.getGoodsIds())) {
List<String> goodsNames = new ArrayList<>();
for (String s : item.getGoodsIds().split(",")) {
if (StringUtils.equals(s, "1")) {
goodsNames.add("原片集");
} else if (StringUtils.equals(s, "2")) {
goodsNames.add("照片集");
} else {
if (StringUtils.isNumeric(s)) {
TemplateRespVO template = templateRepository.getTemplate(Long.valueOf(s));
if (template != null) {
goodsNames.add(template.getName());
} else {
goodsNames.add("?未知商品【"+s+"】?");
}
} else {
goodsNames.add("!未知商品【"+s+"】!");
}
}
}
item.setGoodsNames(StringUtils.join(goodsNames, ","));
}
}
}

View File

@ -70,9 +70,6 @@ wx:
miniProgramSecret: 5252fbbc68513bc77b7cc0052b9f9695 miniProgramSecret: 5252fbbc68513bc77b7cc0052b9f9695
# 申请openid授权 # 申请openid授权
grandType: authorization_code grandType: authorization_code
# 推送模板
push:
templateId: 5b8vTm7kvwYubqDxb3dxBqFIhc3Swt5l7QHSK5r-ZRI
# 商户号 # 商户号
mchId: 1700540331 mchId: 1700540331
# 商户证书序列号 # 商户证书序列号

View File

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ycwl.basic.mapper.PriceConfigMapper">
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
insert into price_config (scenic_id, type, goods_ids, price, slash_price, create_time, update_time)
values (#{scenicId}, #{type}, #{goodsIds}, #{price}, #{slashPrice}, now(), now())
</insert>
<update id="update">
update price_config
<set>
<if test="scenicId != null">scenic_id = #{scenicId},</if>
<if test="type != null">type = #{type},</if>
<if test="goodsIds != null">goods_ids = #{goodsIds},</if>
<if test="price != null">price = #{price},</if>
<if test="slashPrice != null">slash_price = #{slashPrice},</if>
update_time = now()
</set>
where id = #{id}
</update>
<delete id="deleteById">
delete from price_config where id = #{id}
</delete>
<select id="getById" resultType="com.ycwl.basic.model.pc.price.resp.PriceConfigRespVO">
select p.*, s.name as scenic_name from price_config p
left join scenic s on s.id = p.scenic_id
where p.id = #{id}
</select>
<select id="listByCondition" resultType="com.ycwl.basic.model.pc.price.resp.PriceConfigRespVO">
select p.*, s.name as scenic_name from price_config p
left join scenic s on s.id = p.scenic_id
<where>
<if test="req.scenicId != null">
and p.scenic_id = #{req.scenicId}
</if>
<if test="req.type != null">
and p.type = #{req.type}
</if>
<if test="req.goodsId != null">
and p.goods_ids like concat('%', #{req.goodsId}, '%')
</if>
</where>
</select>
<select id="getPriceByScenicTypeGoods" resultType="com.ycwl.basic.model.pc.price.entity.PriceConfigEntity">
select * from price_config
where scenic_id = #{scenicId}
and type = #{type}
<if test="goodsId != null">
and goods_ids like concat('%', #{goodsId}, '%')
</if>
</select>
</mapper>