id-verification.vue 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. <template>
  2. <view class="id-verification-page">
  3. <!-- 自定义导航栏 -->
  4. <view class="custom-navbar">
  5. <view class="navbar-back" @click="goBack">
  6. <text class="back-icon">←</text>
  7. </view>
  8. <view class="navbar-title">绑定身份证</view>
  9. <view class="navbar-placeholder"></view>
  10. </view>
  11. <!-- 提示信息 -->
  12. <view class="tip-card">
  13. <text class="tip-icon">🔒</text>
  14. <view class="tip-content">
  15. <text class="tip-title">信息安全保障</text>
  16. <text class="tip-text">您的身份信息将严格加密保存,仅用于实名认证</text>
  17. </view>
  18. </view>
  19. <!-- 表单区域 -->
  20. <view class="form-container">
  21. <view class="form-item">
  22. <text class="form-label">真实姓名</text>
  23. <input class="form-input" v-model="formData.realName" placeholder="请输入真实姓名" />
  24. </view>
  25. <view class="form-item">
  26. <text class="form-label">身份证号</text>
  27. <input class="form-input" v-model="formData.idCard" placeholder="请输入18位身份证号" maxlength="18" />
  28. </view>
  29. </view>
  30. <!-- 上传身份证照片 -->
  31. <view class="upload-section">
  32. <text class="section-title">上传身份证照片</text>
  33. <view class="upload-grid">
  34. <view class="upload-item">
  35. <image v-if="formData.idCardFront" :src="formData.idCardFront" class="id-card-image" mode="aspectFill"></image>
  36. <view v-else class="upload-placeholder" @click="uploadIdCard('front')">
  37. <text class="upload-icon">📷</text>
  38. <text class="upload-text">身份证正面</text>
  39. </view>
  40. </view>
  41. <view class="upload-item">
  42. <image v-if="formData.idCardBack" :src="formData.idCardBack" class="id-card-image" mode="aspectFill"></image>
  43. <view v-else class="upload-placeholder" @click="uploadIdCard('back')">
  44. <text class="upload-icon">📷</text>
  45. <text class="upload-text">身份证反面</text>
  46. </view>
  47. </view>
  48. </view>
  49. <text class="upload-tip">请确保照片清晰,信息完整可见</text>
  50. </view>
  51. <!-- 提交按钮 -->
  52. <view class="submit-container">
  53. <button class="submit-btn" :disabled="canSubmit" @click="handleSubmit">
  54. {{ submitting ? '提交中...' : '提交认证' }}
  55. </button>
  56. </view>
  57. <!-- 协议说明 -->
  58. <view class="agreement">
  59. <text class="agreement-text">提交即表示同意</text>
  60. <text class="agreement-link" @click="showAgreement">《实名认证协议》</text>
  61. </view>
  62. </view>
  63. </template>
  64. <script>
  65. export default {
  66. data() {
  67. return {
  68. formData: {
  69. realName: '',
  70. idCard: '',
  71. idCardFront: '',
  72. idCardBack: ''
  73. },
  74. countdown: 0,
  75. submitting: false,
  76. timer: null
  77. }
  78. },
  79. computed: {
  80. canSubmit() {
  81. return this.formData.realName &&
  82. this.formData.idCard &&
  83. this.formData.code &&
  84. this.formData.idCardFront &&
  85. this.formData.idCardBack &&
  86. !this.submitting
  87. }
  88. },
  89. onUnload() {
  90. if (this.timer) {
  91. clearInterval(this.timer)
  92. }
  93. },
  94. methods: {
  95. // 发送验证码
  96. async sendCode() {
  97. if (this.countdown > 0) return
  98. try {
  99. // TODO: 调用发送验证码API
  100. uni.showToast({
  101. title: '验证码已发送',
  102. icon: 'success'
  103. })
  104. // 开始倒计时
  105. this.countdown = 60
  106. this.timer = setInterval(() => {
  107. this.countdown--
  108. if (this.countdown <= 0) {
  109. clearInterval(this.timer)
  110. }
  111. }, 1000)
  112. } catch (error) {
  113. console.error('发送验证码失败:', error)
  114. uni.showToast({
  115. title: '发送失败',
  116. icon: 'none'
  117. })
  118. }
  119. },
  120. // 上传身份证照片
  121. uploadIdCard(type) {
  122. uni.chooseImage({
  123. count: 1,
  124. sizeType: ['compressed'],
  125. sourceType: ['album', 'camera'],
  126. success: (res) => {
  127. const tempFilePath = res.tempFilePaths[0]
  128. // TODO: 上传到服务器
  129. // 暂时使用本地临时路径
  130. if (type === 'front') {
  131. this.formData.idCardFront = tempFilePath
  132. } else {
  133. this.formData.idCardBack = tempFilePath
  134. }
  135. uni.showToast({
  136. title: '照片已选择',
  137. icon: 'success'
  138. })
  139. }
  140. })
  141. },
  142. // 提交认证
  143. async handleSubmit() {
  144. if (this.canSubmit) return
  145. // 验证身份证格式
  146. if (!this.validateIdCard(this.formData.idCard)) {
  147. uni.showToast({
  148. title: '请输入正确的身份证号',
  149. icon: 'none'
  150. })
  151. return
  152. }
  153. this.submitting = true
  154. try {
  155. // TODO: 调用实名认证API
  156. await new Promise(resolve => setTimeout(resolve, 2000))
  157. uni.showToast({
  158. title: '提交成功,等待审核',
  159. icon: 'success'
  160. })
  161. setTimeout(() => {
  162. uni.navigateBack()
  163. }, 1500)
  164. } catch (error) {
  165. console.error('提交失败:', error)
  166. uni.showToast({
  167. title: '提交失败,请重试',
  168. icon: 'none'
  169. })
  170. } finally {
  171. this.submitting = false
  172. }
  173. },
  174. // 验证身份证号
  175. validateIdCard(idCard) {
  176. const reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/
  177. return reg.test(idCard)
  178. },
  179. // 显示协议
  180. showAgreement() {
  181. uni.showModal({
  182. title: '实名认证协议',
  183. content: '为了保障您的权益,我们会严格保护您的个人信息...',
  184. showCancel: false
  185. })
  186. },
  187. // 返回
  188. goBack() {
  189. uni.navigateBack()
  190. }
  191. }
  192. }
  193. </script>
  194. <style scoped>
  195. .id-verification-page {
  196. min-height: 100vh;
  197. background: #F5F5F5;
  198. }
  199. /* 自定义导航栏 */
  200. .custom-navbar {
  201. height: 88rpx;
  202. background: #E91E63;
  203. display: flex;
  204. align-items: center;
  205. justify-content: space-between;
  206. padding: 0 20rpx;
  207. color: white;
  208. }
  209. .navbar-back {
  210. padding: 10rpx 20rpx;
  211. }
  212. .back-icon {
  213. font-size: 40rpx;
  214. color: white;
  215. font-weight: bold;
  216. }
  217. .navbar-title {
  218. font-size: 32rpx;
  219. font-weight: bold;
  220. position: absolute;
  221. left: 50%;
  222. transform: translateX(-50%);
  223. }
  224. .navbar-placeholder {
  225. width: 80rpx;
  226. }
  227. /* 提示卡片 */
  228. .tip-card {
  229. margin: 24rpx;
  230. padding: 30rpx;
  231. background: linear-gradient(135deg, #FFF3E0 0%, #FFECB3 100%);
  232. border-radius: 16rpx;
  233. display: flex;
  234. align-items: center;
  235. gap: 20rpx;
  236. border-left: 6rpx solid #FF9800;
  237. }
  238. .tip-icon {
  239. font-size: 48rpx;
  240. }
  241. .tip-content {
  242. flex: 1;
  243. display: flex;
  244. flex-direction: column;
  245. gap: 8rpx;
  246. }
  247. .tip-title {
  248. font-size: 28rpx;
  249. font-weight: bold;
  250. color: #E65100;
  251. }
  252. .tip-text {
  253. font-size: 24rpx;
  254. color: #F57C00;
  255. line-height: 1.5;
  256. }
  257. /* 表单区域 */
  258. .form-container {
  259. margin: 24rpx;
  260. }
  261. .form-item {
  262. background: white;
  263. padding: 32rpx;
  264. margin-bottom: 24rpx;
  265. border-radius: 16rpx;
  266. }
  267. .form-label {
  268. display: block;
  269. font-size: 28rpx;
  270. color: #333;
  271. margin-bottom: 20rpx;
  272. font-weight: bold;
  273. }
  274. .form-input {
  275. width: 100%;
  276. height: 80rpx;
  277. padding: 0 24rpx;
  278. background: #F5F5F5;
  279. border-radius: 12rpx;
  280. font-size: 28rpx;
  281. border: 2rpx solid #E0E0E0;
  282. }
  283. .code-input-group {
  284. display: flex;
  285. gap: 16rpx;
  286. }
  287. .code-input {
  288. flex: 1;
  289. }
  290. .send-code-btn {
  291. width: 200rpx;
  292. height: 80rpx;
  293. line-height: 80rpx;
  294. background: #E91E63;
  295. color: white;
  296. border: none;
  297. border-radius: 12rpx;
  298. font-size: 26rpx;
  299. padding: 0;
  300. }
  301. .send-code-btn[disabled] {
  302. background: #BDBDBD;
  303. }
  304. /* 上传区域 */
  305. .upload-section {
  306. margin: 24rpx;
  307. padding: 32rpx;
  308. background: white;
  309. border-radius: 16rpx;
  310. }
  311. .section-title {
  312. font-size: 28rpx;
  313. font-weight: bold;
  314. color: #333;
  315. margin-bottom: 24rpx;
  316. display: block;
  317. }
  318. .upload-grid {
  319. display: flex;
  320. gap: 24rpx;
  321. margin-bottom: 16rpx;
  322. }
  323. .upload-item {
  324. flex: 1;
  325. aspect-ratio: 16/10;
  326. }
  327. .upload-placeholder {
  328. width: 100%;
  329. height: 100%;
  330. background: #F5F5F5;
  331. border: 2rpx dashed #BDBDBD;
  332. border-radius: 12rpx;
  333. display: flex;
  334. flex-direction: column;
  335. align-items: center;
  336. justify-content: center;
  337. gap: 12rpx;
  338. }
  339. .upload-icon {
  340. font-size: 60rpx;
  341. }
  342. .upload-text {
  343. font-size: 24rpx;
  344. color: #999;
  345. }
  346. .id-card-image {
  347. width: 100%;
  348. height: 100%;
  349. border-radius: 12rpx;
  350. }
  351. .upload-tip {
  352. font-size: 24rpx;
  353. color: #999;
  354. text-align: center;
  355. }
  356. /* 提交按钮 */
  357. .submit-container {
  358. padding: 40rpx 24rpx;
  359. }
  360. .submit-btn {
  361. width: 100%;
  362. height: 100rpx;
  363. background: linear-gradient(135deg, #E91E63 0%, #C2185B 100%);
  364. color: white;
  365. border-radius: 50rpx;
  366. font-size: 32rpx;
  367. font-weight: bold;
  368. border: none;
  369. box-shadow: 0 8rpx 24rpx rgba(233, 30, 99, 0.3);
  370. }
  371. .submit-btn[disabled] {
  372. background: #BDBDBD;
  373. box-shadow: none;
  374. }
  375. /* 协议 */
  376. .agreement {
  377. text-align: center;
  378. padding: 0 24rpx 40rpx;
  379. font-size: 24rpx;
  380. color: #999;
  381. }
  382. .agreement-link {
  383. color: #E91E63;
  384. text-decoration: underline;
  385. }
  386. </style>