-
16pages.json
-
515pages/register/register-form.vue
-
490pages/register/register.vue
-
8pages/user/user.vue
-
BINstatic/register/1.jpg
-
BINstatic/register/2.jpg
-
BINstatic/register/3.jpg
-
BINstatic/register/4.jpg
-
BINstatic/register/5.jpg
-
BINstatic/register/6.jpg
-
BINstatic/register/7.jpg
-
0subpkg/pages/seat-record/seat-record.vue
@ -0,0 +1,515 @@ |
|||||
|
<template> |
||||
|
<view class="page-container"> |
||||
|
<!-- 顶部背景 + 标题 --> |
||||
|
<view class="top-bar"> |
||||
|
<image class="top-bar-bg" src="@/static/images/mingqi-beij@2x.png" mode="aspectFill"></image> |
||||
|
<view class="library-info"> |
||||
|
<image class="avatar" src="@/static/images/logo.jpg" mode="aspectFill"></image> |
||||
|
<view class="library-name">葛店经济技术开发区图书馆</view> |
||||
|
<view class="sub-title">读者证办理</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 表单卡片 --> |
||||
|
<view class="form-card"> |
||||
|
<!-- 姓名 --> |
||||
|
<view class="form-item"> |
||||
|
<uni-icons class="form-icon" custom-prefix="iconfont" type="icon-xingming" size="22"></uni-icons> |
||||
|
<input |
||||
|
class="input" |
||||
|
placeholder="请输入真实姓名" |
||||
|
v-model="formData.name" |
||||
|
maxlength="20" |
||||
|
/> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 身份证号 --> |
||||
|
<view class="form-item"> |
||||
|
<uni-icons class="form-icon" custom-prefix="iconfont" type="icon-duzhezheng" size="24"></uni-icons> |
||||
|
<input |
||||
|
class="input" |
||||
|
placeholder="请输入18位身份证号" |
||||
|
v-model="formData.idCard" |
||||
|
maxlength="18" |
||||
|
/> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 手机号 --> |
||||
|
<view class="form-item"> |
||||
|
<uni-icons class="form-icon" type="phone" size="24"></uni-icons> |
||||
|
<input |
||||
|
class="input" |
||||
|
placeholder="请输入手机号" |
||||
|
v-model="formData.phone" |
||||
|
type="number" |
||||
|
maxlength="11" |
||||
|
/> |
||||
|
<button class="get-phone-btn" open-type="getPhoneNumber" @getphonenumber="getPhoneNumber"> |
||||
|
一键获取 |
||||
|
</button> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 密码 --> |
||||
|
<view class="form-item"> |
||||
|
<uni-icons class="form-icon" type="locked" size="24"></uni-icons> |
||||
|
<input |
||||
|
class="input" |
||||
|
placeholder="请设置6-20位密码" |
||||
|
:password="!showPwd" |
||||
|
v-model="formData.password" |
||||
|
maxlength="20" |
||||
|
/> |
||||
|
<uni-icons |
||||
|
class="pwd-icon" |
||||
|
:type="showPwd ? 'eye' : 'eye-slash'" |
||||
|
size="20" |
||||
|
@click="togglePwd" |
||||
|
></uni-icons> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 确认密码 --> |
||||
|
<view class="form-item"> |
||||
|
<uni-icons class="form-icon" type="locked" size="24"></uni-icons> |
||||
|
<input |
||||
|
class="input" |
||||
|
placeholder="请再次确认密码" |
||||
|
:password="!showConfirmPwd" |
||||
|
v-model="formData.confirmPassword" |
||||
|
maxlength="20" |
||||
|
/> |
||||
|
<uni-icons |
||||
|
class="pwd-icon" |
||||
|
:type="showConfirmPwd ? 'eye' : 'eye-slash'" |
||||
|
size="20" |
||||
|
@click="toggleConfirmPwd" |
||||
|
></uni-icons> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 提交按钮 --> |
||||
|
<button class="submit-btn" type="primary" @click="submit" :loading="loading"> |
||||
|
{{ loading ? '提交中...' : '确认办理' }} |
||||
|
</button> |
||||
|
|
||||
|
<!-- 同意协议 --> |
||||
|
<view class="agreement-item"> |
||||
|
<view class="radio-box" :class="{ checked: agreed }" @click="agreed = !agreed"> |
||||
|
<view class="radio-inner" v-if="agreed"></view> |
||||
|
</view> |
||||
|
<text class="agreement-text"> |
||||
|
我已阅读并同意遵守 |
||||
|
<text class="agreement-link" @click="openAgreement">《爱图智服服务协议》</text> |
||||
|
</text> |
||||
|
</view> |
||||
|
|
||||
|
</view> |
||||
|
|
||||
|
<!-- 温馨提示 --> |
||||
|
<view class="tips-card"> |
||||
|
<view class="tips-title">温馨提示</view> |
||||
|
<view class="tips-text"> |
||||
|
1. 请填写真实身份信息,用于办理读者证<br> |
||||
|
2. 密码请牢记,用于登录和借阅查询<br> |
||||
|
<!-- 3. 提交后工作人员将尽快审核 --> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import config from '@/utils/config'; |
||||
|
import { getOpenId } from '@/utils/storage'; |
||||
|
import { FetchSessionKey, FetchDecryptPhone } from '@/api/user.js'; |
||||
|
|
||||
|
export default { |
||||
|
data() { |
||||
|
return { |
||||
|
sessionKey: '', |
||||
|
openid: '', |
||||
|
formData: { |
||||
|
name: '', |
||||
|
idCard: '', |
||||
|
phone: '', |
||||
|
password: '', |
||||
|
confirmPassword: '' |
||||
|
}, |
||||
|
showPwd: false, |
||||
|
showConfirmPwd: false, |
||||
|
loading: false, |
||||
|
agreed: false |
||||
|
}; |
||||
|
}, |
||||
|
|
||||
|
onLoad() { |
||||
|
this.getSessionKey(); |
||||
|
}, |
||||
|
|
||||
|
methods: { |
||||
|
async getSessionKey() { |
||||
|
try { |
||||
|
uni.login({ |
||||
|
success: async (loginRes) => { |
||||
|
console.log('loginRes',loginRes) |
||||
|
if (loginRes.code) { |
||||
|
const res = await FetchSessionKey({ |
||||
|
libcode: config.LIB_CODE, |
||||
|
code: loginRes.code |
||||
|
}); |
||||
|
if (res.code === 200) { |
||||
|
this.sessionKey = res.data.session_key; |
||||
|
this.openid = res.data.openid; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
} catch (error) { |
||||
|
console.error('获取sessionKey失败:', error); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
getPhoneNumber(e) { |
||||
|
if (e.detail.errMsg !== 'getPhoneNumber:ok') { |
||||
|
uni.showToast({ title: '取消授权', icon: 'none' }); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (!this.sessionKey) { |
||||
|
uni.showToast({ title: '请稍后再试', icon: 'none' }); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
FetchDecryptPhone({ |
||||
|
sessionKey: this.sessionKey, |
||||
|
encryptedData: e.detail.encryptedData, |
||||
|
iv: e.detail.iv |
||||
|
}).then(res => { |
||||
|
if (res.code === 200) { |
||||
|
this.formData.phone = res.data.phoneNumber || ''; |
||||
|
uni.showToast({ title: '获取成功', icon: 'success' }); |
||||
|
} else { |
||||
|
uni.showToast({ title: res.message || '获取失败', icon: 'none' }); |
||||
|
} |
||||
|
}).catch(() => { |
||||
|
uni.showToast({ title: '获取手机号失败', icon: 'none' }); |
||||
|
}); |
||||
|
}, |
||||
|
togglePwd() { |
||||
|
this.showPwd = !this.showPwd; |
||||
|
}, |
||||
|
toggleConfirmPwd() { |
||||
|
this.showConfirmPwd = !this.showConfirmPwd; |
||||
|
}, |
||||
|
|
||||
|
// 身份证验证(支持15位和18位,自动去除空格和连字符) |
||||
|
validateIdCard(idCard) { |
||||
|
if (!idCard) return false; |
||||
|
// 去除空格和连字符 |
||||
|
idCard = idCard.replace(/[\s-]/g, ''); |
||||
|
// 15位身份证格式验证 |
||||
|
const idCard15Reg = /^[1-9]\d{5}\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}$/; |
||||
|
// 18位身份证格式验证 |
||||
|
const idCard18Reg = /^[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]$/; |
||||
|
// 15位身份证直接验证格式 |
||||
|
if (idCard.length === 15) { |
||||
|
return idCard15Reg.test(idCard); |
||||
|
} |
||||
|
// 18位身份证需要验证格式、日期和校验码 |
||||
|
if (idCard.length !== 18 || !idCard18Reg.test(idCard)) { |
||||
|
return false; |
||||
|
} |
||||
|
// 验证日期有效性(宽松模式:跳过校验码验证) |
||||
|
const year = +idCard.substring(6, 10); |
||||
|
const month = +idCard.substring(10, 12); |
||||
|
const day = +idCard.substring(12, 14); |
||||
|
const date = new Date(year, month - 1, day); |
||||
|
return date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day; |
||||
|
}, |
||||
|
// 手机号验证 |
||||
|
validatePhone(phone) { |
||||
|
return /^1[3-9]\d{9}$/.test(phone); |
||||
|
}, |
||||
|
|
||||
|
// 表单验证(更严谨) |
||||
|
validateForm() { |
||||
|
const { name, idCard, phone, password, confirmPassword } = this.formData; |
||||
|
|
||||
|
// 1. 姓名:必须非空且trim后有内容 |
||||
|
if (!name || name.trim() === '') { |
||||
|
uni.showToast({ title: '请输入姓名', icon: 'none' }); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
// 2. 身份证:非空 + 格式正确 |
||||
|
if (!idCard || idCard.trim() === '') { |
||||
|
uni.showToast({ title: '请输入身份证号', icon: 'none' }); |
||||
|
return false; |
||||
|
} |
||||
|
if (!this.validateIdCard(idCard.trim())) { |
||||
|
uni.showToast({ title: '身份证号格式不正确', icon: 'none' }); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
// 3. 手机号:非空 + 格式正确 |
||||
|
if (!phone || phone.trim() === '') { |
||||
|
uni.showToast({ title: '请输入手机号', icon: 'none' }); |
||||
|
return false; |
||||
|
} |
||||
|
if (!this.validatePhone(phone.trim())) { |
||||
|
uni.showToast({ title: '手机号格式不正确', icon: 'none' }); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
// 4. 密码:至少6位 |
||||
|
if (!password || password.length < 6) { |
||||
|
uni.showToast({ title: '密码至少6位', icon: 'none' }); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
// 5. 确认密码:必须一致 |
||||
|
if (password !== confirmPassword) { |
||||
|
uni.showToast({ title: '两次密码不一致', icon: 'none' }); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
// 所有校验通过 |
||||
|
return true; |
||||
|
}, |
||||
|
|
||||
|
// 显示协议弹窗 |
||||
|
showAgreementModal() { |
||||
|
uni.showModal({ |
||||
|
title: '提示', |
||||
|
content: '请先阅读并同意《爱图智服服务协议》', |
||||
|
confirmText: '同意', |
||||
|
cancelText: '不同意', |
||||
|
success: (res) => { |
||||
|
if (res.confirm) { |
||||
|
// 用户同意,选中radio并继续提交 |
||||
|
this.agreed = true; |
||||
|
this.submitForm(); |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// 跳转到协议详情页面 |
||||
|
openAgreement() { |
||||
|
uni.navigateTo({ |
||||
|
url: '/subpkg/pages/agreement/agreement' |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
async submit() { |
||||
|
// 防止重复点击 |
||||
|
if (this.loading) return; |
||||
|
|
||||
|
// 小程序关键:等 input 数据同步到 data |
||||
|
await this.$nextTick(); |
||||
|
|
||||
|
// 校验不通过直接 return |
||||
|
if (!this.validateForm()) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// 如果未同意协议,显示协议弹窗 |
||||
|
if (!this.agreed) { |
||||
|
this.showAgreementModal(); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// 已同意协议,直接提交 |
||||
|
await this.submitForm(); |
||||
|
}, |
||||
|
|
||||
|
// 实际提交表单 |
||||
|
async submitForm() { |
||||
|
this.loading = true; |
||||
|
try { |
||||
|
const openId = await getOpenId(); |
||||
|
if (!openId) { |
||||
|
uni.showToast({ title: '获取用户信息失败', icon: 'none' }); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
uni.showToast({ title: '后续流程正在研发中,请稍后试用~', icon: 'none' }); |
||||
|
setTimeout(() => uni.navigateBack(), 1500); |
||||
|
|
||||
|
// 提交(trim 后再发) |
||||
|
// const res = await uni.request({ |
||||
|
// url: config.baseUrl + '/api/reader/register', |
||||
|
// method: 'POST', |
||||
|
// data: { |
||||
|
// name: this.formData.name.trim(), |
||||
|
// idCard: this.formData.idCard.trim(), |
||||
|
// phone: this.formData.phone.trim(), |
||||
|
// password: this.formData.password, |
||||
|
// openId, |
||||
|
// libcode: config.LIB_CODE |
||||
|
// } |
||||
|
// }); |
||||
|
|
||||
|
// if (res.data?.code === 200) { |
||||
|
// uni.showToast({ title: '办理成功', icon: 'success' }); |
||||
|
// setTimeout(() => uni.navigateBack(), 1500); |
||||
|
// } else { |
||||
|
// uni.showToast({ title: res.data?.message || '提交失败', icon: 'none' }); |
||||
|
// } |
||||
|
} catch (err) { |
||||
|
console.error('提交异常', err); |
||||
|
uni.showToast({ title: '网络异常,请重试', icon: 'none' }); |
||||
|
} finally { |
||||
|
this.loading = false; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
page { |
||||
|
background-color: #f5f7fa; |
||||
|
} |
||||
|
.page-container { |
||||
|
min-height: 100vh; |
||||
|
background-color: #f5f7fa; |
||||
|
padding-bottom: 20px; |
||||
|
} |
||||
|
|
||||
|
/* 顶部 */ |
||||
|
.top-bar { |
||||
|
height: 210px; |
||||
|
.library-info { |
||||
|
position: relative; |
||||
|
z-index: 2; |
||||
|
color: #fff; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* 表单卡片 */ |
||||
|
.form-card { |
||||
|
margin: -30px 12px 12px; |
||||
|
background: #fff; |
||||
|
border-radius: 12px; |
||||
|
padding: 20px 16px; |
||||
|
box-shadow: 0 4px 15px rgba(0,0,0,0.08); |
||||
|
position: relative; |
||||
|
z-index: 3; |
||||
|
} |
||||
|
|
||||
|
.form-item { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
height: 44px; |
||||
|
border-bottom: 1rpx solid #f2f3f5; |
||||
|
margin-bottom: 4px; |
||||
|
|
||||
|
.form-icon { |
||||
|
font-size: 14px; |
||||
|
color: #01a4fe; |
||||
|
margin-right: 10px; |
||||
|
} |
||||
|
|
||||
|
.input { |
||||
|
flex: 1; |
||||
|
font-size: 14px; |
||||
|
color: #333; |
||||
|
} |
||||
|
|
||||
|
.pwd-icon { |
||||
|
color: #999; |
||||
|
padding: 5px; |
||||
|
} |
||||
|
|
||||
|
.get-phone-btn { |
||||
|
font-size: 12px; |
||||
|
color: #fff; |
||||
|
background-color: #01a4fe; |
||||
|
border-radius: 20px; |
||||
|
padding: 6px 10px; |
||||
|
border: none; |
||||
|
line-height: 1.2; |
||||
|
|
||||
|
&::after { |
||||
|
border: none; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* 提交按钮 */ |
||||
|
.submit-btn { |
||||
|
width: 100%; |
||||
|
height: 44px; |
||||
|
background-color: #01a4fe; |
||||
|
color: #fff; |
||||
|
border-radius: 22px; |
||||
|
font-size: 15px; |
||||
|
margin-top: 20px; |
||||
|
border: none; |
||||
|
|
||||
|
&::after { |
||||
|
border: none; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* 同意协议 */ |
||||
|
.agreement-item { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
margin-top: 16px; |
||||
|
|
||||
|
.radio-box { |
||||
|
width: 22rpx; |
||||
|
height: 22rpx; |
||||
|
border: 2rpx solid #ccc; |
||||
|
border-radius: 50%; |
||||
|
margin-right: 10rpx; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
transition: all 0.2s; |
||||
|
|
||||
|
&.checked { |
||||
|
border-color: #01a4fe; |
||||
|
background-color: #01a4fe; |
||||
|
} |
||||
|
|
||||
|
.radio-inner { |
||||
|
width: 12rpx; |
||||
|
height: 12rpx; |
||||
|
background-color: #fff; |
||||
|
border-radius: 50%; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.agreement-text { |
||||
|
font-size: 12px; |
||||
|
color: #666; |
||||
|
flex: 1; |
||||
|
} |
||||
|
|
||||
|
.agreement-link { |
||||
|
color: #01a4fe; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* 温馨提示 */ |
||||
|
.tips-card { |
||||
|
margin: 0 12px; |
||||
|
background: #fff; |
||||
|
border-radius: 10px; |
||||
|
padding: 15px; |
||||
|
box-shadow: 0 2px 10px rgba(0,0,0,0.05); |
||||
|
|
||||
|
.tips-title { |
||||
|
font-size: 13px; |
||||
|
color: #333; |
||||
|
font-weight: 500; |
||||
|
margin-bottom: 8px; |
||||
|
} |
||||
|
|
||||
|
.tips-text { |
||||
|
font-size: 12px; |
||||
|
color: #666; |
||||
|
line-height: 1.6; |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
|
After Width: 1313 | Height: 2335 | Size: 94 KiB |
|
After Width: 1280 | Height: 2637 | Size: 248 KiB |
|
After Width: 1312 | Height: 2716 | Size: 130 KiB |
|
After Width: 1312 | Height: 2716 | Size: 102 KiB |
|
After Width: 1312 | Height: 2716 | Size: 87 KiB |
|
After Width: 1312 | Height: 2703 | Size: 111 KiB |
|
After Width: 1312 | Height: 2716 | Size: 144 KiB |