go-receivingAccount.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. <template>
  2. <el-dialog
  3. :model-value="modelValue"
  4. title="设置收款账号"
  5. width="520px"
  6. destroy-on-close
  7. append-to-body
  8. @update:model-value="emit('update:modelValue', $event)"
  9. >
  10. <el-form ref="formRef" :model="form" :rules="rules" label-width="140px" label-position="top">
  11. <el-form-item label="账号类型" prop="accountType">
  12. <el-radio-group v-model="form.accountType">
  13. <el-radio value="wechat"> 微信 </el-radio>
  14. <el-radio value="alipay"> 支付宝 </el-radio>
  15. </el-radio-group>
  16. </el-form-item>
  17. <el-form-item label="appid" prop="wechatAppid" v-if="form.accountType === 'wechat'">
  18. <el-input v-model="form.wechatAppid" placeholder="请输入" clearable />
  19. </el-form-item>
  20. <el-form-item label="mchld" prop="wechatMchld" v-if="form.accountType === 'wechat'">
  21. <el-input v-model="form.wechatMchld" placeholder="请输入" clearable />
  22. </el-form-item>
  23. <el-form-item label="小程序appid" prop="wechatMiniAppId" v-if="form.accountType === 'wechat'">
  24. <el-input v-model="form.wechatMiniAppId" placeholder="请输入" clearable />
  25. </el-form-item>
  26. <el-form-item label="API证书序列号" prop="wechatApiCertSerialNo" v-if="form.accountType === 'wechat'">
  27. <el-input v-model="form.wechatApiCertSerialNo" placeholder="请输入" clearable />
  28. </el-form-item>
  29. <el-form-item label="APIv3 Key" prop="wechatApiV3Key" v-if="form.accountType === 'wechat'">
  30. <el-input v-model="form.wechatApiV3Key" placeholder="请输入" clearable />
  31. </el-form-item>
  32. <el-form-item label="支付公钥ID" prop="wechatPayPublicKeyId" v-if="form.accountType === 'wechat'">
  33. <el-input v-model="form.wechatPayPublicKeyId" placeholder="请输入" clearable />
  34. </el-form-item>
  35. <el-form-item label="私钥证书" prop="wechatPrivateKeyFile" v-if="form.accountType === 'wechat'">
  36. <el-upload
  37. v-model:file-list="form.wechatPrivateKeyFile"
  38. class="set-pay-key-upload"
  39. drag
  40. :auto-upload="false"
  41. :limit="1"
  42. accept=".pem"
  43. :on-exceed="() => ElMessage.warning('最多上传1个文件')"
  44. >
  45. <div class="set-pay-upload-box">
  46. <el-icon :size="32" color="#6c8ff8">
  47. <UploadFilled />
  48. </el-icon>
  49. <p>点击或拖拽文件至此处上传</p>
  50. <span>支持.pem 格式文件,大小不超过2MB</span>
  51. </div>
  52. </el-upload>
  53. </el-form-item>
  54. <el-form-item label="公钥证书" prop="wechatPayPublicKeyFile" v-if="form.accountType === 'wechat'">
  55. <el-upload
  56. v-model:file-list="form.wechatPayPublicKeyFile"
  57. class="set-pay-key-upload"
  58. drag
  59. :auto-upload="false"
  60. :limit="1"
  61. accept=".pem"
  62. :on-exceed="() => ElMessage.warning('最多上传1个文件')"
  63. >
  64. <div class="set-pay-upload-box">
  65. <el-icon :size="32" color="#6c8ff8">
  66. <UploadFilled />
  67. </el-icon>
  68. <p>点击或拖拽文件至此处上传</p>
  69. <span>支持.pem 格式文件,大小不超过2MB</span>
  70. </div>
  71. </el-upload>
  72. </el-form-item>
  73. <!-- 支付宝 -->
  74. <el-form-item label="应用ID" prop="aliAppid" v-if="form.accountType === 'alipay'">
  75. <el-input v-model="form.aliAppid" placeholder="请输入" clearable />
  76. </el-form-item>
  77. <el-form-item label="应用私钥" prop="aliPrivateId" v-if="form.accountType === 'alipay'">
  78. <el-input v-model="form.aliPrivateId" placeholder="请输入" clearable />
  79. </el-form-item>
  80. <el-form-item label="应用公钥证书" prop="appPublicCertFile" v-if="form.accountType === 'alipay'">
  81. <el-upload
  82. v-model:file-list="form.appPublicCertFile"
  83. class="set-pay-key-upload"
  84. drag
  85. :auto-upload="false"
  86. :limit="1"
  87. accept=".pem"
  88. :on-exceed="() => ElMessage.warning('最多上传1个文件')"
  89. >
  90. <div class="set-pay-upload-box">
  91. <el-icon :size="32" color="#6c8ff8">
  92. <UploadFilled />
  93. </el-icon>
  94. <p>点击或拖拽文件至此处上传</p>
  95. <span>支持.pem 格式文件,大小不超过2MB</span>
  96. </div>
  97. </el-upload>
  98. </el-form-item>
  99. <el-form-item label="支付宝公钥证书" prop="alipayPublicCertFile" v-if="form.accountType === 'alipay'">
  100. <el-upload
  101. v-model:file-list="form.alipayPublicCertFile"
  102. class="set-pay-key-upload"
  103. drag
  104. :auto-upload="false"
  105. :limit="1"
  106. accept=".pem"
  107. :on-exceed="() => ElMessage.warning('最多上传1个文件')"
  108. >
  109. <div class="set-pay-upload-box">
  110. <el-icon :size="32" color="#6c8ff8">
  111. <UploadFilled />
  112. </el-icon>
  113. <p>点击或拖拽文件至此处上传</p>
  114. <span>支持.pem 格式文件,大小不超过2MB</span>
  115. </div>
  116. </el-upload>
  117. </el-form-item>
  118. <el-form-item label="支付宝根证书" prop="alipayRootCertFile" v-if="form.accountType === 'alipay'">
  119. <el-upload
  120. v-model:file-list="form.alipayRootCertFile"
  121. class="set-pay-key-upload"
  122. drag
  123. :auto-upload="false"
  124. :limit="1"
  125. accept=".pem"
  126. :on-exceed="() => ElMessage.warning('最多上传1个文件')"
  127. >
  128. <div class="set-pay-upload-box">
  129. <el-icon :size="32" color="#6c8ff8">
  130. <UploadFilled />
  131. </el-icon>
  132. <p>点击或拖拽文件至此处上传</p>
  133. <span>支持.pem 格式文件,大小不超过2MB</span>
  134. </div>
  135. </el-upload>
  136. </el-form-item>
  137. </el-form>
  138. <template #footer>
  139. <el-button @click="emit('update:modelValue', false)"> 取消 </el-button>
  140. <el-button type="primary" @click="submit"> 确定 </el-button>
  141. </template>
  142. </el-dialog>
  143. </template>
  144. <script setup lang="ts">
  145. import { ref, reactive, watch } from "vue";
  146. import { ElMessage, type FormInstance, type UploadUserFile } from "element-plus";
  147. import { UploadFilled } from "@element-plus/icons-vue";
  148. import { getPaymentStoreUserId, saveWechatWithFiles, saveAlipayWithFiles } from "@/api/modules/newLoginApi";
  149. import { localGet } from "@/utils/index";
  150. const props = defineProps<{
  151. modelValue: boolean;
  152. }>();
  153. const emit = defineEmits<{
  154. (e: "update:modelValue", value: boolean): void;
  155. (e: "success"): void;
  156. (e: "hasConfig", value: boolean): void;
  157. }>();
  158. const formRef = ref<FormInstance>();
  159. const form = reactive({
  160. accountType: "wechat",
  161. wechatAppid: "",
  162. wechatMchld: "",
  163. wechatMiniAppId: "",
  164. wechatApiCertSerialNo: "",
  165. wechatApiV3Key: "",
  166. wechatPayPublicKeyId: null as string | null,
  167. wechatPrivateKeyFile: [] as UploadUserFile[],
  168. wechatPayPublicKeyFile: [] as UploadUserFile[],
  169. aliAppid: "",
  170. aliPrivateId: "",
  171. alipayRootCertFile: [] as UploadUserFile[],
  172. alipayPublicCertFile: [] as UploadUserFile[],
  173. appPublicCertFile: [] as UploadUserFile[]
  174. });
  175. const rules = ref({
  176. accountType: [{ required: true, message: "请选择账号类型", trigger: "change" }],
  177. wechatAppid: [{ required: true, message: "请输入appid", trigger: "blur" }],
  178. wechatMchld: [{ required: true, message: "请输入mchId", trigger: "blur" }],
  179. wechatApiCertSerialNo: [{ required: true, message: "请输入API证书序列号", trigger: "blur" }],
  180. wechatApiV3Key: [{ required: true, message: "请输入APIv3 Key", trigger: "blur" }],
  181. wechatPayPublicKeyId: [{ required: true, message: "请输入支付公钥ID", trigger: "blur" }],
  182. wechatMiniAppId: [{ required: true, message: "请输入小程序AppId", trigger: "blur" }],
  183. wechatPrivateKeyFile: [{ required: true, type: "array" as const, min: 1, message: "请上传私钥证书", trigger: "change" }],
  184. wechatPayPublicKeyFile: [{ required: true, type: "array" as const, min: 1, message: "请上传公钥证书", trigger: "change" }]
  185. });
  186. const base64ToFile = (base64Str: string, fileName: string): File => {
  187. const bstr = atob(base64Str);
  188. const u8arr = new Uint8Array(bstr.length);
  189. for (let i = 0; i < bstr.length; i++) u8arr[i] = bstr.charCodeAt(i);
  190. return new File([u8arr], fileName, { type: "application/x-pem-file" });
  191. };
  192. const fetchPayAccountConfig = async () => {
  193. const storeUserId = localGet("geeker-user")?.userInfo?.id;
  194. if (!storeUserId) return;
  195. const res: any = await getPaymentStoreUserId({ storeUserId });
  196. if (res?.code !== 200 || !res.data) {
  197. emit("hasConfig", false);
  198. return;
  199. }
  200. const data = res.data;
  201. emit("hasConfig", !!(data.wechatAppId || data.appId));
  202. if (data.wechatAppId) {
  203. form.accountType = "wechat";
  204. form.wechatAppid = data.wechatAppId ?? "";
  205. form.wechatMchld = data.wechatMchId ?? "";
  206. form.wechatMiniAppId = data.wechatMiniAppId ?? "";
  207. form.wechatApiCertSerialNo = data.merchantSerialNumber ?? "";
  208. form.wechatApiV3Key = data.apiV3Key ?? "";
  209. form.wechatPayPublicKeyId = data.wechatPayPublicKeyId ?? null;
  210. form.wechatPrivateKeyFile = [];
  211. form.wechatPayPublicKeyFile = [];
  212. if (data.wechatPrivateKeyFile && data.wechatPrivateKeyName) {
  213. const file = base64ToFile(data.wechatPrivateKeyFile, data.wechatPrivateKeyName);
  214. form.wechatPrivateKeyFile = [{ name: file.name, raw: file, status: "success", uid: Date.now() } as UploadUserFile];
  215. }
  216. if (data.wechatPayPublicKeyFile && data.wechatPayPublicKeyFileName) {
  217. const file = base64ToFile(data.wechatPayPublicKeyFile, data.wechatPayPublicKeyFileName);
  218. form.wechatPayPublicKeyFile = [{ name: file.name, raw: file, status: "success", uid: Date.now() + 1 } as UploadUserFile];
  219. }
  220. }
  221. if (data.appId) {
  222. form.aliAppid = data.appId ?? "";
  223. form.aliPrivateId = data.appSecretCert ?? "";
  224. form.appPublicCertFile = [];
  225. form.alipayPublicCertFile = [];
  226. form.alipayRootCertFile = [];
  227. if (data.appPublicCert && data.appPublicCertName) {
  228. const file = base64ToFile(data.appPublicCert, data.appPublicCertName);
  229. form.appPublicCertFile = [{ name: file.name, raw: file, status: "success", uid: Date.now() } as UploadUserFile];
  230. }
  231. if (data.alipayPublicCert && data.alipayPublicCertName) {
  232. const file = base64ToFile(data.alipayPublicCert, data.alipayPublicCertName);
  233. form.alipayPublicCertFile = [{ name: file.name, raw: file, status: "success", uid: Date.now() + 1 } as UploadUserFile];
  234. }
  235. if (data.alipayRootCert && data.alipayRootCertName) {
  236. const file = base64ToFile(data.alipayRootCert, data.alipayRootCertName);
  237. form.alipayRootCertFile = [{ name: file.name, raw: file, status: "success", uid: Date.now() + 2 } as UploadUserFile];
  238. }
  239. if (!data.wechatAppId) form.accountType = "alipay";
  240. }
  241. };
  242. const submit = async () => {
  243. if (!formRef.value) return;
  244. await formRef.value.validate(async valid => {
  245. if (!valid) return;
  246. const storeUserId = localGet("geeker-user")?.userInfo?.id;
  247. if (!storeUserId) {
  248. ElMessage.warning("请先登录");
  249. return;
  250. }
  251. if (form.accountType === "alipay") {
  252. const appPublicCertFile = (form.appPublicCertFile as UploadUserFile[])[0]?.raw as File | undefined;
  253. const alipayPublicCertFile = (form.alipayPublicCertFile as UploadUserFile[])[0]?.raw as File | undefined;
  254. const alipayRootCertFile = (form.alipayRootCertFile as UploadUserFile[])[0]?.raw as File | undefined;
  255. if (!form.aliAppid?.trim()) {
  256. ElMessage.warning("请输入应用ID");
  257. return;
  258. }
  259. if (!form.aliPrivateId?.trim()) {
  260. ElMessage.warning("请输入应用私钥");
  261. return;
  262. }
  263. if (!appPublicCertFile || !alipayPublicCertFile || !alipayRootCertFile) {
  264. ElMessage.warning("请上传应用公钥证书、支付宝公钥证书和支付宝根证书");
  265. return;
  266. }
  267. try {
  268. const res: any = await saveAlipayWithFiles(
  269. {
  270. storeUserId: String(storeUserId),
  271. appId: form.aliAppid.trim(),
  272. appSecretCert: form.aliPrivateId.trim()
  273. },
  274. appPublicCertFile,
  275. alipayPublicCertFile,
  276. alipayRootCertFile
  277. );
  278. if (res?.code === 200) {
  279. ElMessage.success("保存成功");
  280. emit("success");
  281. emit("update:modelValue", false);
  282. } else {
  283. ElMessage.error(res?.msg || "保存失败");
  284. }
  285. } catch (e: any) {
  286. ElMessage.error(e?.message || "保存失败");
  287. }
  288. return;
  289. }
  290. if (form.accountType === "wechat") {
  291. const privateKeyUpload = (form.wechatPrivateKeyFile as UploadUserFile[])[0];
  292. const publicKeyUpload = (form.wechatPayPublicKeyFile as UploadUserFile[])[0];
  293. const privateKeyFile = privateKeyUpload?.raw as File | undefined;
  294. const publicKeyFile = publicKeyUpload?.raw as File | undefined;
  295. if (!privateKeyFile || !publicKeyFile) {
  296. ElMessage.warning("请上传私钥证书和公钥证书");
  297. return;
  298. }
  299. try {
  300. const res: any = await saveWechatWithFiles(
  301. {
  302. storeUserId: String(storeUserId),
  303. apiV3Key: form.wechatApiV3Key || "",
  304. merchantSerialNumber: form.wechatApiCertSerialNo || "",
  305. wechatAppId: form.wechatAppid || "",
  306. wechatMchId: form.wechatMchld || "",
  307. wechatMiniAppId: form.wechatMiniAppId || "",
  308. wechatPayPublicKeyId: form.wechatPayPublicKeyId || "",
  309. accountType: form.accountType || "wechat"
  310. },
  311. privateKeyFile,
  312. publicKeyFile
  313. );
  314. if (res?.code === 200) {
  315. ElMessage.success("保存成功");
  316. emit("success");
  317. emit("update:modelValue", false);
  318. } else {
  319. ElMessage.error(res?.msg || "保存失败");
  320. }
  321. } catch (e: any) {
  322. ElMessage.error(e?.message || "保存失败");
  323. }
  324. }
  325. });
  326. };
  327. watch(
  328. () => props.modelValue,
  329. visible => {
  330. if (visible) fetchPayAccountConfig();
  331. }
  332. );
  333. </script>
  334. <style scoped>
  335. .set-pay-key-upload :deep(.el-upload-dragger) {
  336. padding: 20px;
  337. }
  338. .set-pay-upload-box {
  339. color: var(--el-text-color-secondary);
  340. text-align: center;
  341. }
  342. .set-pay-upload-box p {
  343. margin: 8px 0 4px;
  344. font-size: 14px;
  345. }
  346. .set-pay-upload-box span {
  347. font-size: 12px;
  348. }
  349. </style>