Files
property-resident-side/property-uniapp-project/pageSubPack/my/addHouse.vue
2026-05-13 17:20:31 +08:00

1448 lines
32 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="contentStyle" style="">
<view class="status-bar"></view>
<uni-nav-bar :title="type+'房屋'" left-icon="left" @clickLeft="goBack" :border="false"
backgroundColor="transparent">
</uni-nav-bar>
<scroll-view class="page" scroll-y="true">
<!-- 步骤条 -->
<view class="step-bar">
<view class="step-item active">
<view class="step-circle">1</view>
<text class="step-text active">房屋信息</text>
</view>
<view class="step-line" :class="{ active: currentStep == 1}"></view>
<view class="step-item" :class="{ active: currentStep == 1}">
<view class="step-circle">2</view>
<text class="step-text" :class="{ active: currentStep == 1}">住户信息</text>
</view>
</view>
<!-- 表单区域 -->
<view class="form-container">
<!-- 第一步 -->
<view v-if="currentStep==0">
<!-- 小区选择 -->
<view class="form-item" @click="selectItem('小区')">
<text class="item-label">小区</text>
<text class="item-placeholder"
:class="{selected:formData.community}">{{ formData.community || '请选择' }}</text>
<text class="item-arrow"></text>
</view>
<!-- 楼栋选择 -->
<view class="form-item" @click="selectItem('楼栋')">
<text class="item-label">楼栋</text>
<text class="item-placeholder"
:class="{selected:formData.building}">{{ formData.building || '请选择' }}</text>
<text class="item-arrow"></text>
</view>
<!-- 单元选择 -->
<view class="form-item" @click="selectItem('单元')">
<text class="item-label">单元</text>
<text class="item-placeholder"
:class="{selected:formData.unit}">{{ formData.unit || '请选择' }}</text>
<text class="item-arrow"></text>
</view>
<!-- 楼层选择 -->
<view class="form-item" @click="selectItem('楼层')">
<text class="item-label">楼层</text>
<text class="item-placeholder"
:class="{selected:formData.floor}">{{ formData.floor || '请选择' }}</text>
<text class="item-arrow"></text>
</view>
<!-- 户号选择 -->
<view class="form-item" @click="selectItem('户号')">
<text class="item-label">户号</text>
<text class="item-placeholder"
:class="{selected:formData.houseNumber}">{{ formData.houseNumber || '请选择' }}</text>
<text class="item-arrow"></text>
</view>
<!-- 房屋状态选择 -->
<!-- <view class="form-item">
<text class="item-label">房屋状态</text>
<text class="item-placeholder">{{ formData.status || '请选择' }}</text>
<text class="item-arrow">\u003E</text>
</view> -->
<!-- 点击这里弹出下拉选择 -->
<view class="form-item" @click="showPopup = true">
<text class="label">房屋状态</text>
<text class="value"
:class="{selected:formData.status}">{{ formData.status.name || '请选择' }}</text>
<text class="item-arrow"></text>
</view>
<!-- 底部弹出下拉选择框全端可用 -->
<view v-if="showPopup" class="mask" @click="showPopup=false"></view>
<view v-if="showPopup" class="popup">
<view class="popup-header">
<text class="title">选择房屋状态</text>
<text class="close" @click="showPopup = false"></text>
</view>
<view class="list">
<view :class="{ active: formData.status.id == item.id }" class="item"
v-for="(item, index) in statusList" :key="upDataListNum" @click="selectClick(item)">
{{ item.name }}
</view>
</view>
</view>
<!-- 设为默认房屋开关 -->
<view class="form-item switch-item">
<text class="item-label" style="width: 100px;">设为默认房屋</text>
<switch class="no-cross-switch" :checked="formData.isDefault" color="#1677ff"
@change="onSwitchChange" />
</view>
</view>
<!-- 第二步 -->
<view v-if="currentStep==1">
<!-- 表单 -->
<scroll-view scroll-y class="form-box">
<view class="form-item">
<text class="label">住户名称</text>
<input class="input" v-model="form.name" placeholder="请输入真实姓名" placeholder-class="ph" />
</view>
<view class="form-item">
<text class="label">住户性别</text>
<view class="gender-group">
<view class="gender-item" :class="{ active: form.gender == '男' }"
@click="form.gender = '男'">
<view class="radio"></view>
<text></text>
</view>
<view class="gender-item" :class="{ active: form.gender == '女' }"
@click="form.gender = '女'">
<view class="radio"></view>
<text></text>
</view>
</view>
</view>
<view class="form-item arrow-item" @click="openCardType">
<text class="label">证件类型</text>
<text class="value"
:class="{selected:form.cardType}">{{ form.cardType.name || '请选择' }}</text>
</view>
<view class="form-item">
<text class="label">证件号码</text>
<input class="input" v-model="form.cardNo" placeholder="请输入证件号码" placeholder-class="ph" />
</view>
<view class="form-item arrow-item" @click="openRelation">
<text class="label">与业主关系</text>
<text class="value"
:class="{selected:form.relation}">{{ form.relation.name || '请选择' }}</text>
</view>
<view class="form-item phone-item">
<text class="label">手机号码</text>
<input class="input" v-model="form.phone" placeholder="请输入手机号" placeholder-class="ph"
type="tel" />
<button class="code-btn" :disabled="cd>0" @click="sendCode">
{{ cd > 0 ? cd+'s' : '获取验证码' }}
</button>
</view>
<view class="form-item">
<text class="label">验证码</text>
<input class="input" v-model="form.code" placeholder="请输入6位验证码" placeholder-class="ph"
type="number" />
</view>
<!-- 身份证上传 -->
<view class="upload-section">
<text class="upload-title">上传本人身份证照片</text>
<text class="upload-desc">请拍摄证件原件并使照片中证件边缘完整文字清晰光线均匀</text>
<view class="upload-wrap">
<!-- 身份证人像面 -->
<view class="upload-item" @click="chooseIdCard('front')">
<!-- 已上传 显示图片 -->
<image :src="idCardFrontUpload.state.previewUrl || frontSideOfIDcardSrc"
class="preview-img" mode="aspectFit">
</image>
</view>
<!-- 身份证国徽面 -->
<view class="upload-item" @click="chooseIdCard('back')">
<image :src="idCardBackUpload.state.previewUrl || backSideOfIDcardSrc" class="preview-img"
mode="aspectFit">
</image>
</view>
</view>
</view>
</scroll-view>
</view>
</view>
<!-- 证件类型弹窗 -->
<view v-if="showCardType" class="mask" @click="showCardType=false"></view>
<view v-if="showCardType" class="popup">
<view class="popup-header">
<text>选择证件类型</text>
<text class="close" @click="showCardType=false"></text>
</view>
<view class="popup-list">
<view :class="{ active: form.cardType.id == item.id }" class="item" v-for="item in cardTypes"
:key="item.id" @click="selectCard(item)">
{{item.name}}
</view>
</view>
</view>
<view v-if="showRelation" class="mask" @click="showRelation=false"></view>
<view v-if="showRelation" class="popup">
<view class="popup-header">
<text>选择与业主关系</text>
<text class="close" @click="showRelation=false"></text>
</view>
<view class="popup-list">
<view :class="{ active: form.relation.id == item.id }" class="item" v-for="item,index in relations"
:key="upDataListNum" @click="selectRelation(item)">
{{item.name}}
</view>
</view>
</view>
</scroll-view>
<!-- 底部下一步按钮 -->
<view class="bottom-btn-wrap">
<button class="next-btn" @click="goNext" v-if="currentStep==0">下一步</button>
<button class="next-btn" @click="goSubmit" v-if="currentStep==1">提交审核</button>
</view>
</view>
</template>
<!-- myHouseApply -->
<script setup>
import {
ref,
onMounted,
reactive
} from 'vue'
import {
onReachBottom,
onLoad,
onUnload,
onPullDownRefresh
} from '@dcloudio/uni-app'
import {
myHouseApply,
getHouseAuthSendSmsCode,
getMyHouseDetail,
upDateMyHouse,
} from '/pageSubPack/api/apiSub.js'
import {
useImageUpload
} from '/pageSubPack/api/useImageUpload.js'
const form = reactive({
name: '',
gender: '男',
cardType: {},
cardNo: '',
relation: {},
phone: '',
code: ''
})
const formData = reactive({
community: uni.getStorageSync('communityName'),
building: uni.getStorageSync('buildingName'),
unit: uni.getStorageSync('unitName'),
floor: uni.getStorageSync('floorName'),
houseNumber: uni.getStorageSync('houseNumberName'),
communityId: uni.getStorageSync('communityId'),
buildingId: uni.getStorageSync('buildingId'),
unitId: uni.getStorageSync('unitId'),
floorId: uni.getStorageSync('floorId'),
houseNumberId: uni.getStorageSync('houseNumberId'),
status: uni.getStorageSync('houseStatus'),
isDefault: uni.getStorageSync('houseIsDefault') == true ? true : false, // 开关默认开启
})
const statusList = ref([{
id: 0,
name: '自住'
},
{
id: 1,
name: '闲置'
},
{
id: 2,
name: '租赁'
},
{
id: 3,
name: '其他'
}
])
const cardTypes = ref([{
id: 0,
name: '居民身份证'
},
{
id: 1,
name: '护照'
},
{
id: 2,
name: '其他'
}
])
const relations = ref([{
id: 0,
name: '本人'
},
{
id: 1,
name: '配偶'
},
{
id: 2,
name: '父母'
},
{
id: 3,
name: '子女'
},
{
id: 4,
name: '亲属'
},
{
id: 5,
name: '租户'
},
{
id: 6,
name: '其他'
}
])
const upDataListNum = ref(0)
// const idCardFront = ref('')
// const idCardBack = ref('')
const frontSideOfIDcardSrc = ref('http://47.104.199.163:9090/images/propertyImgs/frontSideOfIDcard.png')
const backSideOfIDcardSrc = ref('http://47.104.199.163:9090/images/propertyImgs/backSideOfIDcard.png')
const houseId = ref(undefined)
const type = ref('')
const currentStep = ref(0)
const showPopup = ref(false)
const cd = ref(0)
const timer = ref(null)
const showCardType = ref(false)
const showRelation = ref(false)
// 身份证正面 - 使用 hook 管理上传
const idCardFrontUpload = useImageUpload({
uploadUrl: '/api/resident/file/uploadImage'
})
// 身份证反面 - 使用 hook 管理上传
const idCardBackUpload = useImageUpload({
uploadUrl: '/api/resident/file/uploadImage'
})
// ==================== 获取列表数据 ====================
const getDetail = async () => {
try {
const res = await getMyHouseDetail({
id: houseId.value
})
const data = res
console.log(data);
if (data.code === 200) {
uni.setStorageSync('communityName', data.data.villageName)
uni.setStorageSync('buildingName', data.data.buildingName)
uni.setStorageSync('unitName', data.data.unitNo)
uni.setStorageSync('floorName', data.data.floorNo)
uni.setStorageSync('houseNumberName', data.data.houseNo)
uni.setStorageSync('communityId', data.data.villageId)
uni.setStorageSync('buildingId', data.data.buildingId)
uni.setStorageSync('unitId', data.data.unitNo)
uni.setStorageSync('floorId', data.data.floorNo)
uni.setStorageSync('houseNumberId', data.data.houseId)
uni.setStorageSync('houseStatus', data.data.houseStatus)
uni.setStorageSync('houseIsDefault', data.data.isDefault)
formData.community = uni.getStorageSync('communityName')
formData.building = uni.getStorageSync('buildingName')
formData.unit = uni.getStorageSync('unitName')
formData.floor = uni.getStorageSync('floorName')
formData.houseNumber = uni.getStorageSync('houseNumberName')
formData.communityId = uni.getStorageSync('communityId')
formData.buildingId = uni.getStorageSync('buildingId')
formData.unitId = uni.getStorageSync('unitId')
formData.floorId = uni.getStorageSync('floorId')
formData.houseNumberId = uni.getStorageSync('houseNumberId')
formData.status = uni.getStorageSync('houseStatus')
formData.isDefault = uni.getStorageSync('houseIsDefault')
form.name = data.data.name
form.gender = data.data.gender == '0' ? '男' : data.data.gender == '1' ? '女' : ''
form.cardNo = data.data.idCard
// 房屋状态回显
let checkHouseStatus = {}
statusList.value.forEach(item => {
if (item.id == data.data.houseStatus) {
checkHouseStatus = {
id: data.data.houseStatus,
name: item.name
}
}
})
// 证件类型回显
let checkCardType = {}
cardTypes.value.forEach(item => {
if (item.id == data.data.idCardType) {
checkCardType = {
id: data.data.idCardType,
name: item.name
}
}
})
// 与户主关系回显
let checkRelation = {}
relations.value.forEach(item => {
if (item.id == data.data.ownerRelationship) {
checkRelation = {
id: data.data.ownerRelationship,
name: item.name
}
}
})
selectClick(checkHouseStatus)
selectCard(checkCardType)
selectRelation(checkRelation)
form.phone = data.data.phone
form.code = ''
// 使用 hook 设置回显图片
idCardFrontUpload.setPreviewUrl(data.data.cardImageFront?.url || data.data.cardImageFront || '')
idCardBackUpload.setPreviewUrl(data.data.cardImageBack?.url || data.data.cardImageBack || '')
} else {
uni.showToast({
title: `${res.msg}`,
icon: 'error'
});
}
} catch (err) {
uni.showToast({
title: `${err}`,
icon: 'none'
})
} finally {
}
}
onUnload(() => {
clearInterval(timer)
})
onLoad((option) => {
console.log(uni.getStorageSync('updateHouseId'));
if (option.id) {
if (uni.getStorageSync('operationType') == 'update') {
houseId.value = option.id;
uni.setStorageSync('updateHouseId', houseId.value)
type.value = '修改';
getDetail()
}
} else {
if (uni.getStorageSync('operationType') == 'update') {
houseId.value = uni.getStorageSync('updateHouseId')
} else
if (uni.getStorageSync('operationType') == 'add') {
houseId.value = undefined;
type.value = '添加';
}
}
})
const chooseIdCard = async (type) => {
try {
const tempPath = await (type === 'front' ? idCardFrontUpload.chooseImage() : idCardBackUpload
.chooseImage())
// 已经由 hook 自动处理了 previewUrl 和 tempFilePath
} catch (err) {
// 用户取消选择,不处理
}
}
const openCardType = () => {
showCardType.value = true
}
const openRelation = () => {
showRelation.value = true
}
const selectCard = (v) => {
form.cardType = v
showCardType.value = false
upDataListNum.value++
}
const selectRelation = (v) => {
form.relation = v
showRelation.value = false
upDataListNum.value++
}
const selectClick = (item) => {
formData.status = item;
uni.setStorageSync('houseStatus', item)
showPopup.value = false;
upDataListNum.value++
}
const sendCode = () => {
if (!/^1[3-9]\d{9}$/.test(form.phone)) {
return uni.showToast({
title: '手机号格式错误',
icon: 'none'
})
}
cd.value = 60
timer.value = setInterval(() => {
cd.value--
if (cd.value <= 0) clearInterval(timer)
}, 1000)
let params = {
phone: form.phone,
scene: "house_bind"
}
getHouseAuthSendSmsCode(params).then(res => {
if (res.code === 200) {
uni.showToast({
title: `发送成功!`,
icon: 'error'
});
} else {
uni.showToast({
title: `${res.msg}`,
icon: 'error'
});
}
}).catch(err => {
uni.showToast({
title: err.msg || '发送失败',
icon: 'none'
});
})
}
// 下一步
const goNext = () => {
console.log(typeof(uni.getStorageSync('communityId')));
// 基础校验
if (!formData.community) {
uni.showToast({
title: '请选择小区',
icon: 'none'
})
return
}
if (!formData.building) {
uni.showToast({
title: '请选择楼栋',
icon: 'none'
})
return
}
if (!formData.unit) {
uni.showToast({
title: '请选择单元',
icon: 'none'
})
return
}
if (!formData.floor) {
uni.showToast({
title: '请选择楼层',
icon: 'none'
})
return
}
if (!formData.houseNumber) {
uni.showToast({
title: '请选择户号',
icon: 'none'
})
return
}
if (!formData.status) {
uni.showToast({
title: '请选择房屋状态',
icon: 'none'
})
return
}
currentStep.value = 1
//跳转
}
// 完整校验
const goSubmit = async () => {
// 1. 前端校验
if (!form.name) return uni.showToast({
title: '请输入住户姓名',
icon: 'none'
})
if (!form.gender) return uni.showToast({
title: '请选择住户性别',
icon: 'none'
})
if (!form.cardType && form.cardType != 0) return uni.showToast({
title: '请选择证件类型',
icon: 'none'
})
if (!form.cardNo) return uni.showToast({
title: '请输入证件号',
icon: 'none'
})
if (!form.relation && form.relation != 0) return uni.showToast({
title: '请选择关系',
icon: 'none'
})
if (!/^1[3-9]\d{9}$/.test(form.phone)) return uni.showToast({
title: '手机号错误',
icon: 'none'
})
if (!form.code || form.code.length !== 6) return uni.showToast({
title: '请输入6位验证码',
icon: 'none'
})
if (!idCardFrontUpload.state.previewUrl) return uni.showToast({
title: '请上传身份证人像面',
icon: 'none'
})
if (!idCardBackUpload.state.previewUrl) return uni.showToast({
title: '请上传身份证国徽面',
icon: 'none'
})
// 2. 确认弹窗
const modalRes = await new Promise((resolve) => {
uni.showModal({
title: '确认提交',
content: '提交后进入审核',
success: resolve
})
})
if (!modalRes.confirm) return
// 3. 开始提交
uni.showLoading({
title: '提交中...',
mask: true
})
try {
// 4. 获取图片URL
let cardImageFrontUrl = ''
let cardImageBackUrl = ''
// 编辑模式
if (houseId.value) {
// 如果重新选择了图片,需要上传
if (idCardFrontUpload.state.tempFilePath) {
cardImageFrontUrl = await idCardFrontUpload.uploadImage()
} else {
const frontUrl = idCardFrontUpload.state.serverUrl || idCardFrontUpload.state.previewUrl
cardImageFrontUrl = typeof frontUrl === 'string' ? frontUrl : ''
}
if (idCardBackUpload.state.tempFilePath) {
cardImageBackUrl = await idCardBackUpload.uploadImage()
} else {
const backUrl = idCardBackUpload.state.serverUrl || idCardBackUpload.state.previewUrl
cardImageBackUrl = typeof backUrl === 'string' ? backUrl : ''
}
} else {
// 新增模式:必须上传
cardImageFrontUrl = await idCardFrontUpload.uploadImage()
cardImageBackUrl = await idCardBackUpload.uploadImage()
}
console.log(cardImageFrontUrl);
// 5. 组装公共参数
const params = {
villageId: uni.getStorageSync('communityId'),
buildingId: uni.getStorageSync('buildingId'),
unitNo: uni.getStorageSync('unitId'),
floorNo: uni.getStorageSync('floorId'),
houseNo: uni.getStorageSync('houseNumberName'),
houseId: uni.getStorageSync('houseNumberId'),
name: form.name,
gender: form.gender == '男' ? '0' : '1',
idCardType: form.cardType.id,
idCard: form.cardNo,
houseStatus: uni.getStorageSync('houseStatus').id,
ownerRelationship: form.relation.id,
phone: form.phone,
smsCode: form.code,
isDefault: uni.getStorageSync('houseIsDefault'),
cardImageFront: cardImageFrontUrl.url,
cardImageBack: cardImageBackUrl.url,
}
// 6. 判断是新增还是修改
if (houseId.value) {
// 修改
params.id = houseId.value
await upDateMyHouse(params)
} else {
// 新增
await myHouseApply(params)
}
// 7. 成功
uni.hideLoading()
uni.showToast({
title: '提交成功',
icon: 'success'
})
setTimeout(() => {
goBack()
}, 1500)
} catch (err) {
// 8. 统一错误处理
uni.hideLoading()
console.log('提交失败:', err)
uni.showToast({
title: err.msg || '提交失败',
icon: 'none',
duration: 2500
})
}
}
const updateMethod = async (params) => {
await upDateMyHouse(params).then(res => {
console.log('33333', res)
if (res.code === 200) {
uni.hideLoading();
uni.showToast({
title: '提交成功',
icon: 'success'
});
setTimeout(() => {
goBack()
}, 1500);
} else {
uni.showToast({
title: `${res.msg}`,
icon: 'error'
});
}
}).catch(err => {
console.log(err);
uni.showToast({
title: `${err}`,
icon: 'error'
});
})
}
// 选择项点击事件可替换为picker/弹窗选择)
const selectItem = (type) => {
console.log(type);
console.log(uni.getStorageSync('checkType'));
if (type === '小区') {
uni.redirectTo({
url: '/pageSubPack/my/selectResidentialCommunity?sourcePage=' + 'addHouse',
success: res => {},
fail: () => {},
complete: () => {}
});
} else if (type === '楼栋') {
if (!formData.community) {
uni.showToast({
title: '请先选择上级',
icon: 'none'
})
} else {
uni.setStorageSync('checkType', '楼栋');
uni.redirectTo({
url: '/pageSubPack/my/selectBuilding',
success: res => {},
fail: () => {},
complete: () => {}
});
}
} else if (type === '单元') {
if (!formData.community || !formData.building) {
uni.showToast({
title: '请先选择上级',
icon: 'none'
})
} else {
uni.setStorageSync('checkType', '单元');
uni.redirectTo({
url: '/pageSubPack/my/selectBuilding',
success: res => {},
fail: () => {},
complete: () => {}
});
}
} else if (type === '楼层') {
if (!formData.community || !formData.building || !formData.unit) {
uni.showToast({
title: '请先选择上级',
icon: 'none'
})
} else {
uni.setStorageSync('checkType', '楼层');
uni.redirectTo({
url: '/pageSubPack/my/selectBuilding',
success: res => {},
fail: () => {},
complete: () => {}
});
}
} else if (type === '户号') {
if (!formData.community || !formData.building || !formData.unit || !formData
.floor) {
uni.showToast({
title: '请先选择上级',
icon: 'none'
})
} else {
uni.setStorageSync('checkType', '户号');
uni.redirectTo({
url: '/pageSubPack/my/selectBuilding',
success: res => {},
fail: () => {},
complete: () => {}
});
}
}
}
// 开关切换
const onSwitchChange = (e) => {
formData.isDefault = e.detail.value
uni.setStorageSync('houseIsDefault', e.detail.value)
}
const goBack = () => {
uni.removeStorageSync('communityId');
uni.removeStorageSync('communityName');
uni.removeStorageSync('buildingId');
uni.removeStorageSync('buildingName');
uni.removeStorageSync('unitId');
uni.removeStorageSync('unitName');
uni.removeStorageSync('floorId');
uni.removeStorageSync('floorName');
uni.removeStorageSync('houseNumberId');
uni.removeStorageSync('houseNumberName');
uni.removeStorageSync('houseStatus')
uni.removeStorageSync('houseIsDefault')
uni.removeStorageSync('updateHouseId')
uni.redirectTo({
url: '/pageSubPack/my/myHouseIndex',
success: res => {},
fail: () => {},
complete: () => {}
});
}
</script>
<style lang="scss">
page {
background: #fff;
}
</style>
<style>
/* 全局样式去掉switch的×保证开关纯净 */
.my-switch::before {
display: none !important;
}
.my-switch {
background-color: #e5e5e5 !important;
border: none !important;
width: 90rpx !important;
height: 48rpx !important;
border-radius: 50rpx !important;
}
.my-switch[checked="true"] {
background-color: #1677ff !important;
}
.my-switch::after {
width: 44rpx !important;
height: 44rpx !important;
border-radius: 50% !important;
margin: 2rpx !important;
}
</style>
<style scoped>
.contentStyle {
display: flex;
flex-direction: column;
height: 100vh;
/* 关键:占满屏幕高度 */
background-color: #fff;
}
.page {
flex: 1;
overflow-y: auto;
padding: 0px 40rpx;
box-sizing: border-box;
}
/* 步骤条 */
.step-bar {
display: flex;
align-items: center;
justify-content: center;
padding: 40rpx 0px 20rpx;
}
.step-item {
display: flex;
flex-direction: column;
align-items: center;
}
.step-circle {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
background-color: #ccc;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
font-size: 28rpx;
margin-bottom: 16rpx;
}
.step-item.active .step-circle {
background-color: #1677ff;
}
.step-text {
font-size: 28rpx;
color: #999;
}
.step-item.active .step-text {
color: #1677ff;
font-weight: 500;
}
.step-line {
width: 150rpx;
height: 4rpx;
background-color: #ccc;
margin: 0 20rpx;
margin-bottom: 40rpx;
}
.step-line.active {
background-color: #1677ff;
}
/* 表单容器 */
.form-container {
/* padding: 0 30rpx; */
}
/* 表单项 */
.form-item {
display: flex;
align-items: center;
padding: 30rpx 0;
border-bottom: 1rpx solid #f0f0f0;
}
.item-label {
font-size: 28rpx;
color: #000;
width: 90px;
font-weight: 600;
}
.item-placeholder {
flex: 1;
font-size: 28rpx;
color: #999;
}
.item-placeholder.selected {
flex: 1;
font-size: 28rpx;
color: #333;
}
/* .item-arrow {
font-size: 40rpx;
color: #ccc;
margin-left: 20rpx;
} */
/* 开关项 */
.switch-item {
justify-content: space-between;
}
/* 底部按钮区 */
.bottom-btn-wrap {
padding: 20rpx 30rpx 40rpx;
display: flex;
gap: 20rpx;
/* background-color: #fff; */
}
.next-btn {
width: 100%;
height: 96rpx;
line-height: 96rpx;
background-color: #1677ff;
color: #fff;
font-size: 36rpx;
border-radius: 12rpx;
border: none;
}
</style>
<style>
/* 注意:这里不能加 scoped必须写全局样式 */
::v-deep .uni-switch-input:before {
background-color: #cccccd !important;
}
/* 隐藏 switch 关闭状态的 × 号 */
.no-cross-switch::before {
display: none !important;
}
.no-cross-switch {
transform: scale(0.85);
border-radius: 50rpx !important;
}
.no-cross-switch>>>.uni-switch-input-checked {
background-color: #007aff !important;
}
</style>
<style scoped>
.status-bar {
width: 100vw;
height: 46px;
}
/* 表单项 —— 和你页面保持一致 */
.form-item {
display: flex;
align-items: center;
padding: 30rpx 0;
border-bottom: 1rpx solid #f0f0f0;
}
.label {
font-size: 28rpx;
color: #000;
width: 90px;
font-weight: 600;
}
.value {
flex: 1;
text-align: left;
font-size: 28rpx;
color: #999;
margin-right: 10rpx;
}
.value.selected {
font-size: 28rpx;
color: #333;
}
.arrow {
font-size: 28rpx;
color: #ccc;
}
/* 遮罩 */
.mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 99;
}
/* 底部弹出框 */
.popup {
position: fixed;
left: 0;
right: 0;
bottom: 0;
background: #fff;
border-radius: 20rpx 20rpx 0 0;
z-index: 100;
max-height: 60vh;
}
.popup-header {
padding: 30rpx;
text-align: center;
border-bottom: 1rpx solid #f0f0f0;
position: relative;
}
.title {
font-size: 32rpx;
font-weight: 500;
}
.close {
position: absolute;
right: 30rpx;
top: 50%;
transform: translateY(-50%);
font-size: 36rpx;
color: #666;
}
/* 选项列表 */
.list {
padding: 0 30rpx;
}
.item {
padding: 30rpx 0;
text-align: center;
font-size: 28rpx;
border-bottom: 1rpx solid #f5f5f5;
}
.item:last-child {
border-bottom: none;
}
.item.active {
color: #337eff;
font-weight: 500;
background-color: #f8f9fa;
}
</style>
<style scoped>
/* 表单 */
.form-item {
display: flex;
align-items: center;
padding: 28rpx 0;
border-bottom: 1rpx solid #f2f2f2;
position: relative;
}
.label {
width: 180rpx;
font-size: 28rpx;
color: #333;
}
.input {
flex: 1;
font-size: 28rpx;
text-align: left;
color: #333;
}
.ph {
color: #999 !important;
}
.arrow-item::after {
content: '>';
position: absolute;
right: 0;
color: #ccc;
font-size: 28rpx;
}
.value {
flex: 1;
text-align: left;
font-size: 28rpx;
color: #999;
padding-right: 40rpx;
}
/* 性别 */
.gender-group {
flex: 1;
display: flex;
justify-content: flex-start;
gap: 40rpx;
}
.gender-item {
display: flex;
align-items: center;
gap: 12rpx;
font-size: 28rpx;
color: #666;
}
.gender-item.active {
color: #1677ff;
}
.radio {
width: 32rpx;
height: 32rpx;
border-radius: 50%;
border: 2rpx solid #ddd;
position: relative;
}
.gender-item.active .radio::after {
content: '';
width: 18rpx;
height: 18rpx;
background: #1677ff;
border-radius: 50%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
/* 手机验证码 */
.phone-item .input {
padding-right: 200rpx;
}
.code-btn {
position: absolute;
right: 0;
background: #2F77FD;
color: #fff;
font-size: 26rpx;
padding: 6rpx 30rpx;
border: none !important;
border-radius: 16rpx;
/* border-radius: 99px; */
}
.code-btn::after {
border: none !important;
display: none !important;
}
/* 自己加一层稳定的边框 */
.code-btn::before {
content: "";
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
border: 1px solid #ccc !important;
/* 边框颜色 */
border-radius: 16rpx;
box-sizing: border-box;
pointer-events: none;
}
/* 禁用状态 */
.code-btn[disabled] {
opacity: 1 !important;
background: #f5f5f5 !important;
color: #999 !important;
}
/* 上传区域 */
.upload-section {
margin-top: 30rpx;
}
.upload-title {
font-size: 28rpx;
font-weight: 500;
color: #333;
margin-bottom: 12rpx;
display: block;
font-weight: 600;
}
.upload-desc {
font-size: 24rpx;
color: #666666;
line-height: 1.5;
margin-bottom: 30rpx;
}
/* 两列布局 */
.upload-wrap {
margin-top: 30rpx;
display: flex;
flex-direction: column;
gap: 30rpx;
}
.upload-item {
/* flex: 1; */
height: 200px;
border-radius: 16rpx;
overflow: hidden;
background: #f3f3f3;
position: relative;
}
/* 上传按钮 */
.upload-box {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.plus {
font-size: 50rpx;
color: #ccc;
margin-bottom: 12rpx;
}
.txt {
font-size: 26rpx;
color: #999;
}
/* 预览图 */
.preview-img {
width: 100%;
height: 100%;
object-fit: cover;
}
/* 弹窗遮罩 */
.mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 99;
}
.popup {
position: fixed;
left: 0;
right: 0;
bottom: 0;
background: #fff;
border-radius: 20rpx 20rpx 0 0;
z-index: 100;
max-height: 60vh;
}
.popup-header {
padding: 30rpx;
text-align: center;
border-bottom: 1rpx solid #eee;
font-size: 32rpx;
font-weight: 500;
position: relative;
}
.close {
position: absolute;
right: 30rpx;
top: 50%;
transform: translateY(-50%);
font-size: 36rpx;
color: #666;
}
.popup-list {
padding: 0 30rpx;
max-height: 40vh;
overflow-y: auto;
}
.item {
padding: 30rpx 0;
text-align: center;
font-size: 28rpx;
border-bottom: 1rpx solid #f5f5f5;
}
.item.active {
color: #337eff;
font-weight: 600;
background-color: #f8f9fa;
}
.item-arrow {
display: inline-block;
width: 10rpx;
height: 10rpx;
border-top: 2rpx solid #999;
border-right: 2rpx solid #999;
transform: rotate(45deg);
margin-left: 10rpx;
margin-right: 10rpx;
}
</style>