Merge remote-tracking branch 'origin/dev' into test

# Conflicts:
#	sf-admin/src/main/java/com/sf/order/domain/res/OrderListResVo.java
#	sf-order/src/main/java/com/sf/order/controller/OrderInfoController.java
#	sf-order/src/main/java/com/sf/order/domain/req/OrderListReqVo.java
#	sf-order/src/main/java/com/sf/order/service/impl/OrderInfoServiceImpl.java
#	sf-order/src/main/resources/mapper/order/OrderInfoMapper.xml
This commit is contained in:
akun 2024-04-18 16:04:41 +08:00
commit 1b3c0826b0
52 changed files with 3194 additions and 1092 deletions

11
pom.xml
View File

@ -174,6 +174,17 @@
<version>${sf.version}</version>
</dependency>
<dependency>
<groupId>com.smarterFramework</groupId>
<artifactId>sf-payment</artifactId>
<version>${sf.version}</version>
</dependency>
<dependency>
<groupId>com.smarterFramework</groupId>
<artifactId>sf-service</artifactId>
<version>${sf.version}</version>
</dependency>
<!-- 通用工具-->
<dependency>
<groupId>com.smarterFramework</groupId>

View File

@ -66,6 +66,21 @@
<artifactId>sf-oauth</artifactId>
</dependency>
<dependency>
<groupId>com.smarterFramework</groupId>
<artifactId>sf-order</artifactId>
</dependency>
<dependency>
<groupId>com.smarterFramework</groupId>
<artifactId>sf-payment</artifactId>
</dependency>
<dependency>
<groupId>com.smarterFramework</groupId>
<artifactId>sf-service</artifactId>
</dependency>
</dependencies>

View File

@ -11,114 +11,133 @@ import com.sf.common.core.domain.BaseEntity;
* @author ztzh
* @date 2024-04-11
*/
public class ApplyListInfo extends BaseEntity
{
public class ApplyListInfo extends BaseEntity {
private static final long serialVersionUID = 1L;
/** 主键 */
/**
* 主键
*/
private Long id;
/** 应用名称 */
/**
* 应用code
*/
@Excel(name = "应用编号")
private String appCode;
/**
* 应用名称
*/
@Excel(name = "应用名称")
private String appName;
/** 应用描述 */
/**
* 应用描述
*/
@Excel(name = "应用描述")
private String appDesc;
/** 图片 */
/**
* 图片
*/
@Excel(name = "图片")
private String picture;
/** 排序 */
/**
* 排序
*/
private Long orderNum;
/** 逻辑删除,0:未删除,1:删除 */
/**
* 逻辑删除,0:未删除,1:删除
*/
private Long isDelete;
/** 创建人 */
/**
* 创建人
*/
private String created;
/** 更新人 */
/**
* 更新人
*/
private String modified;
public void setId(Long id)
{
public void setId(Long id) {
this.id = id;
}
public Long getId()
{
public Long getId() {
return id;
}
public void setAppName(String appName)
{
public void setAppName(String appName) {
this.appName = appName;
}
public String getAppName()
{
public String getAppName() {
return appName;
}
public void setAppDesc(String appDesc)
{
public void setAppDesc(String appDesc) {
this.appDesc = appDesc;
}
public String getAppDesc()
{
public String getAppDesc() {
return appDesc;
}
public void setPicture(String picture)
{
public void setPicture(String picture) {
this.picture = picture;
}
public String getPicture()
{
public String getPicture() {
return picture;
}
public void setOrderNum(Long orderNum)
{
public void setOrderNum(Long orderNum) {
this.orderNum = orderNum;
}
public Long getOrderNum()
{
public Long getOrderNum() {
return orderNum;
}
public void setIsDelete(Long isDelete)
{
public void setIsDelete(Long isDelete) {
this.isDelete = isDelete;
}
public Long getIsDelete()
{
public Long getIsDelete() {
return isDelete;
}
public void setCreated(String created)
{
public void setCreated(String created) {
this.created = created;
}
public String getCreated()
{
public String getCreated() {
return created;
}
public void setModified(String modified)
{
public void setModified(String modified) {
this.modified = modified;
}
public String getModified()
{
public String getModified() {
return modified;
}
public void setAppCode(String appCode) {
this.appCode = appCode;
}
public String getAppCode() {
return appCode;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("appCode",getAppCode())
.append("appName", getAppName())
.append("appDesc", getAppDesc())
.append("picture", getPicture())
@ -130,4 +149,5 @@ public class ApplyListInfo extends BaseEntity
.append("updateTime", getUpdateTime())
.toString();
}
}

View File

@ -2,6 +2,7 @@ package com.sf.index.service.impl;
import java.util.List;
import com.sf.common.utils.DateUtils;
import com.sf.common.utils.uuid.IdUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.sf.index.mapper.ApplyListInfoMapper;
@ -54,6 +55,7 @@ public class ApplyListInfoServiceImpl implements IApplyListInfoService
public int insertApplyListInfo(ApplyListInfo applyListInfo)
{
applyListInfo.setCreateTime(DateUtils.getNowDate());
applyListInfo.setAppCode(IdUtils.randomTime("ZT"));
return applyListInfoMapper.insertApplyListInfo(applyListInfo);
}

View File

@ -1,367 +0,0 @@
package com.sf.order.domain;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.sf.common.annotation.Excel;
import com.sf.common.core.domain.BaseEntity;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import java.util.Date;
/**
* 订单基础信息对象 ORDER_INFO
*
* @author ztzh
* @date 2024-04-09
*/
public class OrderInfo extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
private Long id;
/**
* 订单编号
*/
@Excel(name = "订单编号")
private Long orderNo;
/**
* 订单状态:
* 0:待支付
* 1:已付款
* 2:支付超时系统结束
* 3:已完成
*/
@Excel(name = "订单状态: 0:待支付 1:已付款 2:支付超时系统结束 3:已完成 ")
private Long orderStatus;
/**
* 支付方式:0-点券 1-现金
*/
@Excel(name = "支付方式:0-点券 1-现金")
private Long payType;
/**
* 支付渠道(支付方式为现金时)
* 0:微信
* 1:支付宝
*/
@Excel(name = "支付渠道(支付方式为现金时) 0:微信 1:支付宝")
private Long payChannel;
/**
* 订单金额
*/
@Excel(name = "订单金额")
private Long orderAmt;
/**
* 运费
*/
@Excel(name = "运费")
private Long freightAmt;
/**
* 总金额
*/
@Excel(name = "总金额")
private Long payAmt;
/**
* 实际支付金额
*/
@Excel(name = "实际支付金额")
private Long reallyAmt;
/**
* 收件方式
* 0-自提
* 1-快递 2-配送
*/
@Excel(name = "收件方式0-自提 1-快递 2-配送")
private Long receiveType;
/**
* 商品Id
*/
@Excel(name = "商品Id")
private Long goodsId;
/**
* 商户Id
*/
@Excel(name = "商户Id")
private Long businessId;
/**
* 收货地址配置Id
*/
@Excel(name = "收货地址配置Id")
private Long receiveAddrId;
/**
* 支付时间
*/
@JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "支付时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date payTime;
/**
* 订单创建人
*/
@Excel(name = "订单创建人")
private Long createUserId;
/**
* 最后一次更新操作人
*/
@Excel(name = "最后一次更新操作人")
private Long updateUserId;
/**
* 逻辑删除标识
* 0:未删除
* 1:已删除
*/
@Excel(name = "逻辑删除标识 0:未删除 1:已删除")
private Long isDelete;
/**
* 快递单号
*/
@Excel(name = "快递单号")
private String trackNo;
/**
* 订单类型0:自动1:手动
*/
@Excel(name = "订单类型0:自动1:手动")
private Long orderType;
/**
* 平台外部订单号
*/
@Excel(name = "平台外部订单号")
private Long outOrderNo;
/**
* 平台支付返回值
*/
@Excel(name = "平台支付返回值")
private String payData;
/**
* 减免金额(优惠券抵扣)
*/
@Excel(name = "减免金额(优惠券抵扣)")
private Long reductionAmout;
public void setId(Long id) {
this.id = id;
}
public Long getId() {
return id;
}
public void setOrderNo(Long orderNo) {
this.orderNo = orderNo;
}
public Long getOrderNo() {
return orderNo;
}
public void setOrderStatus(Long orderStatus) {
this.orderStatus = orderStatus;
}
public Long getOrderStatus() {
return orderStatus;
}
public void setPayType(Long payType) {
this.payType = payType;
}
public Long getPayType() {
return payType;
}
public void setPayChannel(Long payChannel) {
this.payChannel = payChannel;
}
public Long getPayChannel() {
return payChannel;
}
public void setOrderAmt(Long orderAmt) {
this.orderAmt = orderAmt;
}
public Long getOrderAmt() {
return orderAmt;
}
public void setFreightAmt(Long freightAmt) {
this.freightAmt = freightAmt;
}
public Long getFreightAmt() {
return freightAmt;
}
public void setPayAmt(Long payAmt) {
this.payAmt = payAmt;
}
public Long getPayAmt() {
return payAmt;
}
public void setReallyAmt(Long reallyAmt) {
this.reallyAmt = reallyAmt;
}
public Long getReallyAmt() {
return reallyAmt;
}
public void setReceiveType(Long receiveType) {
this.receiveType = receiveType;
}
public Long getReceiveType() {
return receiveType;
}
public void setGoodsId(Long goodsId) {
this.goodsId = goodsId;
}
public Long getGoodsId() {
return goodsId;
}
public void setBusinessId(Long businessId) {
this.businessId = businessId;
}
public Long getBusinessId() {
return businessId;
}
public void setReceiveAddrId(Long receiveAddrId) {
this.receiveAddrId = receiveAddrId;
}
public Long getReceiveAddrId() {
return receiveAddrId;
}
public void setPayTime(Date payTime) {
this.payTime = payTime;
}
public Date getPayTime() {
return payTime;
}
public void setCreateUserId(Long createUserId) {
this.createUserId = createUserId;
}
public Long getCreateUserId() {
return createUserId;
}
public void setUpdateUserId(Long updateUserId) {
this.updateUserId = updateUserId;
}
public Long getUpdateUserId() {
return updateUserId;
}
public void setIsDelete(Long isDelete) {
this.isDelete = isDelete;
}
public Long getIsDelete() {
return isDelete;
}
public void setTrackNo(String trackNo) {
this.trackNo = trackNo;
}
public String getTrackNo() {
return trackNo;
}
public void setOrderType(Long orderType) {
this.orderType = orderType;
}
public Long getOrderType() {
return orderType;
}
public void setOutOrderNo(Long outOrderNo) {
this.outOrderNo = outOrderNo;
}
public Long getOutOrderNo() {
return outOrderNo;
}
public void setPayData(String payData) {
this.payData = payData;
}
public String getPayData() {
return payData;
}
public void setReductionAmout(Long reductionAmout) {
this.reductionAmout = reductionAmout;
}
public Long getReductionAmout() {
return reductionAmout;
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("orderNo", getOrderNo())
.append("orderStatus", getOrderStatus())
.append("payType", getPayType())
.append("payChannel", getPayChannel())
.append("orderAmt", getOrderAmt())
.append("freightAmt", getFreightAmt())
.append("payAmt", getPayAmt())
.append("reallyAmt", getReallyAmt())
.append("receiveType", getReceiveType())
.append("goodsId", getGoodsId())
.append("businessId", getBusinessId())
.append("receiveAddrId", getReceiveAddrId())
.append("createTime", getCreateTime())
.append("payTime", getPayTime())
.append("createUserId", getCreateUserId())
.append("updateUserId", getUpdateUserId())
.append("isDelete", getIsDelete())
.append("updateTime", getUpdateTime())
.append("trackNo", getTrackNo())
.append("orderType", getOrderType())
.append("outOrderNo", getOutOrderNo())
.append("payData", getPayData())
.append("reductionAmout", getReductionAmout())
.toString();
}
}

View File

@ -1,55 +0,0 @@
package com.sf.order.domain.res;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 活动信息详情
*
*/
@Data
@Schema(name = "OrderListResVo", description = "订单列表")
public class OrderListResVo {
/**
* 主键id
*/
private Long id;
/**
* 订单编号
*/
private String orderNo;
/**
* 订单状态:
* 0:待支付
* 1:已付款
* 2:支付超时系统结束
* 3:已完成
*/
private Long orderStatus;
/**
* 订单金额
*/
private Long orderAmt;
/**
* 商品标题
*/
private String productTitle;
/**
* 图片
*/
private String productPicture;
/**
* 商品规格
*/
private String goodsSpec;
/**
* 商品数量
*/
private Integer goodsCount = 1;
}

View File

@ -0,0 +1,117 @@
package com.sf.web.controller.system;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import com.sf.common.utils.SecurityUtils;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.sf.common.annotation.Log;
import com.sf.common.core.controller.BaseController;
import com.sf.common.core.domain.AjaxResult;
import com.sf.common.enums.BusinessType;
import com.sf.system.domain.UserMember;
import com.sf.system.service.IUserMemberService;
import com.sf.common.utils.poi.ExcelUtil;
import com.sf.common.core.page.TableDataInfo;
/**
* 会员Controller
*
* @author ztzh
* @date 2024-04-16
*/
@RestController
@RequestMapping("/system/member")
public class UserMemberController extends BaseController
{
@Autowired
private IUserMemberService userMemberService;
/**
* 查询会员列表
*/
@PreAuthorize("@ss.hasPermi('system:member:list')")
@GetMapping("/list")
public TableDataInfo list(UserMember userMember)
{
startPage();
List<UserMember> list = userMemberService.selectUserMemberList(userMember);
return getDataTable(list);
}
/**
* 导出会员列表
*/
@PreAuthorize("@ss.hasPermi('system:member:export')")
@Log(title = "会员", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, UserMember userMember)
{
List<UserMember> list = userMemberService.selectUserMemberList(userMember);
ExcelUtil<UserMember> util = new ExcelUtil<UserMember>(UserMember.class);
util.exportExcel(response, list, "会员数据");
}
/**
* 获取会员详细信息
*/
@PreAuthorize("@ss.hasPermi('system:member:query')")
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id)
{
return success(userMemberService.selectUserMemberById(id));
}
/**
* 获取会员详细信息,通过用户id
* 当前用户
*/
@GetMapping(value = "/currentUser")
public AjaxResult getInfoByUser()
{
Long userId = SecurityUtils.getUserId();
return success(userMemberService.selectUserMemberByUserId(userId));
}
/**
* 新增会员
*/
@PreAuthorize("@ss.hasPermi('system:member:add')")
@Log(title = "会员", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody UserMember userMember)
{
return toAjax(userMemberService.insertUserMember(userMember));
}
/**
* 修改会员
*/
@PreAuthorize("@ss.hasPermi('system:member:edit')")
@Log(title = "会员", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody UserMember userMember)
{
return toAjax(userMemberService.updateUserMember(userMember));
}
/**
* 删除会员
*/
@PreAuthorize("@ss.hasPermi('system:member:remove')")
@Log(title = "会员", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Long[] ids)
{
return toAjax(userMemberService.deleteUserMemberByIds(ids));
}
}

View File

@ -18,7 +18,7 @@ sf:
# 开发环境配置
server:
# 服务器的HTTP端口默认为8080
port: 7781
port: 80
servlet:
# 应用的访问路径
context-path: /

View File

@ -6,6 +6,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<resultMap type="ApplyListInfo" id="ApplyListInfoResult">
<result property="id" column="id" />
<result property="appCode" column="app_code" />
<result property="appName" column="app_name" />
<result property="appDesc" column="app_desc" />
<result property="picture" column="picture" />
@ -18,7 +19,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap>
<sql id="selectApplyListInfoVo">
select id, app_name, app_desc, picture, order_num, is_delete, created, modified, create_time, update_time from APPLY_LIST_INFO
select id, app_code, app_name, app_desc, picture, order_num, is_delete, created, modified, create_time, update_time from APPLY_LIST_INFO
</sql>
<select id="selectApplyListInfoList" parameterType="ApplyListInfo" resultMap="ApplyListInfoResult">
@ -36,6 +37,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<insert id="insertApplyListInfo" parameterType="ApplyListInfo" useGeneratedKeys="true" keyProperty="id">
insert into APPLY_LIST_INFO
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="appCode != null and appCode != ''">app_code,</if>
<if test="appName != null and appName != ''">app_name,</if>
<if test="appDesc != null and appDesc != ''">app_desc,</if>
<if test="picture != null">picture,</if>
@ -47,6 +49,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="updateTime != null">update_time,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="appCode != null and appCode != ''">#{appCode},</if>
<if test="appName != null and appName != ''">#{appName},</if>
<if test="appDesc != null and appDesc != ''">#{appDesc},</if>
<if test="picture != null">#{picture},</if>
@ -62,6 +65,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<update id="updateApplyListInfo" parameterType="ApplyListInfo">
update APPLY_LIST_INFO
<trim prefix="SET" suffixOverrides=",">
<if test="appCode != null and appCode != ''">app_code = #{appCode},</if>
<if test="appName != null and appName != ''">app_name = #{appName},</if>
<if test="appDesc != null and appDesc != ''">app_desc = #{appDesc},</if>
<if test="picture != null">picture = #{picture},</if>

View File

@ -5,15 +5,13 @@ package com.sf.common.utils.uuid;
*
* @author ztzh
*/
public class IdUtils
{
public class IdUtils {
/**
* 获取随机UUID
*
* @return 随机UUID
*/
public static String randomUUID()
{
public static String randomUUID() {
return UUID.randomUUID().toString();
}
@ -22,8 +20,7 @@ public class IdUtils
*
* @return 简化的UUID去掉了横线
*/
public static String simpleUUID()
{
public static String simpleUUID() {
return UUID.randomUUID().toString(true);
}
@ -32,8 +29,7 @@ public class IdUtils
*
* @return 随机UUID
*/
public static String fastUUID()
{
public static String fastUUID() {
return UUID.fastUUID().toString();
}
@ -42,8 +38,17 @@ public class IdUtils
*
* @return 简化的UUID去掉了横线
*/
public static String fastSimpleUUID()
{
public static String fastSimpleUUID() {
return UUID.fastUUID().toString(true);
}
/**
* 生成一个由时间错与字母组成的唯一id
*
* @return
*/
public static String randomTime(String data) {
long uniqueID = System.currentTimeMillis();
return data + "_" + uniqueID;
}
}

View File

@ -72,6 +72,18 @@
<groupId>com.smarterFramework</groupId>
<artifactId>sf-common</artifactId>
</dependency>
<!-- swagger3-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
</dependency>
<!-- 防止进入swagger页面报类型转换错误排除3.0.0中的引用手动增加1.6.2版本 -->
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
<version>1.6.2</version>
</dependency>
</dependencies>
</project>

33
sf-order/pom.xml Normal file
View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>smarterFramework</artifactId>
<groupId>com.smarterFramework</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>sf-order</artifactId>
<description>
订单模块
</description>
<dependencies>
<!-- 通用工具-->
<dependency>
<groupId>com.smarterFramework</groupId>
<artifactId>sf-common</artifactId>
</dependency>
<dependency>
<groupId>com.smarterFramework</groupId>
<artifactId>sf-framework</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -3,17 +3,14 @@ package com.sf.order.controller;
import com.sf.common.annotation.Log;
import com.sf.common.core.controller.BaseController;
import com.sf.common.core.domain.AjaxResult;
import com.sf.common.core.domain.entity.SysUser;
import com.sf.common.core.page.TableDataInfo;
import com.sf.common.enums.BusinessType;
import com.sf.common.utils.SecurityUtils;
import com.sf.common.utils.poi.ExcelUtil;
import com.sf.order.domain.OrderInfo;
import com.sf.order.domain.dto.OrderCreateDto;
import com.sf.order.domain.req.OrderListReqVo;
import com.sf.order.domain.res.OrderListResVo;
import com.sf.order.service.IOrderInfoService;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@ -39,10 +36,7 @@ public class OrderInfoController extends BaseController {
@GetMapping("/list")
public TableDataInfo list(OrderListReqVo vo) {
startPage();
SysUser user = SecurityUtils.getLoginUser().getUser();
vo.setUserId(user.getUserId());
List<OrderListResVo> list = orderInfoService.queryList(vo);
logger.info("prderList"+list);
return getDataTable(list);
}
@ -72,7 +66,7 @@ public class OrderInfoController extends BaseController {
@Log(title = "创建订单基础信息", businessType = BusinessType.INSERT)
@PostMapping(value = "/createOrder")
public AjaxResult createOrder(@RequestBody OrderCreateDto orderCreateDto) {
return toAjax(orderInfoService.createOrder(orderCreateDto));
return AjaxResult.success(orderInfoService.createOrder(orderCreateDto));
}
/**
@ -87,7 +81,6 @@ public class OrderInfoController extends BaseController {
/**
* 支付订单
*/
@Operation(summary = "支付订单")
@PostMapping(value = "/pay/{orderId}")
private String orderPay(@PathVariable(value = "orderId") Long orderId) {
orderInfoService.orderPay(orderId);

View File

@ -0,0 +1,183 @@
package com.sf.order.domain;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.sf.common.annotation.Excel;
import com.sf.common.core.domain.BaseEntity;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import java.util.Date;
/**
* 订单基础信息对象 ORDER_INFO
*
* @author ztzh
* @date 2024-04-09
*/
@Data
public class OrderInfo extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
private Long id;
/**
* 订单编号
*/
@Excel(name = "订单编号")
private Long orderNo;
/**
* 订单状态: 0:待支付 1:已付款待发货 2:配送中 3:待取货 4:支付超时系统结束 5:客户自主取消 6:已完成
*/
@Excel(name = "订单状态: 0:待支付 1:已付款待发货 2:配送中 3:待取货 4:支付超时系统结束 5:客户自主取消 6:已完成 ")
private Long orderStatus;
/**
* 支付方式:0-点券 1-现金
*/
@Excel(name = "支付方式:0-点券 1-现金")
private Long payType;
/**
* 支付渠道(支付方式为现金时)
* 0:微信
* 1:支付宝
*/
@Excel(name = "支付渠道(支付方式为现金时) 0:微信 1:支付宝")
private Long payChannel;
/**
* 订单金额
*/
@Excel(name = "订单金额")
private Long orderAmt;
/**
* 运费
*/
@Excel(name = "运费")
private Long freightAmt;
/**
* 总金额
*/
@Excel(name = "总金额")
private Long payAmt;
/**
* 实际支付金额
*/
@Excel(name = "实际支付金额")
private Long reallyAmt;
/**
* 收件方式
* 0-自提
* 1-快递 2-配送
*/
@Excel(name = "收件方式0-自提 1-快递 2-配送")
private Long receiveType;
/**
* 商品Id
*/
@Excel(name = "商品Id")
private Long goodsId;
/**
* 商户Id
*/
@Excel(name = "商户Id")
private Long businessId;
/**
* 收货地址配置Id
*/
@Excel(name = "收货地址配置Id")
private Long receiveAddrId;
/**
* 支付时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "支付时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date payTime;
/**
* 订单创建人
*/
@Excel(name = "订单创建人")
private Long createUserId;
/**
* 最后一次更新操作人
*/
@Excel(name = "最后一次更新操作人")
private Long updateUserId;
/**
* 逻辑删除标识
* 0:未删除
* 1:已删除
*/
@Excel(name = "逻辑删除标识 0:未删除 1:已删除")
private Long isDelete;
/**
* 快递单号
*/
@Excel(name = "快递单号")
private String trackNo;
/**
* 订单类型0:自动1:手动
*/
@Excel(name = "订单类型0:自动1:手动")
private Long orderType;
/**
* 平台外部订单号
*/
@Excel(name = "平台外部订单号")
private String outOrderNo;
/**
* 平台支付返回值
*/
@Excel(name = "平台支付返回值")
private String payData;
/**
* 减免金额(优惠券抵扣)
*/
@Excel(name = "减免金额(优惠券抵扣)")
private Long reductionAmout;
/**
* * 商品数量
*/
private Integer goodsCount;
/**
* * 商品类型
* * 0消耗型商品
* * 1非消耗型商品
* * 2自动续期订阅商品
*/
private Integer goodsType;
/**
* 商品单价
*/
private Long goodsPrice;
/**
* 商品编号
*/
private String goodsCode;
}

View File

@ -1,5 +1,6 @@
package com.sf.order.domain.dto;
import com.sf.common.annotation.Excel;
import io.swagger.v3.oas.annotations.media.Schema;
import javax.validation.constraints.NotNull;
@ -15,12 +16,13 @@ public class OrderCreateDto {
@NotNull(message = "商品id不能为空")
private Long goodsId;
@Schema(description = "平台外部订单号")
private String outOrderNo;
@Schema(description = "数量")
@NotNull(message = "数量不能唯恐")
private Long count;
@Schema(description = "金额")
@NotNull(message = "金额不能为空")
private Long amount;
@Schema(description = "用户id")
@ -56,4 +58,12 @@ public class OrderCreateDto {
public void setUserId(Long userId) {
this.userId = userId;
}
public String getOutOrderNo() {
return outOrderNo;
}
public void setOutOrderNo(String outOrderNo) {
this.outOrderNo = outOrderNo;
}
}

View File

@ -14,7 +14,7 @@ public class OrderListReqVo extends BaseEntity {
private Long userId;
/**
* 订单类型
* 订单状态
*/
private Long orderStatus;

View File

@ -0,0 +1,93 @@
package com.sf.order.domain.res;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.sf.common.annotation.Excel;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.Date;
/**
* 活动信息详情
*
*/
@Data
@Schema(name = "OrderListResVo", description = "订单列表")
public class OrderListResVo {
/**
* 主键id
*/
private Long id;
/**
* 订单编号
*/
private String orderNo;
/**
* 订单状态: 0:待支付 1:已付款待发货 2:配送中 3:待取货 4:支付超时系统结束 5:客户自主取消 6:已完成
*/
private Long orderStatus;
/**
* 订单金额
*/
private Long orderAmt;
/**
* 支付时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date payTime;
/**
* 订阅订单取消时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date subscriptionCancellationTime;
/**
* 商品标题
*/
private String productTitle;
/**
* 图片
*/
private String productPicture;
/**
* 商品描述
*/
private String productDesc;
/**
* 商品规格
*/
private String goodsSpec;
/**
* 商品数量
*/
private Integer goodsCount;
/**
* 商品价格
*/
private Long goodsPrice;
/**
* * 商品类型
* * 0消耗型商品
* * 1非消耗型商品
* * 2自动续期订阅商品
*/
private Integer goodsType;
/**
* 商品编码
*/
private String goodsCode;
}

View File

@ -64,4 +64,6 @@ public interface OrderInfoMapper {
* @return 结果
*/
public int deleteOrderInfoByIds(Long[] ids);
OrderInfo selectOrderInfoByOrderNo(String orderNo);
}

View File

@ -43,7 +43,7 @@ public interface IOrderInfoService
* @param orderInfo 订单基础信息
* @return 结果
*/
public int createOrder(OrderCreateDto orderInfo);
public Long createOrder(OrderCreateDto orderInfo);
/**
* 修改订单基础信息
@ -70,4 +70,9 @@ public interface IOrderInfoService
public int deleteOrderInfoById(Long id);
void orderPay(Long orderId);
OrderInfo selectOrderInfoByOrderNo(String orderNo);
void insertOrder(OrderInfo orderInfo);
}

View File

@ -21,8 +21,7 @@ import java.util.List;
* @date 2024-04-09
*/
@Service
public class OrderInfoServiceImpl implements IOrderInfoService
{
public class OrderInfoServiceImpl implements IOrderInfoService {
@Resource
private OrderInfoMapper orderInfoMapper;
@Resource
@ -35,8 +34,7 @@ public class OrderInfoServiceImpl implements IOrderInfoService
* @return 订单基础信息
*/
@Override
public OrderInfo selectOrderInfoById(Long id)
{
public OrderInfo selectOrderInfoById(Long id) {
return orderInfoMapper.selectOrderInfoById(id);
}
@ -47,12 +45,11 @@ public class OrderInfoServiceImpl implements IOrderInfoService
* @return 订单基础信息
*/
@Override
public List<OrderInfo> selectOrderInfoList(OrderInfo orderInfo)
{
public List<OrderInfo> selectOrderInfoList(OrderInfo orderInfo) {
return orderInfoMapper.selectOrderInfoList(orderInfo);
}
public List<OrderListResVo> queryList(OrderListReqVo vo)
{
public List<OrderListResVo> queryList(OrderListReqVo vo) {
return orderInfoMapper.queryList(vo);
}
@ -63,11 +60,10 @@ public class OrderInfoServiceImpl implements IOrderInfoService
* @return 结果
*/
@Override
public int createOrder(OrderCreateDto orderCreateDto)
{
public Long createOrder(OrderCreateDto orderCreateDto) {
OrderInfo orderInfo = new OrderInfo();
orderInfo.setOrderNo(snowflakeIdWorker.nextId());
orderInfo.setPayType(0L);
orderInfo.setPayType(1L);
orderInfo.setReceiveType(0L);
orderInfo.setOrderStatus(0L);
orderInfo.setCreateUserId(orderCreateDto.getUserId());
@ -77,7 +73,9 @@ public class OrderInfoServiceImpl implements IOrderInfoService
orderInfo.setPayAmt(orderCreateDto.getAmount());
orderInfo.setCreateTime(DateUtils.getNowDate());
orderInfo.setUpdateTime(DateUtils.getNowDate());
return orderInfoMapper.insertOrderInfo(orderInfo);
orderInfo.setOutOrderNo(orderCreateDto.getOutOrderNo());
orderInfoMapper.insertOrderInfo(orderInfo);
return snowflakeIdWorker.nextId();
}
/**
@ -87,11 +85,11 @@ public class OrderInfoServiceImpl implements IOrderInfoService
* @return 结果
*/
@Override
public int updateOrderInfo(OrderInfo orderInfo)
{
public int updateOrderInfo(OrderInfo orderInfo) {
orderInfo.setUpdateTime(DateUtils.getNowDate());
return orderInfoMapper.updateOrderInfo(orderInfo);
}
@Override
public void orderPay(Long orderId) {
OrderInfo updateOrder = this.selectOrderInfoById(orderId);
@ -104,11 +102,22 @@ public class OrderInfoServiceImpl implements IOrderInfoService
updateOrder.setOrderStatus(1L);
updateOrder.setPayTime(DateUtils.getNowDate());
// 修改订单状态
if (1>this.updateOrderInfo(updateOrder)) {
if (1 > this.updateOrderInfo(updateOrder)) {
throw new ServiceException("支付异常,请联系管理员!");
}
}
@Override
public OrderInfo selectOrderInfoByOrderNo(String orderNo) {
return orderInfoMapper.selectOrderInfoByOrderNo(orderNo);
}
@Override
public void insertOrder(OrderInfo orderInfo) {
orderInfoMapper.insertOrderInfo(orderInfo);
}
/**
* 批量删除订单基础信息
*
@ -116,8 +125,7 @@ public class OrderInfoServiceImpl implements IOrderInfoService
* @return 结果
*/
@Override
public int deleteOrderInfoByIds(Long[] ids)
{
public int deleteOrderInfoByIds(Long[] ids) {
return orderInfoMapper.deleteOrderInfoByIds(ids);
}
@ -128,8 +136,7 @@ public class OrderInfoServiceImpl implements IOrderInfoService
* @return 结果
*/
@Override
public int deleteOrderInfoById(Long id)
{
public int deleteOrderInfoById(Long id) {
return orderInfoMapper.deleteOrderInfoById(id);
}

View File

@ -35,18 +35,24 @@
<result property="orderNo" column="order_no" />
<result property="orderStatus" column="order_status" />
<result property="orderAmt" column="order_amt" />
<result property="payTime" column="pay_time" />
<result property="productTitle" column="product_title" />
<result property="productPicture" column="product_picture" />
<result property="productDesc" column="product_desc" />
<result property="goodsSpec" column="goods_spec" />
<result property="goodsCount" column="goods_count" />
<result property="subscriptionCancellationTime" column="subscription_cancellation_time" />
<result property="goodsType" column="goods_type" />
<result property="goodsPrice" column="goods_price" />
<result property="goodsCode" column="goods_code" />
</resultMap>
<sql id="selectOrderInfoVo">
select id, order_no, order_status, pay_type, pay_channel, order_amt, freight_amt, pay_amt, really_amt, receive_type, goods_id, business_id, receive_addr_id, create_time, pay_time, create_user_id, update_user_id, is_delete, update_time, track_no, order_type, out_order_no, pay_data, reduction_amout from ORDER_INFO
select id, order_no, order_status, pay_type, pay_channel, order_amt, freight_amt, pay_amt, really_amt, receive_type, goods_id, business_id, receive_addr_id, create_time, pay_time, create_user_id, update_user_id, is_delete, update_time, track_no, order_type, out_order_no, pay_data, reduction_amout from Order_info
</sql>
<sql id="OrderListInfoVo">
SELECT a.order_no,a.order_status,a.order_amt,b.product_title,b.product_picture,b.product_desc,b.goods_spec
FROM ORDER_INFO a LEFT JOIN GOODS_MESSAGES b ON a.goods_id = b.id
SELECT a.id,a.order_no,a.order_status,a.order_amt,a.pay_time,a.goods_count,a.subscription_cancellation_time,a.goods_type,a.goods_price,a.goods_code,b.product_title,b.product_picture,b.product_desc,b.goods_spec
FROM Order_info a LEFT JOIN GOODS_MESSAGES b ON a.goods_id = b.id
</sql>
<select id="selectOrderInfoList" parameterType="OrderInfo" resultMap="OrderInfoResult">
@ -89,8 +95,13 @@
where id = #{id}
</select>
<select id="selectOrderInfoByOrderNo" resultMap="OrderInfoResult">
<include refid="selectOrderInfoVo"/>
where order_no = #{orderNo}
</select>
<insert id="insertOrderInfo" parameterType="OrderInfo">
insert into ORDER_INFO
insert into Order_info
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">id,</if>
<if test="orderNo != null">order_no,</if>
@ -116,6 +127,10 @@
<if test="outOrderNo != null">out_order_no,</if>
<if test="payData != null">pay_data,</if>
<if test="reductionAmout != null">reduction_amout,</if>
<if test="goodsCount != null">goods_count,</if>
<if test="goodsType != null">goods_type,</if>
<if test="goodsPrice != null">goods_price,</if>
<if test="goodsCode != null">goods_code,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">#{id},</if>
@ -142,11 +157,15 @@
<if test="outOrderNo != null">#{outOrderNo},</if>
<if test="payData != null">#{payData},</if>
<if test="reductionAmout != null">#{reductionAmout},</if>
<if test="goodsCount != null">#{goodsCount},</if>
<if test="goodsType != null">#{goodsType},</if>
<if test="goodsPrice != null">#{goodsPrice},</if>
<if test="goodsCode != null">#{goodsCode},</if>
</trim>
</insert>
<update id="updateOrderInfo" parameterType="OrderInfo">
update ORDER_INFO
update Order_info
<trim prefix="SET" suffixOverrides=",">
<if test="orderNo != null">order_no = #{orderNo},</if>
<if test="orderStatus != null">order_status = #{orderStatus},</if>
@ -176,11 +195,11 @@
</update>
<delete id="deleteOrderInfoById" parameterType="Long">
delete from ORDER_INFO where id = #{id}
delete from Order_info where id = #{id}
</delete>
<delete id="deleteOrderInfoByIds" parameterType="String">
delete from ORDER_INFO where id in
delete from Order_info where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>

50
sf-payment/pom.xml Normal file
View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>smarterFramework</artifactId>
<groupId>com.smarterFramework</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>sf-payment</artifactId>
<description>
支付模块
</description>
<dependencies>
<!-- 通用工具-->
<dependency>
<groupId>com.smarterFramework</groupId>
<artifactId>sf-common</artifactId>
</dependency>
<dependency>
<groupId>com.smarterFramework</groupId>
<artifactId>sf-framework</artifactId>
</dependency>
<dependency>
<groupId>com.smarterFramework</groupId>
<artifactId>sf-order</artifactId>
</dependency>
<dependency>
<groupId>com.smarterFramework</groupId>
<artifactId>sf-service</artifactId>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId>
<version>1.73</version>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>4.4.0</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,37 @@
package com.sf.payment.config;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
/**
* 功能描述:
*
* @author a_kun
* @date 2024/4/17 9:23
*/
@Data
@Configuration
public class HuaweiPaymentConfig {
/**
* 客户端idoauth用
*/
@Value("${huawei.payment.clientId:110693217}")
private String clientId;
/**
* 客户端Secret对应各平台的appSecret
*/
@Value("${huawei.payment.clientSecret:1410c01bc71c7ba587175ae79e500137c70945acc1416a38127cf98a09a6f8ba}")
private String clientSecret;
/**
* 应用id
*/
@Value("${huawei.payment.appId:5765880207854169373}")
private String appId;
}

View File

@ -0,0 +1,29 @@
package com.sf.payment.constant;
import io.jsonwebtoken.Claims;
/**
* 商品信息
*
* @author zoukun
*/
public class GoodsConstants {
/**
* 商品类型
* 0消耗型商品
*/
public static final Integer GOODS_TYPE_CONSUMABLE = 0;
/**
* 商品类型
* 1非消耗型商品
*/
public static final Integer GOODS_TYPE_NON_CONSUMABLE = 1;
/**
* 商品类型
* 2自动续期订阅商品
*/
public static final Integer GOODS_TYPE_AUTOMATIC_RENEWAL_SUBSCRIPTION = 2;
}

View File

@ -0,0 +1,48 @@
package com.sf.payment.controller;
import com.alibaba.fastjson2.JSONObject;
import com.sf.common.core.domain.AjaxResult;
import com.sf.payment.constant.GoodsConstants;
import com.sf.payment.domain.HuaweiPaymentCallback;
import com.sf.payment.domain.HuaweiPurchasesVerifyDTO;
import com.sf.payment.service.IHuaweiPaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
/**
* @author zoukun
*/
@Slf4j
@RestController
@RequestMapping("/payment")
public class HuaweiPaymentController {
@Autowired
private IHuaweiPaymentService huaweiPaymentService;
/**
* 华为支付回调地址
*/
@RequestMapping("/callback/huawei")
public AjaxResult callback(@RequestBody HuaweiPaymentCallback callback) {
log.info("进入callback params" + JSONObject.toJSONString(callback));
AjaxResult ajax = AjaxResult.success();
return ajax;
}
/**
* 华为购买验证
*/
@PostMapping("/huawei/purchases/verify")
public AjaxResult purchasesVerify(@Validated @RequestBody HuaweiPurchasesVerifyDTO verifyDTO) {
log.info("进入/huawei/purchases/tokens/verify params" + JSONObject.toJSONString(verifyDTO));
huaweiPaymentService.purchasesVerify(verifyDTO);
return AjaxResult.success();
}
}

View File

@ -0,0 +1,35 @@
package com.sf.payment.domain;
import lombok.*;
import java.io.Serializable;
/**
* 授权回调时的参数类
*
* @author zk
*/
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class HuaweiPaymentCallback implements Serializable {
/**
* 访问AuthorizeUrl后回调时带的参数code
*/
private String code;
/**
* 客户端id对应各平台的appKey
*/
private String clientId;
/**
* 客户端Secret对应各平台的appSecret
*/
private String clientSecret;
}

View File

@ -0,0 +1,53 @@
package com.sf.payment.domain;
import apijson.NotNull;
import lombok.*;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
/**
* 华为验证购买tokenDTO
*
* @author zk
*/
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class HuaweiPurchasesVerifyDTO implements Serializable {
/**
* 商品类型
* 0消耗型商品
* 1非消耗型商品
* 2自动续期订阅商品
*/
@NotNull
private Integer type;
/**
* 包含订单信息的JWS格式数据
* 可参见对返回结果验签
* 解码验签获取相关购买数据的JSON字符串
* 其包含的参数请参见PurchaseOrderPayload
*/
private String jwsPurchaseOrder;
/**
* 包含订阅状态信息的
* JWS格式数据
* 可参见对返回结果验签
* 解码验签获取相关订阅状态
* 信息的JSON字符串
* 其包含的参数请参见
* SubGroupStatusPayload
*/
private String jwsSubscriptionStatus;
}

View File

@ -0,0 +1,56 @@
package com.sf.payment.domain;
import apijson.NotNull;
import lombok.*;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
/**
* 华为验证购买tokenD返回
*
* @author zk
*/
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class HuaweiPurchasesVerifyResponseDTO implements Serializable {
/**
* 返回码
*
* 0成功
* 其他失败具体请参见错误码
*/
private String responseCode;
/**
* 响应描述
*/
private String responseMessage;
/**
*
* 包含购买数据的JSON字符串具体请参见表InappPurchaseDetails
*
* 该字段原样参与签名
*/
private String purchaseTokenData;
/**
* purchaseTokenData基于应用RSA IAP私钥的签名信息签名算法为signatureAlgorithm
* 应用请参见对返回结果验签使用IAP公钥对PurchaseTokenData的JSON字符串进行验签
*/
private String dataSignature;
/**
*
* 签名算法
*/
@NotBlank(message = "待下发商品ID不能为空")
private String signatureAlgorithm;
}

View File

@ -0,0 +1,35 @@
package com.sf.payment.domain;
import lombok.Data;
/**
* 功能描述:
*
* @author a_kun
* @date 2024/4/17 14:41
*/
@Data
public class HuaweiQueryResponse {
/**
* 返回码
* 0成功
* 其他失败具体请参见错误码
*/
private String responseCode;
/**
* 响应描述
*/
private String responseMessage;
/**
* 包含已购订单相关状态信息的JWS格式数据可参见对返回结果验签解码验签获取相关订单状态信息的JSON字符串其包含的参数具体请参见表PurchaseOrderPayload说明
*/
private String jwsPurchaseOrder;
/**
* 包含已购订阅相关状态信息的JWS格式数据可参见对返回结果验签解码验签获取相关订阅状态信息的JSON字符串其包含的参数请参见SubGroupStatusPayload
*/
private String jwsSubGroupStatus;
}

View File

@ -0,0 +1,233 @@
package com.sf.payment.domain;
import lombok.Data;
/**
* 功能描述:
*
* @author a_kun
* @date 2024/4/16 15:29
*/
@Data
public class InAppPurchaseData {
/**
* 应用ID
*/
private Long applicationId;
/**
* 消耗型商品或者非消耗型商品固定为false
*
* 订阅型商品
*
* true订阅处于活动状态并且将在下一个结算日期自动续订
* false用户已经取消订阅 用户可以在下一个结算日期之前访问订阅内容并且在该日期后将无法访问除非重新启用自动续订 如果提供了宽限期只要宽限期未过此值就会对所有订阅保持设置为true 下一次结算日期每天都会自动延长直至宽限期结束或者用户更改付款方式
*/
private Boolean autoRenewing;
/**
* 订单ID唯一标识一笔需要收费的收据由华为应用内支付服务器在创建订单以及订阅型商品续费时生成
*
* 每一笔新的收据都会使用不同的orderId
*/
private String orderId;
/**
* 商品类别取值包括
*
* 0消耗型商品
* 1非消耗型商品
* 2订阅型商品
*/
private Integer kind;
/**
* 商品ID每种商品必须有唯一的ID由应用在PMS中维护或者应用发起购买时传入
* 说明
* 为避免资金损失您在对支付结果验签成功后必须对其进行校验
*/
private String productId;
/**
* 商品名称
*/
private String productName;
/**
* 商品购买时间UTC时间戳以毫秒为单位
*/
private Long purchaseTime;
/**
* 订单交易状态
*
* -1初始化
* 0已购买
* 1已取消
* 2已撤销或已退款
* 3待处理
*/
private Integer purchaseState;
/**
*
* 商户侧保留信息由您在调用支付接口时传入
*/
private String developerPayload;
/**
*消耗状态仅一次性商品存在取值包括
*
* 0未消耗
* 1已消耗
*/
private Integer consumptionState;
/**
*确认状态取值包括
*
* 0 未确认
* 1已确认
* 没有值表示不需要确认
*/
private Integer confirmed;
/**
* 用于唯一标识商品和用户对应关系的购买令牌在支付完成时由华为应用内支付服务器生成
* 说明
* 该字段是唯一标识商品和用户对应关系的在订阅型商品正常续订时不会改变
* 当前92位后续存在扩展可能如要进行存储建议您预留128位的长度
* 如要进行存储为保证安全建议加密存储
*/
private String purchaseToken;
/**
* 用定价货币的币种请参见ISO 4217标准
* 说明
* 为避免资金损失您在对支付结果验签成功后必须对其进行校验
*/
private String currency;
/**
* 商品实际价格*100以后的值商品实际价格精确到小数点后2位例如此参数值为501则表示商品实际价格为5.01
*/
private Long price;
/**
* 支付方式取值请参见payType说明
*/
private String payType;
/**
* 交易单号用户支付成功后生成
*/
private String payOrderId;
// 以下参数只在订阅场景返回
/**
* 上次续期收款的订单ID由支付服务器在续期扣费时生成首次购买订阅型商品时的lastOrderId与orderId数值相同
*/
private String lastOrderId;
/**
* 订阅型商品所属的订阅组ID
*/
private String productGroup;
/**
* 原购买的时间即本订阅型商品首次成功收费的时间UTC时间戳以毫秒为单位
*/
private Long oriPurchaseTime;
/**
* 订阅ID
* 说明
* subscriptionId是用户与商品之间的一一对应关系在订阅型商品正常续订时不会改变
*/
private String subscriptionId;
/**
* 原订阅ID有值表示当前订阅是从其他商品切换来的该值可以关联切换前的商品订阅信息
*/
private String oriSubscriptionId;
/**
* 购买数量
*/
private Integer quantity;
/**
* 已经付费订阅的天数免费试用和促销期周期除外
*/
private Long daysLasted;
/**
* 成功标准续期没有设置促销的续期的期数为0或者不存在表示还没有成功续期
*/
private Long numOfPeriods;
/**
* 成功促销续期期数
*/
private Long numOfDiscount;
/**
* 订阅型商品过期时间UTC时间戳以毫秒为单位
*
* 对于一个成功收费的自动续订收据该时间表示续期日期或者超期日期如果商品最近的收据的该时间是一个过去的时间则订阅已经过期
*/
private Long expirationDate;
/**
* 对于已经过期的订阅表示过期原因取值包括
*
* 1用户取消
* 2商品不可用
* 3用户签约信息异常
* 4Billing错误
* 5用户未同意涨价
* 6未知错误
* 同时有多个异常时优先级为1 > 2 > 3
*/
private Integer expirationIntent;
/**
* 订阅撤销时间UTC时间戳以毫秒为单位发生退款且服务立即不可用在顾客投诉通过客服撤销订阅或者顾客升级跨级到同组其他商品并且立即生效场景下需要撤销原有订阅的上次收据时有值
* 说明
* 已经撤销的收据等同于没有完成购买
*/
private Long cancelTime;
/**
* 取消原因
*
* 3: 应用调用IAP接口取消
* 2顾客升级跨级等
* 1顾客因为在App内遇到了问题而取消了订阅
* 0其他原因取消比如顾客错误地订阅了商品
* 说明
* 如果为空且cancelTime有值表示是升级等操作导致的取消
*/
private Integer cancelReason;
/**
* 续期状态
*
* 1当前周期到期时自动续期
* 0用户停止了续期
* 仅针对自动续期订阅对有效和过期的订阅均有效并不代表顾客的订阅状态通常取值为0时应用可以给顾客提供其他的订阅选项
* 例如推荐一个同组更低级别的商品该值为0通常代表着顾客主动取消了该订阅
*/
private Integer renewStatus;
/**
* 用户取消订阅的时间UTC时间戳以毫秒为单位在该时间进行了订阅续期停止的设定商品在有效期内仍然有效但后续的续期会终止无退款
*/
private Integer cancellationTime;
}

View File

@ -0,0 +1,165 @@
package com.sf.payment.domain;
import lombok.Data;
/**
* 功能描述:
* 订单信息模型支持消耗型商品非消耗型商品和自动续期订阅商品
* @author a_kun
* @date 2024/4/16 15:29
*/
@Data
public class PurchaseOrderPayload {
/**
* 具体一笔订单中对应的购买订单号ID
*/
private String purchaseOrderId;
/**
* 购买token
* 在购买消耗型/非消耗型商品场景中与具体购买订单一一对应
* 在自动续期订阅商品场景中与订阅ID一一对应
*/
private String purchaseToken;
/**
* 应用ID
*/
private String applicationId;
/**
* 商品ID每种商品必须有唯一的ID由应用在PMS中维护或者应用发起购买时传入
* 说明
* 为避免资金损失您在对支付结果验签成功后必须对其进行校验
*/
private String productId;
/**
* 商品类型具体取值如下
* 0消耗型商品
* 1非消耗型商品
* 2自动续期订阅商品
*/
private Integer productType;
/**
* 购买时间UTC时间戳以毫秒为单位
* 如果没有完成购买则没有值
*/
private Long purchaseTime;
/**
* 发货状态具体取值如下
* 1已发货
* 2未发货
*/
private Integer finishStatus;
/**
* 价格单位
* 实际价格*100以后的值商品实际价格精确到小数点后2位例如此参数值为501则表示商品实际价格为5.01
*/
private Long price;
/**
* 用定价货币的币种请参见ISO 4217标准
* 说明
* 为避免资金损失您在对支付结果验签成功后必须对其进行校验
*/
private String currency;
/**
* 商户侧保留信息由您在调用支付接口时传入
*/
private String developerPayload;
/**
* 购买订单撤销原因
* 0其他
* 1用户遇到问题退款
*/
private Integer purchaseOrderRevocationReasonCode;
/**
* 购买订单撤销时间
* UTC时间戳以毫秒为单位
*/
private Long revocationTime;
/**
* 优惠类型
* 1推介促销
*/
private Integer offerTypeCode;
/**
* 优惠ID
*/
private String offerId;
/**
* 国家/地区码用于区分国家/地区信息请参见ISO 3166
*/
private String countryCode;
/**
* 签名时间UTC时间戳以毫秒为单位
*/
private Long signedTime;
// 以下参数只在自动续期订阅商品场景返回
/**
* 订阅连续购买段的唯一ID
* 当用户切换商品不会重置此ID
*/
private String subGroupGenerationId;
/**
* 订阅连续购买段的唯一ID
* 当用户切换订阅商品时
* 此订阅ID会发生改变
*/
private String subscriptionId;
/**
* 订阅组ID
*/
private String subGroupId;
/**
* 此次购买的有效周期
* 采用ISO 8601格式
* 例如P1W表示一周
* P1M表示一个月
*/
private String duration;
/**
* 订阅周期段类型
* 0正常周期段
* 1延期周期段
*/
private Integer durationTypeCode;
/*
ISO 8601的时间持续期限表示
在ISO 8601中时间持续期限的表示采用了一种简洁而明确的格式例如 P10D其中 P 表示周期Period后面的数字表示周期的长度而末尾的字母表示周期的单位这种表示法主要用于描述时间段的长度而不关注具体的时刻
P 表示周期Period 此字母指示接下来的时间表示将是一个时间段的描述而非具体的日期或时刻
后面的数字 这个数字表示时间段的长度可以是整数或小数它指示了在时间单位内的周期数量
末尾的字母表示周期的单位 P10D 末尾的 D 表示周期的单位是天DaysISO 8601定义了多种可能的时间单位包括
Y 表示年份例如 P2Y 表示2年的时间段
M 表示月份例如 P3M 表示3个月的时间段
W 表示周数例如 P1W 表示1周的时间段
D 表示天数例如 P10D 表示10天的时间段
T时间分隔符 如果时间段中包含了时间信息日期和时间之间用 T 分隔例如 P1DT12H 表示1天12小时的时间段
H小时M分钟S 用于表示时秒的时间段长度例如 PT2H30M 表示2小时30分钟的时间段
示例
P1Y 表示1年的时间段
P3M 表示3个月的时间段
P2W 表示2周的时间段
P4DT6H30M 表示4天6小时30分钟的时间段
*/
}

View File

@ -0,0 +1,48 @@
package com.sf.payment.domain;
import lombok.Data;
import java.util.List;
/**
* 功能描述:
* 已购订阅相关状态信息
* @author a_kun
* @date 2024/4/16 15:29
*/
@Data
public class SubGroupStatusPayload {
/**
* 应用ID
*/
private String applicationId;
/**
* 应用包名
*/
private String packageName;
/**
* 订阅组ID
*/
private String subGroupId;
/**
* 订阅组中最后生效的
* 订阅状态
* SubscriptionStatus
* 比如A切换BB切换C
* 此处是C的订阅状态
*/
private SubscriptionStatus lastSubscriptionStatus;
/**
* 订阅组最近生效的
* 历史订阅状态
* SubscriptionStatus的列表比如A切换BB切换C这里包含CBA三个订阅状态信息
*/
private List<SubscriptionStatus> historySubscriptionStatusList;
}

View File

@ -0,0 +1,91 @@
package com.sf.payment.domain;
import lombok.Data;
import java.util.List;
/**
* 功能描述:
* 当前订阅最新的未来扣费计划
* @author a_kun
* @date 2024/4/16 15:29
*/
@Data
public class SubRenewalInfo {
/**
* 订阅连续购买段的唯一ID
* 当用户切换商品不会重置此ID
*/
private String subGroupGenerationId;
/**
* 下周期生效场景下下期将续期的商品ID
*/
private String nextRenewPeriodProductId;
/**
* 当前生效的商品ID
*/
private String productId;
/**
* 自动续期状态
* 0关闭
* 1打开
*/
private Integer autoRenewStatusCode;
/**
* 系统是否还在尝试扣费
* true
* false
*/
private Boolean hasInBillingRetryPeriod;
/**
* 目前涨价状态码
* 1用户暂未同意涨价
* 2用户已同意涨价
*/
private Integer priceIncreaseStatusCode;
/**
* 优惠类型
* 1推介促销
*/
private Integer offerTypeCode;
/**
* 优惠ID
*/
private String offerId;
/**
* 下期续费价格单位取消订阅场景下不返回
*/
private String renewalPrice;
/**
* 币种
*/
private String currency;
/**
* 续期时间UTC时间戳以毫秒为单位
*/
private Long renewalTime;
/**
* 订阅续期失败的原因
* 1用户取消
* 2商品无效
* 3签约无效
* 4扣费异常
* 5用户不同意涨价
* 6未知
*/
private String expirationIntent;
}

View File

@ -0,0 +1,68 @@
package com.sf.payment.domain;
import lombok.Data;
import java.util.List;
/**
* 功能描述:
* 订阅组中最后生效的订阅状态
* @author a_kun
* @date 2024/4/16 15:29
*/
@Data
public class SubscriptionStatus {
/**
* 订阅连续购买段的唯一ID
* 当用户切换商品不会重置此ID
*/
private String subGroupGenerationId;
/**
* 订阅连续购买段的唯一ID
* 当用户切换订阅商品时
* 此订阅ID会发生改变
*/
private String subscriptionId;
/**
* 购买token
* 在购买消耗型/非消耗型商品场景中与具体购买订单一一对应
* 在自动续期订阅商品场景中与订阅ID一一对应
*/
private String purchaseToken;
/**
* 订阅状态
* 1生效状态
* 2已到期
* 3尝试扣费
* 5撤销
* 6暂停
*/
private Integer status;
/**
* 自动续期订阅商品的过期时间UTC时间戳以毫秒为单位
*/
private Long expiresTime;
/**
* 当前订阅最新的一笔购买订单包含的参数请参见PurchaseOrderPayload
*/
private PurchaseOrderPayload lastPurchaseOrder;
/**
* 当前订阅最新的购买订单列表包含续期延期折算等产生的购买订单
* 购买订单包含的参数请参见PurchaseOrderPayload
*/
private List<PurchaseOrderPayload> recentPurchaseOrderList;
/**
* 当前订阅最新的未来扣费计划包含的参数请参见SubRenewalInfo
*/
private SubRenewalInfo renewalInfo;
}

View File

@ -0,0 +1,14 @@
package com.sf.payment.service;
import com.sf.payment.domain.HuaweiPurchasesVerifyDTO;
/**
* 功能描述:
*
* @author a_kun
* @date 2024/4/12 10:21
*/
public interface IHuaweiPaymentService {
void purchasesVerify(HuaweiPurchasesVerifyDTO verifyDTO);
}

View File

@ -0,0 +1,395 @@
package com.sf.payment.service.impl;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSON;
import com.auth0.jwt.JWT;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.sf.common.utils.SecurityUtils;
import com.sf.common.utils.SnowflakeIdWorker;
import com.sf.order.domain.OrderInfo;
import com.sf.order.service.IOrderInfoService;
import com.sf.payment.config.HuaweiPaymentConfig;
import com.sf.payment.constant.GoodsConstants;
import com.sf.payment.domain.*;
import com.sf.payment.service.IHuaweiPaymentService;
import com.sf.payment.utils.HuaweiTokenGenerator;
import com.sf.service.domain.GoodsMessages;
import com.sf.service.service.IGoodsMessagesService;
import com.sf.system.domain.UserMember;
import com.sf.system.service.IUserMemberService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.Base64Utils;
import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.MessageDigest;
import java.security.PublicKey;
import java.security.Security;
import java.security.spec.X509EncodedKeySpec;
import java.text.MessageFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* 功能描述:
*
* @author a_kun
* @date 2024/4/12 10:21
*/
@Slf4j
@Service
public class HuaweiPaymentServiceImpl implements IHuaweiPaymentService {
/**
* token url to get the authorization
*/
private static final String TOKEN_URL = "https://oauth-login.cloud.huawei.com/oauth2/v3/token";
/**
* 查询消耗型/非消耗型商品的订单最新状态
*/
private static final String ORDER_STATUS_QUERY_URL = "/order/harmony/v1/application/order/status/query";
/**
* 查询自动续期订阅商品的最新状态
*/
private static final String SUBSCRIPTION_STATUS_QUERY_URL = "/subscription/harmony/v1/application/subscription/status/query";
/**
* 站点信息(中国)
*/
private static final String ROOT_URL = "https://iap.cloud.huawei.com";
private static final String PUBLIC_KEY = "PUBLIC_KEY";
@Resource
private IOrderInfoService orderInfoService;
@Resource
private IUserMemberService userMemberService;
@Resource
private IGoodsMessagesService goodsMessagesService;
@Resource
private HuaweiPaymentConfig huaweiPaymentConfig;
@Resource
private SnowflakeIdWorker snowflakeIdWorker;
@Override
@Transactional(rollbackFor = Exception.class)
public void purchasesVerify(HuaweiPurchasesVerifyDTO verifyDTO) {
// 待发放会员商品
PurchaseOrderPayload huaweiQueryResponsePurchaseOrderPayload;
// 验证 TODO 证书验签官网未实现
if (GoodsConstants.GOODS_TYPE_CONSUMABLE.equals(verifyDTO.getType())
|| GoodsConstants.GOODS_TYPE_NON_CONSUMABLE.equals(verifyDTO.getType())) {
Assert.hasText(verifyDTO.getJwsPurchaseOrder(), "订单信息不能为空");
// 消耗/非消耗商品购买验证
consumablePurchasesVerify(verifyDTO.getJwsPurchaseOrder());
} else if (GoodsConstants.GOODS_TYPE_AUTOMATIC_RENEWAL_SUBSCRIPTION.equals(verifyDTO.getType())) {
Assert.hasText(verifyDTO.getJwsSubscriptionStatus(), "订单信息不能为空");
// 订阅商品购买验证
subscriptionPurchasesVerify(verifyDTO.getJwsSubscriptionStatus());
} else {
throw new IllegalArgumentException("商品类型错误!");
}
}
private PurchaseOrderPayload subscriptionPurchasesVerify(String jwsSubscriptionStatus) {
DecodedJWT decodedJWT = JWT.decode(jwsSubscriptionStatus);
//String header = decodedJWT.getHeader();
String payload = decodedJWT.getPayload();
// 前面应该不是base64编码后的官网说都是编码后的但是解码会报错
//String signature = decodedJWT.getSignature();
String decodeAppPayload = new String(Base64Utils.decode(payload.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
// String decodeHeader = new String(Base64Utils.decode(header.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
// String decodeSignature = new String(Base64Utils.decode(signature.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
SubGroupStatusPayload appSubGroupStatusPayload = JSON.parseObject(decodeAppPayload, SubGroupStatusPayload.class);
SubscriptionStatus lastSubscriptionStatus = appSubGroupStatusPayload.getLastSubscriptionStatus();
PurchaseOrderPayload lastPurchaseOrder = lastSubscriptionStatus.getLastPurchaseOrder();
// pack the request body
Map<String, String> bodyMap = new HashMap<>();
bodyMap.put("purchaseToken", lastPurchaseOrder.getPurchaseToken());
bodyMap.put("purchaseOrderId", lastPurchaseOrder.getPurchaseOrderId());
// construct the Authorization in Header
Map<String, String> headers = buildAuthorization(huaweiPaymentConfig.getAppId(), bodyMap);
// 订阅状态查询
String response = HttpUtil.createPost(ROOT_URL + SUBSCRIPTION_STATUS_QUERY_URL)
.addHeaders(headers)
.body(JSON.toJSONString(bodyMap))
.execute().body();
log.info("订单状态查询返回信息:{}", response);
HuaweiQueryResponse huaweiQueryResponse = JSON.parseObject(response, HuaweiQueryResponse.class);
if (!"0".equals(huaweiQueryResponse.getResponseCode())) {
throw new RuntimeException("订单状态查询失败");
}
DecodedJWT huaweiQueryResponseDecodedJWT = JWT.decode(huaweiQueryResponse.getJwsSubGroupStatus());
String huaweiQueryResponsepayload = huaweiQueryResponseDecodedJWT.getPayload();
String decodeHuaweiQueryResponsepayload = new String(Base64Utils.decode(huaweiQueryResponsepayload.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
SubGroupStatusPayload subGroupStatusPayload = JSON.parseObject(decodeHuaweiQueryResponsepayload, SubGroupStatusPayload.class);
PurchaseOrderPayload huaweiQueryResponsePurchaseOrderPayload = subGroupStatusPayload.getLastSubscriptionStatus().getLastPurchaseOrder();
// 发货
return delivery(lastPurchaseOrder, huaweiQueryResponsePurchaseOrderPayload);
}
/**
* 发货
* @param purchaseOrder
* @param huaweiQueryResponsePurchaseOrderPayload
* @return
*/
private PurchaseOrderPayload delivery(PurchaseOrderPayload purchaseOrder, PurchaseOrderPayload huaweiQueryResponsePurchaseOrderPayload) {
Assert.isTrue(purchaseOrder.getPurchaseOrderId().equals(huaweiQueryResponsePurchaseOrderPayload.getPurchaseOrderId()), "订单不一致,发货失败!");
if (2 == huaweiQueryResponsePurchaseOrderPayload.getFinishStatus()) {
// 还未发货
// 查询平台是否配置该商品
// 查询平台是否配置该商品
GoodsMessages goods = goodsMessagesService.selectGoodsMessagesByCode(huaweiQueryResponsePurchaseOrderPayload.getProductId());
Assert.notNull(goods, "未配置此商品,请检查商品配置");
Assert.isTrue(goods.getOriginalPrice().equals(huaweiQueryResponsePurchaseOrderPayload.getPrice()), "商品价格与订单价格不一致,请检查价格配置");
// 创建完成订单
createOrder(huaweiQueryResponsePurchaseOrderPayload, goods);
// 发放会员权益
distributeMembershipBenefits(huaweiQueryResponsePurchaseOrderPayload);
} else {
log.info("华为应用内支付订单已发货!{}", JSON.toJSONString(huaweiQueryResponsePurchaseOrderPayload));
}
return huaweiQueryResponsePurchaseOrderPayload;
}
private PurchaseOrderPayload consumablePurchasesVerify(String jwsPurchaseOrder) {
DecodedJWT decodedJWT = JWT.decode(jwsPurchaseOrder);
//String header = decodedJWT.getHeader();
String payload = decodedJWT.getPayload();
// 前面应该不是base64编码后的官网说都是编码后的但是解码会报错
//String signature = decodedJWT.getSignature();
String decodeAppPayload = new String(Base64Utils.decode(payload.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
// String decodeHeader = new String(Base64Utils.decode(header.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
// String decodeSignature = new String(Base64Utils.decode(signature.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
PurchaseOrderPayload appPurchaseOrderPayload = JSON.parseObject(decodeAppPayload, PurchaseOrderPayload.class);
// pack the request body
Map<String, String> bodyMap = new HashMap<>();
bodyMap.put("purchaseToken", appPurchaseOrderPayload.getPurchaseToken());
bodyMap.put("purchaseOrderId", appPurchaseOrderPayload.getPurchaseOrderId());
// construct the Authorization in Header
Map<String, String> headers = buildAuthorization(huaweiPaymentConfig.getAppId(), bodyMap);
// 订单状态查询
String response = HttpUtil.createPost(ROOT_URL + ORDER_STATUS_QUERY_URL)
.addHeaders(headers)
.body(JSON.toJSONString(bodyMap))
.execute().body();
log.info("订单状态查询返回信息:{}", response);
HuaweiQueryResponse huaweiQueryResponse = JSON.parseObject(response, HuaweiQueryResponse.class);
if (!"0".equals(huaweiQueryResponse.getResponseCode())) {
throw new RuntimeException("订单状态查询失败");
}
DecodedJWT huaweiQueryResponseDecodedJWT = JWT.decode(huaweiQueryResponse.getJwsPurchaseOrder());
// String huaweiQueryResponseHeader = huaweiQueryResponseDecodedJWT.getHeader();
String huaweiQueryResponsepayload = huaweiQueryResponseDecodedJWT.getPayload();
// String huaweiQueryResponsesignature = huaweiQueryResponseDecodedJWT.getSignature();
//String decodehuaweiQueryResponseHeader = new String(Base64Utils.decode(huaweiQueryResponseHeader.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
String decodehuaweiQueryResponsepayload = new String(Base64Utils.decode(huaweiQueryResponsepayload.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
// String decodehuaweiQueryResponsesignature = new String(Base64Utils.decode(huaweiQueryResponsesignature.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
PurchaseOrderPayload huaweiQueryResponsePurchaseOrderPayload = JSON.parseObject(decodehuaweiQueryResponsepayload, PurchaseOrderPayload.class);
// 暂时只做简单验证
return delivery(appPurchaseOrderPayload, huaweiQueryResponsePurchaseOrderPayload);
}
private void createOrder(PurchaseOrderPayload appPurchaseOrderPayload, GoodsMessages goods) {
Long userId = SecurityUtils.getUserId();
OrderInfo orderInfo = new OrderInfo();
orderInfo.setOrderNo(snowflakeIdWorker.nextId());
orderInfo.setOrderStatus(6L);
orderInfo.setPayType(1L);
orderInfo.setPayChannel(2L);
orderInfo.setOrderAmt(appPurchaseOrderPayload.getPrice());
orderInfo.setPayAmt(appPurchaseOrderPayload.getPrice());
orderInfo.setReallyAmt(appPurchaseOrderPayload.getPrice());
orderInfo.setReceiveType(0L);
orderInfo.setGoodsId(goods.getId());
orderInfo.setPayTime(DateUtil.date(appPurchaseOrderPayload.getPurchaseTime()));
orderInfo.setCreateUserId(userId);
orderInfo.setUpdateUserId(userId);
orderInfo.setOutOrderNo(appPurchaseOrderPayload.getPurchaseOrderId());
orderInfo.setPayData(JSON.toJSONString(appPurchaseOrderPayload));
orderInfo.setGoodsPrice(goods.getOriginalPrice());
orderInfo.setGoodsType(goods.getGoodsType());
orderInfo.setGoodsCode(goods.getGoodsCode());
orderInfoService.insertOrder(orderInfo);
}
private void distributeMembershipBenefits(PurchaseOrderPayload purchaseOrderPayload) {
// 发放会员权益
Long userId = SecurityUtils.getUserId();
UserMember userMember = userMemberService.selectUserMemberByUserId(userId);
if (userMember == null) {
// 添加会员信息
boolean isSubscription = GoodsConstants.GOODS_TYPE_AUTOMATIC_RENEWAL_SUBSCRIPTION.equals(purchaseOrderPayload.getProductType());
DateTime payTime = DateUtil.date(purchaseOrderPayload.getPurchaseTime());
userMember = new UserMember();
userMember.setMemberLevel(isSubscription ? 1 : 2);
userMember.setSubscriptionStatus(isSubscription ? 1 : 0);
userMember.setUserId(userId);
userMember.setIntegration(0L);
DateTime expirationTime = DateUtil.offset(payTime, DateField.MONTH, 1);
userMember.setExpirationTime(expirationTime);
userMember.setCreateTime(new Date());
userMember.setUpdateTime(new Date());
userMemberService.insertUserMember(userMember);
} else {
// 更新
DateTime expirationTime = DateUtil.offset(userMember.getExpirationTime(), DateField.MONTH, 1);
userMember.setExpirationTime(expirationTime);
userMember.setUpdateTime(new Date());
userMemberService.updateUserMember(userMember);
}
}
/**
* Build Authorization in Header
*
* @return headers
*/
public static Map<String, String> buildAuthorization(String appId, Map<String, String> body) {
Map<String, Object> jwtHeader = new HashMap<>(8);
jwtHeader.put("alg", "ES256");
jwtHeader.put("typ", "JWT");
jwtHeader.put("kid", "0ae3e1be-374b-43a5-a297-045addbf76eb");
Map<String, Object> jwtPayload = new HashMap<>(8);
jwtPayload.put("iss", "f59509e6-dd17-4644-b832-ff05233146c8");
jwtPayload.put("aud", "iap-v1");
jwtPayload.put("iat", DateUtil.currentSeconds());
jwtPayload.put("exp", DateUtil.currentSeconds() + 1800L); // 半小时过期
jwtPayload.put("aid", appId);
jwtPayload.put("digest", getJwtPayloadDigest(body));
String token = HuaweiTokenGenerator.createToken(jwtHeader, jwtPayload);
// String authorization = MessageFormat.format("Basic {0}", Base64.encodeBase64String(oriString.getBytes(StandardCharsets.UTF_8)));
String authorization = MessageFormat.format("Bearer {0}", token);
Map<String, String> headers = new HashMap<>();
headers.put("Authorization", authorization);
headers.put("Content-Type", "application/json; charset=UTF-8");
return headers;
}
private static String getJwtPayloadDigest(Map<String, String> body) {
try {
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update(JSON.toJSONString(body).getBytes(StandardCharsets.UTF_8));
byte[] digestByte = messageDigest.digest();
StringBuilder stringBuffer = new StringBuilder();
String temp;
for (byte aByte : digestByte) {
temp = Integer.toHexString(aByte & 0xFF);
if (temp.length() == 1) {
stringBuffer.append("0");
}
stringBuffer.append(temp);
}
return stringBuffer.toString();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 校验签名信息校验InAppPurchaseData中的productIdpricecurrency等信息的一致性
*
* @param content 结果字符串
* @param sign 签名字符串
* @param publicKey IAP公钥
* @return 是否校验通过
*/
public static boolean checkSuccessOrder(String content, String sign, String publicKey, String signatureAlgorithm, OrderInfo orderInfo) {
// 校验签名信息
boolean checkRes = checkSign(content, sign, publicKey, StrUtil.blankToDefault(signatureAlgorithm, "SHA256WithRSA"));
if (checkRes) {
// 校验InAppPurchaseData中的productIdpricecurrency等信息的一致性
checkRes = checkProductIdAndPriceAndCurrency(content, orderInfo);
}
return checkRes;
}
/**
* 校验InAppPurchaseData中的productIdpricecurrency等信息的一致性
*
* @param content 结果字符串
* @param orderInfo 您的订单信息包括productIdpricecurrency
* @return 是否校验通过
*/
public static boolean checkProductIdAndPriceAndCurrency(String content, OrderInfo orderInfo) {
InAppPurchaseData inAppPurchaseData = JSON.parseObject(content, InAppPurchaseData.class);
// 校验InAppPurchaseData中的productIdpricecurrency等信息的一致性
return inAppPurchaseData.getProductId().equals(orderInfo.getGoodsId())
&& inAppPurchaseData.getPrice().equals(orderInfo.getOrderAmt());
}
/**
* 校验签名信息
*
* @param content 结果字符串
* @param sign 签名字符串
* @param publicKey IAP公钥
* @param signatureAlgorithm 签名算法字段可从接口返回数据中获取例如OwnedPurchasesResult.getSignatureAlgorithm()
* @return 是否校验通过
*/
public static boolean checkSign(String content, String sign, String publicKey, String signatureAlgorithm) {
if (sign == null) {
return false;
}
if (publicKey == null) {
return false;
}
// 当signatureAlgorithm为空时使用默认签名算法
if (signatureAlgorithm == null || signatureAlgorithm.length() == 0) {
signatureAlgorithm = "SHA256WithRSA";
System.out.println("doCheck, algorithm: SHA256WithRSA");
}
try {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
// 生成"RSA"的KeyFactory对象
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] decodedKey = Base64.decodeBase64(publicKey);
// 生成公钥
PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(decodedKey));
java.security.Signature signature = null;
// 根据SHA256WithRSA算法获取签名对象实例
signature = java.security.Signature.getInstance(signatureAlgorithm);
// 初始化验证签名的公钥
signature.initVerify(pubKey);
// 把原始报文更新到签名对象中
signature.update(content.getBytes(StandardCharsets.UTF_8));
// 将sign解码
byte[] bsign = Base64.decodeBase64(sign);
// 进行验签
return signature.verify(bsign);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
}

View File

@ -0,0 +1,43 @@
package com.sf.payment.utils;
import cn.hutool.core.io.resource.ClassPathResource;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import org.apache.commons.io.IOUtils;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.ECPrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.Map;
public class HuaweiTokenGenerator {
public static String createToken(Map<String, Object> jwtHeader, Map<String, Object> jwtPayload) {
try {
// AppGallery Connect 华为应用内支付配置密钥下载私钥文件
ClassPathResource classPathResource = new ClassPathResource("IAPKey_0ae3e1be-374b-43a5-a297-045addbf76eb.p8");
InputStream IAPKeyStream = classPathResource.getStream();
String content = IOUtils.toString(IAPKeyStream, String.valueOf(StandardCharsets.UTF_8));
String privateKey = content
.replace("-----BEGIN PRIVATE KEY-----", "")
.replaceAll("\\R+", "")
.replace("-----END PRIVATE KEY-----", "");
KeyFactory keyFactory = KeyFactory.getInstance("EC");
byte[] privateKeyBytes = Base64.getDecoder().decode(privateKey);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
ECPrivateKey ecPrivateKey = (ECPrivateKey) keyFactory.generatePrivate(keySpec);
return JWT.create()
.withHeader(jwtHeader)
.withPayload(jwtPayload)
.sign(Algorithm.ECDSA256(ecPrivateKey));
} catch (IOException | NoSuchAlgorithmException | InvalidKeySpecException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,6 @@
-----BEGIN PRIVATE KEY-----
MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQggG04243qynU/yWYy
XpYVy9ZWMuLKzZiwhXCBWQBCOLigCgYIKoZIzj0DAQehRANCAARNln2/d+TM2pIO
LWQzvI77gPAVEvVCSlIuiJ+J7CJSG5KCysBaEeiiD5cc4dZWnUBijF8FBh7nDLaH
VwFXfrS+
-----END PRIVATE KEY-----

33
sf-service/pom.xml Normal file
View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>smarterFramework</artifactId>
<groupId>com.smarterFramework</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>sf-service</artifactId>
<description>
业务模块
</description>
<dependencies>
<!-- 通用工具-->
<dependency>
<groupId>com.smarterFramework</groupId>
<artifactId>sf-common</artifactId>
</dependency>
<dependency>
<groupId>com.smarterFramework</groupId>
<artifactId>sf-framework</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,7 +1,10 @@
package com.sf.goods.controller;
package com.sf.service.controller;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import com.sf.service.domain.GoodsMessages;
import com.sf.service.service.IGoodsMessagesService;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
@ -16,19 +19,17 @@ import com.sf.common.annotation.Log;
import com.sf.common.core.controller.BaseController;
import com.sf.common.core.domain.AjaxResult;
import com.sf.common.enums.BusinessType;
import com.sf.goods.domain.GoodsMessages;
import com.sf.goods.service.IGoodsMessagesService;
import com.sf.common.utils.poi.ExcelUtil;
import com.sf.common.core.page.TableDataInfo;
/**
* 商品信息Controller
*
* @author ztzh
* @date 2024-04-11
* @author zoukun
* @date 2024-04-18
*/
@RestController
@RequestMapping("/goods/goods")
@RequestMapping("/service/goods")
public class GoodsMessagesController extends BaseController
{
@Autowired
@ -37,7 +38,7 @@ public class GoodsMessagesController extends BaseController
/**
* 查询商品信息列表
*/
@PreAuthorize("@ss.hasPermi('goods:goods:list')")
@PreAuthorize("@ss.hasPermi('service:goods:list')")
@GetMapping("/list")
public TableDataInfo list(GoodsMessages goodsMessages)
{
@ -49,7 +50,7 @@ public class GoodsMessagesController extends BaseController
/**
* 导出商品信息列表
*/
@PreAuthorize("@ss.hasPermi('goods:goods:export')")
@PreAuthorize("@ss.hasPermi('service:goods:export')")
@Log(title = "商品信息", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, GoodsMessages goodsMessages)
@ -62,7 +63,7 @@ public class GoodsMessagesController extends BaseController
/**
* 获取商品信息详细信息
*/
@PreAuthorize("@ss.hasPermi('goods:goods:query')")
@PreAuthorize("@ss.hasPermi('service:goods:query')")
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id)
{
@ -72,7 +73,7 @@ public class GoodsMessagesController extends BaseController
/**
* 新增商品信息
*/
@PreAuthorize("@ss.hasPermi('goods:goods:add')")
@PreAuthorize("@ss.hasPermi('service:goods:add')")
@Log(title = "商品信息", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody GoodsMessages goodsMessages)
@ -83,7 +84,7 @@ public class GoodsMessagesController extends BaseController
/**
* 修改商品信息
*/
@PreAuthorize("@ss.hasPermi('goods:goods:edit')")
@PreAuthorize("@ss.hasPermi('service:goods:edit')")
@Log(title = "商品信息", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody GoodsMessages goodsMessages)
@ -94,7 +95,7 @@ public class GoodsMessagesController extends BaseController
/**
* 删除商品信息
*/
@PreAuthorize("@ss.hasPermi('goods:goods:remove')")
@PreAuthorize("@ss.hasPermi('service:goods:remove')")
@Log(title = "商品信息", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Long[] ids)

View File

@ -1,4 +1,4 @@
package com.sf.goods.domain;
package com.sf.service.domain;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
@ -8,8 +8,8 @@ import com.sf.common.core.domain.BaseEntity;
/**
* 商品信息对象 GOODS_MESSAGES
*
* @author ztzh
* @date 2024-04-11
* @author zoukun
* @date 2024-04-18
*/
public class GoodsMessages extends BaseEntity
{
@ -26,6 +26,7 @@ public class GoodsMessages extends BaseEntity
private Long stockId;
/** 审核状态1通过0未通过 */
@Excel(name = "审核状态1通过0未通过")
private Long reviewStatus;
/** 商品标题 */
@ -36,16 +37,23 @@ public class GoodsMessages extends BaseEntity
@Excel(name = "商品图片")
private String productPicture;
/** 原价 */
@Excel(name = "原价")
/** 商品原价 */
@Excel(name = "商品原价")
private Long originalPrice;
/** 商品描述 */
@Excel(name = "商品描述")
private String productDesc;
/** 商品类型。 * • 0消耗型商品 * • 1非消耗型商品 * • 2自动续期订阅商品 */
@Excel(name = "商品类型。 * • 0消耗型商品 * • 1非消耗型商品 * • 2自动续期订阅商品")
private Integer goodsType;
/** 商品规格 */
@Excel(name = "商品规格")
private String goodsSpec;
/** 排序 */
@Excel(name = "排序")
private Long orderNum;
/** 逻辑删除,0:未删除,1:删除 */
@ -57,13 +65,12 @@ public class GoodsMessages extends BaseEntity
/** 更新人 */
private String modified;
/** 商品类型 */
@Excel(name = "商品类型")
private String goodsType;
/** 商品名称 */
private String goodsName;
/** 商品规格 */
@Excel(name = "商品规格")
private String goodsSpec;
/** 商品型号 */
@Excel(name = "商品型号")
private String goodsModel;
public void setId(Long id)
{
@ -137,6 +144,24 @@ public class GoodsMessages extends BaseEntity
{
return productDesc;
}
public void setGoodsType(Integer goodsType)
{
this.goodsType = goodsType;
}
public Integer getGoodsType()
{
return goodsType;
}
public void setGoodsSpec(String goodsSpec)
{
this.goodsSpec = goodsSpec;
}
public String getGoodsSpec()
{
return goodsSpec;
}
public void setOrderNum(Long orderNum)
{
this.orderNum = orderNum;
@ -173,23 +198,23 @@ public class GoodsMessages extends BaseEntity
{
return modified;
}
public void setGoodsType(String goodsType)
public void setGoodsName(String goodsName)
{
this.goodsType = goodsType;
this.goodsName = goodsName;
}
public String getGoodsType()
public String getGoodsName()
{
return goodsType;
return goodsName;
}
public void setGoodsSpec(String goodsSpec)
public void setGoodsModel(String goodsModel)
{
this.goodsSpec = goodsSpec;
this.goodsModel = goodsModel;
}
public String getGoodsSpec()
public String getGoodsModel()
{
return goodsSpec;
return goodsModel;
}
@Override
@ -203,14 +228,16 @@ public class GoodsMessages extends BaseEntity
.append("productPicture", getProductPicture())
.append("originalPrice", getOriginalPrice())
.append("productDesc", getProductDesc())
.append("goodsType", getGoodsType())
.append("goodsSpec", getGoodsSpec())
.append("orderNum", getOrderNum())
.append("isDelete", getIsDelete())
.append("created", getCreated())
.append("modified", getModified())
.append("createTime", getCreateTime())
.append("updateTime", getUpdateTime())
.append("goodsType", getGoodsType())
.append("goodsSpec", getGoodsSpec())
.append("goodsName", getGoodsName())
.append("goodsModel", getGoodsModel())
.toString();
}
}

View File

@ -1,13 +1,13 @@
package com.sf.goods.mapper;
package com.sf.service.mapper;
import java.util.List;
import com.sf.goods.domain.GoodsMessages;
import com.sf.service.domain.GoodsMessages;
/**
* 商品信息Mapper接口
*
* @author ztzh
* @date 2024-04-11
* @author zoukun
* @date 2024-04-18
*/
public interface GoodsMessagesMapper
{
@ -58,4 +58,6 @@ public interface GoodsMessagesMapper
* @return 结果
*/
public int deleteGoodsMessagesByIds(Long[] ids);
GoodsMessages selectGoodsMessagesByCode(String goodsCode);
}

View File

@ -1,13 +1,13 @@
package com.sf.goods.service;
package com.sf.service.service;
import java.util.List;
import com.sf.goods.domain.GoodsMessages;
import com.sf.service.domain.GoodsMessages;
/**
* 商品信息Service接口
*
* @author ztzh
* @date 2024-04-11
* @author zoukun
* @date 2024-04-18
*/
public interface IGoodsMessagesService
{
@ -58,4 +58,6 @@ public interface IGoodsMessagesService
* @return 结果
*/
public int deleteGoodsMessagesById(Long id);
GoodsMessages selectGoodsMessagesByCode(String goodsCode);
}

View File

@ -1,18 +1,19 @@
package com.sf.goods.service.impl;
package com.sf.service.service.impl;
import java.util.List;
import com.sf.common.utils.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.sf.goods.mapper.GoodsMessagesMapper;
import com.sf.goods.domain.GoodsMessages;
import com.sf.goods.service.IGoodsMessagesService;
import com.sf.service.mapper.GoodsMessagesMapper;
import com.sf.service.domain.GoodsMessages;
import com.sf.service.service.IGoodsMessagesService;
import org.springframework.util.StringUtils;
/**
* 商品信息Service业务层处理
*
* @author ztzh
* @date 2024-04-11
* @author zoukun
* @date 2024-04-18
*/
@Service
public class GoodsMessagesServiceImpl implements IGoodsMessagesService
@ -93,4 +94,12 @@ public class GoodsMessagesServiceImpl implements IGoodsMessagesService
{
return goodsMessagesMapper.deleteGoodsMessagesById(id);
}
@Override
public GoodsMessages selectGoodsMessagesByCode(String goodsCode) {
if (StringUtils.hasText(goodsCode)){
return goodsMessagesMapper.selectGoodsMessagesByCode(goodsCode);
}
return null;
}
}

View File

@ -2,7 +2,7 @@
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.sf.goods.mapper.GoodsMessagesMapper">
<mapper namespace="com.sf.service.mapper.GoodsMessagesMapper">
<resultMap type="GoodsMessages" id="GoodsMessagesResult">
<result property="id" column="id" />
@ -13,26 +13,32 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="productPicture" column="product_picture" />
<result property="originalPrice" column="original_price" />
<result property="productDesc" column="product_desc" />
<result property="goodsType" column="goods_type" />
<result property="goodsSpec" column="goods_spec" />
<result property="orderNum" column="order_num" />
<result property="isDelete" column="is_delete" />
<result property="created" column="created" />
<result property="modified" column="modified" />
<result property="createTime" column="create_time" />
<result property="updateTime" column="update_time" />
<result property="goodsType" column="goods_type" />
<result property="goodsSpec" column="goods_spec" />
<result property="goodsName" column="goods_name" />
<result property="goodsModel" column="goods_model" />
</resultMap>
<sql id="selectGoodsMessagesVo">
select id, goods_code, stock_id, review_status, product_title, product_picture, original_price, product_desc, order_num, is_delete, created, modified, create_time, update_time, goods_type, goods_spec from GOODS_MESSAGES
select id, goods_code, stock_id, review_status, product_title, product_picture, original_price, product_desc, goods_type, goods_spec, order_num, is_delete, created, modified, create_time, update_time, goods_name, goods_model from GOODS_MESSAGES
</sql>
<select id="selectGoodsMessagesList" parameterType="GoodsMessages" resultMap="GoodsMessagesResult">
<include refid="selectGoodsMessagesVo"/>
<where>
<if test="goodsCode != null and goodsCode != ''"> and goods_code = #{goodsCode}</if>
<if test="reviewStatus != null "> and review_status = #{reviewStatus}</if>
<if test="productTitle != null and productTitle != ''"> and product_title like concat('%', #{productTitle}, '%')</if>
<if test="goodsType != null and goodsType != ''"> and goods_type = #{goodsType}</if>
<if test="params.beginOriginalPrice != null and params.beginOriginalPrice != '' and params.endOriginalPrice != null and params.endOriginalPrice != ''"> and original_price between #{params.beginOriginalPrice} and #{params.endOriginalPrice}</if>
<if test="goodsType != null "> and goods_type = #{goodsType}</if>
<if test="goodsSpec != null and goodsSpec != ''"> and goods_spec = #{goodsSpec}</if>
<if test="goodsModel != null and goodsModel != ''"> and goods_model = #{goodsModel}</if>
</where>
</select>
@ -40,9 +46,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<include refid="selectGoodsMessagesVo"/>
where id = #{id}
</select>
<select id="selectGoodsMessagesByCode" parameterType="java.lang.String" resultMap="GoodsMessagesResult">
<select id="selectGoodsMessagesByCode" parameterType="String" resultMap="GoodsMessagesResult">
<include refid="selectGoodsMessagesVo"/>
where goods_code = #{code}
where goods_code = #{goodsCode}
</select>
<insert id="insertGoodsMessages" parameterType="GoodsMessages" useGeneratedKeys="true" keyProperty="id">
@ -55,14 +61,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="productPicture != null and productPicture != ''">product_picture,</if>
<if test="originalPrice != null">original_price,</if>
<if test="productDesc != null">product_desc,</if>
<if test="goodsType != null">goods_type,</if>
<if test="goodsSpec != null and goodsSpec != ''">goods_spec,</if>
<if test="orderNum != null">order_num,</if>
<if test="isDelete != null">is_delete,</if>
<if test="created != null">created,</if>
<if test="modified != null">modified,</if>
<if test="createTime != null">create_time,</if>
<if test="updateTime != null">update_time,</if>
<if test="goodsType != null and goodsType != ''">goods_type,</if>
<if test="goodsSpec != null and goodsSpec != ''">goods_spec,</if>
<if test="goodsName != null and goodsName != ''">goods_name,</if>
<if test="goodsModel != null">goods_model,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="goodsCode != null and goodsCode != ''">#{goodsCode},</if>
@ -72,14 +80,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="productPicture != null and productPicture != ''">#{productPicture},</if>
<if test="originalPrice != null">#{originalPrice},</if>
<if test="productDesc != null">#{productDesc},</if>
<if test="goodsType != null">#{goodsType},</if>
<if test="goodsSpec != null and goodsSpec != ''">#{goodsSpec},</if>
<if test="orderNum != null">#{orderNum},</if>
<if test="isDelete != null">#{isDelete},</if>
<if test="created != null">#{created},</if>
<if test="modified != null">#{modified},</if>
<if test="createTime != null">#{createTime},</if>
<if test="updateTime != null">#{updateTime},</if>
<if test="goodsType != null and goodsType != ''">#{goodsType},</if>
<if test="goodsSpec != null and goodsSpec != ''">#{goodsSpec},</if>
<if test="goodsName != null and goodsName != ''">#{goodsName},</if>
<if test="goodsModel != null">#{goodsModel},</if>
</trim>
</insert>
@ -93,14 +103,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="productPicture != null and productPicture != ''">product_picture = #{productPicture},</if>
<if test="originalPrice != null">original_price = #{originalPrice},</if>
<if test="productDesc != null">product_desc = #{productDesc},</if>
<if test="goodsType != null">goods_type = #{goodsType},</if>
<if test="goodsSpec != null and goodsSpec != ''">goods_spec = #{goodsSpec},</if>
<if test="orderNum != null">order_num = #{orderNum},</if>
<if test="isDelete != null">is_delete = #{isDelete},</if>
<if test="created != null">created = #{created},</if>
<if test="modified != null">modified = #{modified},</if>
<if test="createTime != null">create_time = #{createTime},</if>
<if test="updateTime != null">update_time = #{updateTime},</if>
<if test="goodsType != null and goodsType != ''">goods_type = #{goodsType},</if>
<if test="goodsSpec != null and goodsSpec != ''">goods_spec = #{goodsSpec},</if>
<if test="goodsName != null and goodsName != ''">goods_name = #{goodsName},</if>
<if test="goodsModel != null">goods_model = #{goodsModel},</if>
</trim>
where id = #{id}
</update>

View File

@ -0,0 +1,110 @@
package com.sf.system.domain;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.sf.common.annotation.Excel;
import com.sf.common.core.domain.BaseEntity;
/**
* 会员对象 User_member
*
* @author ztzh
* @date 2024-04-16
*/
public class UserMember extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** $column.columnComment */
private Long id;
/** 用户会员等级0普通会员 1订阅会员 2月度会员 */
@Excel(name = "用户会员等级", readConverterExp = "0=普通会员,1=订阅会员,2=月度会员")
private Integer memberLevel;
/** 会员等级为订阅会员时的订阅状态未订阅就是取消了0未订阅 1已订阅 */
@Excel(name = "会员等级为订阅会员时的订阅状态,未订阅就是取消了", readConverterExp = "0=未订阅,1=已订阅")
private Integer subscriptionStatus;
/** 关联的用户id */
@Excel(name = "关联的用户id")
private Long userId;
/** 积分 */
@Excel(name = "积分")
private Long integration;
/** 过期时间 */
private Date expirationTime;
public void setId(Long id)
{
this.id = id;
}
public Long getId()
{
return id;
}
public void setMemberLevel(Integer memberLevel)
{
this.memberLevel = memberLevel;
}
public Integer getMemberLevel()
{
return memberLevel;
}
public void setSubscriptionStatus(Integer subscriptionStatus)
{
this.subscriptionStatus = subscriptionStatus;
}
public Integer getSubscriptionStatus()
{
return subscriptionStatus;
}
public void setUserId(Long userId)
{
this.userId = userId;
}
public Long getUserId()
{
return userId;
}
public void setIntegration(Long integration)
{
this.integration = integration;
}
public Long getIntegration()
{
return integration;
}
public void setExpirationTime(Date expirationTime)
{
this.expirationTime = expirationTime;
}
public Date getExpirationTime()
{
return expirationTime;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("memberLevel", getMemberLevel())
.append("subscriptionStatus", getSubscriptionStatus())
.append("userId", getUserId())
.append("createTime", getCreateTime())
.append("updateTime", getUpdateTime())
.append("integration", getIntegration())
.append("expirationTime", getExpirationTime())
.toString();
}
}

View File

@ -0,0 +1,63 @@
package com.sf.system.mapper;
import java.util.List;
import com.sf.system.domain.UserMember;
/**
* 会员Mapper接口
*
* @author ztzh
* @date 2024-04-16
*/
public interface UserMemberMapper
{
/**
* 查询会员
*
* @param id 会员主键
* @return 会员
*/
public UserMember selectUserMemberById(Long id);
/**
* 查询会员列表
*
* @param userMember 会员
* @return 会员集合
*/
public List<UserMember> selectUserMemberList(UserMember userMember);
/**
* 新增会员
*
* @param userMember 会员
* @return 结果
*/
public int insertUserMember(UserMember userMember);
/**
* 修改会员
*
* @param userMember 会员
* @return 结果
*/
public int updateUserMember(UserMember userMember);
/**
* 删除会员
*
* @param id 会员主键
* @return 结果
*/
public int deleteUserMemberById(Long id);
/**
* 批量删除会员
*
* @param ids 需要删除的数据主键集合
* @return 结果
*/
public int deleteUserMemberByIds(Long[] ids);
UserMember selectUserMemberByUserId(Long userId);
}

View File

@ -0,0 +1,63 @@
package com.sf.system.service;
import java.util.List;
import com.sf.system.domain.UserMember;
/**
* 会员Service接口
*
* @author ztzh
* @date 2024-04-16
*/
public interface IUserMemberService
{
/**
* 查询会员
*
* @param id 会员主键
* @return 会员
*/
public UserMember selectUserMemberById(Long id);
/**
* 查询会员列表
*
* @param userMember 会员
* @return 会员集合
*/
public List<UserMember> selectUserMemberList(UserMember userMember);
/**
* 新增会员
*
* @param userMember 会员
* @return 结果
*/
public int insertUserMember(UserMember userMember);
/**
* 修改会员
*
* @param userMember 会员
* @return 结果
*/
public int updateUserMember(UserMember userMember);
/**
* 批量删除会员
*
* @param ids 需要删除的会员主键集合
* @return 结果
*/
public int deleteUserMemberByIds(Long[] ids);
/**
* 删除会员信息
*
* @param id 会员主键
* @return 结果
*/
public int deleteUserMemberById(Long id);
UserMember selectUserMemberByUserId(Long userId);
}

View File

@ -0,0 +1,101 @@
package com.sf.system.service.impl;
import java.util.List;
import com.sf.common.utils.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.sf.system.mapper.UserMemberMapper;
import com.sf.system.domain.UserMember;
import com.sf.system.service.IUserMemberService;
/**
* 会员Service业务层处理
*
* @author ztzh
* @date 2024-04-16
*/
@Service
public class UserMemberServiceImpl implements IUserMemberService
{
@Autowired
private UserMemberMapper userMemberMapper;
/**
* 查询会员
*
* @param id 会员主键
* @return 会员
*/
@Override
public UserMember selectUserMemberById(Long id)
{
return userMemberMapper.selectUserMemberById(id);
}
/**
* 查询会员列表
*
* @param userMember 会员
* @return 会员
*/
@Override
public List<UserMember> selectUserMemberList(UserMember userMember)
{
return userMemberMapper.selectUserMemberList(userMember);
}
/**
* 新增会员
*
* @param userMember 会员
* @return 结果
*/
@Override
public int insertUserMember(UserMember userMember)
{
userMember.setCreateTime(DateUtils.getNowDate());
return userMemberMapper.insertUserMember(userMember);
}
/**
* 修改会员
*
* @param userMember 会员
* @return 结果
*/
@Override
public int updateUserMember(UserMember userMember)
{
userMember.setUpdateTime(DateUtils.getNowDate());
return userMemberMapper.updateUserMember(userMember);
}
/**
* 批量删除会员
*
* @param ids 需要删除的会员主键
* @return 结果
*/
@Override
public int deleteUserMemberByIds(Long[] ids)
{
return userMemberMapper.deleteUserMemberByIds(ids);
}
/**
* 删除会员信息
*
* @param id 会员主键
* @return 结果
*/
@Override
public int deleteUserMemberById(Long id)
{
return userMemberMapper.deleteUserMemberById(id);
}
@Override
public UserMember selectUserMemberByUserId(Long userId) {
return userMemberMapper.selectUserMemberByUserId(userId);
}
}

View File

@ -0,0 +1,89 @@
<?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.sf.system.mapper.UserMemberMapper">
<resultMap type="UserMember" id="UserMemberResult">
<result property="id" column="id" />
<result property="memberLevel" column="member_level" />
<result property="subscriptionStatus" column="subscription_status" />
<result property="userId" column="user_id" />
<result property="createTime" column="create_time" />
<result property="updateTime" column="update_time" />
<result property="integration" column="integration" />
<result property="expirationTime" column="expiration_time" />
</resultMap>
<sql id="selectUserMemberVo">
select id, member_level, subscription_status, user_id, create_time, update_time, integration, expiration_time from User_member
</sql>
<select id="selectUserMemberList" parameterType="UserMember" resultMap="UserMemberResult">
<include refid="selectUserMemberVo"/>
<where>
<if test="memberLevel != null "> and member_level = #{memberLevel}</if>
<if test="subscriptionStatus != null "> and subscription_status = #{subscriptionStatus}</if>
<if test="userId != null "> and user_id = #{userId}</if>
<if test="integration != null "> and integration = #{integration}</if>
<if test="expirationTime != null "> and expiration_time = #{expirationTime}</if>
</where>
</select>
<select id="selectUserMemberById" parameterType="Long" resultMap="UserMemberResult">
<include refid="selectUserMemberVo"/>
where id = #{id}
</select>
<select id="selectUserMemberByUserId" resultMap="UserMemberResult">
<include refid="selectUserMemberVo"/>
where user_id = #{userId}
</select>
<insert id="insertUserMember" parameterType="UserMember" useGeneratedKeys="true" keyProperty="id">
insert into User_member
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="memberLevel != null">member_level,</if>
<if test="subscriptionStatus != null">subscription_status,</if>
<if test="userId != null">user_id,</if>
<if test="createTime != null">create_time,</if>
<if test="updateTime != null">update_time,</if>
<if test="integration != null">integration,</if>
<if test="expirationTime != null">expiration_time,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="memberLevel != null">#{memberLevel},</if>
<if test="subscriptionStatus != null">#{subscriptionStatus},</if>
<if test="userId != null">#{userId},</if>
<if test="createTime != null">#{createTime},</if>
<if test="updateTime != null">#{updateTime},</if>
<if test="integration != null">#{integration},</if>
<if test="expirationTime != null">#{expirationTime},</if>
</trim>
</insert>
<update id="updateUserMember" parameterType="UserMember">
update User_member
<trim prefix="SET" suffixOverrides=",">
<if test="memberLevel != null">member_level = #{memberLevel},</if>
<if test="subscriptionStatus != null">subscription_status = #{subscriptionStatus},</if>
<if test="userId != null">user_id = #{userId},</if>
<if test="createTime != null">create_time = #{createTime},</if>
<if test="updateTime != null">update_time = #{updateTime},</if>
<if test="integration != null">integration = #{integration},</if>
<if test="expirationTime != null">expiration_time = #{expirationTime},</if>
</trim>
where id = #{id}
</update>
<delete id="deleteUserMemberById" parameterType="Long">
delete from User_member where id = #{id}
</delete>
<delete id="deleteUserMemberByIds" parameterType="String">
delete from User_member where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
</mapper>

View File

@ -3,7 +3,7 @@ import request from '@/utils/request'
// 查询商品信息列表
export function listGoods(query) {
return request({
url: '/goods/goods/list',
url: '/service/goods/list',
method: 'get',
params: query
})
@ -12,7 +12,7 @@ export function listGoods(query) {
// 查询商品信息详细
export function getGoods(id) {
return request({
url: '/goods/goods/' + id,
url: '/service/goods/' + id,
method: 'get'
})
}
@ -20,7 +20,7 @@ export function getGoods(id) {
// 新增商品信息
export function addGoods(data) {
return request({
url: '/goods/goods',
url: '/service/goods',
method: 'post',
data: data
})
@ -29,7 +29,7 @@ export function addGoods(data) {
// 修改商品信息
export function updateGoods(data) {
return request({
url: '/goods/goods',
url: '/service/goods',
method: 'put',
data: data
})
@ -38,7 +38,7 @@ export function updateGoods(data) {
// 删除商品信息
export function delGoods(id) {
return request({
url: '/goods/goods/' + id,
url: '/service/goods/' + id,
method: 'delete'
})
}

View File

@ -9,6 +9,16 @@
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="审核状态1通过0未通过" prop="reviewStatus">
<el-select v-model="queryParams.reviewStatus" placeholder="请选择审核状态1通过0未通过" clearable>
<el-option
v-for="dict in dict.type.goods_review_status"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="商品标题" prop="productTitle">
<el-input
v-model="queryParams.productTitle"
@ -17,8 +27,16 @@
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="商品类型" prop="goodsType">
<el-select v-model="queryParams.goodsType" placeholder="请选择商品类型" clearable>
<el-form-item label="商品原价" prop="originalPrice">
<el-input
v-model="queryParams.originalPrice"
placeholder="请输入商品原价"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="商品类型。 * • 0消耗型商品 * • 1非消耗型商品 * • 2自动续期订阅商品" prop="goodsType">
<el-select v-model="queryParams.goodsType" placeholder="请选择商品类型。 * • 0消耗型商品 * • 1非消耗型商品 * • 2自动续期订阅商品" clearable>
<el-option
v-for="dict in dict.type.goods_type"
:key="dict.value"
@ -27,6 +45,22 @@
/>
</el-select>
</el-form-item>
<el-form-item label="商品规格" prop="goodsSpec">
<el-input
v-model="queryParams.goodsSpec"
placeholder="请输入商品规格"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="商品型号" prop="goodsModel">
<el-input
v-model="queryParams.goodsModel"
placeholder="请输入商品型号"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
@ -41,7 +75,7 @@
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['goods:goods:add']"
v-hasPermi="['service:goods:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
@ -52,7 +86,7 @@
size="mini"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['goods:goods:edit']"
v-hasPermi="['service:goods:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
@ -63,7 +97,7 @@
size="mini"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['goods:goods:remove']"
v-hasPermi="['service:goods:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
@ -73,7 +107,7 @@
icon="el-icon-download"
size="mini"
@click="handleExport"
v-hasPermi="['goods:goods:export']"
v-hasPermi="['service:goods:export']"
>导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
@ -81,23 +115,28 @@
<el-table v-loading="loading" :data="goodsList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="商品id" align="center" prop="id" />
<el-table-column label="主键" align="center" prop="id" />
<el-table-column label="商品编号" align="center" prop="goodsCode" />
<el-table-column label="审核状态1通过0未通过" align="center" prop="reviewStatus">
<template slot-scope="scope">
<dict-tag :options="dict.type.goods_review_status" :value="scope.row.reviewStatus"/>
</template>
</el-table-column>
<el-table-column label="商品标题" align="center" prop="productTitle" />
<el-table-column label="商品图片" align="center" prop="productPicture" width="100">
<template slot-scope="scope">
<image-preview :src="scope.row.productPicture" :width="50" :height="50"/>
</template>
</el-table-column>
<el-table-column label="" align="center" prop="originalPrice" />
<el-table-column label="商品原价" align="center" prop="originalPrice" />
<el-table-column label="商品描述" align="center" prop="productDesc" />
<el-table-column label="排序" align="center" prop="orderNum" />
<el-table-column label="商品类型" align="center" prop="goodsType">
<el-table-column label="商品类型。 * • 0消耗型商品 * • 1非消耗型商品 * • 2自动续期订阅商品" align="center" prop="goodsType">
<template slot-scope="scope">
<dict-tag :options="dict.type.goods_type" :value="scope.row.goodsType"/>
</template>
</el-table-column>
<el-table-column label="商品规格" align="center" prop="goodsSpec" />
<el-table-column label="商品型号" align="center" prop="goodsModel" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button
@ -105,14 +144,14 @@
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['goods:goods:edit']"
v-hasPermi="['service:goods:edit']"
>修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPermi="['goods:goods:remove']"
v-hasPermi="['service:goods:remove']"
>删除</el-button>
</template>
</el-table-column>
@ -132,33 +171,60 @@
<el-form-item label="商品编号" prop="goodsCode">
<el-input v-model="form.goodsCode" placeholder="请输入商品编号" />
</el-form-item>
<el-form-item label="库存表编号" prop="stockId">
<el-input v-model="form.stockId" placeholder="请输入库存表编号" />
</el-form-item>
<el-form-item label="审核状态1通过0未通过" prop="reviewStatus">
<el-radio-group v-model="form.reviewStatus">
<el-radio
v-for="dict in dict.type.goods_review_status"
:key="dict.value"
:label="parseInt(dict.value)"
>{{dict.label}}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="商品标题" prop="productTitle">
<el-input v-model="form.productTitle" placeholder="请输入商品标题" />
</el-form-item>
<el-form-item label="商品图片" prop="productPicture">
<image-upload v-model="form.productPicture"/>
</el-form-item>
<el-form-item label="原价格" prop="originalPrice">
<el-input v-model="form.originalPrice" placeholder="请输入原价格" />
<el-form-item label="商品原价" prop="originalPrice">
<el-input v-model="form.originalPrice" placeholder="请输入商品原价" />
</el-form-item>
<el-form-item label="商品描述" prop="productDesc">
<el-input v-model="form.productDesc" type="textarea" placeholder="请输入内容" />
</el-form-item>
<el-form-item label="排序" prop="orderNum">
<el-input v-model="form.orderNum" placeholder="请输入排序" />
</el-form-item>
<el-form-item label="商品类型" prop="goodsType">
<el-form-item label="商品类型。 * • 0消耗型商品 * • 1非消耗型商品 * • 2自动续期订阅商品" prop="goodsType">
<el-radio-group v-model="form.goodsType">
<el-radio
v-for="dict in dict.type.goods_type"
:key="dict.value"
:label="dict.value"
:label="parseInt(dict.value)"
>{{dict.label}}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="商品规格" prop="goodsSpec">
<el-input v-model="form.goodsSpec" placeholder="请输入商品规格" />
</el-form-item>
<el-form-item label="排序" prop="orderNum">
<el-input v-model="form.orderNum" placeholder="请输入排序" />
</el-form-item>
<el-form-item label="逻辑删除,0:未删除,1:删除" prop="isDelete">
<el-input v-model="form.isDelete" placeholder="请输入逻辑删除,0:未删除,1:删除" />
</el-form-item>
<el-form-item label="创建人" prop="created">
<el-input v-model="form.created" placeholder="请输入创建人" />
</el-form-item>
<el-form-item label="更新人" prop="modified">
<el-input v-model="form.modified" placeholder="请输入更新人" />
</el-form-item>
<el-form-item label="商品名称" prop="goodsName">
<el-input v-model="form.goodsName" placeholder="请输入商品名称" />
</el-form-item>
<el-form-item label="商品型号" prop="goodsModel">
<el-input v-model="form.goodsModel" placeholder="请输入商品型号" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
@ -169,11 +235,11 @@
</template>
<script>
import { listGoods, getGoods, delGoods, addGoods, updateGoods } from "@/api/goods/goods";
import { listGoods, getGoods, delGoods, addGoods, updateGoods } from "@/api/service/goods";
export default {
name: "Goods",
dicts: ['sys_notice_status', 'goods_type'],
dicts: ['goods_review_status', 'goods_type'],
data() {
return {
//
@ -199,8 +265,12 @@ export default {
pageNum: 1,
pageSize: 10,
goodsCode: null,
reviewStatus: null,
productTitle: null,
originalPrice: null,
goodsType: null,
goodsSpec: null,
goodsModel: null
},
//
form: {},
@ -216,7 +286,13 @@ export default {
{ required: true, message: "商品图片不能为空", trigger: "blur" }
],
originalPrice: [
{ required: true, message: "原价格不能为空", trigger: "blur" }
{ required: true, message: "商品原价不能为空", trigger: "blur" }
],
goodsType: [
{ required: true, message: "商品类型。 * • 0消耗型商品 * • 1非消耗型商品 * • 2自动续期订阅商品不能为空", trigger: "change" }
],
goodsSpec: [
{ required: true, message: "商品规格不能为空", trigger: "blur" }
],
orderNum: [
{ required: true, message: "排序不能为空", trigger: "blur" }
@ -224,12 +300,9 @@ export default {
createTime: [
{ required: true, message: "创建时间不能为空", trigger: "blur" }
],
goodsType: [
{ required: true, message: "商品类型不能为空", trigger: "change" }
goodsName: [
{ required: true, message: "商品名称不能为空", trigger: "blur" }
],
goodsSpec: [
{ required: true, message: "商品规格不能为空", trigger: "blur" }
]
}
};
},
@ -262,14 +335,16 @@ export default {
productPicture: null,
originalPrice: null,
productDesc: null,
goodsType: null,
goodsSpec: null,
orderNum: null,
isDelete: null,
created: null,
modified: null,
createTime: null,
updateTime: null,
goodsType: null,
goodsSpec: null
goodsName: null,
goodsModel: null
};
this.resetForm("form");
},
@ -339,7 +414,7 @@ export default {
},
/** 导出按钮操作 */
handleExport() {
this.download('goods/goods/export', {
this.download('service/goods/export', {
...this.queryParams
}, `goods_${new Date().getTime()}.xlsx`)
}