diff --git a/pom.xml b/pom.xml index a82b5d6..9c6a7a9 100644 --- a/pom.xml +++ b/pom.xml @@ -174,6 +174,17 @@ ${sf.version} + + com.smarterFramework + sf-payment + ${sf.version} + + + + com.smarterFramework + sf-service + ${sf.version} + com.smarterFramework diff --git a/sf-admin/pom.xml b/sf-admin/pom.xml index 3603c72..6a68f81 100644 --- a/sf-admin/pom.xml +++ b/sf-admin/pom.xml @@ -66,6 +66,21 @@ sf-oauth + + com.smarterFramework + sf-order + + + + com.smarterFramework + sf-payment + + + + com.smarterFramework + sf-service + + diff --git a/sf-admin/src/main/java/com/sf/index/domain/ApplyListInfo.java b/sf-admin/src/main/java/com/sf/index/domain/ApplyListInfo.java index 65eba05..47eaa62 100644 --- a/sf-admin/src/main/java/com/sf/index/domain/ApplyListInfo.java +++ b/sf-admin/src/main/java/com/sf/index/domain/ApplyListInfo.java @@ -7,127 +7,147 @@ import com.sf.common.core.domain.BaseEntity; /** * 应用列对象 APPLY_LIST_INFO - * + * * @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) - .append("id", getId()) - .append("appName", getAppName()) - .append("appDesc", getAppDesc()) - .append("picture", getPicture()) - .append("orderNum", getOrderNum()) - .append("isDelete", getIsDelete()) - .append("created", getCreated()) - .append("modified", getModified()) - .append("createTime", getCreateTime()) - .append("updateTime", getUpdateTime()) - .toString(); + return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) + .append("id", getId()) + .append("appCode",getAppCode()) + .append("appName", getAppName()) + .append("appDesc", getAppDesc()) + .append("picture", getPicture()) + .append("orderNum", getOrderNum()) + .append("isDelete", getIsDelete()) + .append("created", getCreated()) + .append("modified", getModified()) + .append("createTime", getCreateTime()) + .append("updateTime", getUpdateTime()) + .toString(); } + } diff --git a/sf-admin/src/main/java/com/sf/index/service/impl/ApplyListInfoServiceImpl.java b/sf-admin/src/main/java/com/sf/index/service/impl/ApplyListInfoServiceImpl.java index 5181ce4..c77d3e8 100644 --- a/sf-admin/src/main/java/com/sf/index/service/impl/ApplyListInfoServiceImpl.java +++ b/sf-admin/src/main/java/com/sf/index/service/impl/ApplyListInfoServiceImpl.java @@ -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); } diff --git a/sf-admin/src/main/java/com/sf/order/domain/OrderInfo.java b/sf-admin/src/main/java/com/sf/order/domain/OrderInfo.java deleted file mode 100644 index 6e165a8..0000000 --- a/sf-admin/src/main/java/com/sf/order/domain/OrderInfo.java +++ /dev/null @@ -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(); - } -} diff --git a/sf-admin/src/main/java/com/sf/order/domain/res/OrderListResVo.java b/sf-admin/src/main/java/com/sf/order/domain/res/OrderListResVo.java deleted file mode 100644 index 1c7a63d..0000000 --- a/sf-admin/src/main/java/com/sf/order/domain/res/OrderListResVo.java +++ /dev/null @@ -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; - -} diff --git a/sf-admin/src/main/java/com/sf/web/controller/system/UserMemberController.java b/sf-admin/src/main/java/com/sf/web/controller/system/UserMemberController.java new file mode 100644 index 0000000..294c62a --- /dev/null +++ b/sf-admin/src/main/java/com/sf/web/controller/system/UserMemberController.java @@ -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 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 list = userMemberService.selectUserMemberList(userMember); + ExcelUtil util = new ExcelUtil(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)); + } +} diff --git a/sf-admin/src/main/resources/application.yml b/sf-admin/src/main/resources/application.yml index 843f1c4..d953204 100644 --- a/sf-admin/src/main/resources/application.yml +++ b/sf-admin/src/main/resources/application.yml @@ -18,7 +18,7 @@ sf: # 开发环境配置 server: # 服务器的HTTP端口,默认为8080 - port: 7781 + port: 80 servlet: # 应用的访问路径 context-path: / diff --git a/sf-admin/src/main/resources/mapper/index/ApplyListInfoMapper.xml b/sf-admin/src/main/resources/mapper/index/ApplyListInfoMapper.xml index bcc6625..6ab3a1f 100644 --- a/sf-admin/src/main/resources/mapper/index/ApplyListInfoMapper.xml +++ b/sf-admin/src/main/resources/mapper/index/ApplyListInfoMapper.xml @@ -6,6 +6,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + @@ -18,7 +19,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - 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 @@ -88,9 +94,14 @@ where id = #{id} + + - insert into ORDER_INFO + insert into Order_info id, order_no, @@ -116,6 +127,10 @@ out_order_no, pay_data, reduction_amout, + goods_count, + goods_type, + goods_price, + goods_code, #{id}, @@ -142,11 +157,15 @@ #{outOrderNo}, #{payData}, #{reductionAmout}, + #{goodsCount}, + #{goodsType}, + #{goodsPrice}, + #{goodsCode}, - update ORDER_INFO + update Order_info order_no = #{orderNo}, order_status = #{orderStatus}, @@ -176,11 +195,11 @@ - delete from ORDER_INFO where id = #{id} + delete from Order_info where id = #{id} - delete from ORDER_INFO where id in + delete from Order_info where id in #{id} diff --git a/sf-payment/pom.xml b/sf-payment/pom.xml new file mode 100644 index 0000000..680816a --- /dev/null +++ b/sf-payment/pom.xml @@ -0,0 +1,50 @@ + + + + smarterFramework + com.smarterFramework + 1.0.0 + + 4.0.0 + + sf-payment + + + 支付模块 + + + + + + + com.smarterFramework + sf-common + + + com.smarterFramework + sf-framework + + + com.smarterFramework + sf-order + + + com.smarterFramework + sf-service + + + org.bouncycastle + bcprov-jdk18on + 1.73 + + + com.auth0 + java-jwt + 4.4.0 + + + + + \ No newline at end of file diff --git a/sf-payment/src/main/java/com/sf/payment/config/HuaweiPaymentConfig.java b/sf-payment/src/main/java/com/sf/payment/config/HuaweiPaymentConfig.java new file mode 100644 index 0000000..f9d76f5 --- /dev/null +++ b/sf-payment/src/main/java/com/sf/payment/config/HuaweiPaymentConfig.java @@ -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 { + + /** + * 客户端id:(oauth用) + */ + @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; + + +} diff --git a/sf-payment/src/main/java/com/sf/payment/constant/GoodsConstants.java b/sf-payment/src/main/java/com/sf/payment/constant/GoodsConstants.java new file mode 100644 index 0000000..53b8b1c --- /dev/null +++ b/sf-payment/src/main/java/com/sf/payment/constant/GoodsConstants.java @@ -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; + +} diff --git a/sf-payment/src/main/java/com/sf/payment/controller/HuaweiPaymentController.java b/sf-payment/src/main/java/com/sf/payment/controller/HuaweiPaymentController.java new file mode 100644 index 0000000..74650cc --- /dev/null +++ b/sf-payment/src/main/java/com/sf/payment/controller/HuaweiPaymentController.java @@ -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(); + } + +} diff --git a/sf-payment/src/main/java/com/sf/payment/domain/HuaweiPaymentCallback.java b/sf-payment/src/main/java/com/sf/payment/domain/HuaweiPaymentCallback.java new file mode 100644 index 0000000..b7e46d2 --- /dev/null +++ b/sf-payment/src/main/java/com/sf/payment/domain/HuaweiPaymentCallback.java @@ -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; + + +} diff --git a/sf-payment/src/main/java/com/sf/payment/domain/HuaweiPurchasesVerifyDTO.java b/sf-payment/src/main/java/com/sf/payment/domain/HuaweiPurchasesVerifyDTO.java new file mode 100644 index 0000000..49a250c --- /dev/null +++ b/sf-payment/src/main/java/com/sf/payment/domain/HuaweiPurchasesVerifyDTO.java @@ -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; + + + +} diff --git a/sf-payment/src/main/java/com/sf/payment/domain/HuaweiPurchasesVerifyResponseDTO.java b/sf-payment/src/main/java/com/sf/payment/domain/HuaweiPurchasesVerifyResponseDTO.java new file mode 100644 index 0000000..c684a59 --- /dev/null +++ b/sf-payment/src/main/java/com/sf/payment/domain/HuaweiPurchasesVerifyResponseDTO.java @@ -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; + + +} diff --git a/sf-payment/src/main/java/com/sf/payment/domain/HuaweiQueryResponse.java b/sf-payment/src/main/java/com/sf/payment/domain/HuaweiQueryResponse.java new file mode 100644 index 0000000..4814e9f --- /dev/null +++ b/sf-payment/src/main/java/com/sf/payment/domain/HuaweiQueryResponse.java @@ -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; +} diff --git a/sf-payment/src/main/java/com/sf/payment/domain/InAppPurchaseData.java b/sf-payment/src/main/java/com/sf/payment/domain/InAppPurchaseData.java new file mode 100644 index 0000000..05f7e97 --- /dev/null +++ b/sf-payment/src/main/java/com/sf/payment/domain/InAppPurchaseData.java @@ -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:用户签约信息异常 + * 4:Billing错误 + * 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; + + + +} diff --git a/sf-payment/src/main/java/com/sf/payment/domain/PurchaseOrderPayload.java b/sf-payment/src/main/java/com/sf/payment/domain/PurchaseOrderPayload.java new file mode 100644 index 0000000..8c8fab2 --- /dev/null +++ b/sf-payment/src/main/java/com/sf/payment/domain/PurchaseOrderPayload.java @@ -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” 表示周期的单位是天(Days)。ISO 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分钟的时间段。 + */ +} diff --git a/sf-payment/src/main/java/com/sf/payment/domain/SubGroupStatusPayload.java b/sf-payment/src/main/java/com/sf/payment/domain/SubGroupStatusPayload.java new file mode 100644 index 0000000..7fcad45 --- /dev/null +++ b/sf-payment/src/main/java/com/sf/payment/domain/SubGroupStatusPayload.java @@ -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切换B,B切换C, + * 此处是C的订阅状态。 + */ + private SubscriptionStatus lastSubscriptionStatus; + + /** + * 订阅组最近生效的 + * 历史订阅状态 + * SubscriptionStatus的列表,比如A切换B,B切换C,这里包含C,B,A三个订阅状态信息。 + */ + private List historySubscriptionStatusList; + + +} diff --git a/sf-payment/src/main/java/com/sf/payment/domain/SubRenewalInfo.java b/sf-payment/src/main/java/com/sf/payment/domain/SubRenewalInfo.java new file mode 100644 index 0000000..cfff488 --- /dev/null +++ b/sf-payment/src/main/java/com/sf/payment/domain/SubRenewalInfo.java @@ -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; + + +} diff --git a/sf-payment/src/main/java/com/sf/payment/domain/SubscriptionStatus.java b/sf-payment/src/main/java/com/sf/payment/domain/SubscriptionStatus.java new file mode 100644 index 0000000..8adb949 --- /dev/null +++ b/sf-payment/src/main/java/com/sf/payment/domain/SubscriptionStatus.java @@ -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 recentPurchaseOrderList; + + /** + * 当前订阅最新的未来扣费计划,包含的参数请参见SubRenewalInfo。 + */ + private SubRenewalInfo renewalInfo; + + +} diff --git a/sf-payment/src/main/java/com/sf/payment/service/IHuaweiPaymentService.java b/sf-payment/src/main/java/com/sf/payment/service/IHuaweiPaymentService.java new file mode 100644 index 0000000..1383be3 --- /dev/null +++ b/sf-payment/src/main/java/com/sf/payment/service/IHuaweiPaymentService.java @@ -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); +} diff --git a/sf-payment/src/main/java/com/sf/payment/service/impl/HuaweiPaymentServiceImpl.java b/sf-payment/src/main/java/com/sf/payment/service/impl/HuaweiPaymentServiceImpl.java new file mode 100644 index 0000000..1a86679 --- /dev/null +++ b/sf-payment/src/main/java/com/sf/payment/service/impl/HuaweiPaymentServiceImpl.java @@ -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 bodyMap = new HashMap<>(); + bodyMap.put("purchaseToken", lastPurchaseOrder.getPurchaseToken()); + bodyMap.put("purchaseOrderId", lastPurchaseOrder.getPurchaseOrderId()); + // construct the Authorization in Header + Map 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 bodyMap = new HashMap<>(); + bodyMap.put("purchaseToken", appPurchaseOrderPayload.getPurchaseToken()); + bodyMap.put("purchaseOrderId", appPurchaseOrderPayload.getPurchaseOrderId()); + // construct the Authorization in Header + Map 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 buildAuthorization(String appId, Map body) { + Map jwtHeader = new HashMap<>(8); + jwtHeader.put("alg", "ES256"); + jwtHeader.put("typ", "JWT"); + jwtHeader.put("kid", "0ae3e1be-374b-43a5-a297-045addbf76eb"); + Map 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 headers = new HashMap<>(); + headers.put("Authorization", authorization); + headers.put("Content-Type", "application/json; charset=UTF-8"); + return headers; + } + + private static String getJwtPayloadDigest(Map 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中的productId、price、currency等信息的一致性 + * + * @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中的productId、price、currency等信息的一致性 + checkRes = checkProductIdAndPriceAndCurrency(content, orderInfo); + } + return checkRes; + } + + /** + * 校验InAppPurchaseData中的productId、price、currency等信息的一致性 + * + * @param content 结果字符串 + * @param orderInfo 您的订单信息,包括productId、price、currency + * @return 是否校验通过 + */ + public static boolean checkProductIdAndPriceAndCurrency(String content, OrderInfo orderInfo) { + InAppPurchaseData inAppPurchaseData = JSON.parseObject(content, InAppPurchaseData.class); + // 校验InAppPurchaseData中的productId、price、currency等信息的一致性 + 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; + } + +} diff --git a/sf-payment/src/main/java/com/sf/payment/utils/HuaweiTokenGenerator.java b/sf-payment/src/main/java/com/sf/payment/utils/HuaweiTokenGenerator.java new file mode 100644 index 0000000..4572ea6 --- /dev/null +++ b/sf-payment/src/main/java/com/sf/payment/utils/HuaweiTokenGenerator.java @@ -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 jwtHeader, Map 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); + } + } +} diff --git a/sf-payment/src/main/resources/IAPKey_0ae3e1be-374b-43a5-a297-045addbf76eb.p8 b/sf-payment/src/main/resources/IAPKey_0ae3e1be-374b-43a5-a297-045addbf76eb.p8 new file mode 100644 index 0000000..e1ebbeb --- /dev/null +++ b/sf-payment/src/main/resources/IAPKey_0ae3e1be-374b-43a5-a297-045addbf76eb.p8 @@ -0,0 +1,6 @@ +-----BEGIN PRIVATE KEY----- +MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQggG04243qynU/yWYy +XpYVy9ZWMuLKzZiwhXCBWQBCOLigCgYIKoZIzj0DAQehRANCAARNln2/d+TM2pIO +LWQzvI77gPAVEvVCSlIuiJ+J7CJSG5KCysBaEeiiD5cc4dZWnUBijF8FBh7nDLaH +VwFXfrS+ +-----END PRIVATE KEY----- diff --git a/sf-service/pom.xml b/sf-service/pom.xml new file mode 100644 index 0000000..84ffb42 --- /dev/null +++ b/sf-service/pom.xml @@ -0,0 +1,33 @@ + + + + smarterFramework + com.smarterFramework + 1.0.0 + + 4.0.0 + + sf-service + + + 业务模块 + + + + + + + com.smarterFramework + sf-common + + + com.smarterFramework + sf-framework + + + + + + \ No newline at end of file diff --git a/sf-admin/src/main/java/com/sf/goods/controller/GoodsMessagesController.java b/sf-service/src/main/java/com/sf/service/controller/GoodsMessagesController.java similarity index 83% rename from sf-admin/src/main/java/com/sf/goods/controller/GoodsMessagesController.java rename to sf-service/src/main/java/com/sf/service/controller/GoodsMessagesController.java index cd2ca0a..4117dab 100644 --- a/sf-admin/src/main/java/com/sf/goods/controller/GoodsMessagesController.java +++ b/sf-service/src/main/java/com/sf/service/controller/GoodsMessagesController.java @@ -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,9 +95,9 @@ public class GoodsMessagesController extends BaseController /** * 删除商品信息 */ - @PreAuthorize("@ss.hasPermi('goods:goods:remove')") + @PreAuthorize("@ss.hasPermi('service:goods:remove')") @Log(title = "商品信息", businessType = BusinessType.DELETE) - @DeleteMapping("/{ids}") + @DeleteMapping("/{ids}") public AjaxResult remove(@PathVariable Long[] ids) { return toAjax(goodsMessagesService.deleteGoodsMessagesByIds(ids)); diff --git a/sf-admin/src/main/java/com/sf/goods/domain/GoodsMessages.java b/sf-service/src/main/java/com/sf/service/domain/GoodsMessages.java similarity index 79% rename from sf-admin/src/main/java/com/sf/goods/domain/GoodsMessages.java rename to sf-service/src/main/java/com/sf/service/domain/GoodsMessages.java index 16a24a5..86c36bb 100644 --- a/sf-admin/src/main/java/com/sf/goods/domain/GoodsMessages.java +++ b/sf-service/src/main/java/com/sf/service/domain/GoodsMessages.java @@ -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(); } } diff --git a/sf-admin/src/main/java/com/sf/goods/mapper/GoodsMessagesMapper.java b/sf-service/src/main/java/com/sf/service/mapper/GoodsMessagesMapper.java similarity index 87% rename from sf-admin/src/main/java/com/sf/goods/mapper/GoodsMessagesMapper.java rename to sf-service/src/main/java/com/sf/service/mapper/GoodsMessagesMapper.java index dfb2188..02a2f1a 100644 --- a/sf-admin/src/main/java/com/sf/goods/mapper/GoodsMessagesMapper.java +++ b/sf-service/src/main/java/com/sf/service/mapper/GoodsMessagesMapper.java @@ -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); } diff --git a/sf-admin/src/main/java/com/sf/goods/service/IGoodsMessagesService.java b/sf-service/src/main/java/com/sf/service/service/IGoodsMessagesService.java similarity index 87% rename from sf-admin/src/main/java/com/sf/goods/service/IGoodsMessagesService.java rename to sf-service/src/main/java/com/sf/service/service/IGoodsMessagesService.java index 3f1c08a..29f7dab 100644 --- a/sf-admin/src/main/java/com/sf/goods/service/IGoodsMessagesService.java +++ b/sf-service/src/main/java/com/sf/service/service/IGoodsMessagesService.java @@ -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); } diff --git a/sf-admin/src/main/java/com/sf/goods/service/impl/GoodsMessagesServiceImpl.java b/sf-service/src/main/java/com/sf/service/service/impl/GoodsMessagesServiceImpl.java similarity index 80% rename from sf-admin/src/main/java/com/sf/goods/service/impl/GoodsMessagesServiceImpl.java rename to sf-service/src/main/java/com/sf/service/service/impl/GoodsMessagesServiceImpl.java index 45b7b42..0541ba8 100644 --- a/sf-admin/src/main/java/com/sf/goods/service/impl/GoodsMessagesServiceImpl.java +++ b/sf-service/src/main/java/com/sf/service/service/impl/GoodsMessagesServiceImpl.java @@ -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; + } } diff --git a/sf-admin/src/main/resources/mapper/goods/GoodsMessagesMapper.xml b/sf-service/src/main/resources/mapper/service/GoodsMessagesMapper.xml similarity index 76% rename from sf-admin/src/main/resources/mapper/goods/GoodsMessagesMapper.xml rename to sf-service/src/main/resources/mapper/service/GoodsMessagesMapper.xml index ffa20fa..3e55f20 100644 --- a/sf-admin/src/main/resources/mapper/goods/GoodsMessagesMapper.xml +++ b/sf-service/src/main/resources/mapper/service/GoodsMessagesMapper.xml @@ -1,118 +1,130 @@ - - - - - - - - - - - - - - - - - - - - - - - - - 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 - - - - - - - - - insert into GOODS_MESSAGES - - 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, - - - #{goodsCode}, - #{stockId}, - #{reviewStatus}, - #{productTitle}, - #{productPicture}, - #{originalPrice}, - #{productDesc}, - #{orderNum}, - #{isDelete}, - #{created}, - #{modified}, - #{createTime}, - #{updateTime}, - #{goodsType}, - #{goodsSpec}, - - - - - update GOODS_MESSAGES - - goods_code = #{goodsCode}, - stock_id = #{stockId}, - review_status = #{reviewStatus}, - product_title = #{productTitle}, - product_picture = #{productPicture}, - original_price = #{originalPrice}, - product_desc = #{productDesc}, - order_num = #{orderNum}, - is_delete = #{isDelete}, - created = #{created}, - modified = #{modified}, - create_time = #{createTime}, - update_time = #{updateTime}, - goods_type = #{goodsType}, - goods_spec = #{goodsSpec}, - - where id = #{id} - - - - delete from GOODS_MESSAGES where id = #{id} - - - - delete from GOODS_MESSAGES where id in - - #{id} - - + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + + + + + + + + insert into GOODS_MESSAGES + + 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, + + + #{goodsCode}, + #{stockId}, + #{reviewStatus}, + #{productTitle}, + #{productPicture}, + #{originalPrice}, + #{productDesc}, + #{goodsType}, + #{goodsSpec}, + #{orderNum}, + #{isDelete}, + #{created}, + #{modified}, + #{createTime}, + #{updateTime}, + #{goodsName}, + #{goodsModel}, + + + + + update GOODS_MESSAGES + + goods_code = #{goodsCode}, + stock_id = #{stockId}, + review_status = #{reviewStatus}, + product_title = #{productTitle}, + product_picture = #{productPicture}, + original_price = #{originalPrice}, + product_desc = #{productDesc}, + goods_type = #{goodsType}, + goods_spec = #{goodsSpec}, + order_num = #{orderNum}, + is_delete = #{isDelete}, + created = #{created}, + modified = #{modified}, + create_time = #{createTime}, + update_time = #{updateTime}, + goods_name = #{goodsName}, + goods_model = #{goodsModel}, + + where id = #{id} + + + + delete from GOODS_MESSAGES where id = #{id} + + + + delete from GOODS_MESSAGES where id in + + #{id} + + \ No newline at end of file diff --git a/sf-system/src/main/java/com/sf/system/domain/UserMember.java b/sf-system/src/main/java/com/sf/system/domain/UserMember.java new file mode 100644 index 0000000..e298567 --- /dev/null +++ b/sf-system/src/main/java/com/sf/system/domain/UserMember.java @@ -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(); + } +} diff --git a/sf-system/src/main/java/com/sf/system/mapper/UserMemberMapper.java b/sf-system/src/main/java/com/sf/system/mapper/UserMemberMapper.java new file mode 100644 index 0000000..f5ad663 --- /dev/null +++ b/sf-system/src/main/java/com/sf/system/mapper/UserMemberMapper.java @@ -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 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); +} diff --git a/sf-system/src/main/java/com/sf/system/service/IUserMemberService.java b/sf-system/src/main/java/com/sf/system/service/IUserMemberService.java new file mode 100644 index 0000000..8e40f1a --- /dev/null +++ b/sf-system/src/main/java/com/sf/system/service/IUserMemberService.java @@ -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 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); +} diff --git a/sf-system/src/main/java/com/sf/system/service/impl/UserMemberServiceImpl.java b/sf-system/src/main/java/com/sf/system/service/impl/UserMemberServiceImpl.java new file mode 100644 index 0000000..6c2890c --- /dev/null +++ b/sf-system/src/main/java/com/sf/system/service/impl/UserMemberServiceImpl.java @@ -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 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); + } +} diff --git a/sf-system/src/main/resources/mapper/system/UserMemberMapper.xml b/sf-system/src/main/resources/mapper/system/UserMemberMapper.xml new file mode 100644 index 0000000..3c8a8a0 --- /dev/null +++ b/sf-system/src/main/resources/mapper/system/UserMemberMapper.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + select id, member_level, subscription_status, user_id, create_time, update_time, integration, expiration_time from User_member + + + + + + + + + + insert into User_member + + member_level, + subscription_status, + user_id, + create_time, + update_time, + integration, + expiration_time, + + + #{memberLevel}, + #{subscriptionStatus}, + #{userId}, + #{createTime}, + #{updateTime}, + #{integration}, + #{expirationTime}, + + + + + update User_member + + member_level = #{memberLevel}, + subscription_status = #{subscriptionStatus}, + user_id = #{userId}, + create_time = #{createTime}, + update_time = #{updateTime}, + integration = #{integration}, + expiration_time = #{expirationTime}, + + where id = #{id} + + + + delete from User_member where id = #{id} + + + + delete from User_member where id in + + #{id} + + + \ No newline at end of file diff --git a/sf-ui/src/api/goods/goods.js b/sf-ui/src/api/service/goods.js similarity index 76% rename from sf-ui/src/api/goods/goods.js rename to sf-ui/src/api/service/goods.js index 68f58bc..ce3cca2 100644 --- a/sf-ui/src/api/goods/goods.js +++ b/sf-ui/src/api/service/goods.js @@ -1,44 +1,44 @@ -import request from '@/utils/request' - -// 查询商品信息列表 -export function listGoods(query) { - return request({ - url: '/goods/goods/list', - method: 'get', - params: query - }) -} - -// 查询商品信息详细 -export function getGoods(id) { - return request({ - url: '/goods/goods/' + id, - method: 'get' - }) -} - -// 新增商品信息 -export function addGoods(data) { - return request({ - url: '/goods/goods', - method: 'post', - data: data - }) -} - -// 修改商品信息 -export function updateGoods(data) { - return request({ - url: '/goods/goods', - method: 'put', - data: data - }) -} - -// 删除商品信息 -export function delGoods(id) { - return request({ - url: '/goods/goods/' + id, - method: 'delete' - }) -} +import request from '@/utils/request' + +// 查询商品信息列表 +export function listGoods(query) { + return request({ + url: '/service/goods/list', + method: 'get', + params: query + }) +} + +// 查询商品信息详细 +export function getGoods(id) { + return request({ + url: '/service/goods/' + id, + method: 'get' + }) +} + +// 新增商品信息 +export function addGoods(data) { + return request({ + url: '/service/goods', + method: 'post', + data: data + }) +} + +// 修改商品信息 +export function updateGoods(data) { + return request({ + url: '/service/goods', + method: 'put', + data: data + }) +} + +// 删除商品信息 +export function delGoods(id) { + return request({ + url: '/service/goods/' + id, + method: 'delete' + }) +} diff --git a/sf-ui/src/views/goods/goods/index.vue b/sf-ui/src/views/service/goods/index.vue similarity index 67% rename from sf-ui/src/views/goods/goods/index.vue rename to sf-ui/src/views/service/goods/index.vue index 819c794..c8bf789 100644 --- a/sf-ui/src/views/goods/goods/index.vue +++ b/sf-ui/src/views/service/goods/index.vue @@ -1,348 +1,423 @@ - - - + + +