realName.vue 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202
  1. <template>
  2. <div class="real-name-page">
  3. <!-- 头部区域 -->
  4. <div class="header-section">
  5. <div class="header-content">
  6. <div class="shop-info">
  7. <el-image :src="homeIcon" class="homeIcon" />
  8. <span class="shop-name">{{ localGet("storeName") }}</span>
  9. </div>
  10. <div class="auth-status">
  11. <span class="status-badge" v-if="!userInfo.idCard">未认证</span>
  12. <span class="status-badge status-badge-success" v-if="userInfo.idCard">已认证</span>
  13. </div>
  14. </div>
  15. </div>
  16. <!-- 标签导航栏 -->
  17. <div class="tabs-section">
  18. <el-tabs v-model="activeTab" @tab-click="handleTabClick">
  19. <el-tab-pane label="实名认证" name="realName" />
  20. <el-tab-pane label="提现密码" name="withdrawPassword" />
  21. <el-tab-pane label="收款账户" name="receivingAccount" />
  22. </el-tabs>
  23. </div>
  24. <!-- 实名认证 -->
  25. <div class="content-section" v-if="activeTab === 'realName'">
  26. <div class="content-wrapper-realName">
  27. <div class="goAuthBtn" v-if="goAuth">
  28. <el-button type="primary" class="auth-button" @click="handleGoAuth">
  29. <el-icon><CirclePlus /></el-icon> &nbsp;去实名认证
  30. </el-button>
  31. </div>
  32. <div class="auth-div" v-if="!goAuth">
  33. <el-row class="auth-row">
  34. <el-col :span="2"> 姓名 </el-col>
  35. <el-col :span="12">
  36. {{ userInfo.name }}
  37. </el-col>
  38. </el-row>
  39. <el-row class="auth-row">
  40. <el-col :span="2"> 身份证号 </el-col>
  41. <el-col :span="12">
  42. {{ userInfo.idCard }}
  43. </el-col>
  44. </el-row>
  45. <el-row class="auth-row">
  46. <el-col :span="2"> 认证时间 </el-col>
  47. <el-col :span="12">
  48. {{ userInfo.createdTime }}
  49. </el-col>
  50. </el-row>
  51. </div>
  52. </div>
  53. </div>
  54. <!-- 实名认证对话框 -->
  55. <el-dialog v-model="dialogVisible" title="实名认证" width="500px" :close-on-click-modal="false">
  56. <el-form ref="authFormRef" :model="authForm" :rules="authRules" label-width="100px" label-position="left">
  57. <el-form-item label="姓名" prop="name">
  58. <el-input v-model="authForm.name" placeholder="请输入姓名" clearable />
  59. </el-form-item>
  60. <el-form-item label="身份证号码" prop="idCard">
  61. <el-input v-model="authForm.idCard" placeholder="请输入身份证号码" clearable maxlength="18" />
  62. </el-form-item>
  63. </el-form>
  64. <template #footer>
  65. <span class="dialog-footer">
  66. <el-button @click="handleCancel">取消</el-button>
  67. <el-button type="primary" :loading="loading" @click="handleConfirm">确认</el-button>
  68. </span>
  69. </template>
  70. </el-dialog>
  71. <!-- 提现密码 -->
  72. <div class="content-section" v-if="activeTab === 'withdrawPassword'">
  73. <div class="content-wrapper">
  74. <div class="password-form-wrapper" v-if="withdrawPass">
  75. <el-form
  76. ref="passwordFormRef"
  77. :model="passwordForm"
  78. :rules="passwordRules"
  79. label-width="120px"
  80. label-position="left"
  81. class="form-wrapper"
  82. >
  83. <el-form-item label="设置提现密码" prop="password">
  84. <el-input
  85. v-model="passwordForm.password"
  86. type="password"
  87. placeholder="请输入6位提现密码"
  88. clearable
  89. maxlength="6"
  90. show-password
  91. class="password-input"
  92. />
  93. </el-form-item>
  94. <el-form-item label="请确认密码" prop="confirmPassword">
  95. <el-input
  96. v-model="passwordForm.confirmPassword"
  97. type="password"
  98. placeholder="请输入6位提现密码"
  99. clearable
  100. maxlength="6"
  101. show-password
  102. class="password-input"
  103. />
  104. </el-form-item>
  105. <el-form-item>
  106. <el-button type="primary" class="submit-button" :loading="passwordLoading" @click="handlePasswordOneSubmit">
  107. 确认
  108. </el-button>
  109. </el-form-item>
  110. </el-form>
  111. </div>
  112. <!---第二次进入此页面--->
  113. <div class="password-form-wrapper-step" v-if="twoEnterPage">
  114. <el-steps :active="currentStep" style="max-width: 600px">
  115. <el-step v-for="(item, index) in passList" :key="index">
  116. <template #title>
  117. <div class="step-title-wrapper">
  118. <span class="step-title">{{ item.title }}</span>
  119. </div>
  120. </template>
  121. </el-step>
  122. </el-steps>
  123. <el-form
  124. ref="passwordFormRef"
  125. :model="passwordForm"
  126. :rules="passwordRules"
  127. label-width="100px"
  128. label-position="left"
  129. class="form-wrapper"
  130. v-if="currentStep == 1"
  131. >
  132. <el-form-item label="验证原密码">
  133. <el-input
  134. v-model="oldPasswordForm.password"
  135. type="password"
  136. placeholder="请输入6位提现密码"
  137. clearable
  138. maxlength="6"
  139. show-password
  140. class="password-input"
  141. />
  142. </el-form-item>
  143. <div class="forget-password" @click="getForgetPassword">忘记密码</div>
  144. <el-button type="primary" class="submit-button" @click="nextStept"> 下一步 </el-button>
  145. </el-form>
  146. <el-form
  147. ref="passwordFormRef"
  148. :model="oldTwoPasswordForm"
  149. :rules="passwordRulesTwo"
  150. label-width="120px"
  151. label-position="left"
  152. class="form-wrapper"
  153. v-if="currentStep == 2"
  154. >
  155. <el-form-item label="设置提现密码">
  156. <el-input
  157. v-model="oldTwoPasswordForm.password"
  158. type="password"
  159. placeholder="请输入6位提现密码"
  160. clearable
  161. maxlength="6"
  162. show-password
  163. class="password-input"
  164. />
  165. </el-form-item>
  166. <el-form-item label="请确认密码">
  167. <el-input
  168. v-model="oldTwoPasswordForm.confirmPassword"
  169. type="password"
  170. placeholder="请输入6位提现密码"
  171. clearable
  172. maxlength="6"
  173. show-password
  174. class="password-input"
  175. />
  176. </el-form-item>
  177. <el-form-item>
  178. <el-button type="primary" class="submit-button" :loading="passwordLoading" @click="handlePasswordTwoSubmit">
  179. 确认
  180. </el-button>
  181. </el-form-item>
  182. </el-form>
  183. </div>
  184. </div>
  185. </div>
  186. <!--收款账户-->
  187. <div class="content-section" v-if="activeTab === 'receivingAccount'">
  188. <div class="content-wrapper">
  189. <el-button type="primary" class="auth-button" @click="handleGoZFB" v-if="!alipayAccount"> 添加支付宝账号 </el-button>
  190. <div class="zfb-wrapper" v-if="alipayAccount">
  191. <div style="width: 100%">
  192. <div style="display: flex; align-items: center; justify-content: space-between; width: 100%; margin-top: 10px">
  193. <div class="zfb-left">
  194. <el-image :src="zfbIcon" class="zfbIcon" />
  195. <div>
  196. <div>支付宝</div>
  197. <div>{{ alipayAccount }}</div>
  198. </div>
  199. </div>
  200. <div class="operate">
  201. <div @click="getEditZfb" style="cursor: pointer">编辑</div>
  202. <div @click="getDelZfb" style="cursor: pointer">删除</div>
  203. </div>
  204. </div>
  205. <!-- <el-button
  206. type="primary"
  207. @click="goToCashApply"
  208. class="submit-button"
  209. style=" position: relative; left: -10%; width: 20%;margin-top: 90px; margin-left: 50%"
  210. >
  211. 去提现
  212. </el-button> -->
  213. </div>
  214. </div>
  215. </div>
  216. </div>
  217. <!--添加支付宝账号--->
  218. <el-dialog v-model="dialogVisibleZFB" :title="zfbTitle" width="500px" :close-on-click-modal="false">
  219. <el-form ref="authFormRef1" :model="authForm1" :rules="authRules1" label-width="100px" label-position="left">
  220. <el-form-item label="支付宝账号" prop="zfbName">
  221. <el-input v-model="authForm1.zfbName" placeholder="请输入支付宝账号" clearable />
  222. </el-form-item>
  223. </el-form>
  224. <template #footer>
  225. <span class="dialog-footer">
  226. <el-button @click="handleCancelZFB">取消</el-button>
  227. <el-button type="primary" :loading="loading" @click="handleConfirmZFB">确认</el-button>
  228. </span>
  229. </template>
  230. </el-dialog>
  231. <!-- 忘记密码对话框 -->
  232. <el-dialog v-model="forgotPasswordVisible" title="忘记密码" width="500px" draggable :close-on-click-modal="false">
  233. <el-form
  234. ref="forgotPasswordFormRef"
  235. :model="forgotPasswordForm"
  236. :rules="forgotPasswordRules"
  237. label-width="100px"
  238. label-position="left"
  239. >
  240. <el-form-item label="手机号码">
  241. <span>{{ maskedPhone }}</span>
  242. </el-form-item>
  243. <el-form-item label="验证码">
  244. <div style="display: flex; gap: 12px; width: 100%">
  245. <el-input v-model="forgotPasswordForm.verificationCode" placeholder="请输入" clearable style="flex: 1" />
  246. <el-button :disabled="codeCountdown > 0" @click="sendForgotCode" class="code-button">
  247. {{ codeCountdown > 0 ? `${codeCountdown}秒后重试` : "获取验证码" }}
  248. </el-button>
  249. </div>
  250. </el-form-item>
  251. <el-form-item label="输入新密码">
  252. <el-input
  253. v-model="forgotPasswordForm.newPassword"
  254. type="password"
  255. placeholder="请输入6位提现密码"
  256. show-password
  257. clearable
  258. />
  259. </el-form-item>
  260. <el-form-item label="确认密码">
  261. <el-input
  262. v-model="forgotPasswordForm.confireNewPassword"
  263. type="password"
  264. placeholder="请输入6位提现密码"
  265. show-password
  266. clearable
  267. />
  268. </el-form-item>
  269. </el-form>
  270. <template #footer>
  271. <span class="dialog-footer">
  272. <el-button @click="forgotPasswordVisible = false">取消</el-button>
  273. <el-button type="primary" :loading="loading" @click="handleForgetConfirmZFB">确认</el-button>
  274. </span>
  275. </template>
  276. </el-dialog>
  277. </div>
  278. </template>
  279. <script setup lang="ts">
  280. import { ref, reactive, computed, onMounted } from "vue";
  281. import { useRouter } from "vue-router";
  282. import { ElMessage, type FormInstance, ElMessageBox, type FormRules } from "element-plus";
  283. import {
  284. verifyIdInfo,
  285. checkPayPassword,
  286. setPayPassword,
  287. getMerchantByPhone,
  288. addAlipayAccount,
  289. deleteAlipayAccount,
  290. getCheckPayPasswordTwo
  291. } from "@/api/modules/homeEntry";
  292. import { localGet, localSet } from "@/utils/index";
  293. import homeIcon from "../../assets/images/home-icon.png";
  294. import zfbIcon from "../../assets/financial/zfb-icon.png";
  295. import { lo } from "element-plus/es/locale";
  296. import { getPhoneCode, getCheckSmsCode } from "@/api/modules/newLoginApi";
  297. // 初始化用户信息,统一处理支付宝账号字段名(兼容 aliPayAccount 和 alipayAccount)
  298. const initUserInfo = () => {
  299. const cachedUserInfo = localGet("geeker-user")?.userInfo || {};
  300. // 统一使用 alipayAccount 字段,兼容 aliPayAccount(驼峰命名)
  301. if (cachedUserInfo.aliPayAccount && !cachedUserInfo.alipayAccount) {
  302. cachedUserInfo.alipayAccount = cachedUserInfo.aliPayAccount;
  303. }
  304. return cachedUserInfo;
  305. };
  306. const userInfo = ref(initUserInfo());
  307. const router = useRouter();
  308. const activeTab = ref("realName");
  309. const dialogVisible = ref(false);
  310. const loading = ref(false);
  311. //实名认证
  312. const goAuth = ref(!userInfo.value.idCard);
  313. const authFormRef = ref<FormInstance>();
  314. const authForm = reactive({
  315. name: "",
  316. idCard: ""
  317. });
  318. // 实名认证表单验证规则
  319. const authRules = reactive<FormRules>({
  320. name: [{ required: true, message: "请输入姓名", trigger: "blur" }],
  321. zfbName: [{ required: true, message: "请输入支付宝账号", trigger: "blur" }],
  322. idCard: [
  323. { required: true, message: "请输入身份证号码", trigger: "blur" },
  324. {
  325. pattern: /^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$/,
  326. message: "请输入正确的身份证号码",
  327. trigger: "blur"
  328. }
  329. ]
  330. });
  331. //去实名认证
  332. const handleGoAuth = () => {
  333. // 打开实名认证对话框
  334. dialogVisible.value = true;
  335. // 重置表单
  336. if (authFormRef.value) {
  337. authFormRef.value.resetFields();
  338. }
  339. };
  340. //实名认证 确认
  341. const shimingInfo = ref(null);
  342. const handleConfirm = async () => {
  343. if (!authFormRef.value) return;
  344. // 表单验证
  345. await authFormRef.value.validate(async valid => {
  346. if (valid) {
  347. loading.value = true;
  348. try {
  349. const params = {
  350. name: authForm.name,
  351. idCard: authForm.idCard,
  352. appType: 1
  353. };
  354. const res: any = await verifyIdInfo(params);
  355. console.log(res);
  356. if (res && res.code == 200) {
  357. ElMessage.success(res.msg || "实名认证提交成功");
  358. let param = {
  359. phone: userInfo.value.phone
  360. };
  361. const res1: any = await getMerchantByPhone(param);
  362. if (res1.code == 200) {
  363. // 统一处理支付宝账号字段名
  364. const updatedData = res1.data || {};
  365. if (updatedData.aliPayAccount && !updatedData.alipayAccount) {
  366. updatedData.alipayAccount = updatedData.aliPayAccount;
  367. }
  368. dialogVisible.value = false;
  369. goAuth.value = false;
  370. // 重置表单
  371. authFormRef.value?.resetFields();
  372. shimingInfo.value = updatedData;
  373. userInfo.value = { ...userInfo.value, ...updatedData };
  374. // 更新本地存储
  375. const geekerUser = localGet("geeker-user");
  376. if (geekerUser) {
  377. geekerUser.userInfo = { ...geekerUser.userInfo, ...updatedData };
  378. if (updatedData.alipayAccount) {
  379. geekerUser.userInfo.alipayAccount = updatedData.alipayAccount;
  380. geekerUser.userInfo.aliPayAccount = updatedData.alipayAccount;
  381. }
  382. localSet("geeker-user", geekerUser);
  383. }
  384. // 这里可以更新认证状态或刷新页面数据
  385. }
  386. } else {
  387. ElMessage.error(res.msg || "实名认证失败,请重试");
  388. }
  389. } catch (error) {
  390. console.error("实名认证失败:", error);
  391. ElMessage.error("实名认证失败,请重试");
  392. } finally {
  393. loading.value = false;
  394. }
  395. }
  396. });
  397. };
  398. //提现密码
  399. const withdrawPass = ref(true);
  400. const passwordFormRef = ref<FormInstance>();
  401. const passwordForm = reactive({
  402. password: "",
  403. confirmPassword: ""
  404. });
  405. // 提现密码表单验证规则
  406. const passwordRules = reactive<FormRules>({
  407. password: [
  408. { required: true, message: "请输入6位提现密码", trigger: "blur" },
  409. {
  410. pattern: /^\d{6}$/,
  411. message: "请输入6位数字密码",
  412. trigger: "blur"
  413. }
  414. ],
  415. confirmPassword: [
  416. { required: true, message: "请确认密码", trigger: "blur" },
  417. {
  418. validator: (rule: any, value: any, callback: any) => {
  419. if (value !== passwordForm.password) {
  420. callback(new Error("两次输入的密码不一致"));
  421. } else {
  422. callback();
  423. }
  424. },
  425. trigger: "blur"
  426. }
  427. ]
  428. });
  429. // 第二步修改密码的验证规则
  430. const passwordRulesTwo = reactive<FormRules>({
  431. password: [
  432. { required: true, message: "请输入6位提现密码", trigger: "blur" },
  433. {
  434. pattern: /^\d{6}$/,
  435. message: "请输入6位数字密码",
  436. trigger: "blur"
  437. }
  438. ],
  439. confirmPassword: [
  440. { required: true, message: "请确认密码", trigger: "blur" },
  441. {
  442. validator: (rule: any, value: any, callback: any) => {
  443. if (value !== oldTwoPasswordForm.password) {
  444. callback(new Error("两次输入的密码不一致"));
  445. } else {
  446. callback();
  447. }
  448. },
  449. trigger: "blur"
  450. }
  451. ]
  452. });
  453. //提现密码 确认
  454. const passwordLoading = ref(false);
  455. const handlePasswordOneSubmit = async () => {
  456. if (!passwordFormRef.value) return;
  457. // 表单验证
  458. await passwordFormRef.value.validate(async valid => {
  459. if (valid) {
  460. passwordLoading.value = true;
  461. try {
  462. const res: any = await setPayPassword({
  463. payPassword: passwordForm.password,
  464. id: userInfo.value.id
  465. });
  466. if (res.code == 200) {
  467. ElMessage.success(res.msg || "提现密码设置成功");
  468. // 更新本地存储中的提现密码
  469. try {
  470. const geekerUser = localGet("geeker-user");
  471. if (geekerUser && geekerUser.userInfo) {
  472. geekerUser.userInfo.payPassword = passwordForm.password;
  473. localSet("geeker-user", geekerUser);
  474. }
  475. } catch (error) {
  476. console.error("更新本地存储失败:", error);
  477. }
  478. // 重置表单
  479. passwordFormRef.value?.resetFields();
  480. // 如果是在修改密码流程中(twoEnterPage为true),设置状态为已设置
  481. if (twoEnterPage.value) {
  482. twoEnterPage.value = true;
  483. withdrawPass.value = false;
  484. currentStep.value = 1; // 重置步骤
  485. } else {
  486. // 首次设置密码,跳转到收款账户
  487. activeTab.value = "receivingAccount";
  488. }
  489. } else {
  490. ElMessage.error(res.msg || "提现密码设置失败");
  491. }
  492. } catch (error) {
  493. console.error("设置提现密码失败:", error);
  494. ElMessage.error("提现密码设置失败,请重试");
  495. } finally {
  496. passwordLoading.value = false;
  497. }
  498. }
  499. });
  500. };
  501. //二次进入显示
  502. const twoEnterPage = ref(false);
  503. //提现密码 验证原密码
  504. const currentStep = ref(1);
  505. const passList = [
  506. {
  507. title: "验证原密码"
  508. },
  509. {
  510. title: "设置新密码"
  511. }
  512. ];
  513. //忘记密码
  514. const forgotPasswordVisible = ref(false);
  515. const forgotPasswordFormRef = ref<FormInstance>();
  516. // 验证码倒计时
  517. const codeCountdown = ref(0);
  518. let countdownTimer: NodeJS.Timeout | null = null;
  519. const forgotPasswordForm = reactive({
  520. newPassword: "",
  521. confireNewPassword: "",
  522. verificationCode: ""
  523. });
  524. const getForgetPassword = async () => {
  525. forgotPasswordVisible.value = true;
  526. };
  527. // 发送短信验证码
  528. const sendForgotCode = async () => {
  529. let phoneCode: any = await getPhoneCode({ phone: userInfo.value.phone, appType: "2", businessType: "7" });
  530. if (phoneCode.code === 200) {
  531. ElMessage.success("验证码已发送");
  532. // 开始倒计时
  533. codeCountdown.value = 60;
  534. countdownTimer = setInterval(() => {
  535. codeCountdown.value--;
  536. if (codeCountdown.value <= 0) {
  537. if (countdownTimer) {
  538. clearInterval(countdownTimer);
  539. countdownTimer = null;
  540. }
  541. }
  542. }, 1000);
  543. }
  544. };
  545. //下一步
  546. const oldPasswordForm = reactive({
  547. password: ""
  548. });
  549. const oldTwoPasswordForm = reactive({
  550. password: "",
  551. confirmPassword: ""
  552. });
  553. const nextStept = async () => {
  554. const res: any = await getCheckPayPasswordTwo({
  555. password: oldPasswordForm.password,
  556. storeUserId: userInfo.value.id
  557. });
  558. if (res.data.data == "false") {
  559. ElMessage.error(res.data.message);
  560. } else {
  561. ElMessage.success(res.msg);
  562. currentStep.value = 2;
  563. // 更新本地存储中的提现密码
  564. try {
  565. const geekerUser = localGet("geeker-user");
  566. if (geekerUser && geekerUser.userInfo) {
  567. geekerUser.userInfo.payPassword = oldTwoPasswordForm.password;
  568. localSet("geeker-user", geekerUser);
  569. }
  570. } catch (error) {
  571. console.error("更新本地存储失败:", error);
  572. }
  573. }
  574. };
  575. const handlePasswordTwoSubmit = async () => {
  576. if (!passwordFormRef.value) return;
  577. // 表单验证
  578. await passwordFormRef.value.validate(async valid => {
  579. if (valid) {
  580. passwordLoading.value = true;
  581. try {
  582. const res: any = await setPayPassword({
  583. payPassword: oldTwoPasswordForm.password,
  584. id: userInfo.value.id
  585. });
  586. if (res.code == 200) {
  587. ElMessage.success(res.msg || "提现密码修改成功");
  588. activeTab.value = "receivingAccount";
  589. // 更新本地存储中的提现密码
  590. try {
  591. const geekerUser = localGet("geeker-user");
  592. if (geekerUser && geekerUser.userInfo) {
  593. geekerUser.userInfo.payPassword = oldTwoPasswordForm.password;
  594. localSet("geeker-user", geekerUser);
  595. }
  596. } catch (error) {
  597. console.error("更新本地存储失败:", error);
  598. }
  599. // 重置表单
  600. passwordFormRef.value?.resetFields();
  601. oldPasswordForm.password = "";
  602. oldTwoPasswordForm.password = "";
  603. oldTwoPasswordForm.confirmPassword = "";
  604. // 重置步骤
  605. currentStep.value = 1;
  606. } else {
  607. ElMessage.error(res.msg || "提现密码修改失败");
  608. }
  609. } catch (error) {
  610. console.error("修改提现密码失败:", error);
  611. ElMessage.error("提现密码修改失败,请重试");
  612. } finally {
  613. passwordLoading.value = false;
  614. }
  615. }
  616. });
  617. };
  618. //收款账户
  619. const authFormRef1 = ref<FormInstance>();
  620. const authRules1 = reactive<FormRules>({
  621. zfbName: [{ required: true, message: "请输入支付宝账号", trigger: "blur" }]
  622. });
  623. const authForm1 = reactive({
  624. zfbName: ""
  625. });
  626. const zfbShow = ref(false);
  627. const zfbTitle = ref("");
  628. const dialogVisibleZFB = ref(false);
  629. const handleGoZFB = async () => {
  630. zfbTitle.value = "添加支付宝账号";
  631. dialogVisibleZFB.value = true;
  632. };
  633. const handleConfirmZFB = async () => {
  634. if (!authFormRef1.value) return;
  635. await authFormRef1.value.validate(async valid => {
  636. if (valid) {
  637. loading.value = true;
  638. try {
  639. const params = {
  640. alipayAccount: authForm1.zfbName
  641. };
  642. const res: any = await addAlipayAccount(params);
  643. if (res && res.code == 200) {
  644. ElMessage.success(res.msg || "添加支付宝账号成功");
  645. // 更新本地存储中的支付宝账号(统一使用 alipayAccount 字段)
  646. try {
  647. const geekerUser = localGet("geeker-user");
  648. if (geekerUser && geekerUser.userInfo) {
  649. geekerUser.userInfo.alipayAccount = authForm1.zfbName;
  650. geekerUser.userInfo.aliPayAccount = authForm1.zfbName; // 兼容旧字段名
  651. localSet("geeker-user", geekerUser);
  652. // 更新响应式的 userInfo
  653. userInfo.value.alipayAccount = authForm1.zfbName;
  654. }
  655. } catch (error) {
  656. console.error("更新本地存储失败:", error);
  657. }
  658. dialogVisibleZFB.value = false;
  659. zfbShow.value = true;
  660. // 重置表单
  661. authFormRef1.value?.resetFields();
  662. } else {
  663. ElMessage.error(res.msg || "添加支付宝账号失败,请重试");
  664. }
  665. } catch (error) {
  666. console.error("添加支付宝账号失败:", error);
  667. ElMessage.error("添加支付宝账号失败,请重试");
  668. } finally {
  669. loading.value = false;
  670. }
  671. }
  672. });
  673. };
  674. const getEditZfb = async () => {
  675. zfbTitle.value = "编辑支付宝账号";
  676. dialogVisibleZFB.value = true;
  677. // 兼容两种字段名:alipayAccount 和 aliPayAccount
  678. authForm1.zfbName = userInfo.value.alipayAccount || userInfo.value.aliPayAccount || userInfo.value.phone;
  679. };
  680. const getDelZfb = async () => {
  681. ElMessageBox.confirm("确定要删除该账号,删除后无法进行提现操作", "删除账号", {
  682. confirmButtonText: "确定",
  683. cancelButtonText: "取消",
  684. type: "warning"
  685. })
  686. .then(async () => {
  687. try {
  688. loading.value = true;
  689. const res: any = await deleteAlipayAccount();
  690. if (res && res.code == 200) {
  691. ElMessage.success(res.msg || "删除成功");
  692. // 立即更新响应式的 userInfo,清空支付宝账号
  693. userInfo.value.alipayAccount = null;
  694. userInfo.value.aliPayAccount = null;
  695. // 更新本地存储中的支付宝账号
  696. try {
  697. const geekerUser = localGet("geeker-user");
  698. if (geekerUser && geekerUser.userInfo) {
  699. geekerUser.userInfo.alipayAccount = null;
  700. geekerUser.userInfo.aliPayAccount = null;
  701. localSet("geeker-user", geekerUser);
  702. }
  703. } catch (error) {
  704. console.error("更新本地存储失败:", error);
  705. }
  706. // 重新获取用户信息
  707. try {
  708. const param = {
  709. phone: userInfo.value.phone
  710. };
  711. const res1: any = await getMerchantByPhone(param);
  712. if (res1.code == 200) {
  713. // 统一处理支付宝账号字段名
  714. const updatedData = res1.data || {};
  715. // 如果后端返回的支付宝账号为空或null,确保两个字段都是null
  716. if (!updatedData.alipayAccount && !updatedData.aliPayAccount) {
  717. updatedData.alipayAccount = null;
  718. updatedData.aliPayAccount = null;
  719. } else if (updatedData.aliPayAccount && !updatedData.alipayAccount) {
  720. updatedData.alipayAccount = updatedData.aliPayAccount;
  721. }
  722. // 更新响应式数据
  723. userInfo.value = { ...userInfo.value, ...updatedData };
  724. // 确保支付宝账号字段正确
  725. userInfo.value.alipayAccount = updatedData.alipayAccount || null;
  726. userInfo.value.aliPayAccount = updatedData.aliPayAccount || null;
  727. // 更新本地存储
  728. const geekerUser = localGet("geeker-user");
  729. if (geekerUser) {
  730. geekerUser.userInfo = { ...geekerUser.userInfo, ...updatedData };
  731. // 确保两个字段名都保存(如果为null也要保存)
  732. geekerUser.userInfo.alipayAccount = updatedData.alipayAccount || null;
  733. geekerUser.userInfo.aliPayAccount = updatedData.aliPayAccount || null;
  734. localSet("geeker-user", geekerUser);
  735. }
  736. }
  737. } catch (error) {
  738. console.error("获取用户信息失败:", error);
  739. }
  740. } else {
  741. ElMessage.error(res.msg || "删除失败,请重试");
  742. }
  743. } catch (error) {
  744. console.error("删除支付宝账号失败:", error);
  745. ElMessage.error("删除失败,请重试");
  746. } finally {
  747. loading.value = false;
  748. }
  749. })
  750. .catch(() => {
  751. // 用户取消删除
  752. });
  753. };
  754. // 跳转到提现申请页面
  755. // const goToCashApply = () => {
  756. // router.push("/financialManagement/cashApply");
  757. // };
  758. // 忘记密码表单验证规则
  759. const forgotPasswordRules: FormRules = {
  760. verificationCode: [{ required: true, message: "请输入验证码", trigger: "blur" }],
  761. newPassword: [
  762. { required: true, message: "请输入新密码", trigger: "blur" },
  763. { pattern: /^\d{6}$/, message: "提现密码必须为6位数字", trigger: "blur" }
  764. ],
  765. confireNewPassword: [
  766. { required: true, message: "请确认密码", trigger: "blur" },
  767. {
  768. validator: (rule, value, callback) => {
  769. if (value !== forgotPasswordForm.newPassword) {
  770. callback(new Error("两次输入的密码不一致"));
  771. } else {
  772. callback();
  773. }
  774. },
  775. trigger: "blur"
  776. }
  777. ]
  778. };
  779. // 检查提现密码状态
  780. const checkPasswordStatus = async () => {
  781. try {
  782. if (userInfo.value.idCard && userInfo.value.id) {
  783. const param = {
  784. storeUserId: userInfo.value.id
  785. };
  786. const res: any = await checkPayPassword(param as any);
  787. if (res.code == 200) {
  788. // 如果已设置提现密码,显示修改密码界面
  789. if (res.data.data == "true") {
  790. twoEnterPage.value = true;
  791. withdrawPass.value = false;
  792. currentStep.value = 1; // 重置步骤
  793. } else {
  794. // 如果未设置提现密码,显示首次设置界面
  795. twoEnterPage.value = false;
  796. withdrawPass.value = true;
  797. }
  798. }
  799. }
  800. } catch (error) {
  801. console.error("检查提现密码状态失败:", error);
  802. }
  803. };
  804. // 检查提现密码并自动跳转
  805. const checkWithdrawPassword = async () => {
  806. try {
  807. // 如果已实名认证,检查是否设置了提现密码
  808. if (userInfo.value.idCard) {
  809. const param = {
  810. storeUserId: userInfo.value.id
  811. };
  812. const res: any = await checkPayPassword(param as any);
  813. if (res.code == 200) {
  814. // 如果未设置提现密码,自动跳转到提现密码标签页
  815. if (res.data.data == "false") {
  816. activeTab.value = "withdrawPassword";
  817. } else {
  818. activeTab.value = "receivingAccount";
  819. }
  820. }
  821. }
  822. } catch (error) {
  823. console.error("检查提现密码失败:", error);
  824. }
  825. };
  826. // 页面加载时检查
  827. onMounted(() => {
  828. checkWithdrawPassword();
  829. });
  830. // 获取用户手机号
  831. const userPhone = computed(() => {
  832. return localGet("iphone") || localGet("geeker-user")?.userInfo?.phone || "";
  833. });
  834. // 掩码显示手机号
  835. const maskedPhone = computed(() => {
  836. if (!userPhone.value || userPhone.value.length !== 11) {
  837. return "";
  838. }
  839. return userPhone.value.replace(/(\d{3})\d{4}(\d{4})/, "$1****$2");
  840. });
  841. // 获取支付宝账号(兼容两种字段名)
  842. const alipayAccount = computed(() => {
  843. return userInfo.value.alipayAccount || userInfo.value.aliPayAccount || null;
  844. });
  845. const handleTabClick = async (tab: any) => {
  846. // 根据不同的标签页可以跳转到不同的页面或显示不同的内容
  847. console.log("切换到标签:", tab.props.name);
  848. // 如果切换到提现密码标签页,检查提现密码状态
  849. if (tab.props.name === "withdrawPassword") {
  850. await checkPasswordStatus();
  851. }
  852. };
  853. const handleCancel = () => {
  854. dialogVisible.value = false;
  855. // 重置表单
  856. if (authFormRef.value) {
  857. authFormRef.value.resetFields();
  858. }
  859. };
  860. const handleForgetConfirmZFB = async () => {
  861. if (!forgotPasswordFormRef.value) return;
  862. // 表单验证
  863. await forgotPasswordFormRef.value.validate(async valid => {
  864. if (valid) {
  865. // 验证新密码和确认密码是否一致
  866. if (forgotPasswordForm.newPassword !== forgotPasswordForm.confireNewPassword) {
  867. ElMessage.error("两次输入的密码不一致");
  868. return;
  869. }
  870. // 验证密码长度
  871. if (forgotPasswordForm.newPassword.length !== 6) {
  872. ElMessage.error("提现密码必须为6位数字");
  873. return;
  874. }
  875. loading.value = true;
  876. try {
  877. // 第一步:验证短信验证码
  878. const checkCodeRes: any = await getCheckSmsCode({
  879. phone: userInfo.value.phone,
  880. appType: "2",
  881. businessType: "7",
  882. code: forgotPasswordForm.verificationCode
  883. });
  884. if (checkCodeRes.code !== 200) {
  885. ElMessage.error(checkCodeRes.msg || "验证码验证失败");
  886. loading.value = false;
  887. return;
  888. }
  889. // 第二步:设置提现密码
  890. const res: any = await setPayPassword({
  891. payPassword: forgotPasswordForm.newPassword,
  892. id: userInfo.value.id
  893. });
  894. if (res.code == 200) {
  895. ElMessage.success(res.msg || "提现密码设置成功");
  896. // 更新本地存储中的提现密码
  897. try {
  898. const geekerUser = localGet("geeker-user");
  899. if (geekerUser && geekerUser.userInfo) {
  900. geekerUser.userInfo.payPassword = forgotPasswordForm.newPassword;
  901. localSet("geeker-user", geekerUser);
  902. }
  903. } catch (error) {
  904. console.error("更新本地存储失败:", error);
  905. }
  906. // 关闭对话框并重置表单
  907. forgotPasswordVisible.value = false;
  908. forgotPasswordFormRef.value?.resetFields();
  909. // 重置表单数据
  910. forgotPasswordForm.newPassword = "";
  911. forgotPasswordForm.confireNewPassword = "";
  912. forgotPasswordForm.verificationCode = "";
  913. // 刷新密码状态
  914. await checkPasswordStatus();
  915. } else {
  916. ElMessage.error(res.msg || "设置提现密码失败");
  917. }
  918. } catch (error: any) {
  919. console.error("设置提现密码失败:", error);
  920. ElMessage.error(error?.response?.data?.msg || error?.message || "设置提现密码失败,请稍后重试");
  921. } finally {
  922. loading.value = false;
  923. }
  924. }
  925. });
  926. };
  927. const handleCancelZFB = () => {
  928. dialogVisibleZFB.value = false;
  929. // 重置表单
  930. if (authFormRef1.value) {
  931. authFormRef1.value.resetFields();
  932. }
  933. };
  934. </script>
  935. <style scoped lang="scss">
  936. .real-name-page {
  937. display: flex;
  938. flex-direction: column;
  939. min-height: calc(100vh - 100px);
  940. background-color: #f5f7fa;
  941. }
  942. // 头部区域
  943. .header-section {
  944. padding: 16px 24px;
  945. background: linear-gradient(90deg, #7f9dff 0%, rgb(255 255 255 / 0%) 100%);
  946. border-bottom: 1px solid #e4e7ed;
  947. border-radius: 10px;
  948. .header-content {
  949. display: flex;
  950. align-items: center;
  951. justify-content: space-between;
  952. max-width: 100%;
  953. margin: 0 auto;
  954. .shop-info {
  955. display: flex;
  956. gap: 12px;
  957. align-items: center;
  958. .homeIcon {
  959. width: 76px;
  960. height: 76px;
  961. margin-right: 8px;
  962. margin-left: 25px;
  963. }
  964. .shop-icon {
  965. display: flex;
  966. align-items: center;
  967. justify-content: center;
  968. width: 32px;
  969. height: 32px;
  970. background-color: #ffffff;
  971. border-radius: 6px;
  972. box-shadow: 0 2px 4px rgb(0 0 0 / 10%);
  973. }
  974. .shop-name {
  975. font-size: 16px;
  976. font-weight: 500;
  977. color: #ffffff;
  978. }
  979. }
  980. .auth-status {
  981. .status-badge {
  982. display: inline-block;
  983. padding: 3px 20px;
  984. font-size: 14px;
  985. font-weight: 500;
  986. color: #ffffff;
  987. background: #f81515;
  988. border-radius: 39px;
  989. }
  990. .status-badge-success {
  991. background: #7f9dff;
  992. }
  993. }
  994. }
  995. }
  996. // 标签导航栏
  997. .tabs-section {
  998. padding: 0 24px;
  999. background-color: #ffffff;
  1000. border-bottom: 1px solid #e4e7ed;
  1001. :deep(.el-tabs) {
  1002. max-width: 100%;
  1003. margin: 0 auto;
  1004. .el-tabs__header {
  1005. margin: 0;
  1006. border-bottom: none;
  1007. }
  1008. .el-tabs__nav-wrap::after {
  1009. height: 1px;
  1010. background-color: #e4e7ed;
  1011. }
  1012. .el-tabs__item {
  1013. height: 48px;
  1014. padding: 0 20px;
  1015. font-size: 15px;
  1016. font-weight: 400;
  1017. line-height: 48px;
  1018. color: #606266;
  1019. &.is-active {
  1020. font-weight: 500;
  1021. color: #409eff;
  1022. &::after {
  1023. position: absolute;
  1024. bottom: 0;
  1025. left: 50%;
  1026. width: 40px;
  1027. height: 3px;
  1028. content: "";
  1029. background-color: #409eff;
  1030. border-radius: 2px 2px 0 0;
  1031. transform: translateX(-50%);
  1032. }
  1033. }
  1034. &:hover {
  1035. color: #409eff;
  1036. }
  1037. }
  1038. }
  1039. }
  1040. .auth-button {
  1041. padding: 22px 35px;
  1042. font-size: 16px;
  1043. font-weight: 500;
  1044. background-color: #7f9dff;
  1045. border: none;
  1046. border-radius: 6px;
  1047. transition: all 0.3s;
  1048. }
  1049. // 主内容区
  1050. .content-section {
  1051. display: flex;
  1052. flex: 1;
  1053. justify-content: center;
  1054. min-height: 400px;
  1055. background-color: #ffffff;
  1056. .content-wrapper-realName {
  1057. width: 100%;
  1058. .goAuthBtn {
  1059. display: flex;
  1060. justify-content: center;
  1061. padding: 180px 0 0;
  1062. }
  1063. .auth-div {
  1064. padding-top: 10px;
  1065. padding-left: 41px;
  1066. .auth-row {
  1067. padding: 10px 0;
  1068. }
  1069. }
  1070. }
  1071. .content-wrapper {
  1072. display: flex;
  1073. justify-content: center;
  1074. width: 100%;
  1075. padding: 40px 24px;
  1076. .zfb-wrapper {
  1077. display: flex;
  1078. justify-content: space-between;
  1079. width: 100%;
  1080. height: 80px;
  1081. padding: 0 20px;
  1082. border: 1px solid #dddddd;
  1083. border-radius: 8px;
  1084. .operate {
  1085. display: flex;
  1086. align-items: center;
  1087. color: #7f9dff;
  1088. div {
  1089. margin-left: 20px;
  1090. }
  1091. }
  1092. .zfb-left {
  1093. display: flex;
  1094. align-items: center;
  1095. }
  1096. .zfbIcon {
  1097. width: 60px;
  1098. height: 60px;
  1099. margin-right: 10px;
  1100. }
  1101. }
  1102. }
  1103. .password-form-wrapper {
  1104. width: 100%;
  1105. padding-left: 15px;
  1106. background-color: #ffffff;
  1107. border-radius: 8px;
  1108. .form-wrapper {
  1109. width: 400px;
  1110. margin: 30px auto;
  1111. }
  1112. .password-input {
  1113. width: 100%;
  1114. }
  1115. :deep(.el-form-item__label) {
  1116. font-weight: 500;
  1117. color: #303133;
  1118. }
  1119. }
  1120. .submit-button {
  1121. width: 100%;
  1122. padding: 22px 35px;
  1123. margin-top: 20px;
  1124. font-size: 16px;
  1125. font-weight: 500;
  1126. background-color: #7f9dff;
  1127. border: none;
  1128. border-radius: 6px;
  1129. }
  1130. .password-form-wrapper-step {
  1131. width: 480px;
  1132. .form-wrapper {
  1133. width: 400px;
  1134. margin-top: 40px;
  1135. }
  1136. .forget-password {
  1137. font-size: 14px;
  1138. color: #7f9dff;
  1139. text-align: right;
  1140. cursor: pointer;
  1141. }
  1142. :deep(.el-step__head.is-process .el-step__icon) {
  1143. color: #909399;
  1144. border-color: #909399 !important; /* 设置圆圈边框为灰色 */
  1145. }
  1146. :deep(.el-steps) {
  1147. .el-step__head {
  1148. .el-step__icon {
  1149. width: 30px;
  1150. height: 30px;
  1151. font-size: 16px;
  1152. font-weight: 600;
  1153. }
  1154. }
  1155. }
  1156. }
  1157. }
  1158. </style>