clientIndex copy.vue 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. <!-- src/views/captcha/CaptchaPage.vue -->
  2. <template>
  3. <div class="captcha-page">
  4. <div class="container">
  5. <!-- 表单区域 -->
  6. <div class="form-group">
  7. <label for="phone">手机号</label>
  8. <input
  9. v-model="form.phone"
  10. type="tel"
  11. id="phone"
  12. placeholder="请输入手机号"
  13. maxlength="11"
  14. />
  15. </div>
  16. <!-- 验证码显示区域 -->
  17. <div id="captcha-container" class="captcha-container"></div>
  18. <div class="form-group">
  19. <label for="smsCode">短信验证码</label>
  20. <div class="sms-input-group">
  21. <input
  22. v-model="form.smsCode"
  23. type="text"
  24. id="smsCode"
  25. placeholder="请输入短信验证码"
  26. maxlength="6"
  27. />
  28. <button
  29. class="get-sms-btn"
  30. :disabled="smsCountdown > 0 || !isPhoneValid"
  31. @click="getSmsCode"
  32. >
  33. {{ smsCountdown > 0 ? `${smsCountdown}s后重试` : '获取验证码' }}
  34. </button>
  35. </div>
  36. </div>
  37. <button
  38. class="submit-btn"
  39. :disabled="!isFormValid || isSubmitting"
  40. @click="handleSubmit"
  41. >
  42. {{ isSubmitting ? '提交中...' : '绑定手机号' }}
  43. </button>
  44. </div>
  45. </div>
  46. </template>
  47. <script setup>
  48. import { ref, computed, onMounted, onUnmounted } from 'vue'
  49. import { tijiao } from '@/api/login.js' // 直接使用你的API
  50. import { toast } from '@/utils/common'
  51. // 表单数据
  52. const form = ref({
  53. phone: '',
  54. smsCode: ''
  55. })
  56. // 状态管理
  57. const captchaVerifyParam = ref(null)
  58. const isSubmitting = ref(false)
  59. const smsCountdown = ref(0)
  60. let countdownTimer = null
  61. // 计算属性
  62. const isPhoneValid = computed(() => {
  63. const phone = form.value.phone
  64. return /^1[3-9]\d{9}$/.test(phone)
  65. })
  66. const isFormValid = computed(() => {
  67. return isPhoneValid.value &&
  68. form.value.smsCode.length === 6 &&
  69. captchaVerifyParam.value
  70. })
  71. // 生命周期
  72. onMounted(() => {
  73. loadAliyunCaptcha()
  74. })
  75. onUnmounted(() => {
  76. if (countdownTimer) {
  77. clearInterval(countdownTimer)
  78. }
  79. })
  80. // 加载阿里云验证码
  81. function loadAliyunCaptcha() {
  82. // 动态加载阿里云验证码脚本
  83. const script = document.createElement('script')
  84. script.src = 'https://o.alicdn.com/captcha-frontend/aliyunCaptcha/AliyunCaptcha.js'
  85. script.onload = () => {
  86. initCaptcha()
  87. }
  88. script.onerror = () => {
  89. toast('验证码加载失败,请重试')
  90. }
  91. document.head.appendChild(script)
  92. }
  93. // 初始化验证码
  94. function initCaptcha() {
  95. window.AliyunCaptchaConfig = {
  96. region: 'cn',
  97. prefix: 'm9a704',
  98. }
  99. try {
  100. window.initAliyunCaptcha({
  101. SceneId: '1xp14eyl',
  102. mode: "embed",
  103. element: "#captcha-container",
  104. success: (param) => {
  105. captchaVerifyParam.value = param
  106. console.log('验证码验证成功:', param)
  107. },
  108. fail: (err) => {
  109. toast('验证失败,请重试')
  110. console.error('验证码验证失败:', err)
  111. },
  112. slideStyle: {
  113. width: 320,
  114. height: 40
  115. },
  116. language: 'cn',
  117. timeout: 5000,
  118. })
  119. } catch (error) {
  120. console.error('初始化验证码失败:', error)
  121. toast('验证码初始化失败')
  122. }
  123. }
  124. // 获取短信验证码
  125. async function getSmsCode() {
  126. if (!isPhoneValid.value) {
  127. toast('请输入正确的手机号')
  128. return
  129. }
  130. try {
  131. // 这里调用你的短信接口
  132. const response = await tijiao({
  133. phone: form.value.phone,
  134. captchaVerifyParam: captchaVerifyParam.value,
  135. type: 'sms'
  136. })
  137. if (response.code === 0) {
  138. toast('验证码已发送')
  139. startSmsCountdown()
  140. } else {
  141. toast(response.msg || '发送失败')
  142. }
  143. } catch (error) {
  144. console.error('获取短信验证码失败:', error)
  145. toast('发送失败,请重试')
  146. }
  147. }
  148. // 开始短信倒计时
  149. function startSmsCountdown() {
  150. smsCountdown.value = 60
  151. countdownTimer = setInterval(() => {
  152. smsCountdown.value--
  153. if (smsCountdown.value <= 0) {
  154. clearInterval(countdownTimer)
  155. countdownTimer = null
  156. }
  157. }, 1000)
  158. }
  159. // 提交表单
  160. async function handleSubmit() {
  161. if (!isFormValid.value || isSubmitting.value) return
  162. isSubmitting.value = true
  163. try {
  164. const params = {
  165. phone: form.value.phone,
  166. smsCode: form.value.smsCode,
  167. captchaVerifyParam: captchaVerifyParam.value
  168. }
  169. // 直接使用你项目中的API
  170. const response = await tijiao(params)
  171. if (response.code === 0) {
  172. toast('绑定成功')
  173. // 通知uniapp页面
  174. if (window.uni && uni.postMessage) {
  175. uni.postMessage({
  176. data: {
  177. status: 'success',
  178. phone: form.value.phone,
  179. captchaResult: captchaVerifyParam.value,
  180. userInfo: response.data // 如果有用户信息
  181. }
  182. })
  183. }
  184. // 延迟返回,确保消息传递
  185. setTimeout(() => {
  186. if (window.uni && uni.navigateBack) {
  187. uni.navigateBack()
  188. }
  189. }, 1000)
  190. } else {
  191. toast(response.msg || '绑定失败')
  192. }
  193. } catch (error) {
  194. console.error('绑定失败:', error)
  195. toast('绑定失败,请重试')
  196. } finally {
  197. isSubmitting.value = false
  198. }
  199. }
  200. </script>
  201. <style scoped>
  202. .captcha-page {
  203. height: 100vh;
  204. display: flex;
  205. align-items: center;
  206. justify-content: center;
  207. background: #f5f5f5;
  208. }
  209. .container {
  210. width: 90%;
  211. max-width: 400px;
  212. background: white;
  213. padding: 30px;
  214. border-radius: 10px;
  215. box-shadow: 0 2px 10px rgba(0,0,0,0.1);
  216. }
  217. .form-group {
  218. margin-bottom: 20px;
  219. }
  220. .form-group label {
  221. display: block;
  222. margin-bottom: 8px;
  223. font-weight: bold;
  224. color: #333;
  225. }
  226. .form-group input {
  227. width: 100%;
  228. padding: 10px;
  229. border: 1px solid #ddd;
  230. border-radius: 5px;
  231. box-sizing: border-box;
  232. }
  233. .sms-input-group {
  234. display: flex;
  235. gap: 10px;
  236. }
  237. .sms-input-group input {
  238. flex: 1;
  239. }
  240. .get-sms-btn {
  241. padding: 10px 15px;
  242. background: #007aff;
  243. color: white;
  244. border: none;
  245. border-radius: 5px;
  246. cursor: pointer;
  247. white-space: nowrap;
  248. }
  249. .get-sms-btn:disabled {
  250. background: #ccc;
  251. cursor: not-allowed;
  252. }
  253. .captcha-container {
  254. margin: 20px 0;
  255. min-height: 100px;
  256. }
  257. .submit-btn {
  258. width: 100%;
  259. padding: 12px;
  260. background: #07c160;
  261. color: white;
  262. border: none;
  263. border-radius: 5px;
  264. font-size: 16px;
  265. cursor: pointer;
  266. }
  267. .submit-btn:disabled {
  268. background: #ccc;
  269. cursor: not-allowed;
  270. }
  271. .submit-btn:hover:not(:disabled) {
  272. background: #06ae56;
  273. }
  274. </style>