2026-04-22 20:57:53 +08:00
|
|
|
|
<!-- 业主认证表单页 -->
|
|
|
|
|
|
<template>
|
|
|
|
|
|
<s-layout title="业主认证">
|
|
|
|
|
|
<view class="auth-page">
|
|
|
|
|
|
<scroll-view scroll-y class="form-scroll">
|
|
|
|
|
|
<!-- 小区名称 -->
|
|
|
|
|
|
<view class="form-item">
|
|
|
|
|
|
<text class="form-label">小区名称</text>
|
2026-04-23 23:51:52 +08:00
|
|
|
|
<view class="form-value" @tap="showCommunityPicker">
|
|
|
|
|
|
<text class="value-text">{{ state.form.communityName || '请选择小区' }}</text>
|
2026-04-22 20:57:53 +08:00
|
|
|
|
<image class="arrow-icon" src="/static/img/right-icon-black.png" mode="aspectFit" />
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 序号:楼号/单元/号 -->
|
2026-04-23 23:51:52 +08:00
|
|
|
|
<view class="form-item form-row" @tap="showHousePicker">
|
2026-04-22 20:57:53 +08:00
|
|
|
|
<text class="form-label">序号</text>
|
|
|
|
|
|
<view class="row-inputs">
|
|
|
|
|
|
<view class="col-item">
|
2026-04-23 23:51:52 +08:00
|
|
|
|
<input class="col-input" v-model="state.form.buildingNo" placeholder="请选择" disabled />
|
2026-04-22 20:57:53 +08:00
|
|
|
|
<text class="col-label">号楼</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="col-item">
|
2026-04-23 23:51:52 +08:00
|
|
|
|
<input class="col-input" v-model="state.form.unitNo" placeholder="请选择" disabled />
|
2026-04-22 20:57:53 +08:00
|
|
|
|
<text class="col-label">单元</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="col-item">
|
2026-04-23 23:51:52 +08:00
|
|
|
|
<input class="col-input" v-model="state.form.roomNo" placeholder="请选择" disabled />
|
2026-04-22 20:57:53 +08:00
|
|
|
|
<text class="col-label">号</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 是否产权人 -->
|
|
|
|
|
|
<view class="form-item">
|
|
|
|
|
|
<text class="form-label">是否产权人</text>
|
|
|
|
|
|
<view class="checkbox-group">
|
|
|
|
|
|
<label class="checkbox-item" @tap="state.form.isOwner = true">
|
|
|
|
|
|
<view :class="['checkbox-box', { active: state.form.isOwner }]">
|
|
|
|
|
|
<text v-if="state.form.isOwner" class="check-mark">✓</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<text class="checkbox-text">是</text>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<label class="checkbox-item" @tap="state.form.isOwner = false">
|
|
|
|
|
|
<view :class="['checkbox-box', { active: !state.form.isOwner && state.form.isOwner !== null }]">
|
|
|
|
|
|
<text v-if="!state.form.isOwner && state.form.isOwner !== null" class="check-mark">✓</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<text class="checkbox-text">否</text>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 与产权人关系 -->
|
|
|
|
|
|
<view class="form-item">
|
|
|
|
|
|
<text class="form-label">与产权人关系</text>
|
|
|
|
|
|
<view class="form-value" @tap="showRelationPicker">
|
2026-04-23 23:51:52 +08:00
|
|
|
|
<text class="value-text placeholder-color">{{ state.form.relationType || '请输入' }}</text>
|
2026-04-22 20:57:53 +08:00
|
|
|
|
<image class="arrow-icon" src="/static/img/right-icon-black.png" mode="aspectFit" />
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 姓名 -->
|
|
|
|
|
|
<view class="form-item">
|
|
|
|
|
|
<text class="form-label">姓名</text>
|
|
|
|
|
|
<view class="form-value">
|
|
|
|
|
|
<input
|
|
|
|
|
|
v-model="state.form.name"
|
|
|
|
|
|
class="form-input"
|
|
|
|
|
|
placeholder="请输入姓名"
|
|
|
|
|
|
placeholder-class="placeholder"
|
|
|
|
|
|
placeholder-style="color: #333333"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<image class="arrow-icon" src="/static/img/right-icon-black.png" mode="aspectFit" />
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 手机号 -->
|
|
|
|
|
|
<view class="form-item">
|
|
|
|
|
|
<text class="form-label">手机号</text>
|
|
|
|
|
|
<view class="form-value">
|
|
|
|
|
|
<input
|
2026-04-23 23:51:52 +08:00
|
|
|
|
v-model="state.form.mobile"
|
2026-04-22 20:57:53 +08:00
|
|
|
|
class="form-input"
|
|
|
|
|
|
type="number"
|
|
|
|
|
|
maxlength="11"
|
|
|
|
|
|
placeholder="请输入手机号"
|
|
|
|
|
|
placeholder-class="placeholder"
|
|
|
|
|
|
placeholder-style="color: #333333"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<image class="arrow-icon" src="/static/img/right-icon-black.png" mode="aspectFit" />
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 证件类型 -->
|
|
|
|
|
|
<view class="form-item">
|
|
|
|
|
|
<text class="form-label">证件类型</text>
|
|
|
|
|
|
<view class="form-value" @tap="showIdTypePicker">
|
|
|
|
|
|
<text class="value-text placeholder-color">{{ state.form.idType || '请选择证件类型' }}</text>
|
|
|
|
|
|
<image class="arrow-icon" src="/static/img/right-icon-black.png" mode="aspectFit" />
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 证件号 -->
|
|
|
|
|
|
<view class="form-item">
|
|
|
|
|
|
<text class="form-label">证件号</text>
|
|
|
|
|
|
<view class="form-value">
|
|
|
|
|
|
<input
|
|
|
|
|
|
v-model="state.form.idNumber"
|
|
|
|
|
|
class="form-input"
|
|
|
|
|
|
placeholder="请输入证件号"
|
|
|
|
|
|
placeholder-class="placeholder"
|
|
|
|
|
|
placeholder-style="color: #333333"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<image class="arrow-icon" src="/static/img/right-icon-black.png" mode="aspectFit" />
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 性别 -->
|
|
|
|
|
|
<view class="form-item">
|
|
|
|
|
|
<text class="form-label">性别</text>
|
|
|
|
|
|
<view class="form-value" @tap="showGenderPicker">
|
2026-04-23 23:51:52 +08:00
|
|
|
|
<text class="value-text placeholder-color">{{ state.form.sex === 1 ? '男' : state.form.sex === 2 ? '女' : '请选择' }}</text>
|
2026-04-22 20:57:53 +08:00
|
|
|
|
<image class="arrow-icon" src="/static/img/right-icon-black.png" mode="aspectFit" />
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 出生日期 -->
|
|
|
|
|
|
<view class="form-item">
|
|
|
|
|
|
<text class="form-label">出生日期</text>
|
|
|
|
|
|
<view class="form-value" @click="triggerDatePicker">
|
|
|
|
|
|
<uni-datetime-picker
|
|
|
|
|
|
ref="datePickerRef"
|
|
|
|
|
|
v-model="state.form.birthday"
|
|
|
|
|
|
type="date"
|
|
|
|
|
|
:border="false"
|
|
|
|
|
|
@change="onDateChange"
|
|
|
|
|
|
class="form-date"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<image class="arrow-icon" src="/static/img/right-icon-black.png" mode="aspectFit" />
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 上传附件 -->
|
|
|
|
|
|
<view class="form-section-title">
|
|
|
|
|
|
<text>上传附件</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="upload-area">
|
2026-04-23 23:51:52 +08:00
|
|
|
|
<view v-if="state.attachmentUrl" class="upload-preview" @tap="handleUploadAttachment">
|
|
|
|
|
|
<image class="preview-img" :src="state.attachmentUrl" mode="aspectFill" />
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view v-else class="upload-btn" @tap="handleUploadAttachment">
|
2026-04-22 20:57:53 +08:00
|
|
|
|
<view class="upload-icon-wrapper">
|
|
|
|
|
|
<text class="upload-folder-icon">📁</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<text class="upload-text">选择文件</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
2026-04-23 23:51:52 +08:00
|
|
|
|
|
|
|
|
|
|
<!-- 上传人脸照片 -->
|
|
|
|
|
|
<view class="form-section-title">
|
|
|
|
|
|
<text>上传人脸照片</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="upload-area">
|
|
|
|
|
|
<view v-if="state.facePhotoUrl" class="upload-preview" @tap="handleUploadFace">
|
|
|
|
|
|
<image class="preview-img" :src="state.facePhotoUrl" mode="aspectFill" />
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view v-else class="upload-btn" @tap="handleUploadFace">
|
|
|
|
|
|
<view class="upload-icon-wrapper">
|
|
|
|
|
|
<text class="upload-folder-icon">📁</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<text class="upload-text">选择照片</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
2026-04-22 20:57:53 +08:00
|
|
|
|
</scroll-view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 底部按钮 -->
|
|
|
|
|
|
<view class="bottom-btn-wrapper">
|
|
|
|
|
|
<button class="submit-btn" @tap="handleSubmit">下一步</button>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</s-layout>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup>
|
2026-04-23 23:51:52 +08:00
|
|
|
|
import { reactive, ref, computed } from 'vue';
|
|
|
|
|
|
import { onLoad } from '@dcloudio/uni-app';
|
|
|
|
|
|
import MemberHouseApi from '@/sheep/api/community/memberHouse';
|
|
|
|
|
|
import CommunityApi from '@/sheep/api/community/community';
|
|
|
|
|
|
import FileApi from '@/sheep/api/infra/file';
|
|
|
|
|
|
import { tenantId } from '@/sheep/config';
|
|
|
|
|
|
import sheep from '@/sheep';
|
|
|
|
|
|
|
|
|
|
|
|
// 用户信息
|
|
|
|
|
|
const userStore = sheep.$store('user');
|
|
|
|
|
|
const userInfo = computed(() => userStore.userInfo || {});
|
2026-04-22 20:57:53 +08:00
|
|
|
|
|
|
|
|
|
|
// 表单数据
|
|
|
|
|
|
const state = reactive({
|
|
|
|
|
|
form: {
|
2026-04-23 23:51:52 +08:00
|
|
|
|
communityId: null, // 选中的小区ID
|
|
|
|
|
|
communityName: '',
|
|
|
|
|
|
houseId: null, // 选中的房屋ID
|
|
|
|
|
|
buildingNo: '',
|
|
|
|
|
|
unitNo: '',
|
|
|
|
|
|
roomNo: '',
|
2026-04-22 20:57:53 +08:00
|
|
|
|
isOwner: true,
|
2026-04-23 23:51:52 +08:00
|
|
|
|
relationType: '',
|
2026-04-22 20:57:53 +08:00
|
|
|
|
name: '',
|
2026-04-23 23:51:52 +08:00
|
|
|
|
mobile: '',
|
2026-04-22 20:57:53 +08:00
|
|
|
|
idType: '',
|
|
|
|
|
|
idNumber: '',
|
2026-04-23 23:51:52 +08:00
|
|
|
|
sex: '',
|
2026-04-22 20:57:53 +08:00
|
|
|
|
birthday: ''
|
2026-04-23 23:51:52 +08:00
|
|
|
|
},
|
|
|
|
|
|
communityList: [], // 小区列表
|
|
|
|
|
|
houseTree: [], // 房屋树(楼号->单元->房号)
|
|
|
|
|
|
attachmentUrl: '', // 附件URL
|
|
|
|
|
|
facePhotoUrl: '', // 人脸照片URL
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
onLoad(async () => {
|
|
|
|
|
|
// 获取小区列表
|
|
|
|
|
|
const { code, data } = await CommunityApi.getSimpleList();
|
|
|
|
|
|
if (code === 0 && data && data.length > 0) {
|
|
|
|
|
|
state.communityList = data;
|
|
|
|
|
|
// 优先匹配 SHOPRO_TENANT_ID 配置的小区,没有则选第一个
|
|
|
|
|
|
const target = data.find((item) => String(item.id) === String(tenantId)) || data[0];
|
|
|
|
|
|
state.form.communityId = target.id;
|
|
|
|
|
|
state.form.communityName = target.communityName;
|
|
|
|
|
|
// 加载该小区的房屋树
|
|
|
|
|
|
await loadHouseTree(target.id);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 兜底:使用当前用户信息里的小区
|
|
|
|
|
|
state.form.communityName = userInfo.value.currentCommunityName || '请选择小区';
|
2026-04-22 20:57:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2026-04-23 23:51:52 +08:00
|
|
|
|
// 加载房屋树
|
|
|
|
|
|
const loadHouseTree = async (communityId) => {
|
|
|
|
|
|
if (!communityId) return;
|
|
|
|
|
|
const { code, data } = await CommunityApi.getHouseTree(communityId);
|
|
|
|
|
|
if (code === 0) {
|
|
|
|
|
|
state.houseTree = data || [];
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 显示小区选择器
|
|
|
|
|
|
const showCommunityPicker = () => {
|
|
|
|
|
|
if (!state.communityList.length) return;
|
|
|
|
|
|
const itemList = state.communityList.map((item) => item.communityName);
|
|
|
|
|
|
uni.showActionSheet({
|
|
|
|
|
|
itemList,
|
|
|
|
|
|
success: async (res) => {
|
|
|
|
|
|
const selected = state.communityList[res.tapIndex];
|
|
|
|
|
|
state.form.communityId = selected.id;
|
|
|
|
|
|
state.form.communityName = selected.communityName;
|
|
|
|
|
|
// 切换小区后加载对应房屋树
|
|
|
|
|
|
await loadHouseTree(selected.id);
|
|
|
|
|
|
// 清空已选房屋
|
|
|
|
|
|
state.form.houseId = null;
|
|
|
|
|
|
state.form.buildingNo = '';
|
|
|
|
|
|
state.form.unitNo = '';
|
|
|
|
|
|
state.form.roomNo = '';
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 级联选择房屋(楼号 -> 单元 -> 房号)
|
|
|
|
|
|
const showHousePicker = () => {
|
|
|
|
|
|
if (!state.houseTree.length) {
|
|
|
|
|
|
uni.showToast({ title: '该小区暂无房屋数据', icon: 'none' });
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 第一级:选择楼号
|
|
|
|
|
|
const buildings = state.houseTree;
|
|
|
|
|
|
const buildingLabels = buildings.map((item) => item.label);
|
|
|
|
|
|
uni.showActionSheet({
|
|
|
|
|
|
itemList: buildingLabels,
|
|
|
|
|
|
success: (buildingRes) => {
|
|
|
|
|
|
const building = buildings[buildingRes.tapIndex];
|
|
|
|
|
|
|
|
|
|
|
|
// 第二级:选择单元
|
|
|
|
|
|
const units = building.children || [];
|
|
|
|
|
|
if (!units.length) {
|
|
|
|
|
|
state.form.houseId = building.value;
|
|
|
|
|
|
state.form.buildingNo = building.label;
|
|
|
|
|
|
state.form.unitNo = '';
|
|
|
|
|
|
state.form.roomNo = '';
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
const unitLabels = units.map((item) => item.label);
|
|
|
|
|
|
uni.showActionSheet({
|
|
|
|
|
|
itemList: unitLabels,
|
|
|
|
|
|
success: (unitRes) => {
|
|
|
|
|
|
const unit = units[unitRes.tapIndex];
|
|
|
|
|
|
|
|
|
|
|
|
// 第三级:选择房号
|
|
|
|
|
|
const rooms = unit.children || [];
|
|
|
|
|
|
if (!rooms.length) {
|
|
|
|
|
|
state.form.houseId = unit.value;
|
|
|
|
|
|
state.form.buildingNo = building.label;
|
|
|
|
|
|
state.form.unitNo = unit.label;
|
|
|
|
|
|
state.form.roomNo = '';
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
const roomLabels = rooms.map((item) => item.label);
|
|
|
|
|
|
uni.showActionSheet({
|
|
|
|
|
|
itemList: roomLabels,
|
|
|
|
|
|
success: (roomRes) => {
|
|
|
|
|
|
const room = rooms[roomRes.tapIndex];
|
|
|
|
|
|
state.form.houseId = room.value;
|
|
|
|
|
|
state.form.buildingNo = building.label;
|
|
|
|
|
|
state.form.unitNo = unit.label;
|
|
|
|
|
|
state.form.roomNo = room.label;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-04-22 20:57:53 +08:00
|
|
|
|
// 显示关系选择器
|
|
|
|
|
|
const showRelationPicker = () => {
|
|
|
|
|
|
uni.showActionSheet({
|
|
|
|
|
|
itemList: ['本人', '配偶', '父母', '子女', '其他'],
|
|
|
|
|
|
success: (res) => {
|
|
|
|
|
|
const relations = ['本人', '配偶', '父母', '子女', '其他'];
|
2026-04-23 23:51:52 +08:00
|
|
|
|
state.form.relationType = relations[res.tapIndex];
|
2026-04-22 20:57:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 显示证件类型选择器
|
|
|
|
|
|
const showIdTypePicker = () => {
|
|
|
|
|
|
uni.showActionSheet({
|
|
|
|
|
|
itemList: ['身份证', '护照', '军官证', '港澳通行证'],
|
|
|
|
|
|
success: (res) => {
|
|
|
|
|
|
const types = ['身份证', '护照', '军官证', '港澳通行证'];
|
|
|
|
|
|
state.form.idType = types[res.tapIndex];
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 显示性别选择器
|
|
|
|
|
|
const showGenderPicker = () => {
|
|
|
|
|
|
uni.showActionSheet({
|
|
|
|
|
|
itemList: ['男', '女'],
|
|
|
|
|
|
success: (res) => {
|
2026-04-23 23:51:52 +08:00
|
|
|
|
state.form.sex = res.tapIndex === 0 ? 1 : 2;
|
2026-04-22 20:57:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 日期选择回调
|
|
|
|
|
|
const onDateChange = (e) => {
|
|
|
|
|
|
console.log('选择的日期:', e);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 点击整行触发日期选择器
|
|
|
|
|
|
const datePickerRef = ref(null);
|
|
|
|
|
|
const triggerDatePicker = () => {
|
|
|
|
|
|
if (datePickerRef.value) {
|
|
|
|
|
|
const picker = datePickerRef.value.$children?.[0] || datePickerRef.value;
|
|
|
|
|
|
if (picker.show) {
|
|
|
|
|
|
picker.show();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-04-23 23:51:52 +08:00
|
|
|
|
// 上传图片通用方法
|
|
|
|
|
|
const uploadImage = (field) => {
|
|
|
|
|
|
uni.chooseImage({
|
2026-04-22 20:57:53 +08:00
|
|
|
|
count: 1,
|
2026-04-23 23:51:52 +08:00
|
|
|
|
sourceType: ['album', 'camera'],
|
|
|
|
|
|
success: async (res) => {
|
|
|
|
|
|
const filePath = res.tempFilePaths[0];
|
|
|
|
|
|
const result = await FileApi.uploadFile(filePath, 'member-house');
|
|
|
|
|
|
if (result && result.data) {
|
|
|
|
|
|
state[field] = result.data;
|
|
|
|
|
|
uni.showToast({ title: '上传成功', icon: 'success' });
|
|
|
|
|
|
} else {
|
|
|
|
|
|
uni.showToast({ title: '上传失败', icon: 'none' });
|
|
|
|
|
|
}
|
2026-04-22 20:57:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-04-23 23:51:52 +08:00
|
|
|
|
// 上传附件
|
|
|
|
|
|
const handleUploadAttachment = () => uploadImage('attachmentUrl');
|
|
|
|
|
|
// 上传人脸照片
|
|
|
|
|
|
const handleUploadFace = () => uploadImage('facePhotoUrl');
|
|
|
|
|
|
|
|
|
|
|
|
// 表单校验
|
|
|
|
|
|
const validateForm = () => {
|
|
|
|
|
|
const f = state.form;
|
|
|
|
|
|
if (!f.communityName) return '请选择小区';
|
|
|
|
|
|
if (!f.buildingNo) return '请输入楼号';
|
|
|
|
|
|
if (!f.unitNo) return '请输入单元号';
|
|
|
|
|
|
if (!f.roomNo) return '请输入门牌号';
|
|
|
|
|
|
if (f.isOwner === null) return '请选择是否产权人';
|
|
|
|
|
|
if (!f.isOwner && !f.relationType) return '请选择与产权人关系';
|
|
|
|
|
|
if (!f.name) return '请输入姓名';
|
|
|
|
|
|
if (!f.mobile) return '请输入手机号';
|
|
|
|
|
|
if (!/^1[3-9]\d{9}$/.test(f.mobile)) return '手机号格式不正确';
|
|
|
|
|
|
if (!f.idType) return '请选择证件类型';
|
|
|
|
|
|
if (!f.idNumber) return '请输入证件号';
|
|
|
|
|
|
if (!f.sex) return '请选择性别';
|
|
|
|
|
|
if (!f.birthday) return '请选择出生日期';
|
|
|
|
|
|
return '';
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-04-22 20:57:53 +08:00
|
|
|
|
// 提交表单
|
2026-04-23 23:51:52 +08:00
|
|
|
|
const handleSubmit = async () => {
|
|
|
|
|
|
const errMsg = validateForm();
|
|
|
|
|
|
if (errMsg) {
|
|
|
|
|
|
uni.showToast({ title: errMsg, icon: 'none' });
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const params = {
|
|
|
|
|
|
communityId: state.form.communityId || userInfo.value.currentCommunityId || '',
|
|
|
|
|
|
communityName: state.form.communityName,
|
|
|
|
|
|
houseId: state.form.houseId || null,
|
|
|
|
|
|
buildingNo: state.form.buildingNo,
|
|
|
|
|
|
unitNo: state.form.unitNo,
|
|
|
|
|
|
roomNo: state.form.roomNo,
|
|
|
|
|
|
isOwner: state.form.isOwner,
|
|
|
|
|
|
relationType: state.form.relationType,
|
|
|
|
|
|
name: state.form.name,
|
|
|
|
|
|
mobile: state.form.mobile,
|
|
|
|
|
|
idType: state.form.idType,
|
|
|
|
|
|
idNumber: state.form.idNumber,
|
|
|
|
|
|
sex: state.form.sex,
|
|
|
|
|
|
birthday: state.form.birthday,
|
|
|
|
|
|
attachmentUrl: state.attachmentUrl,
|
|
|
|
|
|
facePhotoUrl: state.facePhotoUrl,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const { code } = await MemberHouseApi.create(params);
|
|
|
|
|
|
if (code === 0) {
|
|
|
|
|
|
uni.redirectTo({ url: '/pages/index/auth-success' });
|
|
|
|
|
|
}
|
2026-04-22 20:57:53 +08:00
|
|
|
|
};
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
|
/* 页面容器 */
|
|
|
|
|
|
.auth-page {
|
|
|
|
|
|
background-color: #F5F5F5;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 表单滚动区域 */
|
|
|
|
|
|
.form-scroll {
|
|
|
|
|
|
height: calc(100vh - 176rpx - 250rpx);
|
|
|
|
|
|
padding-top: 20rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 表单项 - 上下结构 */
|
|
|
|
|
|
.form-item {
|
|
|
|
|
|
background-color: #FFFFFF;
|
|
|
|
|
|
padding: 24rpx 32rpx;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
border-bottom: 1rpx solid #F0F0F0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 标签文字 - 上方 */
|
|
|
|
|
|
.form-label {
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
color: #333333;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
margin-bottom: 16rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 值区域 - 下方 */
|
|
|
|
|
|
.form-value {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
|
|
|
|
.value-text {
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
|
|
|
|
|
|
// 已选中值:深色加粗
|
|
|
|
|
|
&:not(.placeholder-color) {
|
|
|
|
|
|
color: #222222;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.placeholder-color {
|
|
|
|
|
|
color: #666666;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.form-input {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
color: #666666;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.form-date{
|
|
|
|
|
|
width:100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.arrow-icon, .calendar-icon {
|
|
|
|
|
|
width: 24rpx;
|
|
|
|
|
|
height: 24rpx;
|
|
|
|
|
|
opacity: 0.4;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.calendar-icon {
|
|
|
|
|
|
opacity: 0.6;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 右侧箭头图标(日期字段用) */
|
|
|
|
|
|
.date-arrow-icon {
|
|
|
|
|
|
width: 24rpx;
|
|
|
|
|
|
height: 24rpx;
|
|
|
|
|
|
opacity: 0.4;
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
margin-left: 8rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 占位符样式 */
|
|
|
|
|
|
:deep(.placeholder) {
|
|
|
|
|
|
color: #666666 !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 日期选择器 - 融入表单整体风格 + 橙色主题 */
|
|
|
|
|
|
.form-value {
|
|
|
|
|
|
:deep(.uni-date-editor--x) {
|
|
|
|
|
|
padding: 0 !important;
|
|
|
|
|
|
border: none !important;
|
|
|
|
|
|
background: transparent !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
:deep(.uni-date-x) {
|
|
|
|
|
|
border: none !important;
|
|
|
|
|
|
justify-content: flex-start !important;
|
|
|
|
|
|
background: transparent !important;
|
|
|
|
|
|
padding: 0 !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
:deep(.uni-date__x-input) {
|
|
|
|
|
|
font-size: 28rpx !important;
|
|
|
|
|
|
color: #333333 !important;
|
|
|
|
|
|
padding-left: 0 !important;
|
|
|
|
|
|
background: transparent !important;
|
|
|
|
|
|
|
|
|
|
|
|
&::placeholder {
|
|
|
|
|
|
color: #CCCCCC !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 隐藏日历图标、清除图标 */
|
|
|
|
|
|
:deep(.uni-icons),
|
|
|
|
|
|
:deep(.uni-date__icon-clear) {
|
|
|
|
|
|
display: none !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 全局覆盖 datetime-picker 弹窗橙色主题 */
|
|
|
|
|
|
:deep(.uni-datetime-picker--btn) {
|
|
|
|
|
|
background-color: #FF6B35 !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 选中日期 - 蓝色圆圈 → 橙色 */
|
|
|
|
|
|
:deep(.uni-calendar-item--checked) {
|
|
|
|
|
|
background-color: #FF6B35 !important;
|
|
|
|
|
|
border-color: #fff !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 今天标记点 - 红色 → 橙色 */
|
|
|
|
|
|
:deep(.uni-calendar-item--isDay) {
|
|
|
|
|
|
background-color: #FF6B35 !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 范围选中的起止日期 */
|
|
|
|
|
|
:deep(.uni-calendar-item--before-checked),
|
|
|
|
|
|
:deep(.uni-calendar-item--after-checked) {
|
|
|
|
|
|
background-color: #FF6B35 !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 序号行 - 三列:文字和输入框同行 */
|
|
|
|
|
|
.form-row {
|
|
|
|
|
|
.row-inputs {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
|
|
|
|
.col-item {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
margin-right: 24rpx;
|
|
|
|
|
|
flex:1;
|
|
|
|
|
|
|
|
|
|
|
|
&:last-child {
|
|
|
|
|
|
margin-right: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.col-label {
|
|
|
|
|
|
font-size: 26rpx;
|
|
|
|
|
|
color: #666666;
|
|
|
|
|
|
margin-left: 8rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.col-input {
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
color: #333333;
|
|
|
|
|
|
width: 100rpx;
|
|
|
|
|
|
padding-bottom: 8rpx;
|
|
|
|
|
|
border-bottom: 1rpx solid #E5E5E5;
|
|
|
|
|
|
flex:1;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 单选 - checkbox方框样式 */
|
|
|
|
|
|
.checkbox-group {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 48rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.checkbox-item {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
margin-right:80rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.checkbox-box {
|
|
|
|
|
|
width: 36rpx;
|
|
|
|
|
|
height: 36rpx;
|
|
|
|
|
|
border-radius: 6rpx;
|
|
|
|
|
|
border: 2rpx solid #DDDDDD;
|
|
|
|
|
|
margin-right: 12rpx;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
transition: all 0.2s;
|
|
|
|
|
|
|
|
|
|
|
|
&.active {
|
|
|
|
|
|
background-color: #FF7B54;
|
|
|
|
|
|
border-color: #FF7B54;
|
|
|
|
|
|
|
|
|
|
|
|
.check-mark {
|
|
|
|
|
|
color: #FFFFFF;
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
line-height: 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.checkbox-text {
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
color: #666666;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 区块标题 */
|
|
|
|
|
|
.form-section-title {
|
|
|
|
|
|
padding: 32rpx 32rpx 20rpx;
|
|
|
|
|
|
|
|
|
|
|
|
text {
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
color: #333333;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 上传区域 */
|
|
|
|
|
|
.upload-area {
|
|
|
|
|
|
background-color: #FFFFFF;
|
|
|
|
|
|
padding: 32rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.upload-btn {
|
|
|
|
|
|
width: 180rpx;
|
|
|
|
|
|
height: 180rpx;
|
|
|
|
|
|
border: 2rpx dashed #DDDDDD;
|
|
|
|
|
|
border-radius: 16rpx;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
|
|
|
|
|
|
&:active {
|
|
|
|
|
|
border-color: #FF7B54;
|
|
|
|
|
|
background-color: rgba(255, 123, 84, 0.02);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.upload-icon-wrapper {
|
|
|
|
|
|
margin-bottom: 12rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.upload-folder-icon {
|
|
|
|
|
|
font-size: 56rpx;
|
|
|
|
|
|
opacity: 0.4;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.upload-text {
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
color: #999999;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-04-23 23:51:52 +08:00
|
|
|
|
|
|
|
|
|
|
.upload-preview {
|
|
|
|
|
|
width: 180rpx;
|
|
|
|
|
|
height: 180rpx;
|
|
|
|
|
|
border-radius: 16rpx;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
|
|
|
|
|
|
.preview-img {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-04-22 20:57:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 底部按钮 */
|
|
|
|
|
|
.bottom-btn-wrapper {
|
|
|
|
|
|
position: fixed;
|
|
|
|
|
|
left: 0;
|
|
|
|
|
|
right: 0;
|
|
|
|
|
|
bottom: 0;
|
|
|
|
|
|
padding: 24rpx 38rpx;
|
|
|
|
|
|
padding-bottom: calc(24rpx + env(safe-area-inset-bottom));
|
|
|
|
|
|
background-color: #F5F5F5;
|
|
|
|
|
|
|
|
|
|
|
|
.submit-btn {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 96rpx;
|
|
|
|
|
|
background: linear-gradient(135deg, #FF8A65 0%, #FF6B35 100%);
|
|
|
|
|
|
border-radius: 48rpx;
|
|
|
|
|
|
border: none;
|
|
|
|
|
|
font-size: 32rpx;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
color: #FFFFFF;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
box-shadow: 0 8rpx 24rpx rgba(255, 107, 53, 0.3);
|
|
|
|
|
|
|
|
|
|
|
|
&::after {
|
|
|
|
|
|
border: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&:active {
|
|
|
|
|
|
opacity: 0.9;
|
|
|
|
|
|
transform: scale(0.98);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|