lsw 11 meses atrás
pai
commit
4ce0c827fd

+ 101 - 0
admin-ui/src/views/work/pay/edit.vue

@@ -0,0 +1,101 @@
+<template>
+  <div class="cmain">
+      <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+        <el-form-item label="充值人id" prop="userId">
+          <el-input v-model="form.userId" placeholder="请输入充值人id" clearable/>
+        </el-form-item>
+        <el-form-item label="充值编号" prop="nums">
+          <el-input v-model="form.nums" placeholder="请输入充值编号" clearable/>
+        </el-form-item>
+        <el-form-item label="充值金额" prop="money">
+          <el-input v-model="form.money" placeholder="请输入充值金额" clearable/>
+        </el-form-item>
+        <el-form-item label="状态" prop="state">
+          <el-input v-model="form.state" placeholder="请输入状态" clearable/>
+        </el-form-item>
+        <el-form-item label="充值无效原因" prop="msg">
+          <el-input v-model="form.msg" placeholder="请输入充值无效原因" clearable/>
+        </el-form-item>
+        <el-form-item label="乐观锁" prop="version">
+          <el-input v-model="form.version" placeholder="请输入乐观锁" clearable/>
+        </el-form-item>
+        <el-form-item label="创建时间" prop="createTime">
+          <el-date-picker clearable
+            v-model="form.createTime"
+            type="date"
+            value-format="yyyy-MM-dd"
+            placeholder="请选择创建时间">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="更新者" prop="updateBy">
+          <el-input v-model="form.updateBy" placeholder="请输入更新者" clearable/>
+        </el-form-item>
+        <el-form-item label="更新时间" prop="updateTime">
+          <el-date-picker clearable
+            v-model="form.updateTime"
+            type="date"
+            value-format="yyyy-MM-dd"
+            placeholder="请选择更新时间">
+          </el-date-picker>
+        </el-form-item>
+      </el-form>
+    <div class="mfooter">
+      <el-button type="primary" @click="submitForm">确 定</el-button>
+      <el-button @click="$layer.close(layerid)">取 消</el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      form: {},
+      rules: {
+        money: [
+          { required: true, message: "充值金额不能为空", trigger: "blur" }
+        ],
+      }
+    };
+  },
+  props: {
+    param: {
+      type: Object,
+      default: () => {
+        return {};
+      }
+    },
+    layerid: {
+      type: String
+    }
+  },
+  mounted() {
+    if (this.param.id) {
+      this.ajax({ url: '/work/pay/detail/' + this.param.id }).then(response => {
+        this.form = response.data;
+      });
+    }
+  },
+  methods: {
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id) {
+              this.ajax({method: 'post',url: '/work/pay/edit', data: this.form }).then(response => {
+                  this.$modal.msgSuccess("修改成功");
+                  this.$layer.close(this.layerid);
+                  this.$parent.getList();
+              });
+          } else {
+              this.ajax({method: 'post',url: '/work/pay/add', data: this.form }).then(response => {
+                  this.$modal.msgSuccess("新增成功");
+                  this.$layer.close(this.layerid);
+                  this.$parent.getList();
+               });
+          }
+        }
+      });
+    }
+  }
+};
+</script>

+ 119 - 0
admin-ui/src/views/work/pay/index.vue

@@ -0,0 +1,119 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" @submit.native.prevent v-show="showSearch">
+      <el-form-item label="充值人id" prop="userId">
+        <el-input v-model="queryParams.userId" placeholder="请输入充值人id"  @keyup.enter.native="handleQuery" clearable class="inp"/>
+      </el-form-item>
+      <el-form-item label="充值编号" prop="nums">
+        <el-input v-model="queryParams.nums" placeholder="请输入充值编号"  @keyup.enter.native="handleQuery" clearable class="inp"/>
+      </el-form-item>
+      <el-form-item label="充值金额" prop="money">
+        <el-input v-model="queryParams.money" placeholder="请输入充值金额"  @keyup.enter.native="handleQuery" clearable class="inp"/>
+      </el-form-item>
+      <el-form-item label="状态" prop="state">
+        <el-input v-model="queryParams.state" placeholder="请输入状态"  @keyup.enter.native="handleQuery" clearable class="inp"/>
+      </el-form-item>
+      <el-form-item label="充值无效原因" prop="msg">
+        <el-input v-model="queryParams.msg" placeholder="请输入充值无效原因"  @keyup.enter.native="handleQuery" clearable class="inp"/>
+      </el-form-item>
+      <el-form-item label="乐观锁" prop="version">
+        <el-input v-model="queryParams.version" placeholder="请输入乐观锁"  @keyup.enter.native="handleQuery" clearable class="inp"/>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+    <el-row :gutter="10" class="mb8">
+        <el-button type="primary" icon="el-icon-plus" :disabled="ids.length > 0" @click="op('add')" v-hasPermi="['work:pay:add']">新增</el-button>
+        <el-button type="success" icon="el-icon-edit" :disabled="ids.length != 1" @click="op('edit',ids)" v-hasPermi="['work:pay:edit']">修改</el-button>
+        <el-button type="danger" icon="el-icon-delete" :disabled="ids.length == 0" @click="del" v-hasPermi="['work:pay:remove']">删除{{ids.length>0?'('+ids.length+')':''}}</el-button>
+        <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table :data="response.rows" border @selection-change="selects" height="calc(100vh - 270px)">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="id" align="center" prop="id" />
+      <el-table-column label="充值人id" align="center" prop="userId" />
+      <el-table-column label="充值编号" align="center" prop="nums" />
+      <el-table-column label="充值金额" align="center" prop="money" />
+      <el-table-column label="状态" align="center" prop="state" />
+      <el-table-column label="充值无效原因" align="center" prop="msg" />
+      <el-table-column label="乐观锁" align="center" prop="version" />
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button size="mini" type="text" icon="el-icon-edit" @click="op('edit',scope.row)" v-hasPermi="['work:pay:edit']">修改</el-button>
+          <el-button size="mini" type="text" icon="el-icon-delete" @click="del(scope.row)" v-hasPermi="['work:pay:remove']">删除</el-button>
+        </template>
+      </el-table-column>
+      <template slot="empty">
+          <el-empty></el-empty>
+      </template>
+    </el-table>
+    <pagination v-if="response.total>0" :total="response.total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList"/>
+  </div>
+</template>
+
+<script>
+import edit from './edit'
+export default {
+  name: "Pay",
+  data() {
+    return {
+      ids: [],
+      showSearch:true,
+      response: {},
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        userId: null,
+        nums: null,
+        money: null,
+        state: null,
+        msg: null,
+        version: null,
+        orderByColumn: 'id',
+        isAsc: 'desc'
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    getList() {
+      this.ajax({ url: '/work/pay/list', data: this.queryParams }).then(response => {
+            this.response = response;
+      });
+    },
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    selects(rows) {
+      this.ids = rows.map(item => item.id)
+    },
+    op(tag, row) {
+          if (tag == 'add') {
+            this.iframe({ obj: edit, param: {}, title:'新增',width: '45%', height: '55%'});
+          }
+          if (tag == 'edit') {
+              const id = row.id || this.ids[0];
+              this.iframe({ obj: edit, param: {id: id}, title:'编辑',width: '50%', height: '50%'});
+          }
+    },
+    del(row) {
+        this.$confirm('是否确认删除选中数据?', '警告', { type: 'warning' }).then(() => {
+        this.get({ url: '/work/pay/remove/' + (row.id || this.ids) }).then(response => {
+                this.$modal.msgSuccess('删除成功');
+                this.getList();
+            });
+        });
+    }
+  }
+};
+</script>

+ 7 - 0
app/pages.json

@@ -253,6 +253,13 @@
 			{
 				"navigationBarTitleText" : "通知详情"
 			}
+		},
+		{
+			"path" : "pages/user/money/index",
+			"style" : 
+			{
+				"navigationBarTitleText" : "资金管理"
+			}
 		}
 	],
 	"tabBar": {

+ 9 - 7
app/pages/news/index.vue

@@ -4,13 +4,12 @@
 			<u-tabs :list="tab" :current="current" keyName="dictLabel" @click="click"></u-tabs>
 		</view>
 		<view class="list">
-			<view class="item" v-for="(item, index) in list" :key="index" @click="go('/pages/news/detail?id=' + item.id)">
+			<view class="item" :style="{backgroundImage:current==1?'url(https://chenglantimes.com/prod-api/profile/upload/2024/06/27/1719479106125.jpg)':'url(https://chenglantimes.com/prod-api/profile/upload/2024/06/27/1719480950166.jpg)'}" v-for="(item, index) in list" :key="index" @click="go('/pages/news/detail?id=' + item.id)">
 				<view class="title omit">
 					<text class="icon" v-if="item.top === 1">&#xe61f;</text>
 					<text>{{ item.title }}</text>
 				</view>
 				<view class="desc">
-					<text>{{ item.type }}</text>
 					<text>发布于 {{ item.createTime }}</text>
 				</view>
 			</view>
@@ -101,10 +100,14 @@ export default {
 .list {
 	padding: 12px;
 	.item {
-		background-color: white;
+		background-repeat: no-repeat;
+		background-size: cover;
+		background-position-y: bottom;
 		border-radius: 5px;
-		padding: 12px;
+		padding: 20px 12px 20px 12px;
 		margin-bottom: 10px;
+		overflow: hidden;
+		box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
 		.title {
 			font-size: 15px;
 			font-weight: bold;
@@ -115,10 +118,9 @@ export default {
 		}
 		.desc {
 			font-size: 14px;
-			color: $font-c;
-			padding-top: 7px;
+			padding-top: 15px;
 			text {
-				padding-right: 20px;
+				padding-right: 30px;
 			}
 		}
 	}

+ 3 - 2
app/pages/other/setting.vue

@@ -1,7 +1,7 @@
 <template>
 	<view class="main pt0">
 		<button class="btn" @click="exit()">退出登陆</button>
-		<!-- <button class="btn" @click="pay()">支付测试</button> -->
+		<button class="btn" @click="pay()">支付测试</button>
 	</view>
 </template>
 
@@ -15,6 +15,7 @@ export default {
 			this.http.request({
 				url: '/app/wxPay/jsApiPay',
 				method: 'POST',
+				data:{money:0.01},
 				success: (res) => {
 					wx.requestPayment({
 						appId: res.data.data.appId,
@@ -34,7 +35,7 @@ export default {
 							});
 						},
 						fail: (r) => {
-							console.log("asd:"+JSON.stringify(r));
+							uni.showModal({ content: r.data.msg, showCancel: false });
 						}
 					});
 				}

+ 19 - 0
app/pages/user/money/index.vue

@@ -0,0 +1,19 @@
+<template>
+	<view>
+		
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				
+			};
+		}
+	}
+</script>
+
+<style lang="scss">
+
+</style>

+ 3 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/work/api/config/InterceptorConfig.java

@@ -33,6 +33,9 @@ public class InterceptorConfig implements WebMvcConfigurer {
         registration.excludePathPatterns("/app/common/type/*"); //排除
         registration.excludePathPatterns("/app/common/agreement/*"); //排除
         registration.excludePathPatterns("/app/enterprise/list"); //排除
+        registration.excludePathPatterns("/app/wxPay/payNotify"); //排除
+        registration.excludePathPatterns("/app/wxPay/platformCert"); //排除
+        registration.excludePathPatterns("/app/wxPay/get"); //排除
     }
 
     @Override

+ 62 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/work/controller/PayController.java

@@ -0,0 +1,62 @@
+package com.ruoyi.web.work.controller;
+
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.web.work.domain.Pay;
+import com.ruoyi.web.work.service.IPayService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 微信在线充值记录
+ * @author lsw
+ * @date 2024-07-01
+ */
+@RestController
+@RequestMapping("/work/pay")
+public class PayController extends BaseController {
+    @Autowired
+    private IPayService payService;
+
+    @PreAuthorize("@ss.hasPermi('work:pay:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(Pay pay){
+        startPage();
+        List<Pay> list = payService.selectList(pay);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('work:pay:query')")
+    @GetMapping(value = "/detail/{id}")
+    public AjaxResult detail(@PathVariable("id") Long id){
+        return AjaxResult.success(payService.getById(id));
+    }
+
+    @PreAuthorize("@ss.hasPermi('work:pay:add')")
+    @Log(title = "微信在线充值记录", businessType = BusinessType.INSERT)
+    @PostMapping("/add")
+    public AjaxResult add(@RequestBody Pay pay){
+        return toAjax(payService.save(pay));
+    }
+
+    @PreAuthorize("@ss.hasPermi('work:pay:edit')")
+    @Log(title = "微信在线充值记录", businessType = BusinessType.UPDATE)
+    @PostMapping("/edit")
+    public AjaxResult edit(@RequestBody Pay pay){
+        return toAjax(payService.updateById(pay));
+    }
+
+    @PreAuthorize("@ss.hasPermi('work:pay:remove')")
+    @Log(title = "微信在线充值记录", businessType = BusinessType.DELETE)
+    @GetMapping("/remove/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids){
+        return toAjax(payService.removeByIds(Arrays.asList(ids)));
+    }
+}

+ 55 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/work/domain/Pay.java

@@ -0,0 +1,55 @@
+package com.ruoyi.web.work.domain;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.math.BigDecimal;
+import java.util.Date;
+/**
+ * @author lsw
+ * @date 2024-07-01
+ */
+@Data
+@TableName(value = "tb_pay")
+@Accessors(chain = true)
+public class Pay{
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    @ApiModelProperty(value = "充值人id")
+    private Long userId;
+
+    @ApiModelProperty(value = "充值编号")
+    private String nums;
+
+    @ApiModelProperty(value = "充值金额")
+    private BigDecimal money;
+
+    @ApiModelProperty(value = "状态:0=待充值,1=成功,2=失败")
+    private Integer state;
+
+    @ApiModelProperty(value = "充值无效原因")
+    private String msg;
+
+    @ApiModelProperty(value = "乐观锁")
+    private Long version;
+
+    @TableField(fill = FieldFill.INSERT)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+
+    @TableField(fill = FieldFill.UPDATE)
+    private String updateBy;
+
+    @TableField(fill = FieldFill.UPDATE)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date updateTime;
+
+
+}

+ 4 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/work/domain/User.java

@@ -8,6 +8,7 @@ import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 import lombok.experimental.Accessors;
 
+import java.math.BigDecimal;
 import java.util.Date;
 /**
  * @author lsw
@@ -81,6 +82,9 @@ public class User{
     @ApiModelProperty(value = "用户类型")
     private Integer type;
 
+    @ApiModelProperty(value = "余额")
+    private BigDecimal money;
+
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     @ApiModelProperty(value = "合同有效期")
     private Date contractDate;

+ 8 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/work/domain/dto/PayDto.java

@@ -2,6 +2,14 @@ package com.ruoyi.web.work.domain.dto;
 
 import lombok.Data;
 
+import javax.validation.constraints.Digits;
+import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+
 @Data
 public class PayDto {
+
+    @NotNull(message = "捐赠金额不能为空")
+    @Digits(integer = 10, fraction = 2, message = "金额只能包含最多两位小数")
+    private BigDecimal money;
 }

+ 17 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/work/mapper/PayMapper.java

@@ -0,0 +1,17 @@
+package com.ruoyi.web.work.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.web.work.domain.Pay;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * @author lsw
+ * @date 2024-07-01
+ */
+public interface PayMapper extends BaseMapper<Pay> {
+    List<Pay> selectList(Pay pay);
+
+    Pay selectByNums(@Param("nums") String nums);
+}

+ 16 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/work/service/IPayService.java

@@ -0,0 +1,16 @@
+package com.ruoyi.web.work.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.web.work.domain.Pay;
+
+import java.util.List;
+
+/**
+ * @author lsw
+ * @date 2024-07-01
+ */
+public interface IPayService extends IService<Pay>{
+    List<Pay> selectList(Pay pay);
+
+    Pay selectByNums(String nums);
+}

+ 30 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/work/service/impl/PayServiceImpl.java

@@ -0,0 +1,30 @@
+package com.ruoyi.web.work.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.web.work.domain.Pay;
+import com.ruoyi.web.work.mapper.PayMapper;
+import com.ruoyi.web.work.service.IPayService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * @author lsw
+ * @date 2024-07-01
+ */
+@Service
+public class PayServiceImpl extends ServiceImpl<PayMapper, Pay> implements IPayService {
+    @Autowired
+    private PayMapper payMapper;
+
+    @Override
+    public List<Pay> selectList(Pay pay) {
+        return payMapper.selectList(pay);
+    }
+
+    @Override
+    public Pay selectByNums(String nums) {
+        return payMapper.selectByNums(nums);
+    }
+}

+ 2 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/work/service/impl/UserServiceImpl.java

@@ -26,6 +26,7 @@ import org.springframework.core.env.Environment;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.math.BigDecimal;
 import java.util.List;
 
 /**
@@ -67,6 +68,7 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IU
             user.setIsCompany(0);
             user.setIsContract(0);
             user.setIsAuthentication(0);
+            user.setMoney(BigDecimal.ZERO);
             user.setState(0);
             user.setIsEnterprise(0);
             save(user);

+ 137 - 42
ruoyi-admin/src/main/java/com/ruoyi/web/work/wxpay/WxPayController.java

@@ -2,11 +2,13 @@ package com.ruoyi.web.work.wxpay;
 
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.http.ContentType;
+import cn.hutool.json.JSONArray;
 import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson2.JSONObject;
 import com.ijpay.core.IJPayHttpResponse;
 import com.ijpay.core.enums.AuthTypeEnum;
 import com.ijpay.core.enums.RequestMethodEnum;
+import com.ijpay.core.kit.AesUtil;
 import com.ijpay.core.kit.HttpKit;
 import com.ijpay.core.kit.PayKit;
 import com.ijpay.core.kit.WxPayKit;
@@ -14,15 +16,23 @@ import com.ijpay.core.utils.DateTimeZoneUtil;
 import com.ijpay.wxpay.WxPayApi;
 import com.ijpay.wxpay.enums.WxDomainEnum;
 import com.ijpay.wxpay.enums.v3.BasePayApiEnum;
+import com.ijpay.wxpay.enums.v3.CertAlgorithmTypeEnum;
 import com.ijpay.wxpay.model.v3.Amount;
 import com.ijpay.wxpay.model.v3.Payer;
 import com.ijpay.wxpay.model.v3.UnifiedOrderModel;
 import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.config.RuoYiConfig;
 import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.enums.BusinessType;
 import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.web.work.api.config.BaseController;
+import com.ruoyi.web.work.domain.Pay;
+import com.ruoyi.web.work.domain.User;
 import com.ruoyi.web.work.domain.dto.PayDto;
+import com.ruoyi.web.work.service.ICompanyService;
+import com.ruoyi.web.work.service.IPayService;
+import com.ruoyi.web.work.service.IUserService;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
@@ -30,10 +40,14 @@ import org.springframework.web.bind.annotation.*;
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-import java.beans.Transient;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileWriter;
+import java.math.BigDecimal;
 import java.nio.charset.StandardCharsets;
 import java.security.cert.X509Certificate;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 @RestController
@@ -42,9 +56,16 @@ public class WxPayController extends BaseController {
     @Resource
     WxPayBean wxPayV3Bean;
 
+    private String serialNo;
 
+    @Autowired
+    private IUserService userService;
 
-    private String serialNo;
+    @Autowired
+    private ICompanyService companyService;
+
+    @Autowired
+    private IPayService payService;
 
     /**
      * PC扫码支付
@@ -52,15 +73,11 @@ public class WxPayController extends BaseController {
      * @param dto
      * @return
      */
-    @Log(title = "在线捐赠", businessType = BusinessType.PAY)
+    @Log(title = "在线扫码支付", businessType = BusinessType.PAY)
     @PostMapping("/pay")
     @Transactional(rollbackFor = Exception.class)
     public AjaxResult pay(@Validated @RequestBody PayDto dto) {
         try {
-     /*       Project project = projectService.getById(dto.getProjectId());
-            if (project == null) {
-                return AjaxResult.error("捐赠项目不存在");
-            }*/
             String orderNum = PayKit.generateStr();
             UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel();
             unifiedOrderModel.setAppid(wxPayV3Bean.getAppId());
@@ -87,59 +104,122 @@ public class WxPayController extends BaseController {
             throw new ServiceException("系统异常");
         }
     }
+
+    @GetMapping("/get")
+    public AjaxResult v3Get() {
+        // 获取平台证书列表
+        try {
+            IJPayHttpResponse response = WxPayApi.v3(RequestMethodEnum.GET, WxDomainEnum.CHINA.toString(), CertAlgorithmTypeEnum.getCertSuffixUrl(CertAlgorithmTypeEnum.RSA.getCode()), wxPayV3Bean.getMchId(), getSerialNumber(), null, wxPayV3Bean.getKeyPath(), "", AuthTypeEnum.RSA.getCode());
+            Map<String, List<String>> headers = response.getHeaders();
+            String timestamp = response.getHeader("Wechatpay-Timestamp");
+            String nonceStr = response.getHeader("Wechatpay-Nonce");
+            String serialNumber = response.getHeader("Wechatpay-Serial");
+            String signature = response.getHeader("Wechatpay-Signature");
+
+            String body = response.getBody();
+            int status = response.getStatus();
+
+            int isOk = 200;
+            if (status == isOk) {
+                cn.hutool.json.JSONObject jsonObject = JSONUtil.parseObj(body);
+                JSONArray dataArray = jsonObject.getJSONArray("data");
+                // 默认认为只有一个平台证书
+                cn.hutool.json.JSONObject encryptObject = dataArray.getJSONObject(0);
+                cn.hutool.json.JSONObject encryptCertificate = encryptObject.getJSONObject("encrypt_certificate");
+                String associatedData = encryptCertificate.getStr("associated_data");
+                String cipherText = encryptCertificate.getStr("ciphertext");
+                String nonce = encryptCertificate.getStr("nonce");
+                String algorithm = encryptCertificate.getStr("algorithm");
+                String serialNo = encryptObject.getStr("serial_no");
+                final String platSerialNo = savePlatformCert(associatedData, nonce, cipherText, algorithm, new File(RuoYiConfig.getUploadPath() + "/platformCert.pem").toString());
+                // 根据证书序列号查询对应的证书来验证签名结果
+                boolean verifySignature = WxPayKit.verifySignature(response, wxPayV3Bean.getPlatformCertPath());
+                System.out.println("verifySignature:"+verifySignature);
+            }
+            return AjaxResult.success(body);
+        } catch (Exception e) {
+            System.out.println("asd:" + e.getMessage());
+            e.printStackTrace();
+            return AjaxResult.error();
+        }
+    }
+
+    private String savePlatformCert(String associatedData, String nonce, String cipherText, String algorithm, String certPath) {
+        try {
+            String key3 = wxPayV3Bean.getApiKey3();
+            String publicKey;
+            if (StrUtil.equals(algorithm, AuthTypeEnum.SM2.getPlatformCertAlgorithm())) {
+                publicKey = PayKit.sm4DecryptToString(key3, cipherText, nonce, associatedData);
+            } else {
+                AesUtil aesUtil = new AesUtil(wxPayV3Bean.getApiKey3().getBytes(StandardCharsets.UTF_8));
+                // 平台证书密文解密
+                // encrypt_certificate 中的  associated_data nonce  ciphertext
+                publicKey = aesUtil.decryptToString(associatedData.getBytes(StandardCharsets.UTF_8), nonce.getBytes(StandardCharsets.UTF_8), cipherText);
+            }
+            if (StrUtil.isNotEmpty(publicKey)) {
+                System.out.println("publicKey:" + publicKey);
+                // 保存证书
+                FileWriter writer = new FileWriter(certPath);
+                writer.write(publicKey);
+                // 获取平台证书序列号
+                X509Certificate certificate = PayKit.getCertificate(new ByteArrayInputStream(publicKey.getBytes()));
+                return certificate.getSerialNumber().toString(16).toUpperCase();
+            }
+            return "";
+        } catch (Exception e) {
+            return e.getMessage();
+        }
+    }
+
     /**
-     * 公众号或者订阅号支付
-     *
      * @param dto
      * @return
      */
     @PostMapping("/jsApiPay")
-    @Transient
-    public AjaxResult jsApiPay() {
+    public AjaxResult jsApiPay(@Validated @RequestBody PayDto dto) {
         try {
-/*            if (StringUtils.isEmpty(dto.getOpenId())) {
-                return AjaxResult.error("openId不能为空");
-            }
-            Project project = projectService.getById(dto.getProjectId());
-            if (project == null) {
-                return AjaxResult.error("捐赠项目不存在");
-            }*/
             String orderNum = PayKit.generateStr();
             UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel();
             unifiedOrderModel.setAppid(wxPayV3Bean.getAppId());
             unifiedOrderModel.setMchid(wxPayV3Bean.getMchId());
-            unifiedOrderModel.setDescription("测试支付");
+            unifiedOrderModel.setDescription("账户充值");
             unifiedOrderModel.setOut_trade_no(orderNum);
             unifiedOrderModel.setTime_expire(DateTimeZoneUtil.dateToTimeZone(System.currentTimeMillis() + 1000 * 60 * 3));
-            unifiedOrderModel.setAttach("爱心捐款");
-            unifiedOrderModel.setAmount(new Amount().setTotal(1));
+            unifiedOrderModel.setAttach("账户充值");
+            unifiedOrderModel.setAmount(new Amount().setTotal(dto.getMoney().multiply(new BigDecimal(100)).intValue()));
             unifiedOrderModel.setNotify_url(wxPayV3Bean.getDomain().concat("/app/wxPay/payNotify"));
             unifiedOrderModel.setPayer(new Payer().setOpenid(getUser().getOpenId()));
+            System.out.println("asd:" + getSerialNumber());
             IJPayHttpResponse response = WxPayApi.v3(RequestMethodEnum.POST, WxDomainEnum.CHINA.toString(), BasePayApiEnum.JS_API_PAY.toString(), wxPayV3Bean.getMchId(), getSerialNumber(), null, wxPayV3Bean.getKeyPath(), JSONUtil.toJsonStr(unifiedOrderModel));
             System.out.println("统一下单响应:" + response);
-            if (response.getStatus() == 200) {
+            boolean verifySignature = WxPayKit.verifySignature(response, wxPayV3Bean.getPlatformCertPath());
+            System.out.println("verifySignature:" + verifySignature);
+            if (response.getStatus() == 200 && verifySignature) {
                 String body = response.getBody();
                 JSONObject jsonObject = JSONObject.parseObject(body);
                 Map<String, String> map = WxPayKit.jsApiCreateSign(wxPayV3Bean.getAppId(), jsonObject.getString("prepay_id"), wxPayV3Bean.getKeyPath());
-                //保存支付订单
-               /* Donate donate = new Donate();
-                BeanUtils.copyProperties(dto, donate);
-                donate.setState(0);
-                donate.setOrderNum(orderNum);
-                donateService.save(donate);*/
+                //保存支付订单记录
+                Pay pay = new Pay();
+                pay.setUserId(getUser().getId());
+                pay.setMoney(dto.getMoney());
+                pay.setState(0);
+                pay.setVersion(System.currentTimeMillis());
+                pay.setNums(orderNum);
+                if (!payService.save(pay)) {
+                    return AjaxResult.error("充值失败,请联系平台");
+                }
                 return AjaxResult.success(map);
             }
-            return AjaxResult.error("系统异常222");
+            return AjaxResult.error("支付异常,请联系平台");
         } catch (Exception e) {
-            System.out.println("asd:"+e.getMessage());
             e.printStackTrace();
-            throw new ServiceException("系统异常");
+            throw new ServiceException(e.getMessage());
         }
     }
 
-    @Log(title = "在线捐赠通知", businessType = BusinessType.PAY)
+    @Transactional
     @PostMapping(value = "/payNotify")
-    public void payNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
+    public void payNotify(HttpServletRequest request, HttpServletResponse response) {
         Map<String, String> map = new HashMap<>(12);
         try {
             String timestamp = request.getHeader("Wechatpay-Timestamp");
@@ -147,19 +227,32 @@ public class WxPayController extends BaseController {
             String serialNo = request.getHeader("Wechatpay-Serial");
             String signature = request.getHeader("Wechatpay-Signature");
             String result = HttpKit.readData(request);
+            System.out.println("timestamp:" + timestamp);
+            System.out.println("nonce:" + nonce);
+            System.out.println("serialNo:" + serialNo);
+            System.out.println("serialNo2:" + getSerialNumber());
+            System.out.println("signature:" + signature);
+            //serialNo=getSerialNumber();
             // 需要通过证书序列号查找对应的证书,verifyNotify 中有验证证书的序列号
             JSONObject res = JSONObject.parseObject(WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp, wxPayV3Bean.getApiKey3(), wxPayV3Bean.getPlatformCertPath()));
             System.out.println("支付通知明文:" + res.toJSONString());
             if (res != null && res.getString("trade_state").equals("SUCCESS")) {
-/*               Donate donate = donateService.selectByOrderNum(res.getString("out_trade_no"));
-                if (donate != null) {
-                    donate.setState(1);
-                    donateService.clearCache();
-                    donateService.updateById(donate);
-                    response.setStatus(200);
-                    map.put("code", "SUCCESS");
-                    map.put("message", "SUCCESS");
-                }*/
+                //业务处理,更新订单信息
+                Pay pay = payService.selectByNums(res.getString("out_trade_no"));
+                if (pay != null && pay.getState() == 0) {
+                    pay.setState(1);
+                    User user = userService.getById(pay.getUserId());
+                    user.setMoney(user.getMoney().add(pay.getMoney()));
+                    if (payService.updateById(pay) && userService.updateById(user)) {
+                        response.setStatus(200);
+                        map.put("code", "SUCCESS");
+                        map.put("message", "SUCCESS");
+                    } else {
+                        response.setStatus(500);
+                        map.put("code", "ERROR");
+                        map.put("message", "支付失败");
+                    }
+                }
             } else {
                 response.setStatus(500);
                 map.put("code", "ERROR");
@@ -169,6 +262,8 @@ public class WxPayController extends BaseController {
             response.getOutputStream().write(JSONUtil.toJsonStr(map).getBytes(StandardCharsets.UTF_8));
             response.flushBuffer();
         } catch (Exception e) {
+            e.printStackTrace();
+            System.out.println("msg:" + e.getMessage());
             throw new ServiceException("系统异常");
         }
     }

+ 23 - 0
ruoyi-admin/src/main/resources/mapper/work/PayMapper.xml

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.web.work.mapper.PayMapper">
+    
+    <select id="selectList" resultType="com.ruoyi.web.work.domain.Pay">
+        select * from tb_pay
+        <where>  
+            <if test="userId != null "> and user_id = #{userId}</if>
+            <if test="nums != null  and nums != ''"> and nums = #{nums}</if>
+            <if test="money != null "> and money = #{money}</if>
+            <if test="state != null "> and state = #{state}</if>
+            <if test="msg != null  and msg != ''"> and msg = #{msg}</if>
+            <if test="version != null "> and version = #{version}</if>
+        </where>
+    </select>
+
+    <select id="selectByNums" resultType="com.ruoyi.web.work.domain.Pay">
+        SELECT * FROM tb_pay WHERE nums=#{nums}
+    </select>
+
+</mapper>

+ 20 - 21
ruoyi-admin/src/main/resources/wxpay/platformCert.pem

@@ -1,25 +1,24 @@
 -----BEGIN CERTIFICATE-----
-MIIELjCCAxagAwIBAgIUYH/jIVu7QRQ6MYMnOxh4lumJRK0wDQYJKoZIhvcNAQEL
+MIIEFDCCAvygAwIBAgIUXTl1ULvbUIA0N+M8QATSAi+j8sIwDQYJKoZIhvcNAQEL
 BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT
 FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg
-Q0EwHhcNMjQwNjIxMDgwNDMxWhcNMjkwNjIwMDgwNDMxWjCBhzETMBEGA1UEAwwK
-MTY3NzA4MzcwNDEbMBkGA1UECgwS5b6u5L+h5ZWG5oi357O757ufMTMwMQYDVQQL
-DCrlub/opb/mib/mj73ml7bku6PmlbDmja7mnI3liqHmnInpmZDlhazlj7gxCzAJ
-BgNVBAYTAkNOMREwDwYDVQQHDAhTaGVuWmhlbjCCASIwDQYJKoZIhvcNAQEBBQAD
-ggEPADCCAQoCggEBALR/VWHYZh9XlzPXBai3+NHxKacLTrcFi22J6o/P+H860D/W
-4BEkaya0hUwjO4bU3FD6zDGPLk7B6HWuvubPREBSfbnrGZ0sRNvu3D88kxmGTwcT
-k75T7XPva8e5i86CBIurqc2c7jh4Gt52vriQzlXSZb828fWn9iOEBZCOX750M5rM
-SgokbQ+qtNYDFkhwP54s/IQN+fP6vn0jeGnyhro8UdPy8tvdfhc+hvv5I1NxbLP8
-9Wd3MStJqj9h6YoGP/E4qmHGFQytizsPr11CmumFzHPh+Zf3loA+aPfhewfHjYf6
-HTSl5g7qpvTSOGNDUJaWNsdaFwgweCmglGTZHxsCAwEAAaOBuTCBtjAJBgNVHRME
-AjAAMAsGA1UdDwQEAwID+DCBmwYDVR0fBIGTMIGQMIGNoIGKoIGHhoGEaHR0cDov
-L2V2Y2EuaXRydXMuY29tLmNuL3B1YmxpYy9pdHJ1c2NybD9DQT0xQkQ0MjIwRTUw
-REJDMDRCMDZBRDM5NzU0OTg0NkMwMUMzRThFQkQyJnNnPUhBQ0M0NzFCNjU0MjJF
-MTJCMjdBOUQzM0E4N0FEMUNERjU5MjZFMTQwMzcxMA0GCSqGSIb3DQEBCwUAA4IB
-AQBqy3zGwJrXag0XwxYedTe7JnNZRMqP8EOV2kp6C9673UshladGyumDyHVoFoma
-fVBLunO6+xtz+janzMqUkpizSRDJVivBrp7H1X72uG6AglKygQqHfuAWaJCOroUj
-/IllF4FUU1v81hegH7XcOceW4B41OzxLtOiyas6MXz4NgNeoz5w1NiYu7yn1qI+1
-VX0QK0iCE+74wv1YTBDDIBIyDZI+5Sdz6s63ZPnoIKgeQ9VJ5OuBiluvLzo/SIp4
-6X9iuCGzHakdLMJP8tgrjGPKfq1ES0Ls9nNBWQ3djsWAeWGLKfDzxn4+iZgG2hpq
-JpBeYfT1ldDHf4J92S/gZaH+
+Q0EwHhcNMjQwNjIxMDgwNDMwWhcNMjkwNjIwMDgwNDMwWjBuMRgwFgYDVQQDDA9U
+ZW5wYXkuY29tIHNpZ24xEzARBgNVBAoMClRlbnBheS5jb20xHTAbBgNVBAsMFFRl
+bnBheS5jb20gQ0EgQ2VudGVyMQswCQYDVQQGEwJDTjERMA8GA1UEBwwIU2hlblpo
+ZW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDzcGNsiLdco5S5XWU8
+/X8URYgL3DUYfBkW/tv93bY/B/Z/1czOkRWRzWht+ZcO9zYNkO1FxA/Oqr7eZjnF
+XcH7D/qRz3I7X6P3Yf4k8uv5lTO+ynUHXj0Pxp/1mW2NesilxphLpYyxpkOM4BpY
+rcOHs1RZAaAg397UImpONzU4uJzvjzF2/cgybMrEORTUrkK2J255kXebwRKlx8MZ
+Vgl4CvURedrakCOvcVP+FWnocXKkKe4O0tMnmuGQ/n6zIADhnNyKhhlWKSBtT2CW
+0/RgJiwt6ydN1utd8iPeC/wHHdhvA7+1520xp4O4iaPnP9H//SD9vlmcPJ56TBUz
+6Lr5AgMBAAGjgbkwgbYwCQYDVR0TBAIwADALBgNVHQ8EBAMCA/gwgZsGA1UdHwSB
+kzCBkDCBjaCBiqCBh4aBhGh0dHA6Ly9ldmNhLml0cnVzLmNvbS5jbi9wdWJsaWMv
+aXRydXNjcmw/Q0E9MUJENDIyMEU1MERCQzA0QjA2QUQzOTc1NDk4NDZDMDFDM0U4
+RUJEMiZzZz1IQUNDNDcxQjY1NDIyRTEyQjI3QTlEMzNBODdBRDFDREY1OTI2RTE0
+MDM3MTANBgkqhkiG9w0BAQsFAAOCAQEAkivic1nCjCLtIrndSG8iP82iNTPTJR98
+PuvSeyAlCwUfwv+me/X1+9aarwKRsvqD1m2Or98oy+qRZX2GZG23W2OS8pshYnHF
+vC4KqDukiobqjKg1Z6ONHF6ewgkGoef8NFPN4hd+0Yqabp6T+vb/RgNTpi2FFNXT
+nvFyr7xqucBjcOl4DW9rlNdU6VcRu+t42KsGPjVgmuGA0lmDOOcfYml2YY+5t6YK
+z26mn3z+udPF2v9inViAya7WjzTbn7dKaQyd8iqPFQMFI+/Tlyy5h4t+JjLTt+/o
+TgYdXMoXewFryumwnio2ig5YfGDpTEKry6C2GVHFhaxitLavVk6REQ==
 -----END CERTIFICATE-----

+ 3 - 2
ruoyi-admin/src/main/resources/wxpay/wxpay.properties

@@ -5,5 +5,6 @@ v3.certP12Path=wxpay/apiclient_cert.p12
 v3.platformCertPath=wxpay/platformCert.pem
 v3.mchId=1677083704
 v3.apiKey3=lswgahsz0826eidwkseewZxgew999999
-v3.apiKey=lswgahsz0826eidwkseewZxgew999999
-v3.domain=https://gahsz.com/prod-api
+v3.apiKey=lswgahsz0826eidwkseewZxgew999998
+#v3.domain=https://gahsz.com/prod-api
+v3.domain=https://1525f532m9.vicp.fun