package com.alatus.mall.order.template; import com.alatus.mall.order.vo.PayVo; import com.alipay.api.AlipayApiException; import com.alipay.api.AlipayClient; import com.alipay.api.DefaultAlipayClient; import com.alipay.api.request.AlipayTradePagePayRequest; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; @Component @Data @ConfigurationProperties(prefix = "alatusmall.alipay") public class AlipayTemplate { public String app_id; public String merchant_private_key; public String alipay_public_key; public String notify_url; public String return_url; public String sign_type; public String charset; public String gatewayUrl; public String log_path; public String pay(PayVo payVo) throws AlipayApiException { //获得初始化的AlipayClient AlipayClient alipayClient = new DefaultAlipayClient(gatewayUrl,app_id,merchant_private_key, "json",charset,alipay_public_key,sign_type); //设置请求参数 AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest(); alipayRequest.setReturnUrl(return_url); alipayRequest.setNotifyUrl(notify_url); //商户订单号,商户网站订单系统中唯一订单号,必填 String out_trade_no = payVo.getOut_trade_no(); //付款金额,必填 String total_amount = payVo.getTotal_amount(); //订单名称,必填 String subject = payVo.getSubject(); //商品描述,可空 String body = payVo.getBody(); alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no +"\"," + "\"total_amount\":\""+ total_amount +"\"," + "\"subject\":\""+ subject +"\"," + "\"body\":\""+ body +"\"," + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}"); //请求 return alipayClient.pageExecute(alipayRequest).getBody(); } }
package com.alatus.mall.order.template; import com.alatus.mall.order.vo.PayVo; import com.alipay.api.AlipayApiException; import com.alipay.api.AlipayClient; import com.alipay.api.DefaultAlipayClient; import com.alipay.api.request.AlipayTradePagePayRequest; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; @Component @Data @ConfigurationProperties(prefix = "alatusmall.alipay") public class AlipayTemplate { public String app_id; public String merchant_private_key; public String alipay_public_key; public String notify_url; public String return_url; public String sign_type; public String charset; public String gatewayUrl; public String log_path; public String pay(PayVo payVo) throws AlipayApiException { //获得初始化的AlipayClient AlipayClient alipayClient = new DefaultAlipayClient(gatewayUrl,app_id,merchant_private_key, "json",charset,alipay_public_key,sign_type); //设置请求参数 AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest(); alipayRequest.setReturnUrl(return_url); alipayRequest.setNotifyUrl(notify_url); //商户订单号,商户网站订单系统中唯一订单号,必填 String out_trade_no = payVo.getOut_trade_no(); //付款金额,必填 String total_amount = payVo.getTotal_amount(); //订单名称,必填 String subject = payVo.getSubject(); //商品描述,可空 String body = payVo.getBody(); alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no +"\"," + "\"total_amount\":\""+ total_amount +"\"," + "\"subject\":\""+ subject +"\"," + "\"body\":\""+ body +"\"," + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}"); //请求 return alipayClient.pageExecute(alipayRequest).getBody(); } }
package com.alatus.mall.order.web; import com.alatus.mall.order.service.OrderService; import com.alatus.mall.order.template.AlipayTemplate; import com.alipay.api.AlipayApiException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class PayWebController { @Autowired private OrderService orderService; @Autowired private AlipayTemplate alipayTemplate; @GetMapping(value = "/payOrder",produces = "text/html") @ResponseBody public String payOrder(@RequestParam("orderSn")String orderSn) throws AlipayApiException { return alipayTemplate.pay(orderService.getOrderPay(orderSn)); } }
package com.alatus.mall.order.web; import com.alatus.mall.order.service.OrderService; import com.alatus.mall.order.template.AlipayTemplate; import com.alipay.api.AlipayApiException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class PayWebController { @Autowired private OrderService orderService; @Autowired private AlipayTemplate alipayTemplate; @GetMapping(value = "/payOrder",produces = "text/html") @ResponseBody public String payOrder(@RequestParam("orderSn")String orderSn) throws AlipayApiException { return alipayTemplate.pay(orderService.getOrderPay(orderSn)); } }
package com.alatus.mall.order.service; import com.alatus.mall.order.vo.OrderConfirmVo; import com.alatus.mall.order.vo.OrderSubmitVo; import com.alatus.mall.order.vo.PayVo; import com.alatus.mall.order.vo.SubmitOrderResponseVo; import com.baomidou.mybatisplus.extension.service.IService; import com.alatus.common.utils.PageUtils; import com.alatus.mall.order.entity.OrderEntity; import java.math.BigDecimal; import java.util.Map; import java.util.concurrent.ExecutionException; /** * 订单 * * @author alatus * @email 1571345941@qq.com * @date 2024-03-12 13:50:51 */ public interface OrderService extends IService<OrderEntity> { PageUtils queryPage(Map<String, Object> params); OrderConfirmVo confirmOrder() throws ExecutionException, InterruptedException; BigDecimal changeAddr(Long addrId) throws ExecutionException, InterruptedException; SubmitOrderResponseVo submitOrder(OrderSubmitVo orderSubmitVo); OrderEntity getOrderByOrderSn(String orderSn); void closeOrder(OrderEntity order); PayVo getOrderPay(String orderSn); PageUtils queryPageWithItem(Map<String, Object> params); }
package com.alatus.mall.order.service; import com.alatus.mall.order.vo.OrderConfirmVo; import com.alatus.mall.order.vo.OrderSubmitVo; import com.alatus.mall.order.vo.PayVo; import com.alatus.mall.order.vo.SubmitOrderResponseVo; import com.baomidou.mybatisplus.extension.service.IService; import com.alatus.common.utils.PageUtils; import com.alatus.mall.order.entity.OrderEntity; import java.math.BigDecimal; import java.util.Map; import java.util.concurrent.ExecutionException; /** * 订单 * * @author alatus * @email 1571345941@qq.com * @date 2024-03-12 13:50:51 */ public interface OrderService extends IService<OrderEntity> { PageUtils queryPage(Map<String, Object> params); OrderConfirmVo confirmOrder() throws ExecutionException, InterruptedException; BigDecimal changeAddr(Long addrId) throws ExecutionException, InterruptedException; SubmitOrderResponseVo submitOrder(OrderSubmitVo orderSubmitVo); OrderEntity getOrderByOrderSn(String orderSn); void closeOrder(OrderEntity order); PayVo getOrderPay(String orderSn); PageUtils queryPageWithItem(Map<String, Object> params); }
package com.alatus.mall.order.service.impl; import com.alatus.common.exception.NoStockException; import com.alatus.common.to.MemberAddressTo; import com.alatus.common.to.mq.OrderTo; import com.alatus.common.utils.R; import com.alatus.common.vo.MemberRespVo; import com.alatus.common.vo.OrderItemVo; import com.alatus.common.vo.SkuHasStockVo; import com.alatus.mall.order.config.RabbitMQConfigProperties; import com.alatus.mall.order.entity.OrderItemEntity; import com.alatus.mall.order.enums.OrderStatusEnum; import com.alatus.mall.order.feign.ProductFeignService; import com.alatus.mall.order.service.OrderItemService; import com.alatus.mall.order.to.OrderCreateTo; import com.alatus.mall.order.constant.OrderConstant; import com.alatus.mall.order.feign.CartFeignService; import com.alatus.mall.order.feign.MemberFeignService; import com.alatus.mall.order.feign.WareFeignService; import com.alatus.mall.order.interceptor.LoginUserInterceptor; import com.alatus.mall.order.vo.*; import com.alibaba.fastjson.TypeReference; import com.baomidou.mybatisplus.core.toolkit.IdWorker; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.script.DefaultRedisScript; import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.alatus.common.utils.PageUtils; import com.alatus.common.utils.Query; import com.alatus.mall.order.dao.OrderDao; import com.alatus.mall.order.entity.OrderEntity; import com.alatus.mall.order.service.OrderService; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; @Service("orderService") public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService { @Autowired private MemberFeignService memberFeignService; @Autowired private CartFeignService cartFeignService; @Autowired private OrderItemService orderItemService; @Autowired private ThreadPoolExecutor threadPoolExecutor; @Autowired private WareFeignService wareFeignService; @Autowired private StringRedisTemplate redisTemplate; @Autowired private ProductFeignService productFeignService; @Autowired private RabbitTemplate rabbitTemplate; @Autowired private RabbitMQConfigProperties rabbitMQConfigProperties; private ThreadLocal<OrderSubmitVo> submitVoThreadLocal = new ThreadLocal<>(); @Override public PageUtils queryPage(Map<String, Object> params) { IPage<OrderEntity> page = this.page( new Query<OrderEntity>().getPage(params), new QueryWrapper<OrderEntity>() ); return new PageUtils(page); } @Override public OrderConfirmVo confirmOrder() throws ExecutionException, InterruptedException { OrderConfirmVo confirmVo = new OrderConfirmVo(); // 获取原请求信息,避免异步导致丢失 RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); MemberRespVo memberRespVo = LoginUserInterceptor.loginUser.get(); // 远程查询购物车所有选中的购物项 CompletableFuture<Void> itemVoList = CompletableFuture.runAsync(() -> { RequestContextHolder.setRequestAttributes(requestAttributes); confirmVo.setItemVoList(cartFeignService.getCurrentCartItem()); }, threadPoolExecutor).thenRunAsync(()->{ // 获取原请求信息,避免异步导致丢失 RequestContextHolder.setRequestAttributes(requestAttributes); // 查询库存 List<OrderItemVo> itemList = confirmVo.getItemVoList(); List<Long> ids = itemList.stream().map(OrderItemVo::getSkuId).collect(Collectors.toList()); R skuHasStock = wareFeignService.getSkuHasStock(ids); if(skuHasStock.getCode()==0){ List<SkuHasStockVo> data = skuHasStock.getData(new TypeReference<List<SkuHasStockVo>>(){}); if(data!=null&& !data.isEmpty()){ Map<Long, Boolean> collect = data.stream().collect(Collectors.toMap(SkuHasStockVo::getSkuId, SkuHasStockVo::getHasStock)); confirmVo.setStocks(collect); } } },threadPoolExecutor); // 远程查询所有的用户地址列表 CompletableFuture<Void> addressTask = CompletableFuture.runAsync(() -> { RequestContextHolder.setRequestAttributes(requestAttributes); confirmVo.setAddress(memberFeignService.getAddress(memberRespVo.getId())); }, threadPoolExecutor).thenRunAsync(()->{ // 获取运费信息 RequestContextHolder.setRequestAttributes(requestAttributes); List<MemberAddressTo> address = confirmVo.getAddress(); for (MemberAddressTo memberAddressTo : address) { if(memberAddressTo.getDefaultStatus()==1){ R fare = wareFeignService.getFare(memberAddressTo.getId()); if (fare.getCode()==0) { confirmVo.setFare(fare.getData(new TypeReference<BigDecimal>() {})); } } } },threadPoolExecutor); // 用户积分 CompletableFuture<Void> integrationTask = CompletableFuture.runAsync(() -> { confirmVo.setIntegration(memberRespVo.getIntegration()); }, threadPoolExecutor); // TODO 订单令牌 // 订单令牌 CompletableFuture<Void> tokenTask = CompletableFuture.runAsync(() -> { String token = UUID.randomUUID().toString().replace("-", ""); confirmVo.setOrderToken(token); redisTemplate.opsForValue().set(OrderConstant.USER_ORDER_TOKEN_PREFIX + memberRespVo.getId(), token, 30, TimeUnit.MINUTES); }, threadPoolExecutor); CompletableFuture.allOf(addressTask,itemVoList,integrationTask,tokenTask).get(); return confirmVo; } @Override public BigDecimal changeAddr(Long addrId) throws ExecutionException, InterruptedException { // 获取原请求信息,避免异步导致丢失 RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); MemberRespVo memberRespVo = LoginUserInterceptor.loginUser.get(); CompletableFuture<Void> changeAddr = CompletableFuture.runAsync(() -> { RequestContextHolder.setRequestAttributes(requestAttributes); R r = memberFeignService.changeAddr(memberRespVo.getId(), addrId); if (r.getCode() != 0) { throw new RuntimeException("修改失败"); } }, threadPoolExecutor); // 查询新的运费信息 CompletableFuture<BigDecimal> getFareTask = CompletableFuture.supplyAsync(() -> { RequestContextHolder.setRequestAttributes(requestAttributes); R fare = wareFeignService.getFare(addrId); if (fare.getCode() == 0) { BigDecimal farePay = fare.getData(new TypeReference<BigDecimal>() {}); return farePay; } else{ return new BigDecimal(0); } }, threadPoolExecutor); CompletableFuture.allOf(changeAddr,getFareTask).get(); return getFareTask.get(); } @Override @Transactional public SubmitOrderResponseVo submitOrder(OrderSubmitVo orderSubmitVo) { SubmitOrderResponseVo responseVo = new SubmitOrderResponseVo(); submitVoThreadLocal.set(orderSubmitVo); // 获取当前登录用户 MemberRespVo memberRespVo = LoginUserInterceptor.loginUser.get(); responseVo.setCode(0); // 验证令牌是否合法,验证和删除必须保证原子性 String orderToken = orderSubmitVo.getOrderToken(); String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; // 原子删除锁和验证 Long result = redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class),Arrays.asList(OrderConstant.USER_ORDER_TOKEN_PREFIX + memberRespVo.getId()),orderToken); if(result == 0L){ // 令牌验证失败 responseVo.setCode(1); return responseVo; } else{ // 令牌验证成功 OrderCreateTo order = createOrder(); BigDecimal payAmount = order.getOrderEntity().getPayAmount(); BigDecimal payPrice = orderSubmitVo.getPayPrice(); if(Math.abs(payAmount.subtract(payPrice).doubleValue())<0.01){ // 金额对比成功 // 保存订单 saveOrder(order); // 锁定库存,只要没锁到,就抛异常让它回滚 WareSkuLockVo wareSkuLockVo = new WareSkuLockVo(); wareSkuLockVo.setOrderSn(order.getOrderEntity().getOrderSn()); List<OrderItemVo> orderItemVoList = order.getOrderItemEntities().stream().map(orderItemEntity -> { OrderItemVo orderItemVo = new OrderItemVo(); orderItemVo.setSkuId(orderItemEntity.getSkuId()); orderItemVo.setCount(orderItemEntity.getSkuQuantity()); orderItemVo.setTitle(orderItemEntity.getSkuName()); return orderItemVo; }).collect(Collectors.toList()); wareSkuLockVo.setLocks(orderItemVoList); R stockResult = wareFeignService.orderLockStock(wareSkuLockVo); // 订单号,skuId,skuName if (stockResult.getCode()==0) { // 锁定成功 responseVo.setOrderEntity(order.getOrderEntity()); // TODO 远程扣除积分 // 订单发送消息给MQ rabbitTemplate.convertAndSend(rabbitMQConfigProperties.getExchange(),rabbitMQConfigProperties.getCreateKey(),order.getOrderEntity()); return responseVo; } else{ // 锁定失败 throw new NoStockException(0L); } } else{ responseVo.setCode(2); return responseVo; } } } @Override public OrderEntity getOrderByOrderSn(String orderSn) { return this.getOne(new QueryWrapper<OrderEntity>().eq("order_sn",orderSn)); } @Override public void closeOrder(OrderEntity order) { OrderEntity orderEntity = this.getById(order.getId()); // 关单状态 if(orderEntity.getStatus()==OrderStatusEnum.CREATE_NEW.getCode()){ OrderEntity entity = new OrderEntity(); entity.setId(orderEntity.getId()); entity.setStatus(OrderStatusEnum.CANCLED.getCode()); this.updateById(entity); // 发送给MQ解锁库存消息 OrderTo orderTo = new OrderTo(); BeanUtils.copyProperties(orderEntity,orderTo); try{ // 发一条消息应该做一次记录到日志 rabbitTemplate.convertAndSend(rabbitMQConfigProperties.getExchange(),rabbitMQConfigProperties.getStockReleaseKey(),orderTo); }catch (Exception e){ // TODO 没发送成功的消息要重新发送 rabbitTemplate.convertAndSend(rabbitMQConfigProperties.getExchange(),rabbitMQConfigProperties.getStockReleaseKey(),orderTo); } } } @Override public PayVo getOrderPay(String orderSn) { // 获取当前订单的支付信息 PayVo payVo = new PayVo(); payVo.setTotal_amount(this.getOrderByOrderSn(orderSn).getPayAmount().setScale(2,BigDecimal.ROUND_UP).toString()); payVo.setOut_trade_no(orderSn); List<OrderItemEntity> orderItems = orderItemService.getItemsByOrderSn(orderSn); OrderItemEntity orderItemEntity = orderItems.get(0); payVo.setSubject(orderItemEntity.getSpuName()); payVo.setBody(orderItemEntity.getSkuAttrsVals()); return payVo; } @Override public PageUtils queryPageWithItem(Map<String, Object> params) { Long id = LoginUserInterceptor.loginUser.get().getId(); IPage<OrderEntity> page = this.page( new Query<OrderEntity>().getPage(params), new QueryWrapper<OrderEntity>().eq("member_id",id) .orderByDesc("id") ); // 转换为 OrderConfirmVo 分页信息 IPage<OrderCreateTo> orderSn = page.convert(orderEntity -> { OrderCreateTo orderPageVo = new OrderCreateTo(); orderPageVo.setOrderEntity(orderEntity); // 获取订单项返回 List<OrderItemEntity> orderItemEntities = orderItemService.list(new QueryWrapper<OrderItemEntity>().eq("order_sn", orderEntity.getOrderSn())); orderPageVo.setOrderItemEntities(orderItemEntities); // 额外的字段转换 orderPageVo.setFare(orderEntity.getFreightAmount()); orderPageVo.setPayPrice(orderEntity.getTotalAmount()); return orderPageVo; }); return new PageUtils(orderSn); } private void saveOrder(OrderCreateTo order) { OrderEntity orderEntity = order.getOrderEntity(); List<OrderItemEntity> orderItemEntities = order.getOrderItemEntities(); orderEntity.setModifyTime(new Date()); save(orderEntity); orderItemService.saveBatch(orderItemEntities); } // 创建订单 private OrderCreateTo createOrder(){ OrderCreateTo orderCreateTo = new OrderCreateTo(); // 利用mybatisPlus的IdWorker生成一个不会重复的订单号 String orderSn = IdWorker.getTimeId(); // 构建订单 OrderEntity orderEntity = buildOrder(orderSn); orderCreateTo.setOrderEntity(orderEntity); // 设置订单项 List<OrderItemEntity> orderItemEntities = buildOrderItems(orderSn); orderCreateTo.setOrderItemEntities(orderItemEntities); // 验证价格 if(!orderItemEntities.isEmpty()){ computePrice(orderEntity,orderItemEntities); } return orderCreateTo; } // 计算价格 private void computePrice(OrderEntity orderEntity, List<OrderItemEntity> orderItemEntities) { // 订单价格相关 BigDecimal totalAmount = new BigDecimal("0.0"); // 优惠卷 BigDecimal coupon = new BigDecimal("0.0"); // 积分 BigDecimal integration = new BigDecimal("0.0"); // 折扣 BigDecimal promotion = new BigDecimal("0.0"); Integer giftIntegration = 0; Integer giftGrowth = 0; for (OrderItemEntity orderItemEntity : orderItemEntities) { totalAmount = totalAmount.add(orderItemEntity.getRealAmount()); coupon = coupon.add(orderItemEntity.getCouponAmount()); integration = integration.add(orderItemEntity.getIntegrationAmount()); promotion = promotion.add(orderItemEntity.getPromotionAmount()); giftIntegration += orderItemEntity.getGiftIntegration(); giftGrowth += orderItemEntity.getGiftGrowth(); } // 设置总额 orderEntity.setTotalAmount(totalAmount); orderEntity.setPromotionAmount(promotion); orderEntity.setCouponAmount(coupon); orderEntity.setIntegrationAmount(integration); // 设置积分和成长值 orderEntity.setGrowth(giftGrowth); orderEntity.setIntegration(giftIntegration); // 设置订单删除状态 orderEntity.setDeleteStatus(0); // 加上运费就是最终总价 orderEntity.setPayAmount(totalAmount.add(orderEntity.getFreightAmount())); } // 构建订单项 private List<OrderItemEntity> buildOrderItems(String orderSn) { // 获取购物车订单项 List<OrderItemVo> currentCartItem = cartFeignService.getCurrentCartItem(); if(!currentCartItem.isEmpty()){ return currentCartItem.stream().map(cartItem -> { // 最后一次再确认订单购物项价格 OrderItemEntity orderItemEntity = buildOrderItem(cartItem); orderItemEntity.setOrderSn(orderSn); return orderItemEntity; }).collect(Collectors.toList()); } return null; } // 构建每一个订单项 private OrderItemEntity buildOrderItem(OrderItemVo cartItem) { OrderItemEntity orderItemEntity = new OrderItemEntity(); // 订单信息,订单号 // 商品的SPU信息 R spuInfo = productFeignService.getSpuInfoBySkuId(cartItem.getSkuId()); SpuInfoVo spuInfoData = spuInfo.getData(new TypeReference<SpuInfoVo>(){}); orderItemEntity.setSpuPic(cartItem.getImage()); orderItemEntity.setSpuBrand(spuInfoData.getBrandId().toString()); orderItemEntity.setSpuId(spuInfoData.getId()); orderItemEntity.setSpuName(spuInfoData.getSpuName()); orderItemEntity.setCategoryId(spuInfoData.getCatalogId()); // 商品的SKU信息 orderItemEntity.setSkuId(cartItem.getSkuId()); orderItemEntity.setSkuName(cartItem.getTitle()); orderItemEntity.setSkuPic(cartItem.getImage()); orderItemEntity.setSkuPrice(cartItem.getPrice()); orderItemEntity.setSkuAttrsVals(StringUtils.collectionToDelimitedString(cartItem.getSkuAttr(),";")); orderItemEntity.setSkuQuantity(cartItem.getCount()); // 积分信息 orderItemEntity.setGiftGrowth(cartItem.getPrice().intValue()*cartItem.getCount()); orderItemEntity.setGiftIntegration(cartItem.getPrice().intValue()*cartItem.getCount()); // 总价 // TODO 商品的优惠信息 // 促销 orderItemEntity.setPromotionAmount(new BigDecimal("0.0")); // 优惠卷 orderItemEntity.setCouponAmount(new BigDecimal("0.0")); // 积分优惠 orderItemEntity.setIntegrationAmount(new BigDecimal("0.0")); // 最终价格 BigDecimal price = orderItemEntity.getSkuPrice().multiply(new BigDecimal(orderItemEntity.getSkuQuantity())); // 减去所有的优惠信息 price = price.subtract(orderItemEntity.getPromotionAmount()).subtract(orderItemEntity.getCouponAmount()).subtract(orderItemEntity.getIntegrationAmount()); orderItemEntity.setRealAmount(price); return orderItemEntity; } private OrderEntity buildOrder(String orderSn){ // 获取当前登录用户 MemberRespVo memberRespVo = LoginUserInterceptor.loginUser.get(); OrderEntity entity = new OrderEntity(); entity.setMemberId(memberRespVo.getId()); entity.setMemberUsername(memberRespVo.getUsername()); // 设置订单号 entity.setOrderSn(orderSn); // 获取物流收货地址信息 OrderSubmitVo orderSubmitVo = submitVoThreadLocal.get(); // 设置运费信息 R fareData = wareFeignService.getFare(orderSubmitVo.getAddrId()); BigDecimal fare = fareData.get("data", new TypeReference<BigDecimal>(){}); entity.setFreightAmount(fare); // 获取用户当前收货默认地址 MemberAddressTo defaultAddr = memberFeignService.getDefaultAddr(memberRespVo.getId()); entity.setReceiverCity(defaultAddr.getCity()); entity.setReceiverDetailAddress(defaultAddr.getDetailAddress()); entity.setReceiverName(defaultAddr.getName()); entity.setReceiverPhone(defaultAddr.getPhone()); entity.setReceiverPostCode(defaultAddr.getPostCode()); entity.setReceiverProvince(defaultAddr.getProvince()); entity.setReceiverRegion(defaultAddr.getRegion()); // 设置订单相关状态 entity.setStatus(OrderStatusEnum.CREATE_NEW.getCode()); entity.setAutoConfirmDay(7); return entity; } }
package com.alatus.mall.order.service.impl; import com.alatus.common.exception.NoStockException; import com.alatus.common.to.MemberAddressTo; import com.alatus.common.to.mq.OrderTo; import com.alatus.common.utils.R; import com.alatus.common.vo.MemberRespVo; import com.alatus.common.vo.OrderItemVo; import com.alatus.common.vo.SkuHasStockVo; import com.alatus.mall.order.config.RabbitMQConfigProperties; import com.alatus.mall.order.entity.OrderItemEntity; import com.alatus.mall.order.enums.OrderStatusEnum; import com.alatus.mall.order.feign.ProductFeignService; import com.alatus.mall.order.service.OrderItemService; import com.alatus.mall.order.to.OrderCreateTo; import com.alatus.mall.order.constant.OrderConstant; import com.alatus.mall.order.feign.CartFeignService; import com.alatus.mall.order.feign.MemberFeignService; import com.alatus.mall.order.feign.WareFeignService; import com.alatus.mall.order.interceptor.LoginUserInterceptor; import com.alatus.mall.order.vo.*; import com.alibaba.fastjson.TypeReference; import com.baomidou.mybatisplus.core.toolkit.IdWorker; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.script.DefaultRedisScript; import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.alatus.common.utils.PageUtils; import com.alatus.common.utils.Query; import com.alatus.mall.order.dao.OrderDao; import com.alatus.mall.order.entity.OrderEntity; import com.alatus.mall.order.service.OrderService; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; @Service("orderService") public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService { @Autowired private MemberFeignService memberFeignService; @Autowired private CartFeignService cartFeignService; @Autowired private OrderItemService orderItemService; @Autowired private ThreadPoolExecutor threadPoolExecutor; @Autowired private WareFeignService wareFeignService; @Autowired private StringRedisTemplate redisTemplate; @Autowired private ProductFeignService productFeignService; @Autowired private RabbitTemplate rabbitTemplate; @Autowired private RabbitMQConfigProperties rabbitMQConfigProperties; private ThreadLocal<OrderSubmitVo> submitVoThreadLocal = new ThreadLocal<>(); @Override public PageUtils queryPage(Map<String, Object> params) { IPage<OrderEntity> page = this.page( new Query<OrderEntity>().getPage(params), new QueryWrapper<OrderEntity>() ); return new PageUtils(page); } @Override public OrderConfirmVo confirmOrder() throws ExecutionException, InterruptedException { OrderConfirmVo confirmVo = new OrderConfirmVo(); // 获取原请求信息,避免异步导致丢失 RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); MemberRespVo memberRespVo = LoginUserInterceptor.loginUser.get(); // 远程查询购物车所有选中的购物项 CompletableFuture<Void> itemVoList = CompletableFuture.runAsync(() -> { RequestContextHolder.setRequestAttributes(requestAttributes); confirmVo.setItemVoList(cartFeignService.getCurrentCartItem()); }, threadPoolExecutor).thenRunAsync(()->{ // 获取原请求信息,避免异步导致丢失 RequestContextHolder.setRequestAttributes(requestAttributes); // 查询库存 List<OrderItemVo> itemList = confirmVo.getItemVoList(); List<Long> ids = itemList.stream().map(OrderItemVo::getSkuId).collect(Collectors.toList()); R skuHasStock = wareFeignService.getSkuHasStock(ids); if(skuHasStock.getCode()==0){ List<SkuHasStockVo> data = skuHasStock.getData(new TypeReference<List<SkuHasStockVo>>(){}); if(data!=null&& !data.isEmpty()){ Map<Long, Boolean> collect = data.stream().collect(Collectors.toMap(SkuHasStockVo::getSkuId, SkuHasStockVo::getHasStock)); confirmVo.setStocks(collect); } } },threadPoolExecutor); // 远程查询所有的用户地址列表 CompletableFuture<Void> addressTask = CompletableFuture.runAsync(() -> { RequestContextHolder.setRequestAttributes(requestAttributes); confirmVo.setAddress(memberFeignService.getAddress(memberRespVo.getId())); }, threadPoolExecutor).thenRunAsync(()->{ // 获取运费信息 RequestContextHolder.setRequestAttributes(requestAttributes); List<MemberAddressTo> address = confirmVo.getAddress(); for (MemberAddressTo memberAddressTo : address) { if(memberAddressTo.getDefaultStatus()==1){ R fare = wareFeignService.getFare(memberAddressTo.getId()); if (fare.getCode()==0) { confirmVo.setFare(fare.getData(new TypeReference<BigDecimal>() {})); } } } },threadPoolExecutor); // 用户积分 CompletableFuture<Void> integrationTask = CompletableFuture.runAsync(() -> { confirmVo.setIntegration(memberRespVo.getIntegration()); }, threadPoolExecutor); // TODO 订单令牌 // 订单令牌 CompletableFuture<Void> tokenTask = CompletableFuture.runAsync(() -> { String token = UUID.randomUUID().toString().replace("-", ""); confirmVo.setOrderToken(token); redisTemplate.opsForValue().set(OrderConstant.USER_ORDER_TOKEN_PREFIX + memberRespVo.getId(), token, 30, TimeUnit.MINUTES); }, threadPoolExecutor); CompletableFuture.allOf(addressTask,itemVoList,integrationTask,tokenTask).get(); return confirmVo; } @Override public BigDecimal changeAddr(Long addrId) throws ExecutionException, InterruptedException { // 获取原请求信息,避免异步导致丢失 RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); MemberRespVo memberRespVo = LoginUserInterceptor.loginUser.get(); CompletableFuture<Void> changeAddr = CompletableFuture.runAsync(() -> { RequestContextHolder.setRequestAttributes(requestAttributes); R r = memberFeignService.changeAddr(memberRespVo.getId(), addrId); if (r.getCode() != 0) { throw new RuntimeException("修改失败"); } }, threadPoolExecutor); // 查询新的运费信息 CompletableFuture<BigDecimal> getFareTask = CompletableFuture.supplyAsync(() -> { RequestContextHolder.setRequestAttributes(requestAttributes); R fare = wareFeignService.getFare(addrId); if (fare.getCode() == 0) { BigDecimal farePay = fare.getData(new TypeReference<BigDecimal>() {}); return farePay; } else{ return new BigDecimal(0); } }, threadPoolExecutor); CompletableFuture.allOf(changeAddr,getFareTask).get(); return getFareTask.get(); } @Override @Transactional public SubmitOrderResponseVo submitOrder(OrderSubmitVo orderSubmitVo) { SubmitOrderResponseVo responseVo = new SubmitOrderResponseVo(); submitVoThreadLocal.set(orderSubmitVo); // 获取当前登录用户 MemberRespVo memberRespVo = LoginUserInterceptor.loginUser.get(); responseVo.setCode(0); // 验证令牌是否合法,验证和删除必须保证原子性 String orderToken = orderSubmitVo.getOrderToken(); String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; // 原子删除锁和验证 Long result = redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class),Arrays.asList(OrderConstant.USER_ORDER_TOKEN_PREFIX + memberRespVo.getId()),orderToken); if(result == 0L){ // 令牌验证失败 responseVo.setCode(1); return responseVo; } else{ // 令牌验证成功 OrderCreateTo order = createOrder(); BigDecimal payAmount = order.getOrderEntity().getPayAmount(); BigDecimal payPrice = orderSubmitVo.getPayPrice(); if(Math.abs(payAmount.subtract(payPrice).doubleValue())<0.01){ // 金额对比成功 // 保存订单 saveOrder(order); // 锁定库存,只要没锁到,就抛异常让它回滚 WareSkuLockVo wareSkuLockVo = new WareSkuLockVo(); wareSkuLockVo.setOrderSn(order.getOrderEntity().getOrderSn()); List<OrderItemVo> orderItemVoList = order.getOrderItemEntities().stream().map(orderItemEntity -> { OrderItemVo orderItemVo = new OrderItemVo(); orderItemVo.setSkuId(orderItemEntity.getSkuId()); orderItemVo.setCount(orderItemEntity.getSkuQuantity()); orderItemVo.setTitle(orderItemEntity.getSkuName()); return orderItemVo; }).collect(Collectors.toList()); wareSkuLockVo.setLocks(orderItemVoList); R stockResult = wareFeignService.orderLockStock(wareSkuLockVo); // 订单号,skuId,skuName if (stockResult.getCode()==0) { // 锁定成功 responseVo.setOrderEntity(order.getOrderEntity()); // TODO 远程扣除积分 // 订单发送消息给MQ rabbitTemplate.convertAndSend(rabbitMQConfigProperties.getExchange(),rabbitMQConfigProperties.getCreateKey(),order.getOrderEntity()); return responseVo; } else{ // 锁定失败 throw new NoStockException(0L); } } else{ responseVo.setCode(2); return responseVo; } } } @Override public OrderEntity getOrderByOrderSn(String orderSn) { return this.getOne(new QueryWrapper<OrderEntity>().eq("order_sn",orderSn)); } @Override public void closeOrder(OrderEntity order) { OrderEntity orderEntity = this.getById(order.getId()); // 关单状态 if(orderEntity.getStatus()==OrderStatusEnum.CREATE_NEW.getCode()){ OrderEntity entity = new OrderEntity(); entity.setId(orderEntity.getId()); entity.setStatus(OrderStatusEnum.CANCLED.getCode()); this.updateById(entity); // 发送给MQ解锁库存消息 OrderTo orderTo = new OrderTo(); BeanUtils.copyProperties(orderEntity,orderTo); try{ // 发一条消息应该做一次记录到日志 rabbitTemplate.convertAndSend(rabbitMQConfigProperties.getExchange(),rabbitMQConfigProperties.getStockReleaseKey(),orderTo); }catch (Exception e){ // TODO 没发送成功的消息要重新发送 rabbitTemplate.convertAndSend(rabbitMQConfigProperties.getExchange(),rabbitMQConfigProperties.getStockReleaseKey(),orderTo); } } } @Override public PayVo getOrderPay(String orderSn) { // 获取当前订单的支付信息 PayVo payVo = new PayVo(); payVo.setTotal_amount(this.getOrderByOrderSn(orderSn).getPayAmount().setScale(2,BigDecimal.ROUND_UP).toString()); payVo.setOut_trade_no(orderSn); List<OrderItemEntity> orderItems = orderItemService.getItemsByOrderSn(orderSn); OrderItemEntity orderItemEntity = orderItems.get(0); payVo.setSubject(orderItemEntity.getSpuName()); payVo.setBody(orderItemEntity.getSkuAttrsVals()); return payVo; } @Override public PageUtils queryPageWithItem(Map<String, Object> params) { Long id = LoginUserInterceptor.loginUser.get().getId(); IPage<OrderEntity> page = this.page( new Query<OrderEntity>().getPage(params), new QueryWrapper<OrderEntity>().eq("member_id",id) .orderByDesc("id") ); // 转换为 OrderConfirmVo 分页信息 IPage<OrderCreateTo> orderSn = page.convert(orderEntity -> { OrderCreateTo orderPageVo = new OrderCreateTo(); orderPageVo.setOrderEntity(orderEntity); // 获取订单项返回 List<OrderItemEntity> orderItemEntities = orderItemService.list(new QueryWrapper<OrderItemEntity>().eq("order_sn", orderEntity.getOrderSn())); orderPageVo.setOrderItemEntities(orderItemEntities); // 额外的字段转换 orderPageVo.setFare(orderEntity.getFreightAmount()); orderPageVo.setPayPrice(orderEntity.getTotalAmount()); return orderPageVo; }); return new PageUtils(orderSn); } private void saveOrder(OrderCreateTo order) { OrderEntity orderEntity = order.getOrderEntity(); List<OrderItemEntity> orderItemEntities = order.getOrderItemEntities(); orderEntity.setModifyTime(new Date()); save(orderEntity); orderItemService.saveBatch(orderItemEntities); } // 创建订单 private OrderCreateTo createOrder(){ OrderCreateTo orderCreateTo = new OrderCreateTo(); // 利用mybatisPlus的IdWorker生成一个不会重复的订单号 String orderSn = IdWorker.getTimeId(); // 构建订单 OrderEntity orderEntity = buildOrder(orderSn); orderCreateTo.setOrderEntity(orderEntity); // 设置订单项 List<OrderItemEntity> orderItemEntities = buildOrderItems(orderSn); orderCreateTo.setOrderItemEntities(orderItemEntities); // 验证价格 if(!orderItemEntities.isEmpty()){ computePrice(orderEntity,orderItemEntities); } return orderCreateTo; } // 计算价格 private void computePrice(OrderEntity orderEntity, List<OrderItemEntity> orderItemEntities) { // 订单价格相关 BigDecimal totalAmount = new BigDecimal("0.0"); // 优惠卷 BigDecimal coupon = new BigDecimal("0.0"); // 积分 BigDecimal integration = new BigDecimal("0.0"); // 折扣 BigDecimal promotion = new BigDecimal("0.0"); Integer giftIntegration = 0; Integer giftGrowth = 0; for (OrderItemEntity orderItemEntity : orderItemEntities) { totalAmount = totalAmount.add(orderItemEntity.getRealAmount()); coupon = coupon.add(orderItemEntity.getCouponAmount()); integration = integration.add(orderItemEntity.getIntegrationAmount()); promotion = promotion.add(orderItemEntity.getPromotionAmount()); giftIntegration += orderItemEntity.getGiftIntegration(); giftGrowth += orderItemEntity.getGiftGrowth(); } // 设置总额 orderEntity.setTotalAmount(totalAmount); orderEntity.setPromotionAmount(promotion); orderEntity.setCouponAmount(coupon); orderEntity.setIntegrationAmount(integration); // 设置积分和成长值 orderEntity.setGrowth(giftGrowth); orderEntity.setIntegration(giftIntegration); // 设置订单删除状态 orderEntity.setDeleteStatus(0); // 加上运费就是最终总价 orderEntity.setPayAmount(totalAmount.add(orderEntity.getFreightAmount())); } // 构建订单项 private List<OrderItemEntity> buildOrderItems(String orderSn) { // 获取购物车订单项 List<OrderItemVo> currentCartItem = cartFeignService.getCurrentCartItem(); if(!currentCartItem.isEmpty()){ return currentCartItem.stream().map(cartItem -> { // 最后一次再确认订单购物项价格 OrderItemEntity orderItemEntity = buildOrderItem(cartItem); orderItemEntity.setOrderSn(orderSn); return orderItemEntity; }).collect(Collectors.toList()); } return null; } // 构建每一个订单项 private OrderItemEntity buildOrderItem(OrderItemVo cartItem) { OrderItemEntity orderItemEntity = new OrderItemEntity(); // 订单信息,订单号 // 商品的SPU信息 R spuInfo = productFeignService.getSpuInfoBySkuId(cartItem.getSkuId()); SpuInfoVo spuInfoData = spuInfo.getData(new TypeReference<SpuInfoVo>(){}); orderItemEntity.setSpuPic(cartItem.getImage()); orderItemEntity.setSpuBrand(spuInfoData.getBrandId().toString()); orderItemEntity.setSpuId(spuInfoData.getId()); orderItemEntity.setSpuName(spuInfoData.getSpuName()); orderItemEntity.setCategoryId(spuInfoData.getCatalogId()); // 商品的SKU信息 orderItemEntity.setSkuId(cartItem.getSkuId()); orderItemEntity.setSkuName(cartItem.getTitle()); orderItemEntity.setSkuPic(cartItem.getImage()); orderItemEntity.setSkuPrice(cartItem.getPrice()); orderItemEntity.setSkuAttrsVals(StringUtils.collectionToDelimitedString(cartItem.getSkuAttr(),";")); orderItemEntity.setSkuQuantity(cartItem.getCount()); // 积分信息 orderItemEntity.setGiftGrowth(cartItem.getPrice().intValue()*cartItem.getCount()); orderItemEntity.setGiftIntegration(cartItem.getPrice().intValue()*cartItem.getCount()); // 总价 // TODO 商品的优惠信息 // 促销 orderItemEntity.setPromotionAmount(new BigDecimal("0.0")); // 优惠卷 orderItemEntity.setCouponAmount(new BigDecimal("0.0")); // 积分优惠 orderItemEntity.setIntegrationAmount(new BigDecimal("0.0")); // 最终价格 BigDecimal price = orderItemEntity.getSkuPrice().multiply(new BigDecimal(orderItemEntity.getSkuQuantity())); // 减去所有的优惠信息 price = price.subtract(orderItemEntity.getPromotionAmount()).subtract(orderItemEntity.getCouponAmount()).subtract(orderItemEntity.getIntegrationAmount()); orderItemEntity.setRealAmount(price); return orderItemEntity; } private OrderEntity buildOrder(String orderSn){ // 获取当前登录用户 MemberRespVo memberRespVo = LoginUserInterceptor.loginUser.get(); OrderEntity entity = new OrderEntity(); entity.setMemberId(memberRespVo.getId()); entity.setMemberUsername(memberRespVo.getUsername()); // 设置订单号 entity.setOrderSn(orderSn); // 获取物流收货地址信息 OrderSubmitVo orderSubmitVo = submitVoThreadLocal.get(); // 设置运费信息 R fareData = wareFeignService.getFare(orderSubmitVo.getAddrId()); BigDecimal fare = fareData.get("data", new TypeReference<BigDecimal>(){}); entity.setFreightAmount(fare); // 获取用户当前收货默认地址 MemberAddressTo defaultAddr = memberFeignService.getDefaultAddr(memberRespVo.getId()); entity.setReceiverCity(defaultAddr.getCity()); entity.setReceiverDetailAddress(defaultAddr.getDetailAddress()); entity.setReceiverName(defaultAddr.getName()); entity.setReceiverPhone(defaultAddr.getPhone()); entity.setReceiverPostCode(defaultAddr.getPostCode()); entity.setReceiverProvince(defaultAddr.getProvince()); entity.setReceiverRegion(defaultAddr.getRegion()); // 设置订单相关状态 entity.setStatus(OrderStatusEnum.CREATE_NEW.getCode()); entity.setAutoConfirmDay(7); return entity; } }
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title></title> <link rel="stylesheet" href="/static/order/pay/css/style.css"> <script src="/static/order/pay/js/jquery-3.1.1.min.js" charset="utf-8"></script> </head> <body> <div class="One_Jdbox"> <div class="Jdbox_head"> <img src="/static/order/pay/img/logo1.jpg" alt=""><span class="bank">收银台</span> <ul> <li><span>[[${session.get('loginUser').getNickname()}]]</span><span>退出</span></li> <li>我的订单</li> <li>支付帮助</li> </ul> </div> <div class="Jdbox_BuySuc"> <dl> <dt><img src="/static/order/pay/img/saoyisao.png" alt=""></dt> <dd> <span>订单提交成功,请尽快付款!订单号:[[${submitOrder.getOrderEntity().getOrderSn()}]]</span> <span>应付金额<font>[[${#numbers.formatDecimal(submitOrder.getOrderEntity().getPayAmount(),1,2)}]]</font>元</span> </dd> <dd> <span>推荐使用</span> <span>扫码支付请您在<font>24小时</font>内完成支付,否则订单会被自动取消(库存紧订单请参见详情页时限)</span> <span>订单详细</span> </dd> </dl> </div> <div class="Jd_Con"> <p class="JdCon_title"><img src="/static/order/pay/img/title.png" alt=""></p> <div class="Jd_Fenqi"> <ul> <li><img src="/static/order/pay/img/BAITIAO_2.0.png" alt="">打白条</li> <li> <span>可用额度 7275.38元</span> <span>白条还款日 2018-01-27</span> <span><font>优惠</font>随机立减(最高10元)</span> </li> <li>支付<font>28.90</font>元</li> </ul> <ol> <li> <p>不分期</p> <p>0服务费</p> </li> <li> <p>3期</p> <p>9.48元/期</p> </li> <li> <p>6期</p> <p>4.94元/期</p> </li> <li> <p>12期</p> <p>2.35元/期</p> </li> <li> <p>24期</p> <p>1.44元/期</p> </li> </ol> </div> <div class="Jd_main"> <ul> <li> <span> <img src="/static/order/pay/img/XJKCONSUME.png" alt="">谷粒学院小金库 </span> <span>未开通小金库</span> </li> <li> <span> <img src="/static/order/pay/img/CMB.png" alt="">招商银行 </span> <span>信用卡(4337)</span> <span><font>优惠</font>单单减最高99元</span> </li> <li> <button>更多付款方式</button> <button>添加新卡/网银支付</button> </li> <li> <p>请输入6位数字支付密码</p> <input type="password"><span>忘记支付密码?</span> </li> <li> <button>立即支付</button> </li> </ul> </div> </div> <div class="Jd_footer"> <ul> <a> <li> <img src="/static/order/pay/img/weixin.png" alt="">微信支付 </li> </a> <a th:href="'http://order.alatusmall.com/payOrder?orderSn='+${submitOrder.getOrderEntity().getOrderSn()}"> <li> <img src="/static/order/pay/img/zhifubao.png" style="weight:auto;height:30px;" alt="">支付宝 </li> </a> </ul> </div> <div class="Jd_foots"> <p> <span>Copyright @2004-2017 谷粒学院gulimall.com 版权所有</span> <span> <img src="/static/order/pay/img/foots.png" alt=""> </span> </p> </div> </div> </body> <script type="text/javascript"> //头部订单成功 订单详细鼠标移入效果 $(".Jdbox_BuySuc dl dd:last-child span:last-child").mouseover(function(){ $(this).css({"cursor":"pointer","color":"#E31613"}) }).mouseout(function(){ $(this).css("color","#7EA4FF") }) //分期付款鼠标移入hover效果 $(".Jd_Fenqi>ol li:not(:first-child)").mouseover(function(){ $(this).css({"cursor":"pointer","border":"1px solid #E31613"}) }).mouseout(function(){ $(this).css("border","1px solid #C9DFFF") }) //支付方式按钮选择hover效果 $(".Jd_main ul li:nth-child(3) button").mouseover(function(){ $(this).css({"cursor":"pointer","color":"#E31613"}) }).mouseout(function(){ $(this).css("color","#67A4FF") }) //忘记密码鼠标移入效果 $(".Jd_main ul li:nth-child(4) span").mouseover(function(){ $(this).css({"cursor":"pointer","color":"#E31613"}) }).mouseout(function(){ $(this).css("color","#67A4FF") }) //立即支付按钮效果 $(".Jd_main ul li:nth-child(5) button").mouseover(function(){ $(this).css({"cursor":"pointer","background":"#FF5350"}) }).mouseout(function(){ $(this).css("background","#FC6E6C") }) $(".Jd_footer ul li").mouseover(function(){ $(this).css({"cursor":"pointer","color":"#E31613"}) }).mouseout(function(){ $(this).css("color","#5E5E5E") }) $(".Jdbox_head>ul li span").mouseover(function(){ $(this).css({"cursor":"pointer","color":"#E31613"}) }).mouseout(function(){ $(this).css("color","#666666") }) $(".Jdbox_head>ul li:not(:first-child)").mouseover(function(){ $(this).css({"cursor":"pointer","color":"#E31613"}) }).mouseout(function(){ $(this).css("color","#666666") }) $(".Jd_Fenqi ul li:first-child").mouseover(function(){ $(this).css({"cursor":"pointer","color":"#666666"}) }).mouseout(function(){ $(this).css({"color":"black"}) }) </script> </html>
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title></title> <link rel="stylesheet" href="/static/order/pay/css/style.css"> <script src="/static/order/pay/js/jquery-3.1.1.min.js" charset="utf-8"></script> </head> <body> <div class="One_Jdbox"> <div class="Jdbox_head"> <img src="/static/order/pay/img/logo1.jpg" alt=""><span class="bank">收银台</span> <ul> <li><span>[[${session.get('loginUser').getNickname()}]]</span><span>退出</span></li> <li>我的订单</li> <li>支付帮助</li> </ul> </div> <div class="Jdbox_BuySuc"> <dl> <dt><img src="/static/order/pay/img/saoyisao.png" alt=""></dt> <dd> <span>订单提交成功,请尽快付款!订单号:[[${submitOrder.getOrderEntity().getOrderSn()}]]</span> <span>应付金额<font>[[${#numbers.formatDecimal(submitOrder.getOrderEntity().getPayAmount(),1,2)}]]</font>元</span> </dd> <dd> <span>推荐使用</span> <span>扫码支付请您在<font>24小时</font>内完成支付,否则订单会被自动取消(库存紧订单请参见详情页时限)</span> <span>订单详细</span> </dd> </dl> </div> <div class="Jd_Con"> <p class="JdCon_title"><img src="/static/order/pay/img/title.png" alt=""></p> <div class="Jd_Fenqi"> <ul> <li><img src="/static/order/pay/img/BAITIAO_2.0.png" alt="">打白条</li> <li> <span>可用额度 7275.38元</span> <span>白条还款日 2018-01-27</span> <span><font>优惠</font>随机立减(最高10元)</span> </li> <li>支付<font>28.90</font>元</li> </ul> <ol> <li> <p>不分期</p> <p>0服务费</p> </li> <li> <p>3期</p> <p>9.48元/期</p> </li> <li> <p>6期</p> <p>4.94元/期</p> </li> <li> <p>12期</p> <p>2.35元/期</p> </li> <li> <p>24期</p> <p>1.44元/期</p> </li> </ol> </div> <div class="Jd_main"> <ul> <li> <span> <img src="/static/order/pay/img/XJKCONSUME.png" alt="">谷粒学院小金库 </span> <span>未开通小金库</span> </li> <li> <span> <img src="/static/order/pay/img/CMB.png" alt="">招商银行 </span> <span>信用卡(4337)</span> <span><font>优惠</font>单单减最高99元</span> </li> <li> <button>更多付款方式</button> <button>添加新卡/网银支付</button> </li> <li> <p>请输入6位数字支付密码</p> <input type="password"><span>忘记支付密码?</span> </li> <li> <button>立即支付</button> </li> </ul> </div> </div> <div class="Jd_footer"> <ul> <a> <li> <img src="/static/order/pay/img/weixin.png" alt="">微信支付 </li> </a> <a th:href="'http://order.alatusmall.com/payOrder?orderSn='+${submitOrder.getOrderEntity().getOrderSn()}"> <li> <img src="/static/order/pay/img/zhifubao.png" style="weight:auto;height:30px;" alt="">支付宝 </li> </a> </ul> </div> <div class="Jd_foots"> <p> <span>Copyright @2004-2017 谷粒学院gulimall.com 版权所有</span> <span> <img src="/static/order/pay/img/foots.png" alt=""> </span> </p> </div> </div> </body> <script type="text/javascript"> //头部订单成功 订单详细鼠标移入效果 $(".Jdbox_BuySuc dl dd:last-child span:last-child").mouseover(function(){ $(this).css({"cursor":"pointer","color":"#E31613"}) }).mouseout(function(){ $(this).css("color","#7EA4FF") }) //分期付款鼠标移入hover效果 $(".Jd_Fenqi>ol li:not(:first-child)").mouseover(function(){ $(this).css({"cursor":"pointer","border":"1px solid #E31613"}) }).mouseout(function(){ $(this).css("border","1px solid #C9DFFF") }) //支付方式按钮选择hover效果 $(".Jd_main ul li:nth-child(3) button").mouseover(function(){ $(this).css({"cursor":"pointer","color":"#E31613"}) }).mouseout(function(){ $(this).css("color","#67A4FF") }) //忘记密码鼠标移入效果 $(".Jd_main ul li:nth-child(4) span").mouseover(function(){ $(this).css({"cursor":"pointer","color":"#E31613"}) }).mouseout(function(){ $(this).css("color","#67A4FF") }) //立即支付按钮效果 $(".Jd_main ul li:nth-child(5) button").mouseover(function(){ $(this).css({"cursor":"pointer","background":"#FF5350"}) }).mouseout(function(){ $(this).css("background","#FC6E6C") }) $(".Jd_footer ul li").mouseover(function(){ $(this).css({"cursor":"pointer","color":"#E31613"}) }).mouseout(function(){ $(this).css("color","#5E5E5E") }) $(".Jdbox_head>ul li span").mouseover(function(){ $(this).css({"cursor":"pointer","color":"#E31613"}) }).mouseout(function(){ $(this).css("color","#666666") }) $(".Jdbox_head>ul li:not(:first-child)").mouseover(function(){ $(this).css({"cursor":"pointer","color":"#E31613"}) }).mouseout(function(){ $(this).css("color","#666666") }) $(".Jd_Fenqi ul li:first-child").mouseover(function(){ $(this).css({"cursor":"pointer","color":"#666666"}) }).mouseout(function(){ $(this).css({"color":"black"}) }) </script> </html>