Browse Source

查询时间范围内当前店铺的交易记录

master
wangfukang 3 days ago
parent
commit
b28714d418
  1. 1
      cp.txt
  2. 13
      hiver-admin/src/main/resources/application.yml
  3. 28
      hiver-modules/hiver-mall/pom.xml
  4. 2
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/SaleMapper.java
  5. 66
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/SalesCalculateServiceImpl.java
  6. 217
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/SaleServiceImpl.java
  7. 234
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/AliOcrUtil.java
  8. 1
      hiver-modules/hiver-mall/src/main/resources/mapper/PurchaseDetailMapper.xml
  9. 9
      hiver-modules/hiver-mall/src/main/resources/mapper/ReturnDetailMapper.xml
  10. 15
      hiver-modules/hiver-mall/src/main/resources/mapper/SaleDetailMapper.xml
  11. 10
      hiver-modules/hiver-mall/src/main/resources/mapper/SaleMapper.xml
  12. 21
      pom.xml

1
cp.txt

File diff suppressed because one or more lines are too long

13
hiver-admin/src/main/resources/application.yml

@ -18,6 +18,13 @@ server:
max-swallow-size: -1 max-swallow-size: -1
# 优雅停机 关闭容器后默认等待30秒继续执行没处理完的任务 避免数据不一致 # 优雅停机 关闭容器后默认等待30秒继续执行没处理完的任务 避免数据不一致
shutdown: graceful shutdown: graceful
# Gzip 响应压缩
compression:
enabled: true
# 需要压缩的 MIME 类型
mime-types: application/json,application/xml,text/html,text/xml,text/plain,text/css,application/javascript,application/x-javascript
# 超过该大小才压缩(单位:字节)
min-response-size: 2048
spring: spring:
lifecycle: lifecycle:
@ -26,7 +33,7 @@ spring:
# 数据源 # 数据源
datasource: datasource:
# url: jdbc:mysql://154.8.162.157:3306/hiver_shop?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true&allowMultiQueries=true # url: jdbc:mysql://154.8.162.157:3306/hiver_shop?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true&allowMultiQueries=true
url: jdbc:mysql://8.140.198.243:3306/hiver_shop?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true&allowMultiQueries=true url: jdbc:mysql://127.0.0.1:3306/hiver_shop?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true&allowMultiQueries=true
username: reddoor username: reddoor
# Jasypt加密 可到common-utils中找到JasyptUtil加解密工具类生成加密结果 格式为ENC(加密结果) 以下解密结果为123456 # Jasypt加密 可到common-utils中找到JasyptUtil加解密工具类生成加密结果 格式为ENC(加密结果) 以下解密结果为123456
password: ENC(Zla4U4+yRLPhicvuX2TmiEgxEpzP4dk8BHzFDEtiEhwLQIIaftZrrEUJZce6efoe) password: ENC(Zla4U4+yRLPhicvuX2TmiEgxEpzP4dk8BHzFDEtiEhwLQIIaftZrrEUJZce6efoe)
@ -68,7 +75,7 @@ spring:
# Redis 若设有密码自行添加配置password # Redis 若设有密码自行添加配置password
redis: redis:
# host: 154.8.162.157 # host: 154.8.162.157
host: 8.140.198.243 host: 127.0.0.1
password: reddoor168 password: reddoor168
# 数据库索引 默认0 # 数据库索引 默认0
database: 1 database: 1
@ -266,7 +273,7 @@ wx:
key-prefix: wx key-prefix: wx
redis: redis:
# host: 154.8.162.157 # host: 154.8.162.157
host: 8.140.198.243 host: 127.0.0.1
password: reddoor168 password: reddoor168
# 数据库索引 默认0 # 数据库索引 默认0
database: 1 database: 1

28
hiver-modules/hiver-mall/pom.xml

@ -20,14 +20,40 @@
<dependency> <dependency>
<groupId>com.alibaba</groupId> <groupId>com.alibaba</groupId>
<artifactId>dashscope-sdk-java</artifactId> <artifactId>dashscope-sdk-java</artifactId>
<version>2.14.1</version> <version>2.21.12</version>
<exclusions> <exclusions>
<exclusion> <exclusion>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId> <artifactId>slf4j-simple</artifactId>
</exclusion> </exclusion>
<!-- SDK 把 lombok 声明为 compile,容易干扰 IDE 注解处理与依赖解析 -->
<exclusion>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclusion>
</exclusions> </exclusions>
</dependency> </dependency>
<!-- dashscope 2.21.x 依赖 okhttp4;Spring Boot 2.5 默认管理到 okhttp3,需显式覆盖 -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.12.0</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp-sse</artifactId>
<version>4.12.0</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>logging-interceptor</artifactId>
<version>4.12.0</version>
</dependency>
<dependency>
<groupId>com.squareup.okio</groupId>
<artifactId>okio</artifactId>
<version>3.6.0</version>
</dependency>
<dependency> <dependency>
<groupId>cc.hiver</groupId> <groupId>cc.hiver</groupId>
<artifactId>hiver-file</artifactId> <artifactId>hiver-file</artifactId>

2
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/SaleMapper.java

@ -48,6 +48,8 @@ public interface SaleMapper extends BaseMapper<Sale> {
List<ShopRevenue> getShopRevenue(QueryShopRevenueVO queryShopRevenueVO); List<ShopRevenue> getShopRevenue(QueryShopRevenueVO queryShopRevenueVO);
List<ShopRevenue> getShopWeekRevenue(@Param("shopId") String shopId, @Param("startTime") String startTime, @Param("endTime") String endTime);
Page<Sale> getSaleListByProductId(Page<Sale> page, @Param("productId") String productId); Page<Sale> getSaleListByProductId(Page<Sale> page, @Param("productId") String productId);
/** /**

66
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/SalesCalculateServiceImpl.java

@ -10,6 +10,7 @@ import cc.hiver.mall.dao.mapper.SaleMapper;
import cc.hiver.mall.entity.ReturnSaleExample; import cc.hiver.mall.entity.ReturnSaleExample;
import cc.hiver.mall.entity.Sale; import cc.hiver.mall.entity.Sale;
import cc.hiver.mall.entity.SaleExample; import cc.hiver.mall.entity.SaleExample;
import cc.hiver.mall.pojo.dto.ShopRevenue;
import cc.hiver.mall.pojo.vo.CategoryNumberVo; import cc.hiver.mall.pojo.vo.CategoryNumberVo;
import cc.hiver.mall.pojo.vo.SaleAllVO; import cc.hiver.mall.pojo.vo.SaleAllVO;
import cc.hiver.mall.pojo.vo.TotalAlreadyEarnDetailVo; import cc.hiver.mall.pojo.vo.TotalAlreadyEarnDetailVo;
@ -20,15 +21,12 @@ import cc.hiver.mall.service.mybatis.SaleService;
import cc.hiver.mall.utils.DateUtil; import cc.hiver.mall.utils.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.utils.DateUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils; import org.springframework.util.ObjectUtils;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.ArrayList; import java.util.*;
import java.util.Date;
import java.util.List;
@Slf4j @Slf4j
@Service @Service
@ -159,17 +157,16 @@ public class SalesCalculateServiceImpl implements SalesCalculateService {
//获取当日门店下单客户数 //获取当日门店下单客户数
final QueryWrapper<Sale> querySaleWrapper = new QueryWrapper<>(); final QueryWrapper<Sale> querySaleWrapper = new QueryWrapper<>();
querySaleWrapper.select("user_id") querySaleWrapper.select("count(distinct user_id)")
.eq("shop_id", shopId) .eq("shop_id", shopId)
.ne("status",SaleConstant.SALE_STATUS[2]) .ne("status",SaleConstant.SALE_STATUS[2])
.ne("status",SaleConstant.SALE_STATUS[8]) .ne("status",SaleConstant.SALE_STATUS[8])
.ne("status",SaleConstant.SALE_STATUS[11]) .ne("status",SaleConstant.SALE_STATUS[11])
.ne("status",SaleConstant.SALE_STATUS[12]) .ne("status",SaleConstant.SALE_STATUS[12])
.between("create_time", startDate, endDate) .between("create_time", startDate, endDate);
.groupBy("user_id");
final List<Object> countCus = saleService.listObjs(querySaleWrapper); final List<Object> countCus = saleService.listObjs(querySaleWrapper);
if (!ObjectUtils.isEmpty(countCus) && !countCus.isEmpty()) { if (!ObjectUtils.isEmpty(countCus) && !countCus.isEmpty()) {
final int countCustomer = countCus.size(); final int countCustomer = Integer.parseInt(countCus.get(0).toString());
saleAllVO.setTotalCCount(countCustomer); saleAllVO.setTotalCCount(countCustomer);
} else { } else {
saleAllVO.setTotalCCount(0); saleAllVO.setTotalCCount(0);
@ -233,49 +230,20 @@ public class SalesCalculateServiceImpl implements SalesCalculateService {
final List<BigDecimal> thisWeekSale = new ArrayList<>(); final List<BigDecimal> thisWeekSale = new ArrayList<>();
try{ try{
// 今天 // 今天
final String todayDateStr = DateUtils.formatDate(new Date(), "yyyy-MM-dd"); final String todayDateStr = DateUtil.COMMON.getDateText(new Date());
String searchDate; final String startTime = DateUtil.addDay(todayDateStr, -6);
final String endTime = DateUtil.addDay(todayDateStr, 1);
// 店铺id从缓存中获取,并放到数据中去
final String shopId = securityUtil.getShopId();
final List<ShopRevenue> shopWeekRevenue = saleMapper.getShopWeekRevenue(shopId, startTime, endTime);
final Map<String, BigDecimal> weekSaleMap = new HashMap<>();
for (ShopRevenue shopRevenue : shopWeekRevenue) {
weekSaleMap.put(DateUtil.COMMON.getDateText(shopRevenue.getDt()), shopRevenue.getRealAmount());
}
for (int i = -6; i < 1; i++) { for (int i = -6; i < 1; i++) {
// 查询的日期加一天 // 查询的日期加一天
searchDate = DateUtil.addDay(todayDateStr, i); final String searchDate = DateUtil.addDay(todayDateStr, i);
// 店铺id从缓存中获取,并放到数据中去 thisWeekSale.add(weekSaleMap.getOrDefault(searchDate, BigDecimal.ZERO));
final String shopId = securityUtil.getShopId();
// 查询日期范围内数据
final Date startDate = DateUtil.COMMON_FULL.getTextDate(searchDate + " 00:00:00");
final Date endDate = DateUtil.COMMON_FULL.getTextDate(searchDate + " 23:59:59");
BigDecimal totalAmount1 = new BigDecimal(0);
//获取当日门店销售总额
final SaleExample saleExample = new SaleExample();
saleExample.createCriteria()
.andCreateTimeBetween(startDate, endDate)
.andStatusNotEqualTo(SaleConstant.SALE_STATUS[2])
.andStatusNotEqualTo(SaleConstant.SALE_STATUS[8])
.andStatusNotEqualTo(SaleConstant.SALE_STATUS[11])
.andStatusNotEqualTo(SaleConstant.SALE_STATUS[12])
.andShopIdEqualTo(shopId);
final SaleAllVO saleAllVO1 = saleMapper.saleSumAndCount(saleExample);
if (!ObjectUtils.isEmpty(saleAllVO1)) {
totalAmount1 = saleAllVO1.getTotalAmount();
}
//获取当日门店利润(当日总营收-当日总成本+(退货总营收-退货总成本))
/*final QueryWrapper<SaleDetail> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("shop_id", shopId)
.between("create_time", startDate, endDate);
BigDecimal totalPurchasePrice = new BigDecimal("0.0");
final List<SaleDetail> list = saleDetailService.list(queryWrapper);
for (SaleDetail saleDetail : list) {
final BigDecimal purchasePrice = saleDetail.getPurchasePrice();
final int productCount = saleDetail.getProductCount();
totalPurchasePrice = totalPurchasePrice.add(purchasePrice.multiply(new BigDecimal(productCount)));
}
// 利润= 销售总金额-成本
final BigDecimal subtract = totalAmount1.subtract(totalPurchasePrice);*/
thisWeekSale.add(totalAmount1);
} }
}catch (Exception e){ }catch (Exception e){
log.error("获取本周日期错误!",e); log.error("获取本周日期错误!",e);

217
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/SaleServiceImpl.java

@ -179,96 +179,11 @@ public class SaleServiceImpl extends ServiceImpl<SaleMapper, Sale> implements Sa
page = new Page<>(saleVO.getPageVo().getPageNumber(), saleVO.getPageVo().getPageSize()); page = new Page<>(saleVO.getPageVo().getPageNumber(), saleVO.getPageVo().getPageSize());
} }
final Page<Sale> saleList = saleMapper.queryPage(page, saleVO); final Page<Sale> saleList = saleMapper.queryPage(page, saleVO);
// 获取订单详情信息
for (Sale sale : saleList.getRecords()) {
final QueryWrapper<SaleDetail> querySaleDetailWrapper = new QueryWrapper<>();
querySaleDetailWrapper.select("product_id")
.eq("sale_id", sale.getId())
.groupBy("product_id");
final List<String> list = saleDetailService.selectByCondition1(querySaleDetailWrapper);
if (!list.isEmpty()) {
final List<SaleDetailDTO> saleDetailDTOS = new ArrayList<>();
final Map<String, Product> productMap = new HashMap<>();
// 获取商品信息
final List<Product> productList = productService.getProductList(list);
for (Product product : productList) {
productMap.putIfAbsent(product.getId(), product);
}
for (String productId : list) {
final QueryWrapper<SaleDetail> queryPWrapper = new QueryWrapper<>();
queryPWrapper.eq("sale_id", sale.getId()).eq("product_id", productId);
final List<SaleDetail> saleDetailList = saleDetailService.list(queryPWrapper);
final List<SaleDetailQueryDTO> saleDetailQueryDTOS = new ArrayList<>();
final SaleDetailDTO saleDetailDTO = new SaleDetailDTO();
// 获取库存信息
final QueryWrapper<Stock> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("product_id", productId);
// 供应商名称
final List<Stock> stockList = stockService.list(queryWrapper);
final Map<String, Integer> attributeMap = new HashMap<>();
for (Stock stock : stockList) {
attributeMap.put(stock.getAttributeList(), stock.getStockCount());
}
for (SaleDetail saleDetail : saleDetailList) {
saleDetailDTO.setProductId(productId);
saleDetailDTO.setProductName(saleDetail.getProductName());
saleDetailDTO.setUnit(saleDetail.getUnit());
saleDetailDTO.setShopId(sale.getShopId());
saleDetailDTO.setCategoryId(saleDetail.getCategoryId());
saleDetailDTO.setSaleId(saleDetail.getSaleId());
saleDetailDTO.setPrice(saleDetail.getPrice());
saleDetailDTO.setWholesalePrice(saleDetail.getWholesalePrice());
saleDetailDTO.setDiscount(saleDetail.getDiscount());
saleDetailDTO.setDiscountAmount(saleDetail.getDiscountAmount());
saleDetailDTO.setRealPrice(saleDetail.getRealPrice());
// 回填商品的的图片及货号
if (productMap.containsKey(productId)) {
final BigDecimal purchasePrice = productMap.get(productId).getPurchasePrice() == null ? BigDecimal.ZERO : productMap.get(productId).getPurchasePrice();
saleDetailDTO.setPurchasePrice(purchasePrice);
saleDetailDTO.setProductPicture(productMap.get(productId).getProductPicture());
saleDetailDTO.setProductSn(productMap.get(productId).getProductSn());
saleDetailDTO.setAttrId(productMap.get(productId).getAttrId());
saleDetailDTO.setCustomerCategoryRule(productMap.get(productId).getCustomerCategoryRule());
} else {
saleDetailDTO.setPurchasePrice(saleDetail.getPurchasePrice());
}
final SaleDetailQueryDTO saleDetailQueryDTO = new SaleDetailQueryDTO();
saleDetailQueryDTO.setAttributeList(saleDetail.getAttributeList());
saleDetailQueryDTO.setProductCount(saleDetail.getProductCount());
if (attributeMap.containsKey(saleDetail.getAttributeList())) {
final Integer stockCount = attributeMap.get(saleDetail.getAttributeList());
saleDetailQueryDTO.setStockCount(stockCount);
} else {
saleDetailQueryDTO.setStockCount(null);
}
saleDetailQueryDTOS.add(saleDetailQueryDTO);
}
saleDetailDTO.setStockLogList1(saleDetailQueryDTOS);
saleDetailDTOS.add(saleDetailDTO);
}
sale.setSaleDetailDTOList(saleDetailDTOS);
}
final List<BuyCountVo> buyCount = saleService.buyCount(sale.getUserId(), list);
// 封装为Map
final Map<String, Integer> buyCountMap = new HashMap<>();
for (BuyCountVo buyCountVo : buyCount) {
buyCountMap.put(buyCountVo.getProductId(), buyCountVo.getBuyCount());
}
if (sale != null && sale.getSaleDetailDTOList() != null) {
for (SaleDetailDTO saleDetailDTO : sale.getSaleDetailDTOList()) {
final String productId = saleDetailDTO.getProductId();
saleDetailDTO.setBuyCount(buyCountMap.getOrDefault(productId, 0));
}
}
}
// 获取saleId
final List<String> saleIdList = new ArrayList<>(); final List<String> saleIdList = new ArrayList<>();
for (Sale sale : saleList.getRecords()) { for (Sale sale : saleList.getRecords()) {
saleIdList.add(sale.getId()); saleIdList.add(sale.getId());
} }
fillSaleDetailDTOList(saleList.getRecords(), saleIdList);
// 根据saleId获取标签信息 // 根据saleId获取标签信息
if (!saleIdList.isEmpty()) { if (!saleIdList.isEmpty()) {
final List<SaleLableVo> lableList = lableService.getLableListBySaleIdList(saleIdList); final List<SaleLableVo> lableList = lableService.getLableListBySaleIdList(saleIdList);
@ -294,6 +209,136 @@ public class SaleServiceImpl extends ServiceImpl<SaleMapper, Sale> implements Sa
return saleList; return saleList;
} }
private void fillSaleDetailDTOList(List<Sale> sales, List<String> saleIdList) {
if (sales == null || sales.isEmpty() || saleIdList.isEmpty()) {
return;
}
final List<SaleDetail> saleDetails = saleDetailService.getSaleDetails(saleIdList);
if (saleDetails == null || saleDetails.isEmpty()) {
return;
}
final Map<String, List<SaleDetail>> saleDetailMap = new LinkedHashMap<>();
final Set<String> productIdSet = new LinkedHashSet<>();
for (SaleDetail saleDetail : saleDetails) {
saleDetailMap.computeIfAbsent(saleDetail.getSaleId(), key -> new ArrayList<>()).add(saleDetail);
if (org.apache.commons.lang3.StringUtils.isNotEmpty(saleDetail.getProductId())) {
productIdSet.add(saleDetail.getProductId());
}
}
final List<String> productIds = new ArrayList<>(productIdSet);
final Map<String, Product> productMap = buildProductMap(productIds);
final Map<String, Map<String, Integer>> stockMap = buildStockMap(productIds);
final Map<String, Map<String, Integer>> buyCountMap = buildBuyCountMap(sales, productIds);
for (Sale sale : sales) {
final List<SaleDetail> details = saleDetailMap.get(sale.getId());
if (details == null || details.isEmpty()) {
continue;
}
final Map<String, List<SaleDetail>> productDetailMap = new LinkedHashMap<>();
for (SaleDetail saleDetail : details) {
productDetailMap.computeIfAbsent(saleDetail.getProductId(), key -> new ArrayList<>()).add(saleDetail);
}
final List<SaleDetailDTO> saleDetailDTOS = new ArrayList<>();
final Map<String, Integer> customerBuyCountMap = buyCountMap.getOrDefault(sale.getUserId(), Collections.emptyMap());
for (Map.Entry<String, List<SaleDetail>> entry : productDetailMap.entrySet()) {
final String productId = entry.getKey();
final SaleDetailDTO saleDetailDTO = buildSaleDetailDTO(sale, productId, entry.getValue(), productMap, stockMap);
saleDetailDTO.setBuyCount(customerBuyCountMap.getOrDefault(productId, 0));
saleDetailDTOS.add(saleDetailDTO);
}
sale.setSaleDetailDTOList(saleDetailDTOS);
}
}
private Map<String, Product> buildProductMap(List<String> productIds) {
final Map<String, Product> productMap = new HashMap<>();
if (productIds.isEmpty()) {
return productMap;
}
final List<Product> productList = productService.getProductList(productIds);
for (Product product : productList) {
productMap.putIfAbsent(product.getId(), product);
}
return productMap;
}
private Map<String, Map<String, Integer>> buildStockMap(List<String> productIds) {
final Map<String, Map<String, Integer>> stockMap = new HashMap<>();
if (productIds.isEmpty()) {
return stockMap;
}
final QueryWrapper<Stock> queryWrapper = new QueryWrapper<>();
queryWrapper.in("product_id", productIds);
final List<Stock> stockList = stockService.list(queryWrapper);
for (Stock stock : stockList) {
stockMap.computeIfAbsent(stock.getProductId(), key -> new HashMap<>())
.put(stock.getAttributeList(), stock.getStockCount());
}
return stockMap;
}
private Map<String, Map<String, Integer>> buildBuyCountMap(List<Sale> sales, List<String> productIds) {
final Map<String, Map<String, Integer>> buyCountMap = new HashMap<>();
if (productIds.isEmpty()) {
return buyCountMap;
}
final Set<String> customerIdSet = new LinkedHashSet<>();
for (Sale sale : sales) {
if (org.apache.commons.lang3.StringUtils.isNotEmpty(sale.getUserId())) {
customerIdSet.add(sale.getUserId());
}
}
for (String customerId : customerIdSet) {
final List<BuyCountVo> buyCount = saleService.buyCount(customerId, productIds);
final Map<String, Integer> customerBuyCountMap = new HashMap<>();
for (BuyCountVo buyCountVo : buyCount) {
customerBuyCountMap.put(buyCountVo.getProductId(), buyCountVo.getBuyCount());
}
buyCountMap.put(customerId, customerBuyCountMap);
}
return buyCountMap;
}
private SaleDetailDTO buildSaleDetailDTO(Sale sale, String productId, List<SaleDetail> saleDetailList,
Map<String, Product> productMap, Map<String, Map<String, Integer>> stockMap) {
final SaleDetailDTO saleDetailDTO = new SaleDetailDTO();
final List<SaleDetailQueryDTO> saleDetailQueryDTOS = new ArrayList<>();
final Map<String, Integer> attributeMap = stockMap.getOrDefault(productId, Collections.emptyMap());
for (SaleDetail saleDetail : saleDetailList) {
saleDetailDTO.setProductId(productId);
saleDetailDTO.setProductName(saleDetail.getProductName());
saleDetailDTO.setUnit(saleDetail.getUnit());
saleDetailDTO.setShopId(sale.getShopId());
saleDetailDTO.setCategoryId(saleDetail.getCategoryId());
saleDetailDTO.setSaleId(saleDetail.getSaleId());
saleDetailDTO.setPrice(saleDetail.getPrice());
saleDetailDTO.setWholesalePrice(saleDetail.getWholesalePrice());
saleDetailDTO.setDiscount(saleDetail.getDiscount());
saleDetailDTO.setDiscountAmount(saleDetail.getDiscountAmount());
saleDetailDTO.setRealPrice(saleDetail.getRealPrice());
if (productMap.containsKey(productId)) {
final Product product = productMap.get(productId);
final BigDecimal purchasePrice = product.getPurchasePrice() == null ? BigDecimal.ZERO : product.getPurchasePrice();
saleDetailDTO.setPurchasePrice(purchasePrice);
saleDetailDTO.setProductPicture(product.getProductPicture());
saleDetailDTO.setProductSn(product.getProductSn());
saleDetailDTO.setAttrId(product.getAttrId());
saleDetailDTO.setCustomerCategoryRule(product.getCustomerCategoryRule());
} else {
saleDetailDTO.setPurchasePrice(saleDetail.getPurchasePrice());
}
final SaleDetailQueryDTO saleDetailQueryDTO = new SaleDetailQueryDTO();
saleDetailQueryDTO.setAttributeList(saleDetail.getAttributeList());
saleDetailQueryDTO.setProductCount(saleDetail.getProductCount());
saleDetailQueryDTO.setStockCount(attributeMap.get(saleDetail.getAttributeList()));
saleDetailQueryDTOS.add(saleDetailQueryDTO);
}
saleDetailDTO.setStockLogList1(saleDetailQueryDTOS);
return saleDetailDTO;
}
@Override @Override
public Map<String, Long> getWaitCount(String shopId) { public Map<String, Long> getWaitCount(String shopId) {
final QueryWrapper<Sale> querySaleWrapper = new QueryWrapper<>(); final QueryWrapper<Sale> querySaleWrapper = new QueryWrapper<>();

234
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/AliOcrUtil.java

@ -11,11 +11,12 @@ import cc.hiver.mall.purchaseocr.vo.PurchaseOcrExample;
import cc.hiver.mall.service.mybatis.*; import cc.hiver.mall.service.mybatis.*;
import cn.hutool.core.date.StopWatch; import cn.hutool.core.date.StopWatch;
import com.alibaba.dashscope.aigc.generation.Generation; import com.alibaba.dashscope.aigc.generation.Generation;
import com.alibaba.dashscope.aigc.generation.GenerationParam;
import com.alibaba.dashscope.aigc.generation.GenerationResult; import com.alibaba.dashscope.aigc.generation.GenerationResult;
import com.alibaba.dashscope.aigc.generation.models.QwenParam; import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversation;
import com.alibaba.dashscope.aigc.multimodalconversation.*; import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationParam;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationResult;
import com.alibaba.dashscope.common.Message; import com.alibaba.dashscope.common.Message;
import com.alibaba.dashscope.common.MessageManager;
import com.alibaba.dashscope.common.MultiModalMessage; import com.alibaba.dashscope.common.MultiModalMessage;
import com.alibaba.dashscope.common.Role; import com.alibaba.dashscope.common.Role;
import com.alibaba.dashscope.exception.ApiException; import com.alibaba.dashscope.exception.ApiException;
@ -50,6 +51,61 @@ public class AliOcrUtil {
private static final Pattern COMPILE = Pattern.compile("\\D+"); private static final Pattern COMPILE = Pattern.compile("\\D+");
private static final Pattern SYYS = Pattern.compile("所有颜色", Pattern.LITERAL); private static final Pattern SYYS = Pattern.compile("所有颜色", Pattern.LITERAL);
private static final Pattern SYCM = Pattern.compile("所有尺码", Pattern.LITERAL); private static final Pattern SYCM = Pattern.compile("所有尺码", Pattern.LITERAL);
/** 图像识别:效果优先 */
private static final String MODEL_VISION = "qwen3.5-plus";
/** 语音/文本开单:速度优先(纯文本走 Generation,通常可压到 1s 左右) */
private static final String MODEL_TEXT = "qwen-flash";
private static Map<String, Object> mmText(String text) {
final Map<String, Object> content = new HashMap<>();
content.put("text", text);
return content;
}
private static Map<String, Object> mmImage(String image) {
final Map<String, Object> content = new HashMap<>();
content.put("image", image);
return content;
}
private static MultiModalMessage mmMessage(String role, List<Map<String, Object>> content) {
return MultiModalMessage.builder().role(role).content(content).build();
}
private static String extractMultiModalText(MultiModalConversationResult result) {
final List<Map<String, Object>> content = result.getOutput().getChoices().get(0).getMessage().getContent();
if (content == null || content.isEmpty() || content.get(0).get("text") == null) {
return "";
}
return content.get(0).get("text").toString();
}
/**
* 文本开单走 Generation + 轻量模型,比 qwen3.5-plus 多模态快很多。
*/
private static String callTextFast(String systemPrompt, String userPrompt)
throws ApiException, NoApiKeyException, InputRequiredException {
final Generation gen = new Generation();
final List<Message> messages = new ArrayList<>();
messages.add(Message.builder().role(Role.SYSTEM.getValue()).content(systemPrompt).build());
messages.add(Message.builder().role(Role.USER.getValue()).content(userPrompt).build());
final GenerationParam param = GenerationParam.builder()
.model(MODEL_TEXT)
.messages(messages)
.resultFormat(GenerationParam.ResultFormat.MESSAGE)
.temperature(0.2F)
.topP(0.8)
.maxTokens(1024)
.enableThinking(false)
.build();
log.info("DashScope 文本调用开始, model={}", MODEL_TEXT);
final long start = System.currentTimeMillis();
final GenerationResult result = gen.call(param);
final String text = result.getOutput().getChoices().get(0).getMessage().getContent();
log.info("DashScope 文本调用结束, cost={}ms, textLength={}", System.currentTimeMillis() - start,
text == null ? 0 : text.length());
return text == null ? "" : text;
}
/** /**
* AI入库图像识别-多轮对话 * AI入库图像识别-多轮对话
@ -83,11 +139,9 @@ public class AliOcrUtil {
Constants.apiKey = "sk-bcfa4865b89548acb8225f910f13d682"; Constants.apiKey = "sk-bcfa4865b89548acb8225f910f13d682";
final CopyOnWriteArrayList<MultiModalConversationResult> multiModalConversationResults = new CopyOnWriteArrayList<>(); final CopyOnWriteArrayList<MultiModalConversationResult> multiModalConversationResults = new CopyOnWriteArrayList<>();
final MultiModalConversation conv = new MultiModalConversation(); final MultiModalConversation conv = new MultiModalConversation();
final MultiModalMessageItemText systemText = new MultiModalMessageItemText("You are a helpful assistant."); final MultiModalMessage systemMessage = mmMessage(Role.SYSTEM.getValue(),
final MultiModalConversationMessage systemMessage = MultiModalConversationMessage.builder() Collections.singletonList(mmText("You are a helpful assistant.")));
.role(Role.SYSTEM.getValue()).content(Collections.singletonList(systemText)).build();
final MultiModalMessageItemImage userImage = new MultiModalMessageItemImage(picturePath);
final String firstQuestionMsg = "请把图片中的内容按照商品的不同规格拆分,返回" + count + "条JSON数据。\n" + final String firstQuestionMsg = "请把图片中的内容按照商品的不同规格拆分,返回" + count + "条JSON数据。\n" +
" JSON示例:[{ \"productSn\": \"" + productSnExample + "\", \"productName\":\"" + productNameExample + "\", \"attributeList\": \"{'color':'" + purchaseOcrExample.getColor() + "','size':'" + purchaseOcrExample.getSize() + "'}\", \"productCount\": \"" + purchaseOcrExample.getProductCount() + "\", \"price\": \"" + purchaseOcrExample.getPrice() + "\" }]。" + " JSON示例:[{ \"productSn\": \"" + productSnExample + "\", \"productName\":\"" + productNameExample + "\", \"attributeList\": \"{'color':'" + purchaseOcrExample.getColor() + "','size':'" + purchaseOcrExample.getSize() + "'}\", \"productCount\": \"" + purchaseOcrExample.getProductCount() + "\", \"price\": \"" + purchaseOcrExample.getPrice() + "\" }]。" +
"以下是几点要求: " + "以下是几点要求: " +
@ -99,23 +153,23 @@ public class AliOcrUtil {
"6.请注意返回JSON符号解析格式正确 ,确保java程序能够正确解析。" + "6.请注意返回JSON符号解析格式正确 ,确保java程序能够正确解析。" +
"7.严格返回" + count + "条JSON数据,如果数量有偏差按照实际条数返回,不能自动省略!"; "7.严格返回" + count + "条JSON数据,如果数量有偏差按照实际条数返回,不能自动省略!";
log.info("AI提问内容:" + firstQuestionMsg); log.info("AI提问内容:" + firstQuestionMsg);
MultiModalMessageItemText userText = new MultiModalMessageItemText(firstQuestionMsg); final MultiModalMessage userMessage = mmMessage(Role.USER.getValue(),
final MultiModalConversationMessage userMessage = Arrays.asList(mmImage(picturePath), mmText(firstQuestionMsg)));
MultiModalConversationMessage.builder().role(Role.USER.getValue()) final CopyOnWriteArrayList<MultiModalMessage> messages = new CopyOnWriteArrayList<>();
.content(Arrays.asList(userImage, userText)).build();
final CopyOnWriteArrayList<MultiModalConversationMessage> messages = new CopyOnWriteArrayList<>();
messages.add(systemMessage); messages.add(systemMessage);
messages.add(userMessage); messages.add(userMessage);
final MultiModalConversationParam param = MultiModalConversationParam.builder() final MultiModalConversationParam param = MultiModalConversationParam.builder()
.model("qwen-vl-max") .model(MODEL_VISION)
.messages(messages) .messages(messages)
.enableThinking(false)
.build(); .build();
stopWatch.start("一轮会话"); stopWatch.start("一轮会话");
log.info("DashScope 图像识别开始, model={}, picture={}", MODEL_VISION, picturePath);
MultiModalConversationResult result = conv.call(param); MultiModalConversationResult result = conv.call(param);
stopWatch.stop(); stopWatch.stop();
multiModalConversationResults.add(result); multiModalConversationResults.add(result);
// 解析结果 // 解析结果
String text = result.getOutput().getChoices().get(0).getMessage().getContent().get(0).get("text").toString(); String text = extractMultiModalText(result);
log.info("一轮对话-的json======" + text); log.info("一轮对话-的json======" + text);
// 根据{}截取数据 // 根据{}截取数据
final int startIndex = text.indexOf('{'); final int startIndex = text.indexOf('{');
@ -170,21 +224,15 @@ public class AliOcrUtil {
log.error(Thread.currentThread().getName() + "-一轮对话--->json识别报错喽,没关系,我来重新识别一下!"); log.error(Thread.currentThread().getName() + "-一轮对话--->json识别报错喽,没关系,我来重新识别一下!");
//尝试重新识别一次 //尝试重新识别一次
final String errorJsonQuestionMsg = "返回的json格式有误,请重新返回。"; final String errorJsonQuestionMsg = "返回的json格式有误,请重新返回。";
final MultiModalMessageItemText assistentText = new MultiModalMessageItemText( messages.add(mmMessage(Role.ASSISTANT.getValue(), Collections.singletonList(mmText(text))));
text); messages.add(mmMessage(Role.USER.getValue(), Collections.singletonList(mmText(errorJsonQuestionMsg))));
final MultiModalConversationMessage assistentMessage = MultiModalConversationMessage.builder() param.setMessages(new CopyOnWriteArrayList<>(messages));
.role(Role.ASSISTANT.getValue()).content(Collections.singletonList(assistentText)).build();
messages.add(assistentMessage);
userText = new MultiModalMessageItemText(errorJsonQuestionMsg);
messages.add(MultiModalConversationMessage.builder().role(Role.USER.getValue())
.content(Collections.singletonList(userText)).build());
param.setMessages(new CopyOnWriteArrayList<Object>(messages));
stopWatch.start("一轮对话json格式错误重新识别!"); stopWatch.start("一轮对话json格式错误重新识别!");
result = conv.call(param); result = conv.call(param);
multiModalConversationResults.add(result); multiModalConversationResults.add(result);
stopWatch.stop(); stopWatch.stop();
// 解析结果 // 解析结果
text = result.getOutput().getChoices().get(0).getMessage().getContent().get(0).get("text").toString(); text = extractMultiModalText(result);
log.info("一轮对话--json格式错误,重新识别的结果======" + text); log.info("一轮对话--json格式错误,重新识别的结果======" + text);
// 根据{}截取数据 // 根据{}截取数据
final int secondStartIndex = text.indexOf('{'); final int secondStartIndex = text.indexOf('{');
@ -242,21 +290,15 @@ public class AliOcrUtil {
final int missingCount = count - fristResultCount; final int missingCount = count - fristResultCount;
if (missingCount > 0) { if (missingCount > 0) {
final String secondQuestionMsg = "缺少了" + missingCount + "条,请完整返回。"; final String secondQuestionMsg = "缺少了" + missingCount + "条,请完整返回。";
final MultiModalMessageItemText assistentText = new MultiModalMessageItemText( messages.add(mmMessage(Role.ASSISTANT.getValue(), Collections.singletonList(mmText(text))));
text); messages.add(mmMessage(Role.USER.getValue(), Collections.singletonList(mmText(secondQuestionMsg))));
final MultiModalConversationMessage assistentMessage = MultiModalConversationMessage.builder() param.setMessages(new CopyOnWriteArrayList<>(messages));
.role(Role.ASSISTANT.getValue()).content(Collections.singletonList(assistentText)).build();
messages.add(assistentMessage);
userText = new MultiModalMessageItemText(secondQuestionMsg);
messages.add(MultiModalConversationMessage.builder().role(Role.USER.getValue())
.content(Collections.singletonList(userText)).build());
param.setMessages(new CopyOnWriteArrayList<Object>(messages));
stopWatch.start("二轮会话"); stopWatch.start("二轮会话");
result = conv.call(param); result = conv.call(param);
multiModalConversationResults.add(result); multiModalConversationResults.add(result);
stopWatch.stop(); stopWatch.stop();
// 解析结果 // 解析结果
String secondText = result.getOutput().getChoices().get(0).getMessage().getContent().get(0).get("text").toString(); String secondText = extractMultiModalText(result);
log.info("二轮对话识别结果:" + secondText); log.info("二轮对话识别结果:" + secondText);
// 根据{}截取数据 // 根据{}截取数据
final int secondStartIndex = secondText.indexOf('{'); final int secondStartIndex = secondText.indexOf('{');
@ -322,21 +364,15 @@ public class AliOcrUtil {
log.error(Thread.currentThread().getName() + "-二轮对话--->json识别报错喽,没关系,我来重新识别一下!"); log.error(Thread.currentThread().getName() + "-二轮对话--->json识别报错喽,没关系,我来重新识别一下!");
//尝试重新识别一次 //尝试重新识别一次
final String errorJsonQuestionMsg = "返回的json格式有误,请重新返回。"; final String errorJsonQuestionMsg = "返回的json格式有误,请重新返回。";
final MultiModalMessageItemText secondJsonErrorAssistentText = new MultiModalMessageItemText( messages.add(mmMessage(Role.ASSISTANT.getValue(), Collections.singletonList(mmText(secondText))));
secondText); messages.add(mmMessage(Role.USER.getValue(), Collections.singletonList(mmText(errorJsonQuestionMsg))));
final MultiModalConversationMessage secondJsonErrorAssistentMessage = MultiModalConversationMessage.builder() param.setMessages(new CopyOnWriteArrayList<>(messages));
.role(Role.ASSISTANT.getValue()).content(Collections.singletonList(secondJsonErrorAssistentText)).build();
messages.add(secondJsonErrorAssistentMessage);
userText = new MultiModalMessageItemText(errorJsonQuestionMsg);
messages.add(MultiModalConversationMessage.builder().role(Role.USER.getValue())
.content(Collections.singletonList(userText)).build());
param.setMessages(new CopyOnWriteArrayList<Object>(messages));
stopWatch.start("二轮会话json格式错误,重新识别!"); stopWatch.start("二轮会话json格式错误,重新识别!");
result = conv.call(param); result = conv.call(param);
multiModalConversationResults.add(result); multiModalConversationResults.add(result);
stopWatch.stop(); stopWatch.stop();
// 解析结果 // 解析结果
secondText = result.getOutput().getChoices().get(0).getMessage().getContent().get(0).get("text").toString(); secondText = extractMultiModalText(result);
log.info("二轮对话-json格式错误,重新识别的结果======" + secondText); log.info("二轮对话-json格式错误,重新识别的结果======" + secondText);
// 根据{}截取数据 // 根据{}截取数据
final int errorSsecondStartIndex = secondText.indexOf('{'); final int errorSsecondStartIndex = secondText.indexOf('{');
@ -531,7 +567,7 @@ public class AliOcrUtil {
} }
})).build(); })).build();
final MultiModalConversationParam param = MultiModalConversationParam.builder() final MultiModalConversationParam param = MultiModalConversationParam.builder()
.model("qwen-vl-max") .model(MODEL_VISION)
.message(userMessage) .message(userMessage)
/*.stream(true) /*.stream(true)
.temperature(1F) .temperature(1F)
@ -543,6 +579,7 @@ public class AliOcrUtil {
.seed(500)*/ .seed(500)*/
// 是否使用增量输出。当使用增量输出时每次流式返回的序列仅包含最新生成的增量内容,默认值为false,即输出完整的全量内容 // 是否使用增量输出。当使用增量输出时每次流式返回的序列仅包含最新生成的增量内容,默认值为false,即输出完整的全量内容
.incrementalOutput(true) .incrementalOutput(true)
.enableThinking(false)
.build(); .build();
stopWatch.start("开始识别!"); stopWatch.start("开始识别!");
final Flowable<MultiModalConversationResult> result = conv.streamCall(param); final Flowable<MultiModalConversationResult> result = conv.streamCall(param);
@ -833,10 +870,6 @@ public class AliOcrUtil {
final JSONObject jsonObject = new JSONObject(); final JSONObject jsonObject = new JSONObject();
Constants.apiKey = "sk-bcfa4865b89548acb8225f910f13d682"; Constants.apiKey = "sk-bcfa4865b89548acb8225f910f13d682";
final StopWatch stopWatch = new StopWatch("Ai回答计时"); final StopWatch stopWatch = new StopWatch("Ai回答计时");
final Generation gen = new Generation();
final MessageManager msgManager = new MessageManager(10);
final Message systemMsg =
Message.builder().role(Role.SYSTEM.getValue()).content("You are a helpful assistant.").build();
//questionMsg += "请帮我把所有内容封装为JSON,json格式为:[{ \"productSn\": \"货号\", \"attributeList\": [{\"color\":\"颜色\",\"size\":\"尺码\",\"productCount\": \"数量\"}] }]。以下是几点要求: 1.“货号”两个字和颜色中间的内容代表productSn,productSn可能包含\"新\"、\"退\"、\"旧\"、\"换\"、\"补\"。 2.\"SYYS色\"代表“所有颜色”,\"color\"字段返回“SYYS色”。 3.\"SYCM码\"代表“所有尺码”,\"size\"字段返回“SYCM码”。 4.只输出JSON数据即可,不用返回字段描述和解析过程。"; //questionMsg += "请帮我把所有内容封装为JSON,json格式为:[{ \"productSn\": \"货号\", \"attributeList\": [{\"color\":\"颜色\",\"size\":\"尺码\",\"productCount\": \"数量\"}] }]。以下是几点要求: 1.“货号”两个字和颜色中间的内容代表productSn,productSn可能包含\"新\"、\"退\"、\"旧\"、\"换\"、\"补\"。 2.\"SYYS色\"代表“所有颜色”,\"color\"字段返回“SYYS色”。 3.\"SYCM码\"代表“所有尺码”,\"size\"字段返回“SYCM码”。 4.只输出JSON数据即可,不用返回字段描述和解析过程。";
questionMsg += "你是一个服装行业库管专家,请帮我把所有内容封装为JSON,json格式为:[{ \"productSn\": \"货号\", \"attributeList\": [{\"color\":\"颜色\",\"size\":\"尺码\",\"productCount\": \"数量\"}] , \"wholesalePrice\":\"价格\"}],\n" + questionMsg += "你是一个服装行业库管专家,请帮我把所有内容封装为JSON,json格式为:[{ \"productSn\": \"货号\", \"attributeList\": [{\"color\":\"颜色\",\"size\":\"尺码\",\"productCount\": \"数量\"}] , \"wholesalePrice\":\"价格\"}],\n" +
"1.productSn的返回值中去掉颜色,尺码等信息,\n" + "1.productSn的返回值中去掉颜色,尺码等信息,\n" +
@ -848,22 +881,9 @@ public class AliOcrUtil {
"7.如果没有识别到\"wholesalePrice\"的内容,则\"wholesalePrice\"赋值\"0\"。\n" + "7.如果没有识别到\"wholesalePrice\"的内容,则\"wholesalePrice\"赋值\"0\"。\n" +
"8.只输出JSON数据即可,禁止返回除JSON数据外的任何内容!" + "8.只输出JSON数据即可,禁止返回除JSON数据外的任何内容!" +
"9.返回的JSON数据不用换行,以最快的速度返回!"; "9.返回的JSON数据不用换行,以最快的速度返回!";
final Message userMsg = Message.builder().role(Role.USER.getValue()).content(questionMsg).build();
msgManager.add(systemMsg);
msgManager.add(userMsg);
stopWatch.start("开始回答"); stopWatch.start("开始回答");
final QwenParam param = final String text = callTextFast("You are a helpful assistant.", questionMsg);
QwenParam.builder().model("qwen-turbo").messages(msgManager.get()) log.info(text);
.resultFormat(QwenParam.ResultFormat.MESSAGE)
.seed(1234)
.temperature(0.7F)
.topP(0.8)
.repetitionPenalty(1.0F)
.build();
final GenerationResult result = gen.call(param);
log.info(result.toString());
// 解析结果
final String text = result.getOutput().getChoices().get(0).getMessage().getContent();
// 根据{}截取数据 // 根据{}截取数据
final int startIndex = text.indexOf('{'); final int startIndex = text.indexOf('{');
final int endIndex = text.lastIndexOf('}'); final int endIndex = text.lastIndexOf('}');
@ -871,7 +891,7 @@ public class AliOcrUtil {
stopWatch.stop(); stopWatch.stop();
log.info(stopWatch.prettyPrint()); log.info(stopWatch.prettyPrint());
jsonObject.put("resultContent", jsonStr); jsonObject.put("resultContent", jsonStr);
jsonObject.put("msg", result.getOutput().getChoices().get(0).getMessage().getContent()); jsonObject.put("msg", text);
return jsonObject; return jsonObject;
} }
@ -887,10 +907,6 @@ public class AliOcrUtil {
throws NoApiKeyException, ApiException, InputRequiredException { throws NoApiKeyException, ApiException, InputRequiredException {
final JSONObject jsonObject = new JSONObject(); final JSONObject jsonObject = new JSONObject();
Constants.apiKey = "sk-bcfa4865b89548acb8225f910f13d682"; Constants.apiKey = "sk-bcfa4865b89548acb8225f910f13d682";
final Generation gen = new Generation();
final MessageManager msgManager = new MessageManager(10);
final Message systemMsg =
Message.builder().role(Role.SYSTEM.getValue()).content("You are a helpful assistant.").build();
// questionMsg += "请帮我把所有内容封装为JSON,json格式为:[{ \"productSn\": \"货号\", \"productName\": \"名称\" , \"price\":\"单价\",\"attributeList\": [{\"color\":\"颜色\",\"size\":\"尺码\",\"productCount\": \"数量\"}] }]。以下是几点要求: 1.“货号”两个字和\"名称\"两个字中间的内容代表productSn的值,如果没有名称则“货号”两个字和颜色中间的内容代表productSn的值,productSn可能包含\"新\"、\"退\"、\"旧\"、\"换\"、\"补\"。2.\"SYYS色\"代表“所有颜色”,\"color\"字段返回“SYYS色”。 3.\"SYCM码\"代表“所有尺码”,\"size\"字段返回“SYCM码”。4.如果没有名称,productName字段返回\"\"。5.只输出JSON数据即可,不用返回字段描述和解析过程。"; // questionMsg += "请帮我把所有内容封装为JSON,json格式为:[{ \"productSn\": \"货号\", \"productName\": \"名称\" , \"price\":\"单价\",\"attributeList\": [{\"color\":\"颜色\",\"size\":\"尺码\",\"productCount\": \"数量\"}] }]。以下是几点要求: 1.“货号”两个字和\"名称\"两个字中间的内容代表productSn的值,如果没有名称则“货号”两个字和颜色中间的内容代表productSn的值,productSn可能包含\"新\"、\"退\"、\"旧\"、\"换\"、\"补\"。2.\"SYYS色\"代表“所有颜色”,\"color\"字段返回“SYYS色”。 3.\"SYCM码\"代表“所有尺码”,\"size\"字段返回“SYCM码”。4.如果没有名称,productName字段返回\"\"。5.只输出JSON数据即可,不用返回字段描述和解析过程。";
questionMsg += "你是一个服装行业库管专家,请帮我把所有内容封装为JSON,json格式为:[{ \"productSn\": \"货号\", \"productName\": \"名称\" , \"attributeList\": [{\"color\":\"颜色\",\"size\":\"尺码\",\"productCount\": \"数量\"}], \"purchasePrice\":\"单价\" , \"price\":\"零售价\" , \"wholesalePrice\":\"批发价\" }]\n" + questionMsg += "你是一个服装行业库管专家,请帮我把所有内容封装为JSON,json格式为:[{ \"productSn\": \"货号\", \"productName\": \"名称\" , \"attributeList\": [{\"color\":\"颜色\",\"size\":\"尺码\",\"productCount\": \"数量\"}], \"purchasePrice\":\"单价\" , \"price\":\"零售价\" , \"wholesalePrice\":\"批发价\" }]\n" +
"1.如果没有识别到\"purchasePrice\"的内容,则\"purchasePrice\"赋值\"0\",purchasePrice为单价!" + "1.如果没有识别到\"purchasePrice\"的内容,则\"purchasePrice\"赋值\"0\",purchasePrice为单价!" +
@ -903,27 +919,14 @@ public class AliOcrUtil {
"8.如果指令中尺码是?码到?码,请完整返回跨度内所有尺码JSON、不要省略中间的尺码。(常见的尺码顺序:S码-M码-L码-XL码-2XL码-3XL码-4XL码-5XL码-6XL码-7XL码......)。\n" + "8.如果指令中尺码是?码到?码,请完整返回跨度内所有尺码JSON、不要省略中间的尺码。(常见的尺码顺序:S码-M码-L码-XL码-2XL码-3XL码-4XL码-5XL码-6XL码-7XL码......)。\n" +
"9.返回的JSON数据不用换行,以最快的速度返回!\n" + "9.返回的JSON数据不用换行,以最快的速度返回!\n" +
"10.只输出JSON数据即可,禁止返回除JSON数据外的任何内容!"; "10.只输出JSON数据即可,禁止返回除JSON数据外的任何内容!";
final Message userMsg = Message.builder().role(Role.USER.getValue()).content(questionMsg).build(); final String text = callTextFast("You are a helpful assistant.", questionMsg);
msgManager.add(systemMsg); log.info(text);
msgManager.add(userMsg);
final QwenParam param =
QwenParam.builder().model("qwen-turbo").messages(msgManager.get())
.resultFormat(QwenParam.ResultFormat.MESSAGE)
.seed(1234)
.temperature(0.7F)
.topP(0.8)
.repetitionPenalty(1.0F)
.build();
final GenerationResult result = gen.call(param);
log.info(result.toString());
// 解析结果
final String text = result.getOutput().getChoices().get(0).getMessage().getContent();
// 根据{}截取数据 // 根据{}截取数据
final int startIndex = text.indexOf('{'); final int startIndex = text.indexOf('{');
final int endIndex = text.lastIndexOf('}'); final int endIndex = text.lastIndexOf('}');
final String jsonStr = '[' + text.substring(startIndex, endIndex + 1) + ']'; final String jsonStr = '[' + text.substring(startIndex, endIndex + 1) + ']';
jsonObject.put("resultContent", jsonStr); jsonObject.put("resultContent", jsonStr);
jsonObject.put("msg", result.getOutput().getChoices().get(0).getMessage().getContent()); jsonObject.put("msg", text);
return jsonObject; return jsonObject;
} }
@ -932,10 +935,6 @@ public class AliOcrUtil {
final JSONObject jsonObject = new JSONObject(); final JSONObject jsonObject = new JSONObject();
Constants.apiKey = "sk-bcfa4865b89548acb8225f910f13d682"; Constants.apiKey = "sk-bcfa4865b89548acb8225f910f13d682";
final StopWatch stopWatch = new StopWatch("Ai回答计时"); final StopWatch stopWatch = new StopWatch("Ai回答计时");
final Generation gen = new Generation();
final MessageManager msgManager = new MessageManager(10);
final Message systemMsg =
Message.builder().role(Role.SYSTEM.getValue()).content("You are a helpful assistant.").build();
// questionMsg += "请帮我把所有内容封装为JSON,json格式为:[{ \"productSn\": \"货号\", \"attributeList\": [{\"color\":\"颜色\",\"size\":\"尺码\",\"productCount\": \"数量\"}] }],只输出JSON数据即可,不用返回字段描述"; // questionMsg += "请帮我把所有内容封装为JSON,json格式为:[{ \"productSn\": \"货号\", \"attributeList\": [{\"color\":\"颜色\",\"size\":\"尺码\",\"productCount\": \"数量\"}] }],只输出JSON数据即可,不用返回字段描述";
questionMsg += "你是一个服装行业库管专家,请帮我把所有内容封装为JSON,json格式为:[{ \"productSn\": \"货号\", \"attributeList\": [{\"color\":\"颜色\",\"size\":\"尺码\",\"productCount\": \"数量\"}] }],\n" + questionMsg += "你是一个服装行业库管专家,请帮我把所有内容封装为JSON,json格式为:[{ \"productSn\": \"货号\", \"attributeList\": [{\"color\":\"颜色\",\"size\":\"尺码\",\"productCount\": \"数量\"}] }],\n" +
"1.productSn的返回值中去掉颜色,尺码等信息,\n" + "1.productSn的返回值中去掉颜色,尺码等信息,\n" +
@ -944,22 +943,9 @@ public class AliOcrUtil {
"4.如果指令中有“各N件”,则每个尺码数量返回N。\n" + "4.如果指令中有“各N件”,则每个尺码数量返回N。\n" +
"5.如果指令中尺码是?码到?码,请完整返回跨度内所有尺码JSON、不要省略中间的尺码。(常见的尺码顺序:S码-M码-L码-XL码-2XL码-3XL码-4XL码-5XL码-6XL码-7XL码......)。\n" + "5.如果指令中尺码是?码到?码,请完整返回跨度内所有尺码JSON、不要省略中间的尺码。(常见的尺码顺序:S码-M码-L码-XL码-2XL码-3XL码-4XL码-5XL码-6XL码-7XL码......)。\n" +
"6.只输出JSON数据即可,禁止返回除JSON数据外的任何内容!"; "6.只输出JSON数据即可,禁止返回除JSON数据外的任何内容!";
final Message userMsg = Message.builder().role(Role.USER.getValue()).content(questionMsg).build();
msgManager.add(systemMsg);
msgManager.add(userMsg);
stopWatch.start("开始回答"); stopWatch.start("开始回答");
final QwenParam param = final String text = callTextFast("You are a helpful assistant.", questionMsg);
QwenParam.builder().model("qwen-turbo").messages(msgManager.get()) log.info(text);
.resultFormat(QwenParam.ResultFormat.MESSAGE)
.seed(1234)
.temperature(0.85F)
.topP(0.8)
.repetitionPenalty(1.0F)
.build();
final GenerationResult result = gen.call(param);
log.info(result.toString());
// 解析结果
final String text = result.getOutput().getChoices().get(0).getMessage().getContent();
// 根据{}截取数据 // 根据{}截取数据
final int startIndex = text.indexOf('{'); final int startIndex = text.indexOf('{');
final int endIndex = text.lastIndexOf('}'); final int endIndex = text.lastIndexOf('}');
@ -968,7 +954,7 @@ public class AliOcrUtil {
stopWatch.stop(); stopWatch.stop();
log.info(stopWatch.prettyPrint()); log.info(stopWatch.prettyPrint());
jsonObject.put("resultContent", jsonStr); jsonObject.put("resultContent", jsonStr);
jsonObject.put("msg", result.getOutput().getChoices().get(0).getMessage().getContent()); jsonObject.put("msg", text);
return jsonObject; return jsonObject;
} }
@ -1218,23 +1204,10 @@ public class AliOcrUtil {
final JSONObject jsonObject = new JSONObject(); final JSONObject jsonObject = new JSONObject();
Constants.apiKey = "sk-bcfa4865b89548acb8225f910f13d682"; Constants.apiKey = "sk-bcfa4865b89548acb8225f910f13d682";
final StopWatch stopWatch = new StopWatch("Ai回答计时"); final StopWatch stopWatch = new StopWatch("Ai回答计时");
final Generation gen = new Generation();
final MessageManager msgManager = new MessageManager(10);
final Message systemMsg =
Message.builder().role(Role.SYSTEM.getValue()).content("You are a helpful assistant.").build();
questionMsg += "请帮我把所有内容封装为JSON,json格式为:[{ \"senderName\": \"发货人\", \"senderPhone\": \"发货人电话\" , \"receiverName\": \"收货人\", \"receiverPhone\": \"收货人电话\" , \"arrivalStation\":\"\"到达站,\"weight\":\"重量\",\"count\":\"件数\",\"methodOfSettlement\":\"结算方式\",\"tips\":\"小费\" }]。没有识别到的信息JSON字段返回\"\"。"; questionMsg += "请帮我把所有内容封装为JSON,json格式为:[{ \"senderName\": \"发货人\", \"senderPhone\": \"发货人电话\" , \"receiverName\": \"收货人\", \"receiverPhone\": \"收货人电话\" , \"arrivalStation\":\"\"到达站,\"weight\":\"重量\",\"count\":\"件数\",\"methodOfSettlement\":\"结算方式\",\"tips\":\"小费\" }]。没有识别到的信息JSON字段返回\"\"。";
final Message userMsg = Message.builder().role(Role.USER.getValue()).content(questionMsg).build();
msgManager.add(systemMsg);
msgManager.add(userMsg);
stopWatch.start("开始回答"); stopWatch.start("开始回答");
final QwenParam param = final String text = callTextFast("You are a helpful assistant.", questionMsg);
QwenParam.builder().model("qwen-max").messages(msgManager.get()) log.info(text);
.resultFormat(QwenParam.ResultFormat.MESSAGE)
.build();
final GenerationResult result = gen.call(param);
log.info(result.toString());
// 解析结果
final String text = result.getOutput().getChoices().get(0).getMessage().getContent();
// 根据{}截取数据 // 根据{}截取数据
final int startIndex = text.indexOf('{'); final int startIndex = text.indexOf('{');
final int endIndex = text.lastIndexOf('}'); final int endIndex = text.lastIndexOf('}');
@ -1242,7 +1215,7 @@ public class AliOcrUtil {
stopWatch.stop(); stopWatch.stop();
log.info(stopWatch.prettyPrint()); log.info(stopWatch.prettyPrint());
jsonObject.put("resultContent", jsonStr); jsonObject.put("resultContent", jsonStr);
jsonObject.put("msg", result.getOutput().getChoices().get(0).getMessage().getContent()); jsonObject.put("msg", text);
return jsonObject; return jsonObject;
} }
@ -1258,10 +1231,6 @@ public class AliOcrUtil {
final JSONObject jsonObject = new JSONObject(); final JSONObject jsonObject = new JSONObject();
Constants.apiKey = "sk-bcfa4865b89548acb8225f910f13d682"; Constants.apiKey = "sk-bcfa4865b89548acb8225f910f13d682";
final StopWatch stopWatch = new StopWatch("Ai回答计时"); final StopWatch stopWatch = new StopWatch("Ai回答计时");
final Generation gen = new Generation();
final MessageManager msgManager = new MessageManager(10);
final Message systemMsg =
Message.builder().role(Role.SYSTEM.getValue()).content("你是一个物流开票员(这句话是给你的角色设定,不要在json信息中返回)").build();
final List<LogisticsAddressBook> shipperLogisticsAddressBooks = logisticsAddressBooks.get("shipper"); final List<LogisticsAddressBook> shipperLogisticsAddressBooks = logisticsAddressBooks.get("shipper");
final List<LogisticsAddressBook> receiverLogisticsAddressBooks = logisticsAddressBooks.get("receiver"); final List<LogisticsAddressBook> receiverLogisticsAddressBooks = logisticsAddressBooks.get("receiver");
final StringBuilder endQuestionMsg = new StringBuilder(); final StringBuilder endQuestionMsg = new StringBuilder();
@ -1295,18 +1264,9 @@ public class AliOcrUtil {
.append("4.weight、count、tips、premium这几个字段只返回数字; ") .append("4.weight、count、tips、premium这几个字段只返回数字; ")
.append("5.不要返回推理过程,只输出1条JSON数据即可,禁止返回除JSON数据外的任何内容!返回的JSON数据不用换行,以最快的速度返回!"); .append("5.不要返回推理过程,只输出1条JSON数据即可,禁止返回除JSON数据外的任何内容!返回的JSON数据不用换行,以最快的速度返回!");
log.info("AI物流最终指令==="+endQuestionMsg); log.info("AI物流最终指令==="+endQuestionMsg);
final Message userMsg = Message.builder().role(Role.USER.getValue()).content(endQuestionMsg.toString()).build();
msgManager.add(systemMsg);
msgManager.add(userMsg);
stopWatch.start("开始回答"); stopWatch.start("开始回答");
final QwenParam param = final String text = callTextFast("你是一个物流开票员(这句话是给你的角色设定,不要在json信息中返回)", endQuestionMsg.toString());
QwenParam.builder().model("qwen-max").messages(msgManager.get()) log.info(text);
.resultFormat(QwenParam.ResultFormat.MESSAGE)
.build();
final GenerationResult result = gen.call(param);
log.info(result.toString());
// 解析结果
final String text = result.getOutput().getChoices().get(0).getMessage().getContent();
// 根据{}截取数据 // 根据{}截取数据
final int startIndex = text.indexOf('{'); final int startIndex = text.indexOf('{');
final int endIndex = text.lastIndexOf('}'); final int endIndex = text.lastIndexOf('}');
@ -1314,7 +1274,7 @@ public class AliOcrUtil {
stopWatch.stop(); stopWatch.stop();
log.info(stopWatch.prettyPrint()); log.info(stopWatch.prettyPrint());
jsonObject.put("resultContent", jsonStr); jsonObject.put("resultContent", jsonStr);
jsonObject.put("msg", result.getOutput().getChoices().get(0).getMessage().getContent()); jsonObject.put("msg", text);
return jsonObject; return jsonObject;
} }
} }

1
hiver-modules/hiver-mall/src/main/resources/mapper/PurchaseDetailMapper.xml

@ -700,6 +700,7 @@
t_purchase tp t_purchase tp
WHERE WHERE
tp.in_storage_status = '1' tp.in_storage_status = '1'
and tp.shop_id = #{supplierBillQueryVo.shopId}
<if test='supplierBillQueryVo.startDate !=null and supplierBillQueryVo.endDate !=null'> <if test='supplierBillQueryVo.startDate !=null and supplierBillQueryVo.endDate !=null'>
AND tp.create_time BETWEEN #{supplierBillQueryVo.startDate} AND #{supplierBillQueryVo.endDate} AND tp.create_time BETWEEN #{supplierBillQueryVo.startDate} AND #{supplierBillQueryVo.endDate}
</if> </if>

9
hiver-modules/hiver-mall/src/main/resources/mapper/ReturnDetailMapper.xml

@ -554,13 +554,16 @@
<select id="getsaleReturnCost" resultType="java.math.BigDecimal"> <select id="getsaleReturnCost" resultType="java.math.BigDecimal">
select select
IFNULL(sum(pd.purchase_price * trd.product_count),0.00) as saleReturnCost IFNULL(sum(pd.purchase_price * trd.product_count),0.00) as saleReturnCost
from t_return_detail trd left join t_sale sa on trd.sale_id = sa.id from t_return_detail trd
join t_sale sa on trd.sale_id = sa.id
join t_return_sale rs on trd.return_sale_id = rs.id
JOIN t_product pd ON trd.product_id = pd.id JOIN t_product pd ON trd.product_id = pd.id
where where
sa.status = '4' sa.status = '4'
and trd.shop_id = #{shopId} and trd.shop_id = #{shopId}
and trd.create_time BETWEEN #{startTime} AND #{endTime} and trd.create_time BETWEEN #{startTime} AND #{endTime}
and trd.return_sale_id in and rs.shop_id = #{shopId}
(select id from t_return_sale where shop_id = #{shopId} and del_flag='0' and status = '4') and rs.del_flag='0'
and rs.status = '4'
</select> </select>
</mapper> </mapper>

15
hiver-modules/hiver-mall/src/main/resources/mapper/SaleDetailMapper.xml

@ -559,30 +559,19 @@
SELECT IFNULL(SUM( COALESCE(pd.purchase_price, 0) * sd.product_count),0.00) AS profit SELECT IFNULL(SUM( COALESCE(pd.purchase_price, 0) * sd.product_count),0.00) AS profit
FROM FROM
t_sale_detail sd t_sale_detail sd
JOIN t_sale ts ON sd.sale_id = ts.id
JOIN t_product pd ON sd.product_id = pd.id JOIN t_product pd ON sd.product_id = pd.id
WHERE WHERE
sd.shop_id = #{shopId} sd.shop_id = #{shopId}
<if test='startDate !=null and endDate !=null'> <if test='startDate !=null and endDate !=null'>
and sd.create_time BETWEEN #{startDate} AND #{endDate} and sd.create_time BETWEEN #{startDate} AND #{endDate}
</if> </if>
AND sale_id IN ( AND ts.del_flag = '0'
SELECT
id
FROM
t_sale ts
WHERE
ts.del_flag = '0'
AND ts.id IN ( SELECT sale_id FROM t_sale_detail tsd WHERE tsd.shop_id = #{shopId}
<if test='startDate !=null and endDate !=null'>
AND tsd.create_time BETWEEN #{startDate} AND #{endDate}
</if>
)
AND ts.shop_id = #{shopId} AND ts.shop_id = #{shopId}
AND ts.STATUS NOT IN ( '2', '6', '7' ) AND ts.STATUS NOT IN ( '2', '6', '7' )
<if test='startDate !=null and endDate !=null'> <if test='startDate !=null and endDate !=null'>
AND ts.create_time BETWEEN #{startDate} AND #{endDate} AND ts.create_time BETWEEN #{startDate} AND #{endDate}
</if> </if>
)
</select> </select>

10
hiver-modules/hiver-mall/src/main/resources/mapper/SaleMapper.xml

@ -770,6 +770,16 @@ trans_company, company_name, product_count, remark, sale_name, company_phone, cr
group by DATE_FORMAT(create_time, '%Y-%m-%d') group by DATE_FORMAT(create_time, '%Y-%m-%d')
</select> </select>
<select id="getShopWeekRevenue" resultType="cc.hiver.mall.pojo.dto.ShopRevenue">
select DATE(create_time) dt, IFNULL(sum(total_amount), 0) real_amount
from t_sale
where shop_id = #{shopId}
and status not in ('2','6','7')
and create_time &gt;= #{startTime}
and create_time &lt; #{endTime}
group by DATE(create_time)
</select>
<!--获取当前的销售单--> <!--获取当前的销售单-->
<select id="getSaleId" parameterType="java.lang.String" resultType="java.lang.String"> <select id="getSaleId" parameterType="java.lang.String" resultType="java.lang.String">
select select

21
pom.xml

@ -282,6 +282,27 @@
<artifactId>selenium-java</artifactId> <artifactId>selenium-java</artifactId>
<version>${selenuim.version}</version> <version>${selenuim.version}</version>
</dependency> </dependency>
<!-- dashscope 2.21.x 需要 okhttp4;覆盖 Spring Boot 2.5 默认的 okhttp 3.14.9 -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.12.0</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp-sse</artifactId>
<version>4.12.0</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>logging-interceptor</artifactId>
<version>4.12.0</version>
</dependency>
<dependency>
<groupId>com.squareup.okio</groupId>
<artifactId>okio</artifactId>
<version>3.6.0</version>
</dependency>
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>

Loading…
Cancel
Save