weixinChannelForm.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. <template>
  2. <div>
  3. <el-dialog :visible.sync="dialogVisible" :title="title" @close="close" append-to-body width="800px">
  4. <el-form ref="form" :model="formData" :rules="rules" size="medium" label-width="120px"
  5. v-loading="formLoading">
  6. <el-form-item label-width="180px" label="渠道费率" prop="feeRate">
  7. <el-input v-model="formData.feeRate" placeholder="请输入渠道费率" clearable :style="{width: '100%'}">
  8. <template slot="append">%</template>
  9. </el-input>
  10. </el-form-item>
  11. <el-form-item label-width="180px" label="公众号 APPID" prop="config.appId">
  12. <el-input v-model="formData.config.appId" placeholder="请输入公众号 APPID" clearable :style="{width: '100%'}">
  13. </el-input>
  14. </el-form-item>
  15. <el-form-item label-width="180px" label="商户号" prop="config.mchId">
  16. <el-input v-model="formData.config.mchId" :style="{width: '100%'}"></el-input>
  17. </el-form-item>
  18. <el-form-item label-width="180px" label="渠道状态" prop="status">
  19. <el-radio-group v-model="formData.status" size="medium">
  20. <el-radio v-for="dict in this.getDictDatas(DICT_TYPE.COMMON_STATUS)" :key="parseInt(dict.value)"
  21. :label="parseInt(dict.value)">
  22. {{ dict.label }}
  23. </el-radio>
  24. </el-radio-group>
  25. </el-form-item>
  26. <el-form-item label-width="180px" label="API 版本" prop="config.apiVersion">
  27. <el-radio-group v-model="formData.config.apiVersion" size="medium">
  28. <el-radio label="v2">v2</el-radio>
  29. <el-radio label="v3">v3</el-radio>
  30. </el-radio-group>
  31. </el-form-item>
  32. <div v-if="formData.config.apiVersion === 'v2'">
  33. <el-form-item label-width="180px" label="商户密钥" prop="config.mchKey">
  34. <el-input v-model="formData.config.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="config.keyContent">
  38. <el-input v-model="formData.config.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>
  50. <div v-if="formData.config.apiVersion === 'v3'">
  51. <el-form-item label-width="180px" label="API V3 密钥" prop="config.apiV3Key">
  52. <el-input v-model="formData.config.apiV3Key" placeholder="请输入 API V3 密钥" clearable
  53. :style="{width: '100%'}" type="textarea" :autosize="{minRows: 8, maxRows: 8}"></el-input>
  54. </el-form-item>
  55. <el-form-item label-width="180px" label="apiclient_key.perm 证书" prop="config.privateKeyContent">
  56. <el-input v-model="formData.config.privateKeyContent" type="textarea"
  57. placeholder="请上传 apiclient_key.perm 证书"
  58. readonly :autosize="{minRows: 8, maxRows: 8}" :style="{width: '100%'}"></el-input>
  59. </el-form-item>
  60. <el-form-item label-width="180px" label="" prop="privateKeyContentFile">
  61. <el-upload ref="privateKeyContentFile"
  62. :limit="1"
  63. accept=".pem"
  64. action=""
  65. :before-upload="pemFileBeforeUpload"
  66. :http-request="privateKeyContentUpload"
  67. >
  68. <el-button size="small" type="primary" icon="el-icon-upload">点击上传</el-button>
  69. </el-upload>
  70. </el-form-item>
  71. <el-form-item label-width="180px" label="apiclient_cert.perm证书" prop="config.privateCertContent">
  72. <el-input v-model="formData.config.privateCertContent" type="textarea"
  73. placeholder="请上传apiclient_cert.perm证书"
  74. readonly :autosize="{minRows: 8, maxRows: 8}" :style="{width: '100%'}"></el-input>
  75. </el-form-item>
  76. <el-form-item label-width="180px" label="" prop="privateCertContentFile">
  77. <el-upload ref="privateCertContentFile"
  78. :limit="1"
  79. accept=".pem"
  80. action=""
  81. :before-upload="pemFileBeforeUpload"
  82. :http-request="privateCertContentUpload"
  83. >
  84. <el-button size="small" type="primary" icon="el-icon-upload">点击上传</el-button>
  85. </el-upload>
  86. </el-form-item>
  87. </div>
  88. <el-form-item label-width="180px" label="备注" prop="remark">
  89. <el-input v-model="formData.remark" :style="{width: '100%'}" />
  90. </el-form-item>
  91. </el-form>
  92. <div slot="footer" class="dialog-footer">
  93. <el-button @click="close">取消</el-button>
  94. <el-button type="primary" @click="submitForm">确定</el-button>
  95. </div>
  96. </el-dialog>
  97. </div>
  98. </template>
  99. <script>
  100. import { createChannel, getChannel, updateChannel } from "@/api/pay/channel";
  101. import { CommonStatusEnum } from "@/utils/constants";
  102. export default {
  103. name: "weixinChannelForm",
  104. data() {
  105. return {
  106. dialogVisible: false,
  107. formLoading: false,
  108. title:'',
  109. formData: {
  110. appId: '',
  111. code: '',
  112. status: undefined,
  113. feeRate: undefined,
  114. remark: '',
  115. config: {
  116. appId: '',
  117. mchId: '',
  118. apiVersion: '',
  119. mchKey: '',
  120. keyContent: '',
  121. privateKeyContent: '',
  122. privateCertContent: '',
  123. apiV3Key:'',
  124. }
  125. },
  126. rules: {
  127. feeRate: [{ required: true, message: '请输入渠道费率', trigger: 'blur' }],
  128. status: [{ required: true, message: '渠道状态不能为空', trigger: 'blur'}],
  129. 'config.mchId': [{ required: true, message: '请传入商户号', trigger: 'blur'}],
  130. 'config.appId': [{ required: true, message: '请输入公众号APPID', trigger: 'blur'}],
  131. 'config.apiVersion': [{ required: true, message: 'API版本不能为空', trigger: 'blur'}],
  132. 'config.mchKey': [{ required: true, message: '请输入商户密钥', trigger: 'blur' }],
  133. 'config.keyContent': [{ required: true, message: '请上传 apiclient_cert.p12 证书', trigger: 'blur' }],
  134. 'config.privateKeyContent': [{ required: true, message: '请上传 apiclient_key.perm 证书', trigger: 'blur' }],
  135. 'config.privateCertContent': [{ required: true, message: '请上传 apiclient_cert.perm证 书', trigger: 'blur' }],
  136. 'config.apiV3Key': [{ required: true, message: '请上传 api V3 密钥值', trigger: 'blur' }],
  137. },
  138. }
  139. },
  140. methods: {
  141. open(appId, code) {
  142. this.dialogVisible = true;
  143. this.formLoading = true;
  144. this.reset(appId, code);
  145. getChannel(appId, code).then(response => {
  146. if (response.data && response.data.id) {
  147. this.formData = response.data;
  148. this.formData.config = JSON.parse(response.data.config);
  149. }
  150. this.title = !this.formData.id ? '创建支付渠道' : '编辑支付渠道'
  151. }).finally(() => {
  152. this.formLoading = false;
  153. });
  154. },
  155. close() {
  156. this.dialogVisible = false;
  157. this.reset(undefined, undefined);
  158. },
  159. submitForm() {
  160. this.$refs['form'].validate(valid => {
  161. if (!valid) {
  162. return
  163. }
  164. const data = { ...this.formData };
  165. data.config = JSON.stringify(this.formData.config);
  166. if (!data.id) {
  167. createChannel(data).then(response => {
  168. this.$modal.msgSuccess("新增成功");
  169. this.$emit('success')
  170. this.close();
  171. });
  172. } else {
  173. updateChannel(data).then(response => {
  174. this.$modal.msgSuccess("修改成功");
  175. this.$emit('success')
  176. this.close();
  177. })
  178. }
  179. });
  180. },
  181. /** 重置表单 */
  182. reset(appId, code) {
  183. this.formData = {
  184. appId: appId,
  185. code: code,
  186. status: CommonStatusEnum.ENABLE,
  187. feeRate: undefined,
  188. remark: '',
  189. config: {
  190. appId: '',
  191. mchId: '',
  192. apiVersion: '',
  193. mchKey: '',
  194. keyContent: '',
  195. privateKeyContent: '',
  196. privateCertContent: '',
  197. apiV3Key:'',
  198. }
  199. }
  200. this.resetForm('form')
  201. },
  202. /**
  203. * apiclient_cert.p12、apiclient_cert.pem、apiclient_key.pem 上传前的校验
  204. */
  205. fileBeforeUpload(file, fileAccept) {
  206. let format = '.' + file.name.split(".")[1];
  207. if (format !== fileAccept) {
  208. debugger
  209. this.$message.error('请上传指定格式"' + fileAccept + '"文件');
  210. return false;
  211. }
  212. let isRightSize = file.size / 1024 / 1024 < 2
  213. if (!isRightSize) {
  214. this.$message.error('文件大小超过 2MB')
  215. }
  216. return isRightSize
  217. },
  218. p12FileBeforeUpload(file) {
  219. this.fileBeforeUpload(file, '.p12')
  220. },
  221. pemFileBeforeUpload(file) {
  222. this.fileBeforeUpload(file, '.pem')
  223. },
  224. /**
  225. * 读取 apiclient_key.pem 到 privateKeyContent 字段
  226. */
  227. privateKeyContentUpload(event) {
  228. const readFile = new FileReader()
  229. readFile.onload = (e) => {
  230. this.formData.config.privateKeyContent = e.target.result
  231. }
  232. readFile.readAsText(event.file);
  233. },
  234. /**
  235. * 读取 apiclient_cert.pem 到 privateCertContent 字段
  236. */
  237. privateCertContentUpload(event) {
  238. const readFile = new FileReader()
  239. readFile.onload = (e) => {
  240. this.formData.config.privateCertContent = e.target.result
  241. }
  242. readFile.readAsText(event.file);
  243. },
  244. /**
  245. * 读取 apiclient_cert.p12 到 keyContent 字段
  246. */
  247. keyContentUpload(event) {
  248. const readFile = new FileReader()
  249. readFile.onload = (e) => {
  250. this.formData.config.keyContent = e.target.result.split(',')[1]
  251. }
  252. readFile.readAsDataURL(event.file); // 读成 base64
  253. }
  254. }
  255. }
  256. </script>