图书馆小程序
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

405 lines
9.5 KiB

1 month ago
  1. <template>
  2. <view style="background-color: #fff; height: calc(100vh);">
  3. <view class="top-bar">
  4. <image class="top-bar-bg" src="@/static/images/mingqi-beij@2x.png" mode="aspectFill"></image>
  5. <view class="library-info">
  6. <image class="avatar" src="@/static/images/logo.jpg" mode="aspectFill"></image>
  7. <view class="library-name">葛店经济技术开发区图书馆</view>
  8. </view>
  9. </view>
  10. <!-- 表单区域 -->
  11. <view class="form-box">
  12. <!-- 姓名 -->
  13. <view class="form-item">
  14. <uni-icons class="form-icon" custom-prefix="iconfont" type="icon-user" size="24"></uni-icons>
  15. <input
  16. class="input"
  17. placeholder="请输入姓名"
  18. v-model="formData.name"
  19. maxlength="20"
  20. />
  21. </view>
  22. <!-- 身份证号 -->
  23. <view class="form-item">
  24. <uni-icons class="form-icon" custom-prefix="iconfont" type="icon-shenfen" size="24"></uni-icons>
  25. <input
  26. class="input"
  27. placeholder="请输入身份证号"
  28. v-model="formData.idCard"
  29. maxlength="18"
  30. />
  31. </view>
  32. <!-- 手机号 -->
  33. <view class="form-item">
  34. <uni-icons class="form-icon" type="phone" size="24"></uni-icons>
  35. <input
  36. class="input"
  37. placeholder="请输入手机号"
  38. v-model="formData.phone"
  39. type="number"
  40. maxlength="11"
  41. />
  42. <button class="get-phone-btn" open-type="getPhoneNumber" @getphonenumber="getPhoneNumber">
  43. 获取手机号
  44. </button>
  45. </view>
  46. <!-- 密码 -->
  47. <view class="form-item">
  48. <uni-icons class="form-icon" type="locked" size="24"></uni-icons>
  49. <input
  50. class="input"
  51. placeholder="请输入密码"
  52. :password="!showPwd"
  53. v-model="formData.password"
  54. maxlength="20"
  55. />
  56. <uni-icons
  57. class="pwd-icon"
  58. :type="showPwd ? 'eye-slash' : 'eye'"
  59. size="20"
  60. @click="togglePwd"
  61. ></uni-icons>
  62. </view>
  63. <!-- 确认密码 -->
  64. <view class="form-item">
  65. <uni-icons class="form-icon" type="locked" size="24"></uni-icons>
  66. <input
  67. class="input"
  68. placeholder="请再次输入密码"
  69. :password="!showConfirmPwd"
  70. v-model="formData.confirmPassword"
  71. maxlength="20"
  72. />
  73. <uni-icons
  74. class="pwd-icon"
  75. :type="showConfirmPwd ? 'eye-slash' : 'eye'"
  76. size="20"
  77. @click="toggleConfirmPwd"
  78. ></uni-icons>
  79. </view>
  80. <!-- 提交按钮 -->
  81. <button class="submit-btn" type="primary" @click="submit" :loading="loading">
  82. {{ loading ? '提交中...' : '提交办证' }}
  83. </button>
  84. </view>
  85. <!-- 温馨提示 -->
  86. <!-- <view class="tips">
  87. <text class="tips-title">温馨提示</text>
  88. <view class="tips-content">
  89. <text>1请确保填写的信息真实准确</text>
  90. <text>2密码建议设置为6-20位数字和字母组合</text>
  91. <text>3提交后工作人员将在1-3个工作日内审核</text>
  92. </view>
  93. </view> -->
  94. </view>
  95. </template>
  96. <script>
  97. import config from '@/utils/config';
  98. import { getOpenId } from '@/utils/storage';
  99. export default {
  100. data() {
  101. return {
  102. formData: {
  103. name: '',
  104. idCard: '',
  105. phone: '',
  106. password: '',
  107. confirmPassword: ''
  108. },
  109. showPwd: false,
  110. showConfirmPwd: false,
  111. loading: false
  112. };
  113. },
  114. onLoad() {
  115. },
  116. methods: {
  117. /**
  118. * 获取手机号通过后端接口解密
  119. */
  120. getPhoneNumber(e) {
  121. if (e.detail.errMsg !== 'getPhoneNumber:ok') {
  122. uni.showToast({ title: '取消授权', icon: 'none' });
  123. return;
  124. }
  125. // #ifdef MP-WEIXIN
  126. // 获取 login code
  127. uni.login({
  128. success: (loginRes) => {
  129. // 调用后端接口解密手机号
  130. uni.request({
  131. url: config.baseUrl + '/api/wx/decryptPhone',
  132. method: 'POST',
  133. data: {
  134. code: loginRes.code,
  135. encryptedData: e.detail.encryptedData,
  136. iv: e.detail.iv
  137. },
  138. success: (res) => {
  139. if (res.data && res.data.code === 200) {
  140. this.formData.phone = res.data.data.phoneNumber || '';
  141. } else {
  142. uni.showToast({
  143. title: res.data?.message || '获取手机号失败',
  144. icon: 'none'
  145. });
  146. }
  147. },
  148. fail: () => {
  149. uni.showToast({
  150. title: '获取手机号失败',
  151. icon: 'none'
  152. });
  153. }
  154. });
  155. },
  156. fail: () => {
  157. uni.showToast({
  158. title: '获取手机号失败',
  159. icon: 'none'
  160. });
  161. }
  162. });
  163. // #endif
  164. // #ifndef MP-WEIXIN
  165. uni.showToast({ title: '该功能仅支持微信小程序', icon: 'none' });
  166. // #endif
  167. },
  168. /**
  169. * 切换密码显示
  170. */
  171. togglePwd() {
  172. this.showPwd = !this.showPwd;
  173. },
  174. /**
  175. * 切换确认密码显示
  176. */
  177. toggleConfirmPwd() {
  178. this.showConfirmPwd = !this.showConfirmPwd;
  179. },
  180. /**
  181. * 验证身份证号
  182. */
  183. validateIdCard(idCard) {
  184. const reg = /^[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]$/;
  185. return reg.test(idCard);
  186. },
  187. /**
  188. * 验证手机号
  189. */
  190. validatePhone(phone) {
  191. const reg = /^1[3-9]\d{9}$/;
  192. return reg.test(phone);
  193. },
  194. /**
  195. * 表单验证
  196. */
  197. validateForm() {
  198. const { name, idCard, phone, password, confirmPassword } = this.formData;
  199. if (!name || name.trim().length === 0) {
  200. uni.showToast({ title: '请输入姓名', icon: 'none' });
  201. return false;
  202. }
  203. if (!idCard || idCard.trim().length === 0) {
  204. uni.showToast({ title: '请输入身份证号', icon: 'none' });
  205. return false;
  206. }
  207. if (!this.validateIdCard(idCard)) {
  208. uni.showToast({ title: '身份证号格式不正确', icon: 'none' });
  209. return false;
  210. }
  211. if (!phone || phone.trim().length === 0) {
  212. uni.showToast({ title: '请输入手机号', icon: 'none' });
  213. return false;
  214. }
  215. if (!this.validatePhone(phone)) {
  216. uni.showToast({ title: '手机号格式不正确', icon: 'none' });
  217. return false;
  218. }
  219. if (!password || password.length < 6) {
  220. uni.showToast({ title: '密码至少需要6位', icon: 'none' });
  221. return false;
  222. }
  223. if (password !== confirmPassword) {
  224. uni.showToast({ title: '两次输入的密码不一致', icon: 'none' });
  225. return false;
  226. }
  227. return true;
  228. },
  229. /**
  230. * 提交表单
  231. */
  232. async submit() {
  233. if (!this.validateForm()) {
  234. return;
  235. }
  236. this.loading = true;
  237. try {
  238. const openId = await getOpenId();
  239. if (!openId) {
  240. uni.showToast({ title: '获取用户信息失败', icon: 'none' });
  241. this.loading = false;
  242. return;
  243. }
  244. const res = await uni.request({
  245. url: config.baseUrl + '/api/reader/register',
  246. method: 'POST',
  247. data: {
  248. name: this.formData.name,
  249. idCard: this.formData.idCard,
  250. phone: this.formData.phone,
  251. password: this.formData.password,
  252. openId: openId,
  253. libcode: config.LIB_CODE
  254. }
  255. });
  256. if (res.data && res.data.code === 200) {
  257. uni.showToast({ title: '提交成功', icon: 'success' });
  258. setTimeout(() => {
  259. uni.navigateBack();
  260. }, 1500);
  261. } else {
  262. uni.showToast({ title: res.data?.message || '提交失败', icon: 'none' });
  263. }
  264. } catch (error) {
  265. console.error('注册失败:', error);
  266. uni.showToast({ title: '提交失败', icon: 'none' });
  267. } finally {
  268. this.loading = false;
  269. }
  270. }
  271. }
  272. };
  273. </script>
  274. <style lang="scss" scoped>
  275. .top-bar {
  276. position: relative;
  277. width: 100%;
  278. height: 180px;
  279. .top-bar-bg {
  280. width: 100%;
  281. height: 100%;
  282. }
  283. .page-title {
  284. position: absolute;
  285. bottom: 20px;
  286. left: 20px;
  287. font-size: 28px;
  288. font-weight: bold;
  289. color: #fff;
  290. text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
  291. }
  292. }
  293. .form-box {
  294. padding: 20px 15px;
  295. }
  296. .form-item {
  297. position: relative;
  298. display: flex;
  299. align-items: center;
  300. height: 44px;
  301. border-bottom: 1px solid #f0f0f0;
  302. margin-bottom: 10px;
  303. .form-icon {
  304. margin-right: 12px;
  305. color: #01a4fe;
  306. }
  307. .input {
  308. flex: 1;
  309. height: 100%;
  310. font-size: 14px;
  311. color: #333;
  312. }
  313. .pwd-icon {
  314. margin-left: 10px;
  315. color: #999;
  316. }
  317. .get-phone-btn {
  318. background-color: #01a4fe;
  319. color: #fff;
  320. font-size: 12px;
  321. border-radius: 20px;
  322. border: none;
  323. }
  324. }
  325. .submit-btn {
  326. width: 100%;
  327. height: 48px;
  328. background-color: #01a4fe;
  329. color: #fff;
  330. border-radius: 24px;
  331. font-size: 16px;
  332. margin-top: 20px;
  333. border: none;
  334. &::after {
  335. border: none;
  336. }
  337. }
  338. .tips {
  339. padding: 15px;
  340. background-color: #fff;
  341. margin: 0 15px;
  342. border-radius: 12px;
  343. box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
  344. .tips-title {
  345. font-size: 14px;
  346. font-weight: bold;
  347. color: #333;
  348. display: block;
  349. margin-bottom: 8px;
  350. }
  351. .tips-content {
  352. text {
  353. display: block;
  354. font-size: 13px;
  355. color: #999;
  356. line-height: 1.8;
  357. }
  358. }
  359. }
  360. </style>