| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464 |
- <template>
- <view class="auth-container">
- <!-- 顶部提示 -->
- <view class="top-tip">请确保身份信息的准确,以免影响后续履约费用结算。</view>
- <!-- 表单信息 -->
- <view class="form-card">
- <!-- 证件类型 -->
- <view class="form-item">
- <text class="label">证件类型</text>
- <view class="read-only-text">居民身份证</view>
- </view>
- <!-- 真实姓名 -->
- <view class="form-item">
- <text class="label"><text class="required">*</text>真实姓名</text>
- <view class="gray-input-box">
- <input class="input-area" type="text" v-model="formData.name" placeholder="证件姓名"
- placeholder-class="input-placeholder" />
- </view>
- </view>
- <!-- 证件号码 -->
- <view class="form-item">
- <text class="label"><text class="required">*</text>证件号码</text>
- <view class="gray-input-box">
- <input class="input-area" type="idcard" v-model="formData.idNumber" placeholder="身份证号"
- placeholder-class="input-placeholder" />
- </view>
- </view>
- <!-- 有效日期 -->
- <view class="form-item">
- <text class="label"><text class="required">*</text>有效日期</text>
- <view class="gray-input-box" @click="openPicker">
- <text class="input-area" :class="{ 'input-placeholder': !formData.expiryDate }">
- {{ formData.expiryDate || '选择有效结束期限' }}
- </text>
- <!-- 箭头SVG -->
- <svg class="arrow-right" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg">
- <path
- d="M340.864 149.312a30.592 30.592 0 0 0 0 42.752L652.736 512 340.864 831.872a30.592 30.592 0 0 0 0 42.752 29.12 29.12 0 0 0 41.728 0L714.24 534.336a32 32 0 0 0 0-45.056L382.592 149.312a29.12 29.12 0 0 0-41.728 0z"
- fill="#CCCCCC"></path>
- </svg>
- </view>
- </view>
- </view>
- <!-- 身份证正面 -->
- <view class="upload-card">
- <view class="upload-box" @click="chooseImage('front')">
- <image v-if="idCardFront" :src="idCardFront" class="preview-img" mode="aspectFill"></image>
- <template v-else>
- <!-- 相机图标SVG -->
- <svg class="camera-icon" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
- <path
- d="M12 12C14.7614 12 17 9.76142 17 7C17 4.23858 14.7614 2 12 2C9.23858 2 7 4.23858 7 7C7 9.76142 9.23858 12 12 12Z"
- fill="#E0E0E0" />
- <circle cx="12" cy="12" r="3" stroke="#CCCCCC" stroke-width="2" />
- <path
- d="M20 6H17.82L16.4 4.47C15.96 4 15.34 3.73 14.68 3.73H9.32C8.66 3.73 8.04 4 7.6 4.47L6.18 6H4C2.9 6 2 6.9 2 8V18C2 19.1 2.9 20 4 20H20C21.1 20 22 19.1 22 18V8C22 6.9 21.1 6 20 6ZM12 17C9.24 17 7 14.76 7 12C7 9.24 9.24 7 12 7C14.76 7 17 9.24 17 12C17 14.76 14.76 17 12 17Z"
- fill="#CCCCCC" />
- </svg>
- <text class="upload-text">点击上传</text>
- </template>
- </view>
- <text class="card-label"><text class="required">*</text>证件带照片面</text>
- </view>
- <!-- 身份证反面 -->
- <view class="upload-card">
- <view class="upload-box" @click="chooseImage('back')">
- <image v-if="idCardBack" :src="idCardBack" class="preview-img" mode="aspectFill"></image>
- <template v-else>
- <!-- 相机图标SVG -->
- <svg class="camera-icon" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
- <path
- d="M20 6H17.82L16.4 4.47C15.96 4 15.34 3.73 14.68 3.73H9.32C8.66 3.73 8.04 4 7.6 4.47L6.18 6H4C2.9 6 2 6.9 2 8V18C2 19.1 2.9 20 4 20H20C21.1 20 22 19.1 22 18V8C22 6.9 21.1 6 20 6ZM12 17C9.24 17 7 14.76 7 12C7 9.24 9.24 7 12 7C14.76 7 17 9.24 17 12C17 14.76 14.76 17 12 17Z"
- fill="#CCCCCC" />
- </svg>
- <text class="upload-text">点击上传</text>
- </template>
- </view>
- <text class="card-label"><text class="required">*</text>证件国徽面</text>
- </view>
- <!-- 底部按钮 -->
- <view class="footer-btn-area">
- <button class="next-btn" @click="goToQualifications">下一步,完善资质</button>
- </view>
- <!-- 自定义日期选择器 -->
- <view class="picker-mask" :class="{ show: showPicker }" @click="closePicker">
- <view class="picker-content" @click.stop>
- <view class="picker-header">
- <text class="picker-btn-cancel" @click="closePicker">取消</text>
- <text class="picker-title">选择有效结束期限</text>
- <text class="picker-btn-confirm" @click="confirmPicker">确定</text>
- </view>
- <picker-view class="picker-view" indicator-style="height: 50px;" :value="pickerValue" @change="onPickerChange">
- <picker-view-column>
- <view class="picker-item" v-for="(item, index) in years" :key="index">{{ item }}年</view>
- </picker-view-column>
- <picker-view-column>
- <view class="picker-item" v-for="(item, index) in months" :key="index">{{ item }}月</view>
- </picker-view-column>
- <picker-view-column>
- <view class="picker-item" v-for="(item, index) in days" :key="index">{{ item }}日</view>
- </picker-view-column>
- </picker-view>
- </view>
- </view>
- </view>
- </template>
- <script>
- import { uploadFile } from '@/api/fulfiller/app'
- export default {
- data() {
- return {
- formData: { idType: '居民身份证', name: '', idNumber: '', expiryDate: '' },
- idCardFront: '', idCardBack: '',
- idCardFrontOssId: '', idCardBackOssId: '',
- showPicker: false, pickerValue: [0, 0, 0],
- years: [], months: [], days: [],
- tempYear: 0, tempMonth: 0, tempDay: 0,
- serviceType: [], isChoosingImage: false
- }
- },
- onLoad(options) {
- if (options.services) {
- try { this.serviceType = JSON.parse(decodeURIComponent(options.services)); }
- catch (e) { console.error('Parse services failed', e); }
- }
- this.initDateData(); this.restoreAuthData();
- },
- onShow() { if (this.isChoosingImage) this.isChoosingImage = false; },
- methods: {
- initDateData() {
- const year = new Date().getFullYear();
- for (let i = year; i <= year + 50; i++) this.years.push(i);
- for (let i = 1; i <= 12; i++) this.months.push(i);
- for (let i = 1; i <= 31; i++) this.days.push(i);
- },
- openPicker() {
- const date = new Date();
- const dateStr = this.formData.expiryDate || `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
- const [y, m, d] = dateStr.split('-').map(Number);
- let yIndex = this.years.indexOf(y); let mIndex = this.months.indexOf(m); let dIndex = this.days.indexOf(d);
- this.pickerValue = [yIndex > -1 ? yIndex : 0, mIndex > -1 ? mIndex : 0, dIndex > -1 ? dIndex : 0];
- this.tempYear = this.years[this.pickerValue[0]]; this.tempMonth = this.months[this.pickerValue[1]]; this.tempDay = this.days[this.pickerValue[2]];
- this.showPicker = true;
- },
- closePicker() { this.showPicker = false; },
- onPickerChange(e) {
- const val = e.detail.value;
- this.tempYear = this.years[val[0]]; this.tempMonth = this.months[val[1]]; this.tempDay = this.days[val[2]];
- },
- confirmPicker() {
- const mStr = this.tempMonth < 10 ? '0' + this.tempMonth : this.tempMonth;
- const dStr = this.tempDay < 10 ? '0' + this.tempDay : this.tempDay;
- this.formData.expiryDate = `${this.tempYear}-${mStr}-${dStr}`; this.closePicker();
- },
- restoreAuthData() {
- try {
- const saved = uni.getStorageSync('recruit_auth_data');
- if (saved) {
- const d = JSON.parse(saved);
- this.formData.name = d.name || ''; this.formData.idNumber = d.idNumber || '';
- this.formData.expiryDate = d.expiryDate || '';
- this.idCardFront = d.idCardFront || ''; this.idCardBack = d.idCardBack || '';
- this.idCardFrontOssId = d.idCardFrontOssId || ''; this.idCardBackOssId = d.idCardBackOssId || '';
- }
- } catch (e) { console.error('恢复认证数据失败', e); }
- },
- saveAuthData() {
- try {
- uni.setStorageSync('recruit_auth_data', JSON.stringify({
- name: this.formData.name, idNumber: this.formData.idNumber, expiryDate: this.formData.expiryDate,
- idCardFront: this.idCardFront, idCardBack: this.idCardBack,
- idCardFrontOssId: this.idCardFrontOssId, idCardBackOssId: this.idCardBackOssId
- }));
- } catch (e) { console.error('保存认证数据失败', e); }
- },
- resetFormData() {
- this.formData.name = ''; this.formData.idNumber = ''; this.formData.expiryDate = '';
- this.idCardFront = ''; this.idCardBack = '';
- this.idCardFrontOssId = ''; this.idCardBackOssId = '';
- try { uni.removeStorageSync('recruit_auth_data'); } catch (e) { console.error('清除缓存失败', e); }
- },
- chooseImage(side) {
- this.isChoosingImage = true;
- uni.chooseImage({
- count: 1, sizeType: ['compressed'], sourceType: ['album', 'camera'],
- success: async (res) => {
- const tempPath = res.tempFilePaths[0];
- if (side === 'front') this.idCardFront = tempPath; else this.idCardBack = tempPath;
- try {
- uni.showLoading({ title: '上传中...' });
- const uploadRes = await uploadFile(tempPath);
- if (side === 'front') this.idCardFrontOssId = uploadRes.data.ossId;
- else this.idCardBackOssId = uploadRes.data.ossId;
- uni.hideLoading(); this.saveAuthData();
- } catch (err) { uni.hideLoading(); console.error('上传身份证图片失败:', err); uni.showToast({ title: err.message || err.msg || '上传失败', icon: 'none' }); }
- }
- });
- },
- goToQualifications() {
- // 必填项校验
- if (!this.formData.name.trim()) {
- uni.showToast({ title: '请输入真实姓名', icon: 'none' });
- return;
- }
- if (!this.formData.idNumber.trim()) {
- uni.showToast({ title: '请输入证件号码', icon: 'none' });
- return;
- }
- // 简单的身份证格式校验建议(此处仅做非空,如果需要正则可以添加)
- if (this.formData.idNumber.length < 15) {
- uni.showToast({ title: '请输入正确的证件号码', icon: 'none' });
- return;
- }
- if (!this.formData.expiryDate) {
- uni.showToast({ title: '请选择有效日期', icon: 'none' });
- return;
- }
- if (!this.idCardFrontOssId) {
- uni.showToast({ title: '请上传身份证照片面', icon: 'none' });
- return;
- }
- if (!this.idCardBackOssId) {
- uni.showToast({ title: '请上传身份证国徽面', icon: 'none' });
- return;
- }
- this.saveAuthData();
- try {
- const stored = uni.getStorageSync('recruit_form_data');
- if (stored) {
- const data = JSON.parse(stored);
- data.realName = this.formData.name; data.idNumber = this.formData.idNumber;
- data.expiryDate = this.formData.expiryDate;
- data.idCardFrontOssId = this.idCardFrontOssId; data.idCardBackOssId = this.idCardBackOssId;
- uni.setStorageSync('recruit_form_data', JSON.stringify(data));
- }
- } catch (e) { console.error('保存认证数据失败', e); }
- const services = JSON.stringify(this.serviceType);
- uni.navigateTo({ url: `/pages/recruit/qualifications/index?services=${encodeURIComponent(services)}` });
- }
- }
- }
- </script>
- <style>
- page {
- background-color: #F8F8F8;
- font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Helvetica, Segoe UI, Arial, Roboto, 'PingFang SC', 'miui', 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif;
- }
- .auth-container {
- padding: 20rpx;
- padding-bottom: 200rpx;
- }
- .top-tip {
- font-size: 24rpx;
- color: #666;
- margin-bottom: 20rpx;
- padding: 0 10rpx;
- }
- .form-card {
- background-color: #fff;
- border-radius: 20rpx;
- padding: 0 30rpx;
- margin-bottom: 20rpx;
- }
- .form-item {
- display: flex;
- align-items: center;
- height: 100rpx;
- border-bottom: none;
- }
- .label {
- width: 170rpx;
- font-size: 26rpx;
- font-weight: bold;
- color: #333;
- }
- .required {
- color: #FF5252;
- margin-right: 4rpx;
- font-weight: bold;
- }
- .input-area {
- flex: 1;
- font-size: 26rpx;
- color: #333;
- }
- .input-placeholder {
- color: #ccc;
- font-size: 26rpx;
- }
- .read-only-text {
- color: #333;
- font-size: 26rpx;
- }
- .card-label {
- font-size: 26rpx;
- color: #333;
- font-weight: bold;
- }
- .next-btn {
- background: linear-gradient(90deg, #FF6F00 0%, #FF5722 100%);
- color: #fff;
- font-size: 28rpx;
- font-weight: bold;
- height: 90rpx;
- line-height: 90rpx;
- border-radius: 45rpx;
- box-shadow: 0 10rpx 20rpx rgba(255, 87, 34, 0.2);
- }
- .gray-input-box {
- flex: 1;
- height: 70rpx;
- background-color: #F8F8F8;
- border-radius: 8rpx;
- display: flex;
- align-items: center;
- padding: 0 20rpx;
- }
- .arrow-right {
- width: 24rpx;
- height: 24rpx;
- margin-left: auto;
- }
- .upload-card {
- background-color: #fff;
- border-radius: 20rpx;
- padding: 40rpx 0;
- margin-bottom: 20rpx;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- }
- .upload-box {
- width: 600rpx;
- height: 360rpx;
- background-color: #F8F8F8;
- border: 2rpx dashed #eee;
- border-radius: 12rpx;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- margin-bottom: 20rpx;
- position: relative;
- overflow: hidden;
- }
- .camera-icon {
- width: 64rpx;
- height: 64rpx;
- margin-bottom: 15rpx;
- }
- .upload-text {
- font-size: 26rpx;
- color: #ccc;
- }
- .preview-img {
- width: 100%;
- height: 100%;
- }
- .footer-btn-area {
- margin-top: 60rpx;
- padding: 0 20rpx;
- }
- .picker-mask {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background-color: rgba(0, 0, 0, 0.5);
- z-index: 999;
- visibility: hidden;
- opacity: 0;
- transition: all 0.3s;
- }
- .picker-mask.show {
- visibility: visible;
- opacity: 1;
- }
- .picker-content {
- position: absolute;
- bottom: 0;
- left: 0;
- width: 100%;
- background-color: #fff;
- border-radius: 20rpx 20rpx 0 0;
- transform: translateY(100%);
- transition: all 0.3s;
- }
- .picker-mask.show .picker-content {
- transform: translateY(0);
- }
- .picker-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 30rpx;
- border-bottom: 1px solid #eee;
- font-size: 32rpx;
- }
- .picker-btn-cancel {
- color: #999;
- }
- .picker-title {
- font-weight: bold;
- color: #333;
- }
- .picker-btn-confirm {
- color: #FF5722;
- font-weight: bold;
- }
- .picker-view {
- width: 100%;
- height: 400rpx;
- }
- .picker-item {
- line-height: 50px;
- text-align: center;
- font-size: 32rpx;
- color: #333;
- }
- </style>
|