Files
property-resident-side/property-uniapp-project/pageSubPack/my/selectOwner.vue
zhouyanli ea1acf1bbc 修复bug
2026-08-27 18:01:35 +08:00

366 lines
7.1 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">
<view class="status-bar"></view>
<uni-nav-bar title="选择业主" left-icon="left" @clickLeft="goBack" backgroundColor="transparent" :border="false">
</uni-nav-bar>
<scroll-view class="page" scroll-y>
<!-- 搜索框 -->
<view class="search-box">
<input class="search-input" v-model="searchKey" placeholder="请输入业主名称"
placeholder-class="input-placeholder" @input="onSearch" />
<uni-icons type="search" size="20" color="#999" />
</view>
<view v-if="filteredList.length === 0" class="empty-state">
<uni-icons type="info" size="30" color="#ccc"></uni-icons>
<text class="empty-text">暂无数据</text>
</view>
<view class="owner-item" v-for="(item, index) in filteredList" :key="index" @click="handleItemClick(item, index)"
:class="{ checked: selectedIndex === index }">
<view class="owner-avatar">
<text class="avatar-text">{{ item.name ? item.name.charAt(0) : '业' }}</text>
</view>
<view class="owner-info">
<view class="owner-name">{{ item.name }}</view>
<view class="owner-phone" v-if="item.phone">{{ item.phone }}</view>
<view class="owner-house" v-if="item.houseName">{{ item.houseName }}</view>
</view>
<view class="check-icon" :class="{ checked: selectedIndex === index }"></view>
</view>
</scroll-view>
<view class="bottom-btn">
<button class="confirm-btn" @click="confirmBind">确定选择</button>
</view>
</view>
</template>
<script setup>
import {
ref,
onMounted,
computed
} from 'vue'
import {
onReachBottom,
onPullDownRefresh,
onLoad
} from '@dcloudio/uni-app'
import {
getOwnerList
} from '@/pageSubPack/api/apiSub.js'
const searchKey = ref('')
const selectedId = ref('')
const selectedName = ref('')
const selectedIndex = ref(-1)
const ownerList = ref([])
const presetOwnerId = ref('')
const loadingMore = ref(false)
const noMoreData = ref(false)
const pageNum = ref(1)
const pageSize = ref(10)
// 过滤后的列表
const filteredList = computed(() => {
if (!searchKey.value.trim()) {
return ownerList.value
}
return ownerList.value.filter(item =>
item.name && item.name.includes(searchKey.value.trim())
)
})
// 搜索输入事件
const onSearch = () => {
// 实时过滤computed 自动处理
}
// 获取列表数据
const getList = async () => {
if (loadingMore.value || noMoreData.value) return
loadingMore.value = true
try {
const res = await getOwnerList({
pageNum: pageNum.value,
pageSize: pageSize.value,
villageId: uni.getStorageSync('communityId')
})
const newList = res.rows || []
if (pageNum.value === 1) {
ownerList.value = newList
// 预设选中已有业主
preselectOwner()
} else {
ownerList.value = [...ownerList.value, ...newList]
}
if (newList.length < pageSize.value) {
noMoreData.value = true
} else {
pageNum.value++
}
} catch (err) {
uni.showToast({
title: err.msg || '加载失败',
icon: 'none'
})
console.error('业主列表接口报错:', err)
} finally {
loadingMore.value = false
uni.stopPullDownRefresh()
}
}
// 根据传入的 ownerId 预设选中
const preselectOwner = () => {
if (!presetOwnerId.value) return
const idx = ownerList.value.findIndex(item => String(item.id) === String(presetOwnerId.value))
if (idx !== -1) {
selectedIndex.value = idx
selectedId.value = ownerList.value[idx].id
selectedName.value = ownerList.value[idx].name
}
}
// 上拉加载更多
onReachBottom(() => {
getList()
})
// 下拉刷新
const refresh = () => {
pageNum.value = 1
noMoreData.value = false
ownerList.value = []
loadingMore.value = false
getList()
}
onPullDownRefresh(() => {
refresh()
})
// 页面加载时请求第一页
onLoad((option) => {
presetOwnerId.value = option.ownerId || ""
})
onMounted(() => {
getList()
})
const handleItemClick = (item, index) => {
selectedIndex.value = index
selectedId.value = item.id
selectedName.value = item.name
}
const confirmBind = () => {
if (selectedIndex.value === -1) {
return uni.showToast({
title: "请先选择业主",
icon: "none"
})
}
uni.showModal({
title: "确认选择",
content: `确定选择业主 ${selectedName.value} 吗?`,
success: (res) => {
if (res.confirm) {
uni.setStorageSync('ownerId', selectedId.value)
uni.setStorageSync('ownerName', selectedName.value)
uni.showToast({
title: '选择成功',
icon: 'success'
})
setTimeout(() => {
goBack()
}, 500)
}
}
})
}
const goBack = () => {
uni.navigateBack()
}
</script>
<style lang="scss">
page {
background: #f9f9f9;
overflow: hidden;
}
</style>
<style scoped>
.status-bar {
width: 100vw;
height: 46px;
}
.contentStyle {
display: flex;
flex-direction: column;
height: 100vh;
}
.page {
flex: 1;
overflow-y: auto;
padding: 0px 40rpx;
box-sizing: border-box;
}
/* 搜索框 */
.search-box {
display: flex;
align-items: center;
background-color: #F3F3F3;
border-radius: 20rpx;
margin: 20rpx 0px 20rpx 0px;
padding: 0 30rpx;
height: 70rpx;
}
.search-input {
flex: 1;
height: 100%;
font-size: 30rpx;
border: none;
background: transparent;
}
.input-placeholder {
color: #999;
font-size: 30rpx;
}
/* 空状态 */
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 100rpx 0;
color: #ccc;
}
.empty-text {
font-size: 32rpx;
color: #999;
margin-top: 20rpx;
margin-bottom: 10rpx;
}
/* 业主列表项 */
.owner-item {
display: flex;
align-items: center;
padding: 24rpx 20rpx;
margin-bottom: 20rpx;
border: 1rpx solid #e6e9ff;
border-radius: 16rpx;
background-color: #fff;
position: relative;
}
.owner-item.checked {
background: #f4f7ff;
border-color: #1677ff;
}
.owner-avatar {
width: 88rpx;
height: 88rpx;
border-radius: 50%;
background-color: #e8f0fe;
margin-right: 24rpx;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
}
.avatar-text {
font-size: 36rpx;
color: #1677ff;
font-weight: bold;
}
.owner-info {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
}
.owner-name {
font-size: 32rpx;
font-weight: bold;
color: #000;
line-height: 1.4;
margin-bottom: 6rpx;
}
.owner-phone {
font-size: 26rpx;
color: #666;
line-height: 1.4;
}
.owner-house {
font-size: 26rpx;
color: #999;
line-height: 1.4;
}
/* 选中对勾 */
.check-icon {
width: 44rpx;
height: 44rpx;
border-radius: 50%;
border: 2rpx solid #ccc;
flex-shrink: 0;
position: relative;
}
.check-icon::after {
content: "✓";
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: #fff;
font-size: 26rpx;
font-weight: bold;
}
.check-icon.checked {
background-color: #1677ff;
border-color: #1677ff;
}
/* 底部按钮 */
.bottom-btn {
padding: 20rpx 30rpx 40rpx;
}
.confirm-btn {
width: 100%;
height: 88rpx;
background-color: #1677ff;
color: #fff;
border-radius: 12rpx;
font-size: 34rpx;
border: none;
line-height: 88rpx;
}
</style>