Commit 66ed61c6416e36adcc7227202130b86737bc9dda
1 parent
7caf8e90
mall + pay:
1. 微信支付配置,补全 apiclient_cert.p12 证书
Showing
6 changed files
with
120 additions
and
59 deletions
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java
| 1 | 1 | package cn.iocoder.yudao.framework.pay.core.client.impl.weixin; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.bean.BeanUtil; |
| 4 | +import cn.hutool.core.codec.Base64; | |
| 4 | 5 | import cn.hutool.core.date.LocalDateTimeUtil; |
| 5 | 6 | import cn.hutool.core.date.TemporalAccessorUtil; |
| 6 | 7 | import cn.hutool.core.lang.Assert; |
| ... | ... | @@ -34,6 +35,7 @@ import static cn.hutool.core.date.DatePattern.UTC_WITH_XXX_OFFSET_PATTERN; |
| 34 | 35 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 35 | 36 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.invalidParamException; |
| 36 | 37 | import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; |
| 38 | +import static cn.iocoder.yudao.framework.pay.core.client.impl.weixin.WxPayClientConfig.API_VERSION_V2; | |
| 37 | 39 | |
| 38 | 40 | /** |
| 39 | 41 | * 微信支付抽象类,实现微信统一的接口、以及部分实现(退款) |
| ... | ... | @@ -59,12 +61,17 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC |
| 59 | 61 | WxPayConfig payConfig = new WxPayConfig(); |
| 60 | 62 | BeanUtil.copyProperties(config, payConfig, "keyContent"); |
| 61 | 63 | payConfig.setTradeType(tradeType); |
| 64 | +// if (WxPayClientConfig.API_VERSION_V2.equals(config.getApiVersion())) { | |
| 65 | +// payConfig.setSignType(WxPayConstants.SignType.MD5); | |
| 66 | +// } | |
| 67 | + // weixin-pay-java 无法设置内容,只允许读取文件,所以这里要创建临时文件来解决 | |
| 68 | + if (Base64.isBase64(config.getKeyContent())) { | |
| 69 | + payConfig.setKeyPath(FileUtils.createTempFile(Base64.decode(config.getKeyContent())).getPath()); | |
| 70 | + } | |
| 62 | 71 | if (StrUtil.isNotEmpty(config.getPrivateKeyContent())) { |
| 63 | - // weixin-pay-java 存在 BUG,无法直接设置内容,所以创建临时文件来解决 | |
| 64 | 72 | payConfig.setPrivateKeyPath(FileUtils.createTempFile(config.getPrivateKeyContent()).getPath()); |
| 65 | 73 | } |
| 66 | 74 | if (StrUtil.isNotEmpty(config.getPrivateCertContent())) { |
| 67 | - // weixin-pay-java 存在 BUG,无法直接设置内容,所以创建临时文件来解决 | |
| 68 | 75 | payConfig.setPrivateCertPath(FileUtils.createTempFile(config.getPrivateCertContent()).getPath()); |
| 69 | 76 | } |
| 70 | 77 | |
| ... | ... | @@ -77,7 +84,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC |
| 77 | 84 | protected PayOrderUnifiedRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) throws Exception { |
| 78 | 85 | try { |
| 79 | 86 | switch (config.getApiVersion()) { |
| 80 | - case WxPayClientConfig.API_VERSION_V2: | |
| 87 | + case API_VERSION_V2: | |
| 81 | 88 | return doUnifiedOrderV2(reqDTO); |
| 82 | 89 | case WxPayClientConfig.API_VERSION_V3: |
| 83 | 90 | return doUnifiedOrderV3(reqDTO); |
| ... | ... | @@ -112,7 +119,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC |
| 112 | 119 | protected PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable { |
| 113 | 120 | try { |
| 114 | 121 | switch (config.getApiVersion()) { |
| 115 | - case WxPayClientConfig.API_VERSION_V2: | |
| 122 | + case API_VERSION_V2: | |
| 116 | 123 | return doUnifiedRefundV2(reqDTO); |
| 117 | 124 | case WxPayClientConfig.API_VERSION_V3: |
| 118 | 125 | return doUnifiedRefundV3(reqDTO); |
| ... | ... | @@ -160,7 +167,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC |
| 160 | 167 | try { |
| 161 | 168 | // 微信支付 v2 回调结果处理 |
| 162 | 169 | switch (config.getApiVersion()) { |
| 163 | - case WxPayClientConfig.API_VERSION_V2: | |
| 170 | + case API_VERSION_V2: | |
| 164 | 171 | return parseOrderNotifyV2(body); |
| 165 | 172 | case WxPayClientConfig.API_VERSION_V3: |
| 166 | 173 | return parseOrderNotifyV3(body); | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPayClientConfig.java
| ... | ... | @@ -37,16 +37,17 @@ public class WxPayClientConfig implements PayClientConfig { |
| 37 | 37 | * |
| 38 | 38 | * 只有公众号或小程序需要该字段 |
| 39 | 39 | */ |
| 40 | + @NotBlank(message = "APPID 不能为空", groups = {V2.class, V3.class}) | |
| 40 | 41 | private String appId; |
| 41 | 42 | /** |
| 42 | 43 | * 商户号 |
| 43 | 44 | */ |
| 44 | - @NotBlank(message = "商户号 不能为空", groups = {V2.class, V3.class}) | |
| 45 | + @NotBlank(message = "商户号不能为空", groups = {V2.class, V3.class}) | |
| 45 | 46 | private String mchId; |
| 46 | 47 | /** |
| 47 | 48 | * API 版本 |
| 48 | 49 | */ |
| 49 | - @NotBlank(message = "API 版本 不能为空", groups = {V2.class, V3.class}) | |
| 50 | + @NotBlank(message = "API 版本不能为空", groups = {V2.class, V3.class}) | |
| 50 | 51 | private String apiVersion; |
| 51 | 52 | |
| 52 | 53 | // ========== V2 版本的参数 ========== |
| ... | ... | @@ -54,36 +55,31 @@ public class WxPayClientConfig implements PayClientConfig { |
| 54 | 55 | /** |
| 55 | 56 | * 商户密钥 |
| 56 | 57 | */ |
| 57 | - @NotBlank(message = "商户密钥 不能为空", groups = V2.class) | |
| 58 | + @NotBlank(message = "商户密钥不能为空", groups = V2.class) | |
| 58 | 59 | private String mchKey; |
| 59 | 60 | /** |
| 60 | - * apiclient_cert.p12 证书文件的绝对路径或者以 classpath: 开头的类路径. | |
| 61 | - * 对应的字符串 | |
| 61 | + * apiclient_cert.p12 证书文件的对应字符串【base64 格式】 | |
| 62 | 62 | * |
| 63 | - * 注意,可通过 {@link #main(String[])} 读取 | |
| 63 | + * 为什么采用 base64 格式?因为 p12 读取后是二进制,需要转换成 base64 格式才好传输和存储 | |
| 64 | 64 | */ |
| 65 | - /// private String keyContent; | |
| 65 | + @NotBlank(message = "apiclient_cert.p12 不能为空", groups = V2.class) | |
| 66 | + private String keyContent; | |
| 66 | 67 | |
| 67 | 68 | // ========== V3 版本的参数 ========== |
| 68 | 69 | /** |
| 69 | - * apiclient_key.pem 证书文件的绝对路径或者以 classpath: 开头的类路径. | |
| 70 | - * 对应的字符串 | |
| 71 | - * 注意,可通过 {@link #main(String[])} 读取 | |
| 70 | + * apiclient_key.pem 证书文件的对应字符串 | |
| 72 | 71 | */ |
| 73 | 72 | @NotBlank(message = "apiclient_key 不能为空", groups = V3.class) |
| 74 | 73 | private String privateKeyContent; |
| 75 | 74 | /** |
| 76 | - * apiclient_cert.pem 证书文件的绝对路径或者以 classpath: 开头的类路径. | |
| 77 | - * 对应的字符串 | |
| 78 | - * <p> | |
| 79 | - * 注意,可通过 {@link #main(String[])} 读取 | |
| 75 | + * apiclient_cert.pem 证书文件的对应的字符串 | |
| 80 | 76 | */ |
| 81 | 77 | @NotBlank(message = "apiclient_cert 不能为空", groups = V3.class) |
| 82 | 78 | private String privateCertContent; |
| 83 | 79 | /** |
| 84 | 80 | * apiV3 密钥值 |
| 85 | 81 | */ |
| 86 | - @NotBlank(message = "apiV3 密钥值 不能为空", groups = V3.class) | |
| 82 | + @NotBlank(message = "apiV3 密钥值不能为空", groups = V3.class) | |
| 87 | 83 | private String apiV3Key; |
| 88 | 84 | |
| 89 | 85 | /** | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxBarPayClientIntegrationTest.java
| ... | ... | @@ -44,7 +44,7 @@ public class WxBarPayClientIntegrationTest { |
| 44 | 44 | .totalFee(1) // 单位分 |
| 45 | 45 | .timeExpire(formatDateV2(LocalDateTimeUtils.addTime(Duration.ofMinutes(2)))) |
| 46 | 46 | .spbillCreateIp("127.0.0.1") |
| 47 | - .authCode("131276541518138032") | |
| 47 | + .authCode("134298744426278497") | |
| 48 | 48 | .build(); |
| 49 | 49 | System.out.println("========= request =========="); |
| 50 | 50 | System.out.println(JsonUtils.toJsonPrettyString(request)); |
| ... | ... | @@ -63,7 +63,7 @@ public class WxBarPayClientIntegrationTest { |
| 63 | 63 | |
| 64 | 64 | // 执行发起退款 |
| 65 | 65 | WxPayRefundRequest request = new WxPayRefundRequest() |
| 66 | - .setOutTradeNo("1689504162805") | |
| 66 | + .setOutTradeNo("1689545667276") | |
| 67 | 67 | .setOutRefundNo(String.valueOf(System.currentTimeMillis())) |
| 68 | 68 | .setRefundFee(1) |
| 69 | 69 | .setRefundDesc("就是想退了") |
| ... | ... | @@ -103,8 +103,6 @@ public class WxBarPayClientIntegrationTest { |
| 103 | 103 | config.setMchKey("dS1ngeN63JLr3NRbvPH9AJy3MyUxZdim"); |
| 104 | 104 | config.setSignType(WxPayConstants.SignType.MD5); |
| 105 | 105 | config.setKeyPath("/Users/yunai/Downloads/wx_pay/apiclient_cert.p12"); |
| 106 | - config.setPrivateCertPath("/Users/yunai/Downloads/wx_pay/apiclient_cert.pem"); | |
| 107 | - config.setPrivateKeyPath("/Users/yunai/Downloads/wx_pay/apiclient_key.pem"); | |
| 108 | 106 | return config; |
| 109 | 107 | } |
| 110 | 108 | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxNativePayClientIntegrationTest.java
| ... | ... | @@ -58,7 +58,7 @@ public class WxNativePayClientIntegrationTest { |
| 58 | 58 | |
| 59 | 59 | // 执行发起退款 |
| 60 | 60 | WxPayRefundV3Request request = new WxPayRefundV3Request() |
| 61 | - .setOutTradeNo("1689506153043") | |
| 61 | + .setOutTradeNo("1689545729695") | |
| 62 | 62 | .setOutRefundNo(String.valueOf(System.currentTimeMillis())) |
| 63 | 63 | .setAmount(new WxPayRefundV3Request.Amount().setTotal(1).setRefund(1).setCurrency("CNY")) |
| 64 | 64 | .setReason("就是想退了"); |
| ... | ... | @@ -73,10 +73,8 @@ public class WxNativePayClientIntegrationTest { |
| 73 | 73 | WxPayConfig config = new WxPayConfig(); |
| 74 | 74 | config.setAppId("wx62056c0d5e8db250"); |
| 75 | 75 | config.setMchId("1545083881"); |
| 76 | - config.setMchKey("dS1ngeN63JLr3NRbvPH9AJy3MyUxZdim"); | |
| 77 | 76 | config.setApiV3Key("459arNsYHl1mgkiO6H9ZH5KkhFXSxaA4"); |
| 78 | 77 | // config.setCertSerialNo(serialNo); |
| 79 | - config.setKeyPath("/Users/yunai/Downloads/wx_pay/apiclient_cert.p12"); | |
| 80 | 78 | config.setPrivateCertPath("/Users/yunai/Downloads/wx_pay/apiclient_cert.pem"); |
| 81 | 79 | config.setPrivateKeyPath("/Users/yunai/Downloads/wx_pay/apiclient_key.pem"); |
| 82 | 80 | return config; | ... | ... |
yudao-ui-admin/src/views/pay/app/components/wechatChannelForm.vue
| ... | ... | @@ -8,8 +8,8 @@ |
| 8 | 8 | <template slot="append">%</template> |
| 9 | 9 | </el-input> |
| 10 | 10 | </el-form-item> |
| 11 | - <el-form-item label-width="180px" label="公众号APPID" prop="weChatConfig.appId"> | |
| 12 | - <el-input v-model="form.weChatConfig.appId" placeholder="请输入公众号APPID" clearable :style="{width: '100%'}"> | |
| 11 | + <el-form-item label-width="180px" label="公众号 APPID" prop="weChatConfig.appId"> | |
| 12 | + <el-input v-model="form.weChatConfig.appId" placeholder="请输入公众号 APPID" clearable :style="{width: '100%'}"> | |
| 13 | 13 | </el-input> |
| 14 | 14 | </el-form-item> |
| 15 | 15 | <el-form-item label-width="180px" label="商户号" prop="weChatConfig.mchId"> |
| ... | ... | @@ -29,29 +29,41 @@ |
| 29 | 29 | </el-radio> |
| 30 | 30 | </el-radio-group> |
| 31 | 31 | </el-form-item> |
| 32 | - <el-form-item label-width="180px" label="商户密钥" prop="weChatConfig.mchKey" | |
| 33 | - v-if="form.weChatConfig.apiVersion === 'v2'"> | |
| 34 | - <el-input v-model="form.weChatConfig.mchKey" placeholder="请输入商户密钥" clearable | |
| 35 | - :style="{width: '100%'}" type="textarea" :autosize="{minRows: 8, maxRows: 8}"></el-input> | |
| 36 | - </el-form-item> | |
| 32 | + <div v-if="form.weChatConfig.apiVersion === 'v2'"> | |
| 33 | + <el-form-item label-width="180px" label="商户密钥" prop="weChatConfig.mchKey"> | |
| 34 | + <el-input v-model="form.weChatConfig.mchKey" placeholder="请输入商户密钥" clearable | |
| 35 | + :style="{width: '100%'}" type="textarea" :autosize="{minRows: 8, maxRows: 8}"></el-input> | |
| 36 | + </el-form-item> | |
| 37 | + <el-form-item label-width="180px" label="apiclient_cert.p12 证书" prop="weChatConfig.keyContent"> | |
| 38 | + <el-input v-model="form.weChatConfig.keyContent" type="textarea" | |
| 39 | + placeholder="请上传 apiclient_cert.p12 证书" | |
| 40 | + readonly :autosize="{minRows: 8, maxRows: 8}" :style="{width: '100%'}"></el-input> | |
| 41 | + </el-form-item> | |
| 42 | + <el-form-item label-width="180px" label=""> | |
| 43 | + <el-upload :limit="1" accept=".p12" action="" | |
| 44 | + :before-upload="p12FileBeforeUpload" | |
| 45 | + :http-request="keyContentUpload"> | |
| 46 | + <el-button size="small" type="primary" icon="el-icon-upload">点击上传</el-button> | |
| 47 | + </el-upload> | |
| 48 | + </el-form-item> | |
| 49 | + </div> | |
| 37 | 50 | <div v-if="form.weChatConfig.apiVersion === 'v3'"> |
| 38 | - <el-form-item label-width="180px" label="API V3密钥" prop="weChatConfig.apiV3Key"> | |
| 39 | - <el-input v-model="form.weChatConfig.apiV3Key" placeholder="请输入API V3密钥" clearable | |
| 51 | + <el-form-item label-width="180px" label="API V3 密钥" prop="weChatConfig.apiV3Key"> | |
| 52 | + <el-input v-model="form.weChatConfig.apiV3Key" placeholder="请输入 API V3 密钥" clearable | |
| 40 | 53 | :style="{width: '100%'}" type="textarea" :autosize="{minRows: 8, maxRows: 8}"></el-input> |
| 41 | 54 | </el-form-item> |
| 42 | - <el-form-item label-width="180px" label="apiclient_key.perm证书" prop="weChatConfig.privateKeyContent"> | |
| 55 | + <el-form-item label-width="180px" label="apiclient_key.perm 证书" prop="weChatConfig.privateKeyContent"> | |
| 43 | 56 | <el-input v-model="form.weChatConfig.privateKeyContent" type="textarea" |
| 44 | - placeholder="请上传apiclient_key.perm证书" | |
| 57 | + placeholder="请上传 apiclient_key.perm 证书" | |
| 45 | 58 | readonly :autosize="{minRows: 8, maxRows: 8}" :style="{width: '100%'}"></el-input> |
| 46 | 59 | </el-form-item> |
| 47 | 60 | <el-form-item label-width="180px" label="" prop="privateKeyContentFile"> |
| 48 | 61 | <el-upload ref="privateKeyContentFile" |
| 49 | 62 | :limit="1" |
| 50 | - :accept="fileAccept" | |
| 51 | - :headers="header" | |
| 63 | + accept=".pem" | |
| 52 | 64 | action="" |
| 53 | 65 | :before-upload="pemFileBeforeUpload" |
| 54 | - :http-request="privateKeyUpload" | |
| 66 | + :http-request="privateKeyContentUpload" | |
| 55 | 67 | > |
| 56 | 68 | <el-button size="small" type="primary" icon="el-icon-upload">点击上传</el-button> |
| 57 | 69 | </el-upload> |
| ... | ... | @@ -64,18 +76,17 @@ |
| 64 | 76 | <el-form-item label-width="180px" label="" prop="privateCertContentFile"> |
| 65 | 77 | <el-upload ref="privateCertContentFile" |
| 66 | 78 | :limit="1" |
| 67 | - :accept="fileAccept" | |
| 68 | - :headers="header" | |
| 79 | + accept=".pem" | |
| 69 | 80 | action="" |
| 70 | 81 | :before-upload="pemFileBeforeUpload" |
| 71 | - :http-request="privateCertUpload" | |
| 82 | + :http-request="privateCertContentUpload" | |
| 72 | 83 | > |
| 73 | 84 | <el-button size="small" type="primary" icon="el-icon-upload">点击上传</el-button> |
| 74 | 85 | </el-upload> |
| 75 | 86 | </el-form-item> |
| 76 | 87 | </div> |
| 77 | 88 | <el-form-item label-width="180px" label="备注" prop="remark"> |
| 78 | - <el-input v-model="form.remark" :style="{width: '100%'}"></el-input> | |
| 89 | + <el-input v-model="form.remark" :style="{width: '100%'}" /> | |
| 79 | 90 | </el-form-item> |
| 80 | 91 | </el-form> |
| 81 | 92 | <div slot="footer" class="dialog-footer"> |
| ... | ... | @@ -100,6 +111,7 @@ const defaultForm = { |
| 100 | 111 | mchId: '', |
| 101 | 112 | apiVersion: '', |
| 102 | 113 | mchKey: '', |
| 114 | + keyContent: '', | |
| 103 | 115 | privateKeyContent: '', |
| 104 | 116 | privateCertContent: '', |
| 105 | 117 | apiV3Key:'', |
| ... | ... | @@ -159,27 +171,27 @@ export default { |
| 159 | 171 | message: '请输入商户密钥', |
| 160 | 172 | trigger: 'blur' |
| 161 | 173 | }], |
| 174 | + 'weChatConfig.keyContent': [{ | |
| 175 | + required: true, | |
| 176 | + message: '请上传 apiclient_cert.p12 证书', | |
| 177 | + trigger: 'blur' | |
| 178 | + }], | |
| 162 | 179 | 'weChatConfig.privateKeyContent': [{ |
| 163 | 180 | required: true, |
| 164 | - message: '请上传apiclient_key.perm证书', | |
| 181 | + message: '请上传 apiclient_key.perm 证书', | |
| 165 | 182 | trigger: 'blur' |
| 166 | 183 | }], |
| 167 | 184 | 'weChatConfig.privateCertContent': [{ |
| 168 | 185 | required: true, |
| 169 | - message: '请上传apiclient_cert.perm证书', | |
| 186 | + message: '请上传 apiclient_cert.perm证 书', | |
| 170 | 187 | trigger: 'blur' |
| 171 | 188 | }], |
| 172 | 189 | 'weChatConfig.apiV3Key': [{ |
| 173 | 190 | required: true, |
| 174 | - message: '请上传apiV3密钥值', | |
| 191 | + message: '请上传 api V3 密钥值', | |
| 175 | 192 | trigger: 'blur' |
| 176 | 193 | }], |
| 177 | 194 | }, |
| 178 | - // 文件上传的header | |
| 179 | - header: { | |
| 180 | - "Authorization": null | |
| 181 | - }, | |
| 182 | - fileAccept: ".pem", | |
| 183 | 195 | // 渠道状态 数据字典 |
| 184 | 196 | statusDictDatas: getDictDatas(DICT_TYPE.COMMON_STATUS), |
| 185 | 197 | versionDictDatas: getDictDatas(DICT_TYPE.PAY_CHANNEL_WECHAT_VERSION), |
| ... | ... | @@ -218,6 +230,7 @@ export default { |
| 218 | 230 | this.form.weChatConfig.apiVersion = config.apiVersion; |
| 219 | 231 | this.form.weChatConfig.mchId = config.mchId; |
| 220 | 232 | this.form.weChatConfig.mchKey = config.mchKey; |
| 233 | + this.form.weChatConfig.keyContent = config.keyContent; | |
| 221 | 234 | this.form.weChatConfig.privateKeyContent = config.privateKeyContent; |
| 222 | 235 | this.form.weChatConfig.privateCertContent = config.privateCertContent; |
| 223 | 236 | this.form.weChatConfig.apiV3Key = config.apiV3Key; |
| ... | ... | @@ -241,7 +254,6 @@ export default { |
| 241 | 254 | this.$modal.msgSuccess("修改成功"); |
| 242 | 255 | this.close(); |
| 243 | 256 | } |
| 244 | - | |
| 245 | 257 | }) |
| 246 | 258 | } else { |
| 247 | 259 | |
| ... | ... | @@ -255,10 +267,14 @@ export default { |
| 255 | 267 | } |
| 256 | 268 | }); |
| 257 | 269 | }, |
| 258 | - pemFileBeforeUpload(file) { | |
| 270 | + /** | |
| 271 | + * apiclient_cert.p12、apiclient_cert.pem、apiclient_key.pem 上传前的校验 | |
| 272 | + */ | |
| 273 | + fileBeforeUpload(file, fileAccept) { | |
| 259 | 274 | let format = '.' + file.name.split(".")[1]; |
| 260 | - if (format !== this.fileAccept) { | |
| 261 | - this.$message.error('请上传指定格式"' + this.fileAccept + '"文件'); | |
| 275 | + if (format !== fileAccept) { | |
| 276 | + debugger | |
| 277 | + this.$message.error('请上传指定格式"' + fileAccept + '"文件'); | |
| 262 | 278 | return false; |
| 263 | 279 | } |
| 264 | 280 | let isRightSize = file.size / 1024 / 1024 < 2 |
| ... | ... | @@ -267,19 +283,41 @@ export default { |
| 267 | 283 | } |
| 268 | 284 | return isRightSize |
| 269 | 285 | }, |
| 270 | - privateKeyUpload(event) { | |
| 286 | + p12FileBeforeUpload(file) { | |
| 287 | + this.fileBeforeUpload(file, '.p12') | |
| 288 | + }, | |
| 289 | + pemFileBeforeUpload(file) { | |
| 290 | + this.fileBeforeUpload(file, '.pem') | |
| 291 | + }, | |
| 292 | + /** | |
| 293 | + * 读取 apiclient_key.pem 到 privateKeyContent 字段 | |
| 294 | + */ | |
| 295 | + privateKeyContentUpload(event) { | |
| 271 | 296 | const readFile = new FileReader() |
| 272 | 297 | readFile.onload = (e) => { |
| 273 | 298 | this.form.weChatConfig.privateKeyContent = e.target.result |
| 274 | 299 | } |
| 275 | 300 | readFile.readAsText(event.file); |
| 276 | 301 | }, |
| 277 | - privateCertUpload(event) { | |
| 302 | + /** | |
| 303 | + * 读取 apiclient_cert.pem 到 privateCertContent 字段 | |
| 304 | + */ | |
| 305 | + privateCertContentUpload(event) { | |
| 278 | 306 | const readFile = new FileReader() |
| 279 | 307 | readFile.onload = (e) => { |
| 280 | 308 | this.form.weChatConfig.privateCertContent = e.target.result |
| 281 | 309 | } |
| 282 | 310 | readFile.readAsText(event.file); |
| 311 | + }, | |
| 312 | + /** | |
| 313 | + * 读取 apiclient_cert.p12 到 keyContent 字段 | |
| 314 | + */ | |
| 315 | + keyContentUpload(event) { | |
| 316 | + const readFile = new FileReader() | |
| 317 | + readFile.onload = (e) => { | |
| 318 | + this.form.weChatConfig.keyContent = e.target.result.split(',')[1] | |
| 319 | + } | |
| 320 | + readFile.readAsDataURL(event.file); // 读成 base64 | |
| 283 | 321 | } |
| 284 | 322 | } |
| 285 | 323 | } | ... | ... |
yudao-ui-admin/src/views/pay/app/index.vue
| ... | ... | @@ -143,6 +143,30 @@ |
| 143 | 143 | </el-button> |
| 144 | 144 | </template> |
| 145 | 145 | </el-table-column> |
| 146 | + <el-table-column :label="payChannelEnum.WX_NATIVE.name" align="center"> | |
| 147 | + <template v-slot="scope"> | |
| 148 | + <el-button type="success" icon="el-icon-check" circle | |
| 149 | + v-if="judgeChannelExist(scope.row.channelCodes,payChannelEnum.WX_NATIVE.code)" | |
| 150 | + @click="handleUpdateChannel(scope.row,payChannelEnum.WX_NATIVE.code,payType.WECHAT)"> | |
| 151 | + </el-button> | |
| 152 | + <el-button v-else | |
| 153 | + type="danger" icon="el-icon-close" circle | |
| 154 | + @click="handleCreateChannel(scope.row,payChannelEnum.WX_NATIVE.code,payType.WECHAT)"> | |
| 155 | + </el-button> | |
| 156 | + </template> | |
| 157 | + </el-table-column> | |
| 158 | + <el-table-column :label="payChannelEnum.WX_BAR.name" align="center"> | |
| 159 | + <template v-slot="scope"> | |
| 160 | + <el-button type="success" icon="el-icon-check" circle | |
| 161 | + v-if="judgeChannelExist(scope.row.channelCodes,payChannelEnum.WX_BAR.code)" | |
| 162 | + @click="handleUpdateChannel(scope.row,payChannelEnum.WX_BAR.code,payType.WECHAT)"> | |
| 163 | + </el-button> | |
| 164 | + <el-button v-else | |
| 165 | + type="danger" icon="el-icon-close" circle | |
| 166 | + @click="handleCreateChannel(scope.row,payChannelEnum.WX_BAR.code,payType.WECHAT)"> | |
| 167 | + </el-button> | |
| 168 | + </template> | |
| 169 | + </el-table-column> | |
| 146 | 170 | </el-table-column> |
| 147 | 171 | <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> |
| 148 | 172 | <template v-slot="scope"> | ... | ... |