@ -0,0 +1,192 @@ | |||
package org.jeecg.config; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.apache.http.HttpEntity; | |||
import org.apache.http.HttpResponse; | |||
import org.apache.http.HttpStatus; | |||
import org.apache.http.ParseException; | |||
import org.apache.http.client.ClientProtocolException; | |||
import org.apache.http.client.methods.CloseableHttpResponse; | |||
import org.apache.http.client.methods.HttpGet; | |||
import org.apache.http.client.methods.HttpPost; | |||
import org.apache.http.entity.StringEntity; | |||
import org.apache.http.impl.client.CloseableHttpClient; | |||
import org.apache.http.impl.client.DefaultHttpClient; | |||
import org.apache.http.impl.client.HttpClients; | |||
import org.apache.http.util.EntityUtils; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import java.io.IOException; | |||
import java.net.URLDecoder; | |||
/** | |||
* Created by null on 2017/2/23. | |||
*/ | |||
@Slf4j | |||
public class HttpRequestUtil { | |||
private static Logger logger = LoggerFactory.getLogger(HttpRequestUtil.class); //日志记录 | |||
/** | |||
* post请求 | |||
* @param url url地址 | |||
* @param jsonParam 参数 | |||
* @return | |||
*/ | |||
public static String post(String url,String jsonParam){ | |||
//post请求返回结果 | |||
DefaultHttpClient httpClient = new DefaultHttpClient(); | |||
String jsonResult = null; | |||
HttpPost method = new HttpPost(url); | |||
try { | |||
if (null != jsonParam) { | |||
//解决中文乱码问题 | |||
StringEntity entity = new StringEntity(jsonParam.toString(), "utf-8"); | |||
entity.setContentEncoding("UTF-8"); | |||
entity.setContentType("application/json"); | |||
method.setEntity(entity); | |||
} | |||
HttpResponse result = httpClient.execute(method); | |||
url = URLDecoder.decode(url, "UTF-8"); | |||
/**请求发送成功,并得到响应**/ | |||
if (result.getStatusLine().getStatusCode() == 200) { | |||
String str = ""; | |||
try { | |||
/**读取服务器返回过来的json字符串数据**/ | |||
str = EntityUtils.toString(result.getEntity()); | |||
return str; | |||
/**把json字符串转换成json对象**/ | |||
// jsonResult = JSONObject.fromObject(str); | |||
} catch (Exception e) { | |||
logger.error("post请求提交失败:" + url, e); | |||
} | |||
} | |||
} catch (IOException e) { | |||
logger.error("post请求提交失败:" + url, e); | |||
} | |||
return jsonResult; | |||
} | |||
/** | |||
* 发送get请求 | |||
* @param url 路径 | |||
* @return | |||
*/ | |||
public static String get(String url){ | |||
String responseString = null; | |||
try { | |||
DefaultHttpClient client = new DefaultHttpClient(); | |||
//发送get请求 | |||
HttpGet request = new HttpGet(url); | |||
HttpResponse response = client.execute(request); | |||
/**请求发送成功,并得到响应**/ | |||
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { | |||
/**读取服务器返回过来的json字符串数据**/ | |||
return EntityUtils.toString(response.getEntity()); | |||
/**把json字符串转换成json对象**/ | |||
} else { | |||
logger.error("get请求提交失败:" + url); | |||
} | |||
} catch (IOException e) { | |||
logger.error("get请求提交失败:" + url, e); | |||
} | |||
return responseString; | |||
} | |||
/** | |||
* 发起批量转账API 批量转账到零钱 | |||
* | |||
* @param requestUrl | |||
* @param requestJson 组合参数 | |||
* @param wechatPayserialNo 商户证书序列号 | |||
* @param mchID4M 商户号 | |||
* @param privatekeypath 商户私钥证书路径 | |||
* @return | |||
*/ | |||
public static String postTransBatRequest( | |||
String requestUrl, | |||
String requestJson, | |||
String wechatPayserialNo, | |||
String wechatPayserialNo2, | |||
String mchID4M, | |||
String privatekeypath) { | |||
CloseableHttpClient httpclient = HttpClients.createDefault(); | |||
CloseableHttpResponse response = null; | |||
HttpEntity entity = null; | |||
try { | |||
//商户私钥证书 | |||
HttpPost httpPost = new HttpPost(requestUrl); | |||
// NOTE: 建议指定charset=utf-8。低于4.4.6版本的HttpCore,不能正确的设置字符集,可能导致签名错误 | |||
httpPost.addHeader("Content-Type", "application/json"); | |||
httpPost.addHeader("Accept", "application/json"); | |||
//"55E551E614BAA5A3EA38AE03849A76D8C7DA735A"); | |||
httpPost.addHeader("Wechatpay-Serial", wechatPayserialNo); | |||
//-------------------------核心认证 start----------------------------------------------------------------- | |||
String strToken = VechatPayV3Util.getToken("POST", | |||
"/v3/fund-app/mch-transfer/transfer-bills", | |||
requestJson,mchID4M,wechatPayserialNo2, privatekeypath); | |||
log.error("微信转账token "+strToken); | |||
// 添加认证信息 | |||
httpPost.addHeader("Authorization", | |||
"WECHATPAY2-SHA256-RSA2048" + " " | |||
+ strToken); | |||
//---------------------------核心认证 end--------------------------------------------------------------- | |||
httpPost.setEntity(new StringEntity(requestJson, "UTF-8")); | |||
//发起转账请求 | |||
response = httpclient.execute(httpPost); | |||
entity = response.getEntity();//获取返回的数据 | |||
log.info("-----getHeaders.Request-ID:"+response.getHeaders("Request-ID")); | |||
return EntityUtils.toString(entity,"UTF-8"); | |||
} catch (Exception e) { | |||
e.printStackTrace(); | |||
} finally { | |||
// 关闭流 | |||
} | |||
return null; | |||
} | |||
/** | |||
* 发送HTTP_GET请求 | |||
* | |||
* @see 该方法会自动关闭连接,释放资源 | |||
* @param reqURL | |||
* 请求地址(含参数) | |||
* @param decodeCharset | |||
* 解码字符集,解析响应数据时用之,其为null时默认采用UTF-8解码 | |||
* @return 远程主机响应正文 | |||
*/ | |||
public static String sendGetRequest(String reqURL,String auth,String decodeCharset) { | |||
long responseLength = 0; // 响应长度 | |||
String responseContent = null; // 响应内容 | |||
CloseableHttpClient httpclient = HttpClients.createDefault(); | |||
HttpGet httpGet = new HttpGet(reqURL); // 创建org.apache.http.client.methods.HttpGet | |||
httpGet.addHeader("Authorization", auth); | |||
httpGet.addHeader("Accept", "application/json"); | |||
httpGet.addHeader("User-Agent", "https://zh.wikipedia.org/wiki/User_agent"); | |||
try { | |||
HttpResponse response = httpclient.execute(httpGet); // 执行GET请求 | |||
HttpEntity entity = response.getEntity(); // 获取响应实体 | |||
if (null != entity) { | |||
responseLength = entity.getContentLength(); | |||
responseContent = EntityUtils.toString(entity, decodeCharset == null ? "UTF-8" : decodeCharset); | |||
EntityUtils.consume(entity); // Consume response content | |||
} | |||
} catch (ClientProtocolException e) { | |||
System.out.println("该异常通常是协议错误导致,比如构造HttpGet对象时传入的协议不对(将'http'写成'htp')或者服务器端返回的内容不符合HTTP协议要求等,堆栈信息如下"); | |||
} catch (ParseException e) { | |||
System.out.println(e.getMessage()); | |||
} catch (IOException e) { | |||
System.out.println("该异常通常是网络原因引起的,如HTTP服务器未启动等,堆栈信息如下"); | |||
} finally { | |||
httpclient.getConnectionManager().shutdown(); // 关闭连接,释放资源 | |||
} | |||
return responseContent; | |||
} | |||
} |
@ -0,0 +1,28 @@ | |||
package org.jeecg.config; | |||
import java.math.BigDecimal; | |||
/** | |||
* Created by 廖师兄 | |||
* 2017-07-02 13:53 | |||
*/ | |||
public class MoneyUtil { | |||
/** | |||
* 元转分 | |||
* @param yuan | |||
* @return | |||
*/ | |||
public static Integer Yuan2Fen(Double yuan) { | |||
return new BigDecimal(String.valueOf(yuan)).movePointRight(2).intValue(); | |||
} | |||
/** | |||
* 分转元 | |||
* @param fen | |||
* @return | |||
*/ | |||
public static Double Fen2Yuan(Integer fen) { | |||
return new BigDecimal(fen).movePointLeft(2).doubleValue(); | |||
} | |||
} |
@ -0,0 +1,122 @@ | |||
package org.jeecg.config; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.apache.commons.codec.binary.Base64; | |||
import org.springframework.util.StringUtils; | |||
import java.io.IOException; | |||
import java.nio.file.Files; | |||
import java.nio.file.Paths; | |||
import java.security.KeyFactory; | |||
import java.security.NoSuchAlgorithmException; | |||
import java.security.PrivateKey; | |||
import java.security.Signature; | |||
import java.security.spec.InvalidKeySpecException; | |||
import java.security.spec.PKCS8EncodedKeySpec; | |||
import java.util.Random; | |||
/** | |||
* @author java996.icu | |||
* @title: VechatPayV3Util | |||
* @projectName chemu | |||
* @description: TODO | |||
* @date 2022/12/8 15:00 | |||
* @Version V1.0 | |||
*/ | |||
@Slf4j | |||
public class VechatPayV3Util { | |||
/** | |||
* | |||
* @param method 请求方法 post | |||
* @param canonicalUrl 请求地址 | |||
* @param body 请求参数 | |||
* @param merchantId 这里用的商户号 | |||
* @param certSerialNo 商户证书序列号 | |||
* @param keyPath 商户证书地址 | |||
* @return | |||
* @throws Exception | |||
*/ | |||
public static String getToken( | |||
String method, | |||
String canonicalUrl, | |||
String body, | |||
String merchantId, | |||
String certSerialNo, | |||
String keyPath) throws Exception { | |||
String signStr = ""; | |||
//获取32位随机字符串 | |||
String nonceStr = getRandomString(32); | |||
//当前系统运行时间 | |||
long timestamp = System.currentTimeMillis() / 1000; | |||
if (StringUtils.isEmpty(body)) { | |||
body = ""; | |||
} | |||
//签名操作 | |||
String message = buildMessage(method, canonicalUrl, timestamp, nonceStr, body); | |||
//签名操作 | |||
String signature = sign(message.getBytes("utf-8"), keyPath); | |||
//组装参数 | |||
signStr = "mchid=\"" + merchantId + "\",timestamp=\"" + timestamp+ "\",nonce_str=\"" + nonceStr | |||
+ "\",serial_no=\"" + certSerialNo + "\",signature=\"" + signature + "\""; | |||
return signStr; | |||
} | |||
public static String buildMessage(String method, String canonicalUrl, long timestamp, String nonceStr, String body) { | |||
// String canonicalUrl = url.encodedPath(); | |||
// if (url.encodedQuery() != null) { | |||
// canonicalUrl += "?" + url.encodedQuery(); | |||
// } | |||
return method + "\n" + canonicalUrl + "\n" + timestamp + "\n" + nonceStr + "\n" + body + "\n"; | |||
} | |||
public static String sign(byte[] message, String keyPath) throws Exception { | |||
Signature sign = Signature.getInstance("SHA256withRSA"); | |||
sign.initSign(getPrivateKey(keyPath)); | |||
sign.update(message); | |||
return Base64.encodeBase64String(sign.sign()); | |||
} | |||
/** | |||
* 微信支付-前端唤起支付参数-获取商户私钥 | |||
* | |||
* @param filename 私钥文件路径 (required) | |||
* @return 私钥对象 | |||
*/ | |||
public static PrivateKey getPrivateKey(String filename) throws IOException { | |||
log.error("签名 证书地址是 "+filename); | |||
String content = new String(Files.readAllBytes(Paths.get(filename)), "utf-8"); | |||
try { | |||
String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "") | |||
.replace("-----END PRIVATE KEY-----", "") | |||
.replaceAll("\\s+", ""); | |||
//System.out.println("--------privateKey---------:"+privateKey); | |||
KeyFactory kf = KeyFactory.getInstance("RSA"); | |||
return kf.generatePrivate( | |||
new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey))); | |||
} catch (NoSuchAlgorithmException e) { | |||
throw new RuntimeException("当前Java环境不支持RSA", e); | |||
} catch (InvalidKeySpecException e) { | |||
throw new RuntimeException("无效的密钥格式"); | |||
} | |||
} | |||
/** | |||
* 获取随机位数的字符串 | |||
* @param length | |||
* @return | |||
*/ | |||
public static String getRandomString(int length) { | |||
String base = "abcdefghijklmnopqrstuvwxyz0123456789"; | |||
Random random = new Random(); | |||
StringBuffer sb = new StringBuffer(); | |||
for (int i = 0; i < length; i++) { | |||
int number = random.nextInt(base.length()); | |||
sb.append(base.charAt(number)); | |||
} | |||
return sb.toString(); | |||
} | |||
} |
@ -0,0 +1,207 @@ | |||
package org.jeecg.config.pay; | |||
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder; | |||
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner; | |||
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier; | |||
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials; | |||
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator; | |||
import com.wechat.pay.contrib.apache.httpclient.cert.CertificatesManager; | |||
import com.wechat.pay.contrib.apache.httpclient.exception.HttpCodeException; | |||
import com.wechat.pay.contrib.apache.httpclient.exception.NotFoundException; | |||
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil; | |||
import lombok.Data; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.apache.http.impl.client.CloseableHttpClient; | |||
import org.springframework.boot.context.properties.ConfigurationProperties; | |||
import org.springframework.context.annotation.Bean; | |||
import org.springframework.stereotype.Component; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.nio.charset.StandardCharsets; | |||
import java.security.GeneralSecurityException; | |||
import java.security.PrivateKey; | |||
/** | |||
* @author java996.icu | |||
* @title: WeChatPayConfig2 | |||
* @projectName chemu | |||
* @description: TODO | |||
* @date 2022/12/7 16:36 | |||
* @Version V1.0 | |||
*/ | |||
@Component | |||
@Data | |||
@Slf4j | |||
@ConfigurationProperties(prefix = "wxpay") | |||
public class WeChatPayConfig2 { | |||
/** | |||
* 应用编号 | |||
*/ | |||
private String appId; | |||
/** | |||
* 商户号 | |||
*/ | |||
private String mchId; | |||
/** | |||
* 服务商商户号 | |||
*/ | |||
private String slMchId; | |||
/** | |||
* APIv2密钥 | |||
*/ | |||
private String apiKey; | |||
/** | |||
* APIv3密钥 | |||
*/ | |||
private String apiV3Key; | |||
/** | |||
* 支付通知回调地址 | |||
*/ | |||
private String notifyUrl; | |||
/** | |||
* 退款回调地址 | |||
*/ | |||
private String refundNotifyUrl; | |||
/** | |||
* API 证书中的 key.pem | |||
*/ | |||
private String keyPemPath; | |||
/** | |||
* 商户序列号 | |||
*/ | |||
private String serialNo; | |||
/** | |||
* 微信支付V3-url前缀 | |||
*/ | |||
private String baseUrl; | |||
/** | |||
* 获取商户的私钥文件 | |||
* @param keyPemPath | |||
* @return | |||
*/ | |||
public PrivateKey getPrivateKey(String keyPemPath){ | |||
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(keyPemPath); | |||
if(inputStream==null){ | |||
throw new RuntimeException("私钥文件不存在"); | |||
} | |||
return PemUtil.loadPrivateKey(inputStream); | |||
} | |||
// | |||
// /** | |||
// * 获取证书管理器实例 | |||
// * @return | |||
// */ | |||
// @Bean | |||
// public Verifier getVerifier() throws GeneralSecurityException, IOException, HttpCodeException, NotFoundException { | |||
// | |||
// log.info("获取证书管理器实例"); | |||
// | |||
// //获取商户私钥 | |||
// PrivateKey privateKey = getPrivateKey(keyPemPath); | |||
// | |||
// //私钥签名对象 | |||
// PrivateKeySigner privateKeySigner = new PrivateKeySigner(serialNo, privateKey); | |||
// | |||
// //身份认证对象 | |||
// WechatPay2Credentials wechatPay2Credentials = new WechatPay2Credentials(mchId, privateKeySigner); | |||
// | |||
// // 使用定时更新的签名验证器,不需要传入证书 | |||
// CertificatesManager certificatesManager = CertificatesManager.getInstance(); | |||
// certificatesManager.putMerchant(mchId,wechatPay2Credentials,apiV3Key.getBytes(StandardCharsets.UTF_8)); | |||
// | |||
// return certificatesManager.getVerifier(mchId); | |||
// } | |||
@Bean | |||
public Verifier getVerifier() throws GeneralSecurityException, IOException, HttpCodeException, NotFoundException { | |||
log.info("开始获取微信支付证书管理器实例"); | |||
// 验证关键参数 | |||
log.debug("商户号: {}", mchId); | |||
log.debug("证书序列号: {}", serialNo); | |||
log.debug("APIv3密钥长度: {}", apiV3Key.length()); // 不记录具体密钥内容 | |||
// 获取商户私钥 | |||
PrivateKey privateKey = getPrivateKey(keyPemPath); | |||
if (privateKey == null) { | |||
throw new IllegalArgumentException("无法从路径加载私钥: " + keyPemPath); | |||
} | |||
// 创建签名器 | |||
PrivateKeySigner privateKeySigner = new PrivateKeySigner(serialNo, privateKey); | |||
WechatPay2Credentials wechatPay2Credentials = new WechatPay2Credentials(mchId, privateKeySigner); | |||
try { | |||
CertificatesManager certificatesManager = CertificatesManager.getInstance(); | |||
// 显式设置域名(如果库需要) | |||
// certificatesManager.setDomain("api.mch.weixin.qq.com"); | |||
// 添加商户信息 | |||
certificatesManager.putMerchant(mchId, wechatPay2Credentials, apiV3Key.getBytes(StandardCharsets.UTF_8)); | |||
// 获取验证器 | |||
Verifier verifier = certificatesManager.getVerifier(mchId); | |||
log.info("成功获取证书管理器实例"); | |||
return verifier; | |||
} catch (HttpCodeException e) { | |||
log.error("微信支付API返回错误: "+ e); | |||
throw e; | |||
} catch (Exception e) { | |||
log.error("获取证书管理器实例时发生错误", e); | |||
throw e; | |||
} | |||
} | |||
/** | |||
* 获取支付http请求对象 | |||
* @param verifier | |||
* @return | |||
*/ | |||
@Bean(name = "wxPayClient") | |||
public CloseableHttpClient getWxPayClient(Verifier verifier) { | |||
//获取商户私钥 | |||
PrivateKey privateKey = getPrivateKey(keyPemPath); | |||
WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create() | |||
.withMerchant(mchId, serialNo, privateKey) | |||
.withValidator(new WechatPay2Validator(verifier)); | |||
// 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签,并进行证书自动更新 | |||
return builder.build(); | |||
} | |||
/** | |||
* 获取HttpClient,无需进行应答签名验证,跳过验签的流程 | |||
*/ | |||
@Bean(name = "wxPayNoSignClient") | |||
public CloseableHttpClient getWxPayNoSignClient(){ | |||
//获取商户私钥 | |||
PrivateKey privateKey = getPrivateKey(keyPemPath); | |||
//用于构造HttpClient | |||
WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create() | |||
//设置商户信息 | |||
.withMerchant(mchId, serialNo, privateKey) | |||
//无需进行签名验证、通过withValidator((response) -> true)实现 | |||
.withValidator((response) -> true); | |||
// 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签,并进行证书自动更新 | |||
return builder.build(); | |||
} | |||
} |
@ -0,0 +1,253 @@ | |||
<template> | |||
<a-card :bordered="false"> | |||
<!-- 查询区域 --> | |||
<div class="table-page-search-wrapper"> | |||
<a-form layout="inline" @keyup.enter.native="searchQuery"> | |||
<a-row :gutter="24"> | |||
<a-col :xl="6" :lg="7" :md="8" :sm="24"> | |||
<a-form-item label="状态"> | |||
<j-dict-select-tag placeholder="请选择状态" v-model="queryParam.state" dictCode="money_pay_state"/> | |||
</a-form-item> | |||
</a-col> | |||
<a-col :xl="6" :lg="7" :md="8" :sm="24"> | |||
<a-form-item label="类型"> | |||
<j-dict-select-tag placeholder="请选择类型" v-model="queryParam.type" dictCode="money_pay"/> | |||
</a-form-item> | |||
</a-col> | |||
<a-col :xl="6" :lg="7" :md="8" :sm="24"> | |||
<span style="float: left;overflow: hidden;" class="table-page-search-submitButtons"> | |||
<a-button type="primary" @click="searchQuery" icon="search">查询</a-button> | |||
<a-button type="primary" @click="searchReset" icon="reload" style="margin-left: 8px">重置</a-button> | |||
<a @click="handleToggleSearch" style="margin-left: 8px"> | |||
{{ toggleSearchStatus ? '收起' : '展开' }} | |||
<a-icon :type="toggleSearchStatus ? 'up' : 'down'"/> | |||
</a> | |||
</span> | |||
</a-col> | |||
</a-row> | |||
</a-form> | |||
</div> | |||
<!-- 查询区域-END --> | |||
<!-- 操作按钮区域 --> | |||
<div class="table-operator"> | |||
<a-button @click="handleAdd" type="primary" icon="plus">新增</a-button> | |||
<a-button type="primary" icon="download" @click="handleExportXls('佣金流水')">导出</a-button> | |||
<a-upload name="file" :showUploadList="false" :multiple="false" :headers="tokenHeader" :action="importExcelUrl" @change="handleImportExcel"> | |||
<a-button type="primary" icon="import">导入</a-button> | |||
</a-upload> | |||
<!-- 高级查询区域 --> | |||
<j-super-query :fieldList="superFieldList" ref="superQueryModal" @handleSuperQuery="handleSuperQuery"></j-super-query> | |||
<a-dropdown v-if="selectedRowKeys.length > 0"> | |||
<a-menu slot="overlay"> | |||
<a-menu-item key="1" @click="batchDel"><a-icon type="delete"/>删除</a-menu-item> | |||
</a-menu> | |||
<a-button style="margin-left: 8px"> 批量操作 <a-icon type="down" /></a-button> | |||
</a-dropdown> | |||
</div> | |||
<!-- table区域-begin --> | |||
<div> | |||
<div class="ant-alert ant-alert-info" style="margin-bottom: 16px;"> | |||
<i class="anticon anticon-info-circle ant-alert-icon"></i> 已选择 <a style="font-weight: 600">{{ selectedRowKeys.length }}</a>项 | |||
<a style="margin-left: 24px" @click="onClearSelected">清空</a> | |||
</div> | |||
<a-table | |||
ref="table" | |||
size="middle" | |||
:scroll="{x:true}" | |||
bordered | |||
rowKey="id" | |||
:columns="columns" | |||
:dataSource="dataSource" | |||
:pagination="ipagination" | |||
:loading="loading" | |||
:rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}" | |||
class="j-table-force-nowrap" | |||
@change="handleTableChange"> | |||
<template slot="htmlSlot" slot-scope="text"> | |||
<div v-html="text"></div> | |||
</template> | |||
<template slot="imgSlot" slot-scope="text,record"> | |||
<span v-if="!text" style="font-size: 12px;font-style: italic;">无图片</span> | |||
<img v-else :src="getImgView(text)" :preview="record.id" height="25px" alt="" style="max-width:80px;font-size: 12px;font-style: italic;"/> | |||
</template> | |||
<template slot="fileSlot" slot-scope="text"> | |||
<span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span> | |||
<a-button | |||
v-else | |||
:ghost="true" | |||
type="primary" | |||
icon="download" | |||
size="small" | |||
@click="downloadFile(text)"> | |||
下载 | |||
</a-button> | |||
</template> | |||
<span slot="action" slot-scope="text, record"> | |||
<a @click="handleEdit(record)">编辑</a> | |||
<a-divider type="vertical" /> | |||
<a-dropdown> | |||
<a class="ant-dropdown-link">更多 <a-icon type="down" /></a> | |||
<a-menu slot="overlay"> | |||
<a-menu-item> | |||
<a @click="handleDetail(record)">详情</a> | |||
</a-menu-item> | |||
<a-menu-item> | |||
<a-popconfirm title="确定删除吗?" @confirm="() => handleDelete(record.id)"> | |||
<a>删除</a> | |||
</a-popconfirm> | |||
</a-menu-item> | |||
</a-menu> | |||
</a-dropdown> | |||
</span> | |||
</a-table> | |||
</div> | |||
<city-money-log-modal ref="modalForm" @ok="modalFormOk"></city-money-log-modal> | |||
</a-card> | |||
</template> | |||
<script> | |||
import '@/assets/less/TableExpand.less' | |||
import { mixinDevice } from '@/utils/mixin' | |||
import { JeecgListMixin } from '@/mixins/JeecgListMixin' | |||
import CityMoneyLogModal from './modules/CityMoneyLogModal' | |||
import {filterMultiDictText} from '@/components/dict/JDictSelectUtil' | |||
export default { | |||
name: 'CityMoneyLogList', | |||
mixins:[JeecgListMixin, mixinDevice], | |||
components: { | |||
CityMoneyLogModal | |||
}, | |||
data () { | |||
return { | |||
description: '佣金流水管理页面', | |||
// 表头 | |||
columns: [ | |||
{ | |||
title: '#', | |||
dataIndex: '', | |||
key:'rowIndex', | |||
width:60, | |||
align:"center", | |||
customRender:function (t,r,index) { | |||
return parseInt(index)+1; | |||
} | |||
}, | |||
{ | |||
title:'创建日期', | |||
align:"center", | |||
sorter: true, | |||
dataIndex: 'createTime' | |||
}, | |||
{ | |||
title:'用户', | |||
align:"center", | |||
dataIndex: 'userId_dictText' | |||
}, | |||
{ | |||
title:'提现者姓名', | |||
align:"center", | |||
dataIndex: 'name' | |||
}, | |||
{ | |||
title:'流水备注', | |||
align:"center", | |||
dataIndex: 'title' | |||
}, | |||
{ | |||
title:'金额', | |||
align:"center", | |||
dataIndex: 'price' | |||
}, | |||
{ | |||
title:'状态', | |||
align:"center", | |||
dataIndex: 'state_dictText' | |||
}, | |||
{ | |||
title:'到账时间', | |||
align:"center", | |||
dataIndex: 'successtime' | |||
}, | |||
{ | |||
title:'类型', | |||
align:"center", | |||
dataIndex: 'type_dictText' | |||
}, | |||
{ | |||
title:'回调', | |||
align:"center", | |||
dataIndex: 'packageInfo' | |||
}, | |||
{ | |||
title:'标识', | |||
align:"center", | |||
dataIndex: 'outBatchNo' | |||
}, | |||
{ | |||
title:'内容', | |||
align:"center", | |||
dataIndex: 'batchId' | |||
}, | |||
{ | |||
title: '操作', | |||
dataIndex: 'action', | |||
align:"center", | |||
fixed:"right", | |||
width:147, | |||
scopedSlots: { customRender: 'action' } | |||
} | |||
], | |||
url: { | |||
list: "/cityMoneyLog/cityMoneyLog/list", | |||
delete: "/cityMoneyLog/cityMoneyLog/delete", | |||
deleteBatch: "/cityMoneyLog/cityMoneyLog/deleteBatch", | |||
exportXlsUrl: "/cityMoneyLog/cityMoneyLog/exportXls", | |||
importExcelUrl: "cityMoneyLog/cityMoneyLog/importExcel", | |||
}, | |||
dictOptions:{}, | |||
superFieldList:[], | |||
} | |||
}, | |||
created() { | |||
this.getSuperFieldList(); | |||
}, | |||
computed: { | |||
importExcelUrl: function(){ | |||
return `${window._CONFIG['domianURL']}/${this.url.importExcelUrl}`; | |||
}, | |||
}, | |||
methods: { | |||
initDictConfig(){ | |||
}, | |||
getSuperFieldList(){ | |||
let fieldList=[]; | |||
fieldList.push({type:'datetime',value:'createTime',text:'创建日期'}) | |||
fieldList.push({type:'sel_search',value:'userId',text:'用户',dictTable:"han_hai_member", dictText:'nick_name', dictCode:'id'}) | |||
fieldList.push({type:'string',value:'name',text:'提现者姓名',dictCode:''}) | |||
fieldList.push({type:'string',value:'title',text:'流水备注',dictCode:''}) | |||
fieldList.push({type:'BigDecimal',value:'price',text:'金额',dictCode:''}) | |||
fieldList.push({type:'int',value:'state',text:'状态',dictCode:'money_pay_state'}) | |||
fieldList.push({type:'datetime',value:'successtime',text:'到账时间'}) | |||
fieldList.push({type:'int',value:'type',text:'类型',dictCode:'money_pay'}) | |||
fieldList.push({type:'Text',value:'packageInfo',text:'回调',dictCode:''}) | |||
fieldList.push({type:'Text',value:'outBatchNo',text:'标识',dictCode:''}) | |||
fieldList.push({type:'Text',value:'batchId',text:'内容',dictCode:''}) | |||
this.superFieldList = fieldList | |||
} | |||
} | |||
} | |||
</script> | |||
<style scoped> | |||
@import '~@assets/less/common.less'; | |||
</style> |
@ -0,0 +1,149 @@ | |||
<template> | |||
<a-spin :spinning="confirmLoading"> | |||
<j-form-container :disabled="formDisabled"> | |||
<a-form-model ref="form" :model="model" :rules="validatorRules" slot="detail"> | |||
<a-row> | |||
<a-col :span="24"> | |||
<a-form-model-item label="用户" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="userId"> | |||
<j-search-select-tag v-model="model.userId" dict="han_hai_member,nick_name,id" /> | |||
</a-form-model-item> | |||
</a-col> | |||
<a-col :span="24"> | |||
<a-form-model-item label="提现者姓名" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="name"> | |||
<a-input v-model="model.name" placeholder="请输入提现者姓名" ></a-input> | |||
</a-form-model-item> | |||
</a-col> | |||
<a-col :span="24"> | |||
<a-form-model-item label="流水备注" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="title"> | |||
<a-input v-model="model.title" placeholder="请输入流水备注" ></a-input> | |||
</a-form-model-item> | |||
</a-col> | |||
<a-col :span="24"> | |||
<a-form-model-item label="金额" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="price"> | |||
<a-input-number v-model="model.price" placeholder="请输入金额" style="width: 100%" /> | |||
</a-form-model-item> | |||
</a-col> | |||
<a-col :span="24"> | |||
<a-form-model-item label="状态" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="state"> | |||
<j-dict-select-tag type="list" v-model="model.state" dictCode="money_pay_state" placeholder="请选择状态" /> | |||
</a-form-model-item> | |||
</a-col> | |||
<a-col :span="24"> | |||
<a-form-model-item label="到账时间" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="successtime"> | |||
<j-date placeholder="请选择到账时间" v-model="model.successtime" :show-time="true" date-format="YYYY-MM-DD HH:mm:ss" style="width: 100%" /> | |||
</a-form-model-item> | |||
</a-col> | |||
<a-col :span="24"> | |||
<a-form-model-item label="类型" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="type"> | |||
<j-dict-select-tag type="list" v-model="model.type" dictCode="money_pay" placeholder="请选择类型" /> | |||
</a-form-model-item> | |||
</a-col> | |||
<a-col :span="24"> | |||
<a-form-model-item label="回调" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="packageInfo"> | |||
<a-input v-model="model.packageInfo" placeholder="请输入回调" ></a-input> | |||
</a-form-model-item> | |||
</a-col> | |||
<a-col :span="24"> | |||
<a-form-model-item label="标识" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="outBatchNo"> | |||
<a-input v-model="model.outBatchNo" placeholder="请输入标识" ></a-input> | |||
</a-form-model-item> | |||
</a-col> | |||
<a-col :span="24"> | |||
<a-form-model-item label="内容" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="batchId"> | |||
<a-input v-model="model.batchId" placeholder="请输入内容" ></a-input> | |||
</a-form-model-item> | |||
</a-col> | |||
</a-row> | |||
</a-form-model> | |||
</j-form-container> | |||
</a-spin> | |||
</template> | |||
<script> | |||
import { httpAction, getAction } from '@/api/manage' | |||
import { validateDuplicateValue } from '@/utils/util' | |||
export default { | |||
name: 'CityMoneyLogForm', | |||
components: { | |||
}, | |||
props: { | |||
//表单禁用 | |||
disabled: { | |||
type: Boolean, | |||
default: false, | |||
required: false | |||
} | |||
}, | |||
data () { | |||
return { | |||
model:{ | |||
}, | |||
labelCol: { | |||
xs: { span: 24 }, | |||
sm: { span: 5 }, | |||
}, | |||
wrapperCol: { | |||
xs: { span: 24 }, | |||
sm: { span: 16 }, | |||
}, | |||
confirmLoading: false, | |||
validatorRules: { | |||
}, | |||
url: { | |||
add: "/cityMoneyLog/cityMoneyLog/add", | |||
edit: "/cityMoneyLog/cityMoneyLog/edit", | |||
queryById: "/cityMoneyLog/cityMoneyLog/queryById" | |||
} | |||
} | |||
}, | |||
computed: { | |||
formDisabled(){ | |||
return this.disabled | |||
}, | |||
}, | |||
created () { | |||
//备份model原始值 | |||
this.modelDefault = JSON.parse(JSON.stringify(this.model)); | |||
}, | |||
methods: { | |||
add () { | |||
this.edit(this.modelDefault); | |||
}, | |||
edit (record) { | |||
this.model = Object.assign({}, record); | |||
this.visible = true; | |||
}, | |||
submitForm () { | |||
const that = this; | |||
// 触发表单验证 | |||
this.$refs.form.validate(valid => { | |||
if (valid) { | |||
that.confirmLoading = true; | |||
let httpurl = ''; | |||
let method = ''; | |||
if(!this.model.id){ | |||
httpurl+=this.url.add; | |||
method = 'post'; | |||
}else{ | |||
httpurl+=this.url.edit; | |||
method = 'put'; | |||
} | |||
httpAction(httpurl,this.model,method).then((res)=>{ | |||
if(res.success){ | |||
that.$message.success(res.message); | |||
that.$emit('ok'); | |||
}else{ | |||
that.$message.warning(res.message); | |||
} | |||
}).finally(() => { | |||
that.confirmLoading = false; | |||
}) | |||
} | |||
}) | |||
}, | |||
} | |||
} | |||
</script> |
@ -0,0 +1,84 @@ | |||
<template> | |||
<a-drawer | |||
:title="title" | |||
:width="width" | |||
placement="right" | |||
:closable="false" | |||
@close="close" | |||
destroyOnClose | |||
:visible="visible"> | |||
<city-money-log-form ref="realForm" @ok="submitCallback" :disabled="disableSubmit" normal></city-money-log-form> | |||
<div class="drawer-footer"> | |||
<a-button @click="handleCancel" style="margin-bottom: 0;">关闭</a-button> | |||
<a-button v-if="!disableSubmit" @click="handleOk" type="primary" style="margin-bottom: 0;">提交</a-button> | |||
</div> | |||
</a-drawer> | |||
</template> | |||
<script> | |||
import CityMoneyLogForm from './CityMoneyLogForm' | |||
export default { | |||
name: 'CityMoneyLogModal', | |||
components: { | |||
CityMoneyLogForm | |||
}, | |||
data () { | |||
return { | |||
title:"操作", | |||
width:800, | |||
visible: false, | |||
disableSubmit: false | |||
} | |||
}, | |||
methods: { | |||
add () { | |||
this.visible=true | |||
this.$nextTick(()=>{ | |||
this.$refs.realForm.add(); | |||
}) | |||
}, | |||
edit (record) { | |||
this.visible=true | |||
this.$nextTick(()=>{ | |||
this.$refs.realForm.edit(record); | |||
}); | |||
}, | |||
close () { | |||
this.$emit('close'); | |||
this.visible = false; | |||
}, | |||
submitCallback(){ | |||
this.$emit('ok'); | |||
this.visible = false; | |||
}, | |||
handleOk () { | |||
this.$refs.realForm.submitForm(); | |||
}, | |||
handleCancel () { | |||
this.close() | |||
} | |||
} | |||
} | |||
</script> | |||
<style lang="less" scoped> | |||
/** Button按钮间距 */ | |||
.ant-btn { | |||
margin-left: 30px; | |||
margin-bottom: 30px; | |||
float: right; | |||
} | |||
.drawer-footer{ | |||
position: absolute; | |||
bottom: -8px; | |||
width: 100%; | |||
border-top: 1px solid #e8e8e8; | |||
padding: 10px 16px; | |||
text-align: right; | |||
left: 0; | |||
background: #fff; | |||
border-radius: 0 0 2px 2px; | |||
} | |||
</style> |
@ -0,0 +1,60 @@ | |||
<template> | |||
<j-modal | |||
:title="title" | |||
:width="width" | |||
:visible="visible" | |||
switchFullscreen | |||
@ok="handleOk" | |||
:okButtonProps="{ class:{'jee-hidden': disableSubmit} }" | |||
@cancel="handleCancel" | |||
cancelText="关闭"> | |||
<city-money-log-form ref="realForm" @ok="submitCallback" :disabled="disableSubmit"></city-money-log-form> | |||
</j-modal> | |||
</template> | |||
<script> | |||
import CityMoneyLogForm from './CityMoneyLogForm' | |||
export default { | |||
name: 'CityMoneyLogModal', | |||
components: { | |||
CityMoneyLogForm | |||
}, | |||
data () { | |||
return { | |||
title:'', | |||
width:800, | |||
visible: false, | |||
disableSubmit: false | |||
} | |||
}, | |||
methods: { | |||
add () { | |||
this.visible=true | |||
this.$nextTick(()=>{ | |||
this.$refs.realForm.add(); | |||
}) | |||
}, | |||
edit (record) { | |||
this.visible=true | |||
this.$nextTick(()=>{ | |||
this.$refs.realForm.edit(record); | |||
}) | |||
}, | |||
close () { | |||
this.$emit('close'); | |||
this.visible = false; | |||
}, | |||
handleOk () { | |||
this.$refs.realForm.submitForm(); | |||
}, | |||
submitCallback(){ | |||
this.$emit('ok'); | |||
this.visible = false; | |||
}, | |||
handleCancel () { | |||
this.close() | |||
} | |||
} | |||
} | |||
</script> |
@ -0,0 +1,25 @@ | |||
package org.jeecg.modules.cityMoneyLog.req; | |||
import com.alibaba.fastjson.annotation.JSONField; | |||
import lombok.Data; | |||
/** | |||
* @author java996.icu | |||
* @title: TransferBatchesDetailsRequest | |||
* @projectName merchant | |||
* @description: TODO | |||
* @date 2022/10/10 15:45 | |||
* @Version V1.0 | |||
*/ | |||
@Data | |||
public class TransferBatchesDetailsRequest { | |||
/**转账场景为1000-现金营销,需填入活动名称、奖励说明*/ | |||
@JSONField(name = "info_type") | |||
private String infoType; | |||
/**信息类型为活动名称,请在信息内容描述用户参与活动的名称,如新会员有礼 | |||
信息类型为奖励说明,请在信息内容描述用户因为什么奖励获取这笔资金,如注册会员抽奖一等奖*/ | |||
@JSONField(name = "info_content") | |||
private String infoContent; | |||
} |
@ -0,0 +1,45 @@ | |||
package org.jeecg.modules.cityMoneyLog.req; | |||
import com.alibaba.fastjson.annotation.JSONField; | |||
import lombok.Data; | |||
import java.util.List; | |||
/** | |||
* @author java996.icu | |||
* @title: TransferBatchesRequest | |||
* @projectName merchant | |||
* @description: TODO | |||
* @date 2022/10/10 15:32 | |||
* @Version V1.0 | |||
*/ | |||
@Data | |||
public class TransferBatchesRequest { | |||
/**直连商户的appid*/ | |||
private String appid; | |||
/**商家批次单号*/ | |||
@JSONField(name = "out_bill_no") | |||
private String outBillNo; | |||
/**批次备注*/ | |||
@JSONField(name = "transfer_remark") | |||
private String transferRemark; | |||
/**转账总金额*/ | |||
@JSONField(name = "transfer_amount") | |||
private Integer transferAmount; | |||
/**转账场景*/ | |||
@JSONField(name = "transfer_scene_id") | |||
private String transferSceneId; | |||
@JSONField(name = "openid") | |||
private String openid; | |||
/**真实姓名*/ | |||
@JSONField(name = "user_name") | |||
private String userName; | |||
/**回调地址*/ | |||
@JSONField(name = "notify_url") | |||
private String notifyUrl; | |||
/**发起批量转账的明细列表,最多三千笔*/ | |||
@JSONField(name = "transfer_scene_report_infos") | |||
private List<TransferBatchesDetailsRequest> transferDetailList; | |||
} |
@ -0,0 +1,32 @@ | |||
package org.jeecg.modules.cityMoneyLog.resp; | |||
import com.alibaba.fastjson.annotation.JSONField; | |||
import lombok.Data; | |||
@Data | |||
public class TransferBatchNotifyResourceResp { | |||
/** | |||
* 加密算法类型 | |||
* 对开启结果数据进行加密的加密算法,目前只支持AEAD_AES_256_GCM | |||
*/ | |||
@JSONField(name = "algorithm") | |||
private String algorithm; | |||
/** | |||
* 数据密文 | |||
* Base64编码后的商家转账结果数据密文 | |||
*/ | |||
@JSONField(name = "ciphertext") | |||
private String ciphertext; | |||
/**附加数据*/ | |||
@JSONField(name = "associated_data") | |||
private String associatedData; | |||
/**原始回调类型,为mch_payment*/ | |||
@JSONField(name = "original_type") | |||
private String originalType; | |||
/**加密使用的随机串*/ | |||
@JSONField(name = "nonce") | |||
private String nonce; | |||
} |
@ -0,0 +1,51 @@ | |||
package org.jeecg.modules.cityMoneyLog.resp; | |||
import com.alibaba.fastjson.annotation.JSONField; | |||
import lombok.Data; | |||
@Data | |||
public class TransferBatchResourceDataResp { | |||
/**微信批次单号*/ | |||
@JSONField(name = "out_bill_no") | |||
private String outBillNo; | |||
/**商家批次单号*/ | |||
@JSONField(name = "transfer_bill_no") | |||
private String transferBillNo; | |||
/** | |||
* 商家转账订单状态 | |||
* ACCEPTED: 转账已受理 | |||
* | |||
* PROCESSING: 转账处理中,转账结果尚未明确,如一直处于此状态,建议检查账户余额是否足够 | |||
* | |||
* WAIT_USER_CONFIRM: 待收款用户确认,可拉起微信收款确认页面进行收款确认 | |||
* | |||
* TRANSFERING: 转账结果尚未明确,可拉起微信收款确认页面再次重试确认收款 | |||
* | |||
* SUCCESS: 转账成功 | |||
* | |||
* FAIL: 转账失败 | |||
* | |||
* CANCELING: 商户撤销请求受理成功,该笔转账正在撤销中 | |||
* | |||
* CANCELLED: 转账撤销完成 | |||
* */ | |||
@JSONField(name = "state") | |||
private String state; | |||
/**失败原因*/ | |||
@JSONField(name = "fail_reason") | |||
private String failReason; | |||
/**商户号*/ | |||
@JSONField(name = "mch_id") | |||
private String mchId; | |||
/**转账总金额,单位为“分”*/ | |||
@JSONField(name = "transfer_amount") | |||
private Integer transferAmount; | |||
@JSONField(name = "openid") | |||
private String openid; | |||
@JSONField(name = "create_time") | |||
private String createTime; | |||
@JSONField(name = "update_time") | |||
private String updateTime; | |||
} |
@ -0,0 +1,31 @@ | |||
package org.jeecg.modules.cityMoneyLog.resp; | |||
import com.alibaba.fastjson.annotation.JSONField; | |||
import lombok.Data; | |||
@Data | |||
public class TransferBatchesNotifyResp { | |||
private String id; | |||
@JSONField(name = "create_time") | |||
private String createTime; | |||
/** | |||
* 通知类型 | |||
* 通知的类型,商家转账通知的类型为MCHTRANSFER.BILL.FINISHED | |||
* */ | |||
@JSONField(name = "event_type") | |||
private String eventType; | |||
/** | |||
* 通知类型 | |||
* 通知的资源数据类型,商家转账通知为encrypt-resource | |||
* */ | |||
@JSONField(name = "resource_type") | |||
private String resourceType; | |||
/**通知数据*/ | |||
@JSONField(name = "resource") | |||
private TransferBatchNotifyResourceResp resource; | |||
/**回调摘要*/ | |||
@JSONField(name = "summary") | |||
private String summary; | |||
} |
@ -0,0 +1,53 @@ | |||
package org.jeecg.modules.cityMoneyLog.resp; | |||
import com.alibaba.fastjson.annotation.JSONField; | |||
import lombok.Data; | |||
/** | |||
* @author java996.icu | |||
* @title: TransferBatchesResp | |||
* @projectName merchant | |||
* @description: TODO | |||
* @date 2022/12/13 14:29 | |||
* @Version V1.0 | |||
*/ | |||
@Data | |||
public class TransferBatchesResp { | |||
/**微信批次单号*/ | |||
@JSONField(name = "out_bill_no") | |||
private String outBillNo; | |||
/**商家批次单号*/ | |||
@JSONField(name = "transfer_bill_no") | |||
private String transferBillNo; | |||
/**批次创建时间*/ | |||
@JSONField(name = "create_time") | |||
private String createTime; | |||
/**商家转账订单状态 | |||
* ACCEPTED: 转账已受理 | |||
* | |||
* PROCESSING: 转账处理中,转账结果尚未明确,如一直处于此状态,建议检查账户余额是否足够 | |||
* | |||
* WAIT_USER_CONFIRM: 待收款用户确认,可拉起微信收款确认页面进行收款确认 | |||
* | |||
* TRANSFERING: 转账结果尚未明确,可拉起微信收款确认页面再次重试确认收款 | |||
* | |||
* SUCCESS: 转账成功 | |||
* | |||
* FAIL: 转账失败 | |||
* | |||
* CANCELING: 商户撤销请求受理成功,该笔转账正在撤销中 | |||
* | |||
* CANCELLED: 转账撤销完成 | |||
* */ | |||
@JSONField(name = "state") | |||
private String state; | |||
/**失败原因*/ | |||
@JSONField(name = "fail_reason") | |||
private String failReason; | |||
/**跳转领取页面的package信息*/ | |||
@JSONField(name = "package_info") | |||
private String packageInfo; | |||
} |
@ -1,14 +1,13 @@ | |||
package org.jeecg.modules.api.bean; | |||
import io.swagger.annotations.ApiModelProperty; | |||
import lombok.Data; | |||
@Data | |||
public class WxQrCodeVo { | |||
/**图片地址*/ | |||
@ApiModelProperty(value = "图片地址") | |||
private String url; | |||
@ApiModelProperty(value = "加油站名称") | |||
private String name; | |||
} |
@ -0,0 +1,25 @@ | |||
-----BEGIN CERTIFICATE----- | |||
MIIELjCCAxagAwIBAgIUJG7Xen+IKln9eZk9Cf3SupqGj/4wDQYJKoZIhvcNAQEL | |||
BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT | |||
FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg | |||
Q0EwHhcNMjUwNTMwMTA1NzMzWhcNMzAwNTI5MTA1NzMzWjCBhzETMBEGA1UEAwwK | |||
MTY3MzUxNjE3NjEbMBkGA1UECgwS5b6u5L+h5ZWG5oi357O757ufMTMwMQYDVQQL | |||
DCrmuZbljZfngJrmtbfpu47mmI7kv6Hmga/np5HmioDmnInpmZDlhazlj7gxCzAJ | |||
BgNVBAYTAkNOMREwDwYDVQQHDAhTaGVuWmhlbjCCASIwDQYJKoZIhvcNAQEBBQAD | |||
ggEPADCCAQoCggEBALAOE2yiLLnpUg7/iVTEZeORO0W7AUdL3zskg4I0aT997pbw | |||
CpeSV+6K83+QlcWKnpdG0WkS9xqRgIuA/WZPYJVJG1iDUo+ndYNofx1UpZxfzvQq | |||
zSZTB1GnxIHHJQTvWF7CpxWXNKRcFmVRx5TKorL3BqYrqD/FgUBKIJNWUgEsVqJs | |||
EW8dv2iBYZdIHB51rc3wWsr2X28SGmBVOSCbG2gEkmgQr7yS7KpzE2rfl2PfsnWs | |||
KQBSX9KMToXRmEIwHVAGmWXV5RlzBACk1vOSz3Cp+GgKFcOPqrFg2pJOXwSyVUL5 | |||
WUc6t6xDqnkfg9bO5za1v4Q8S7fxK5NhMIChXVsCAwEAAaOBuTCBtjAJBgNVHRME | |||
AjAAMAsGA1UdDwQEAwID+DCBmwYDVR0fBIGTMIGQMIGNoIGKoIGHhoGEaHR0cDov | |||
L2V2Y2EuaXRydXMuY29tLmNuL3B1YmxpYy9pdHJ1c2NybD9DQT0xQkQ0MjIwRTUw | |||
REJDMDRCMDZBRDM5NzU0OTg0NkMwMUMzRThFQkQyJnNnPUhBQ0M0NzFCNjU0MjJF | |||
MTJCMjdBOUQzM0E4N0FEMUNERjU5MjZFMTQwMzcxMA0GCSqGSIb3DQEBCwUAA4IB | |||
AQBjK72tgf+Fn+9qxWhiiwyow6MtIE3arbPDhB/3WfKjHp7AA6eqdGPMrUvfufYv | |||
evM2I7ZJWsk6IiJMJlweyBalqn84Aq3raurEoL5Y+jPjXqLHTrcUfyIiGpbF8Auy | |||
bpW1pl1w2GqRnA17Ep/o0Na+9KOX+iBvv1Lm/LJnwlxJaSaOU2PFRS5QT8NRuV2/ | |||
82/FFnFfM+rDk98YjLVtob45tBKIkBeRJZ+Zsz5a7SBYnR2eVW6YgOS0fFtBI9Q/ | |||
6fuMHLbuAH9/xubPG6K4bHwVyNGHCeDp4GjfuOX/DSw49qVGiy5GxYGCczgNta+L | |||
hlDUuptj8HhkGjrExeXfZQsR | |||
-----END CERTIFICATE----- |
@ -0,0 +1,9 @@ | |||
-----BEGIN PUBLIC KEY----- | |||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxK2wqQooeGKkAQchZdwK | |||
U3qFiPSyf83l7USGGAdEhb78iq0Dvi7RfgdHuqSVBv0fnSQJicNO+s10ofi9waxl | |||
SCPnuO8t9MeOuS4IpZ54VWY/9pJ5A2Z0x49L0djoFWStFCpKzsg2fWBvc/7kYVFr | |||
nq/jFyRho8/GZtxL9RLZjWLyfnpe+erxSNFEnQLoW6LC4D5L0w9oiHboHmN9Igzc | |||
uB6pIuMwccImX1xPeu/jx2QMYrxAW/2bW3e6z4ojQWqhRtFq55INnXLV8VXE7rwI | |||
1L0RB4R39JOsKroVE/g7SiHRbGEem2BbNaAFhjCMuZzpWSCFQkTlxLJMxxTt9j0S | |||
+wIDAQAB | |||
-----END PUBLIC KEY----- |
@ -1,7 +1,7 @@ | |||
pay.mchId=1673516176 | |||
pay.appId=wxa4d29e67e8a58d38 | |||
pay.mchKey=GVIP1008611ABCDEFGGGGJKHLOSJFLGK | |||
pay.keyPath= | |||
pay.keyPath=classpath:apiclient_cert.pem | |||
pay.notifyUrl=http://h5.xzaiyp.top/api/order/payNotify | |||
pay.notifyUrlDev=http://h5.xzaiyp.top/api/order/payNotify | |||
pay.notifyVipUrl=http://h5.xzaiyp.top/api/order/vipPayNotify |
@ -0,0 +1,18 @@ | |||
欢迎使用微信支付! | |||
附件中的三份文件(证书pkcs12格式、证书pem格式、证书密钥pem格式),为接口中强制要求时需携带的证书文件。 | |||
证书属于敏感信息,请妥善保管不要泄露和被他人复制。 | |||
不同开发语言下的证书格式不同,以下为说明指引: | |||
证书pkcs12格式(apiclient_cert.p12) | |||
包含了私钥信息的证书文件,为p12(pfx)格式,由微信支付签发给您用来标识和界定您的身份 | |||
部分安全性要求较高的API需要使用该证书来确认您的调用身份 | |||
windows上可以直接双击导入系统,导入过程中会提示输入证书密码,证书密码默认为您的商户号(如:1900006031) | |||
证书pem格式(apiclient_cert.pem) | |||
从apiclient_cert.p12中导出证书部分的文件,为pem格式,请妥善保管不要泄漏和被他人复制 | |||
部分开发语言和环境,不能直接使用p12文件,而需要使用pem,所以为了方便您使用,已为您直接提供 | |||
您也可以使用openssl命令来自己导出:openssl pkcs12 -clcerts -nokeys -in apiclient_cert.p12 -out apiclient_cert.pem | |||
证书密钥pem格式(apiclient_key.pem) | |||
从apiclient_cert.p12中导出密钥部分的文件,为pem格式 | |||
部分开发语言和环境,不能直接使用p12文件,而需要使用pem,所以为了方便您使用,已为您直接提供 | |||
您也可以使用openssl命令来自己导出:openssl pkcs12 -nocerts -in apiclient_cert.p12 -out apiclient_key.pem | |||
备注说明: | |||
由于绝大部分操作系统已内置了微信支付服务器证书的根CA证书, 2018年3月6日后, 不再提供CA证书文件(rootca.pem)下载 |