staff/pagesB/call/index.vue

1184 lines
30 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>
<page-meta :page-style="`overflow:${showHouseDetail ? 'hidden' : 'visible'};`"></page-meta>
<view class="call-page">
<!-- 自定义导航栏 -->
<wd-navbar :bordered="false"
custom-style="background: transparent !important; backdrop-filter: blur(10px) !important; -webkit-backdrop-filter: blur(10px) !important;"
safeAreaInsetTop fixed placeholder>
<template #left>
<view class="li-ml-15 li-mt-10 li-flex li-items-center">
<text v-if="hasMultiplePages" class="ri-arrow-left-s-line li-text-70"
@click="toPages({type:'nav'})"></text>
<text v-if="!hasMultiplePages" class="ri-home-5-line li-text-55 li-mb-8 li-mr-10"
@click="toPages({type:'home'})"></text>
<text class="li-text-42">物业费催缴</text>
</view>
</template>
<!-- #ifdef MP-WEIXIN -->
<!-- <template #right>
<view class="li-mr-180 li-flex li-items-center">
<view class="community-switcher" @click="showCommunityPicker = true">
<text class="community-name">{{activeCommunity.name}}</text>
<text class="arrow-icon ri-arrow-down-s-line"></text>
</view>
</view>
</template> -->
<!-- #endif -->
<!-- #ifndef MP-WEIXIN -->
<!-- <template #right>
<view class="li-mr-25 li-flex li-items-center">
<view class="community-switcher" @click="showCommunityPicker = true">
<text class="community-name">{{activeCommunity.name}}</text>
<text class="arrow-icon ri-arrow-down-s-line"></text>
</view>
</view>
</template> -->
<!-- #endif -->
</wd-navbar>
<!-- 导航栏背景 -->
<view class="nav-bg-layer"></view>
<!-- 页面内容 -->
<view class="content">
<!-- 小区信息 -->
<view class="community-card li-mx-40 li-mt-40">
<view class="community-header li-p-30">
<view class="li-flex li-justify-between li-items-center">
<text
class="community-name li-text-42 li-font-bold li-text-white">{{activeCommunity.name}}</text>
<button class="refresh-btn" @tap.stop="handleRefreshClick">
<text class="li-text-24 li-text-white">刷新数据</text>
</button>
</view>
<view class="li-flex li-items-center li-mt-20">
<text class="li-text-28 li-text-white li-opacity-80">{{activeCommunity.address}}</text>
</view>
<view class="li-flex li-items-center li-mt-10">
<text class="li-text-28 li-text-white li-opacity-80">欠费总量:</text>
<text class="li-text-32 li-text-white li-font-bold">¥{{activeCommunity.totalUnpaid}}</text>
</view>
</view>
<view class="community-footer li-p-30 li-bg-white">
<view class="li-flex li-items-center">
<text class="ri-community-line li-text-28 li-text-#666 li-mr-10"></text>
<text class="li-text-28 li-text-#666">物业管理中心:</text>
<text class="li-text-28 li-text-#333">{{activeCommunity.managementAddress}}</text>
</view>
</view>
</view>
<view class="building-selector-container li-mt-30">
<view class="building-sidebar-layout">
<!-- 左侧楼栋侧边导航 -->
<view class="sidebar-container">
<wd-sidebar v-model="activeBuilding" custom-class="building-sidebar">
<wd-sidebar-item v-for="item in buildingList" :key="item.id" :value="String(item.id)"
:label="item.name" :badge="getBuildingUnpaidCount(item.id)"
:badge-props="{ type: 'primary', bgColor: '#ff4d4f' }" />
</wd-sidebar>
</view>
<!-- 右侧单元与房屋内容 -->
<view class="content-container">
<!-- 单元选择 -->
<view class="unit-selector li-px-30 li-py-20">
<view class="li-flex li-justify-between li-items-center li-mb-15">
<text class="li-text-30 li-font-bold">{{getActiveBuilding().name}}</text>
<text class="li-text-24 li-text-#3e9bff">单元数量: {{unitList.length}}</text>
</view>
<view class="unit-grid">
<view v-for="unit in unitList" :key="unit.value" class="unit-item li-mr-15 li-mb-15"
:class="activeUnitId === String(unit.value) ? 'unit-item-active' : ''"
@click="handleUnitSelect(unit.value)">
<text class="unit-text"
:class="activeUnitId === String(unit.value) ? 'unit-text-active' : ''">{{unit.label}}</text>
<view v-if="getUnitUnpaidCount(unit.value) > 0" class="unit-badge">
{{getUnitUnpaidCount(unit.value)}}
</view>
</view>
</view>
</view>
<!-- 楼层和房屋数据 -->
<view class="house-list li-px-30 li-pb-40">
<view v-for="(floor, floorIndex) in floorHouseList" :key="floorIndex"
class="floor-item li-mb-20">
<view class="floor-header">
<text class="floor-title">{{floor.floor}}层</text>
</view>
<view class="house-grid">
<view v-for="(house, houseIndex) in floor.houses" :key="houseIndex"
class="house-card" @click="showHouseDetailFunc(house)">
<view class="house-card-inner" :class="{'house-has-unpaid': house.unpaid > 0}">
<view class="house-number-box">
<text class="house-number">{{house.number}}</text>
</view>
<view class="house-content">
<view v-if="house.unpaid > 0" class="house-unpaid">
<text class="unpaid-count">{{house.unpaid}}</text>
<text class="unpaid-text">笔欠费</text>
</view>
<view v-else class="house-paid">
<text class="paid-text">无欠费</text>
</view>
</view>
<view v-if="house.unpaid > 0" class="house-badge">{{house.unpaid}}</view>
</view>
</view>
</view>
</view>
<!-- 空状态 -->
<view v-if="floorHouseList.length === 0"
class="empty-state li-py-100 li-flex-center li-flex-col">
<wd-status-tip :image="uni.$globalData?.RESOURCE_URL+'tip/search.png'" tip="该单元暂无数据" />
</view>
<!-- 添加底部安全间距 -->
<view class="bottom-safe-area"></view>
</view>
</view>
</view>
</view>
</view>
<!-- 房屋详情弹窗 -->
<wd-popup v-model="showHouseDetail" position="bottom" custom-class="custom-class-popup">
<view class="house-detail" :style="{ height: '60vh' }">
<view class="detail-header li-p-30 li-bottom-border">
<view class="li-flex li-justify-between li-items-center">
<text class="li-text-36 li-font-bold">{{selectedHouse.number}}</text>
<text class="ri-close-line li-text-50 li-text-#999" @click="showHouseDetail = false"></text>
</view>
<view class="li-flex li-items-center li-mt-10">
<text class="li-text-28 li-text-#666">{{activeCommunity.name}} {{getActiveBuilding().name}}
{{activeUnit}}</text>
</view>
</view>
<scroll-view scroll-y class="detail-content-scroll">
<view class="detail-content li-p-30">
<view v-if="selectedHouse.unpaid > 0">
<view class="li-flex li-justify-between li-items-center li-mb-20">
<text class="li-text-32 li-font-bold">欠费账单</text>
<text class="li-text-28 li-text-#3e9bff">共 {{selectedHouse.unpaid}} 笔</text>
</view>
<view v-for="(bill, index) in selectedHouse.bills" :key="index"
class="bill-item li-p-30 li-mb-20">
<view class="li-flex li-items-center li-justify-between">
<text class="li-text-30 li-font-bold">{{bill.type}}</text>
<text class="li-text-30 li-text-#ff4d4f">¥{{bill.amount}}</text>
</view>
<view class="li-flex li-items-center li-mt-15">
<text class="li-text-26 li-text-#999">创建时间:</text>
<text class="li-text-26 li-text-#666">{{bill.overdueTime}}</text>
</view>
<view class="li-flex li-items-center li-mt-10">
<text class="li-text-26 li-text-#999">缴费时间段:</text>
<text class="li-text-26 li-text-#666">{{bill.period}}</text>
</view>
<view class="li-flex li-justify-between li-items-center li-flex-row-reverse li-mt-20">
<wd-button size="small" type="primary"
@click="prepareCaller(selectedHouse)">电话催缴</wd-button>
<!-- <wd-button size="small" type="primary"
@click="sendReminder(selectedHouse)">发送通知</wd-button> -->
</view>
</view>
</view>
<view v-else class="empty-bills li-flex-center li-flex-col">
<text class="ri-check-double-line li-text-100 li-text-#52c41a"></text>
<text class="li-text-30 li-text-#666 li-mt-20">该住户暂无欠费</text>
</view>
</view>
</scroll-view>
</view>
</wd-popup>
<community-selector :communities="formattedCommunityList" v-model="selectedCommunity"
v-model:visible="showCommunityPicker" @confirm="handleCommunityConfirm" />
<!-- 电话催缴动作面板 -->
<wd-action-sheet v-model="showPhoneActionSheet" :actions="phoneActions" title="选择拨打业主电话" cancel-text="取消"
@select="handlePhoneSelect" :close-on-click-action="true" :close-on-click-modal="true"
custom-style="border-radius: 16px; max-height: 70vh;" />
</view>
</template>
<script setup>
import {
ref,
reactive,
computed,
onMounted,
watch
} from 'vue';
import {
onLoad
} from '@dcloudio/uni-app';
import {
useNavigation
} from '@/hooks/useNavigation';
import {
useToast
} from '@/uni_modules/wot-design-uni';
import CommunitySelector from '@/components/community-selector/community-selector.vue';
import {
feeInfo
} from '/api/fee'
const Toast = useToast();
// 使用导航composable
const {
hasMultiplePages,
isTabBarPage,
checkRouteStack
} = useNavigation();
// 小区信息
const village = ref({});
// 楼栋列表
const buildingList = ref([]);
// 当前选中的楼栋
const activeBuilding = ref('');
// 单元列表
const unitList = ref([]);
// 当前选中的单元 (使用字符串类型)
const activeUnitId = ref('');
// 兼容原有的数字类型单元ID
const activeUnit = computed(() => {
// 确保返回的是当前选中的单元名称,用于显示
if (!activeUnitId.value || !unitList.value.length) return '';
const unit = unitList.value.find(u => String(u.value) === String(activeUnitId.value));
return unit ? unit.label : '';
});
// 当前选中的小区数据
const activeCommunity = computed(() => {
return {
id: '1',
name: village.value.village_name || '暂无数据',
address: `${village.value.province_name || ''}-${village.value.city_name || ''}-${village.value.area_name || ''}`,
managementAddress: village.value.address || '暂无地址',
totalUnpaid: calculateTotalUnpaid()
};
});
// 计算总欠费数量
const calculateTotalUnpaid = () => {
let total = 0;
if (!village.value.regions) return total;
village.value.regions.forEach(region => {
region.cells.forEach(cell => {
cell.houses.forEach(house => {
// 计算房屋的欠费金额总和
if (house.estate && house.estate.length > 0) {
house.estate.forEach(item => {
// 将字符串金额转换为数字并累加
total += parseFloat(item.total_money || 0);
});
}
if (house.meter && house.meter.length > 0) {
house.meter.forEach(item => {
// 将字符串金额转换为数字并累加
total += parseFloat(item.total_money || 0);
});
}
});
});
});
// 格式化为两位小数
return total.toFixed(2);
};
// 房屋数据结构处理
const floorHouseList = computed(() => {
if (!activeBuilding.value || !activeUnitId.value) return [];
// 找到当前选中的楼栋和单元
const region = village.value.regions?.find(r => String(r.region_id) === activeBuilding.value);
if (!region) return [];
const cell = region.cells?.find(c => String(c.cell_id) === activeUnitId.value);
if (!cell) return [];
// 按楼层分组
const floorGroups = {};
cell.houses.forEach(house => {
const floor = house.floor;
if (!floorGroups[floor]) {
floorGroups[floor] = {
floor: `${floor}`,
houses: []
};
}
floorGroups[floor].houses.push({
id: String(house.house_id), // 使用字符串ID
number: house.house_name,
unpaid: (house.estate || []).length + (house.meter || []).length,
owner: house.owner && house.owner.length > 0 ? house.owner[0].owner_name : '未知',
phone: house.owner && house.owner.length > 0 ? house.owner[0].mobile : '',
bills: formatBills(house)
});
});
// 转换为数组并按楼层排序
return Object.values(floorGroups).sort((a, b) => parseInt(a.floor) - parseInt(b.floor));
});
// 格式化账单数据
const formatBills = (house) => {
const bills = [];
// 处理物业费账单
if (house.estate && house.estate.length > 0) {
house.estate.forEach(item => {
bills.push({
type: item.fee_name || '物业费',
amount: item.total_money,
period: `${item.begin_date} 至 ${item.end_date}`,
overdueTime: item.create_time
});
});
}
// 处理抄表账单
if (house.meter && house.meter.length > 0) {
house.meter.forEach(item => {
bills.push({
type: item.fee_name || '抄表费',
amount: item.total_money,
period: `${item.create_time}`,
overdueTime: item.create_time
});
});
}
return bills;
};
// 获取当前选中的楼栋对象
const getActiveBuilding = () => {
if (!activeBuilding.value || !village.value.regions) return {
id: '',
name: ''
};
const region = village.value.regions.find(r => String(r.region_id) === activeBuilding.value);
return region ? {
id: String(region.region_id),
name: region.region_name
} : {
id: '',
name: ''
};
};
// 获取楼栋的欠费住户数量
const getBuildingUnpaidCount = (buildingId) => {
if (!village.value.regions) return '';
const region = village.value.regions.find(r => String(r.region_id) === buildingId);
if (!region) return '';
let count = 0;
region.cells.forEach(cell => {
cell.houses.forEach(house => {
const unpaidCount = (house.estate || []).length + (house.meter || []).length;
if (unpaidCount > 0) count++;
});
});
return count > 0 ? count : '';
};
// 获取单元欠费数量
const getUnitUnpaidCount = (unitId) => {
if (!village.value.regions || !activeBuilding.value) return 0;
const region = village.value.regions.find(r => String(r.region_id) === activeBuilding.value);
if (!region) return 0;
const cell = region.cells.find(c => String(c.cell_id) === unitId);
if (!cell) return 0;
let count = 0;
cell.houses.forEach(house => {
const unpaidCount = (house.estate || []).length + (house.meter || []).length;
if (unpaidCount > 0) count++;
});
return count;
};
// 房屋详情弹窗
const showHouseDetail = ref(false);
const selectedHouse = ref({
id: '',
number: '',
unpaid: 0,
owner: [],
phone: '',
bills: []
});
// 电话催缴动作面板
const showPhoneActionSheet = ref(false);
const phoneActions = ref([]);
// 显示房屋详情
const showHouseDetailFunc = (house) => {
selectedHouse.value = house;
showHouseDetail.value = true;
};
// 准备并显示电话催缴动作面板
const prepareCaller = (house) => {
// 显示加载状态
uni.showLoading({
title: '获取联系人...',
mask: true
});
// 找到原始房屋数据
if (!activeBuilding.value || !activeUnitId.value) {
uni.hideLoading();
Toast.fail('无法获取房屋信息');
return;
}
const region = village.value.regions?.find(r => String(r.region_id) === activeBuilding.value);
if (!region) {
uni.hideLoading();
Toast.fail('未找到楼栋信息');
return;
}
const cell = region.cells?.find(c => String(c.cell_id) === activeUnitId.value);
if (!cell) {
uni.hideLoading();
Toast.fail('未找到单元信息');
return;
}
// 找到对应的房屋
const originalHouse = cell.houses.find(h => String(h.house_id) === String(house.id));
if (!originalHouse || !originalHouse.owner) {
uni.hideLoading();
Toast.fail('未找到该房屋业主信息');
return;
}
// 生成业主电话列表
if (originalHouse.owner.length === 0) {
uni.hideLoading();
Toast.fail('该房屋暂无业主联系方式');
return;
}
// 更新selectedHouse的owner字段
selectedHouse.value.owner = originalHouse.owner;
// 生成动作列表
phoneActions.value = originalHouse.owner.map(owner => ({
name: `${owner.owner_name || '未知'}${owner.sex === 0 ? '(先生)' : owner.sex === 1 ? '(女士)' : ''}`,
subname: owner.mobile || '无电话',
disabled: !owner.mobile,
color: !owner.mobile ? '#999999' : ''
}));
// 隐藏加载状态
setTimeout(() => {
uni.hideLoading();
// 显示动作面板
showPhoneActionSheet.value = true;
}, 300);
};
// 电话催缴 - 选择后执行
const handlePhoneSelect = (item, index) => {
const owner = item.item.subname;
if (!owner) {
Toast.error('无效的联系电话');
return;
}
uni.makePhoneCall({
phoneNumber: owner,
});
};
// 刷新按钮点击处理
let isRefreshing = false;
const handleRefreshClick = async () => {
getFeeInfo();
};
// 页面跳转
const toPages = (item) => {
switch (item.type) {
case 'nav':
uni.navigateBack({
delta: 1
});
break;
case 'home':
uni.switchTab({
url: '/pages/index/index'
});
break;
default:
break;
}
};
// 获取接口数据
const getFeeInfo = async () => {
try {
uni.showLoading({
title: '加载中...'
});
const res = await feeInfo();
console.log('API返回数据:', res);
if (res.code === 200 && res.data) {
// 设置小区信息
village.value = res.data.village || {};
console.log('小区信息:', village.value);
// 处理楼栋列表
if (village.value.regions && village.value.regions.length > 0) {
buildingList.value = village.value.regions.map(region => ({
id: String(region.region_id), // 确保ID是字符串类型
name: region.region_name
}));
console.log('楼栋列表:', buildingList.value);
// 默认选中第一个楼栋
if (buildingList.value.length > 0) {
// 直接设置为第一个楼栋的ID已确保是字符串类型
activeBuilding.value = buildingList.value[0].id;
console.log('默认选中楼栋:', activeBuilding.value);
// 立即更新单元列表
updateUnitList();
}
} else {
console.log('没有找到楼栋数据');
}
} else {
Toast.fail('获取数据失败');
console.error('API返回错误:', res);
}
} catch (error) {
console.error('获取数据出错:', error);
Toast.fail('网络异常,请重试');
} finally {
uni.hideLoading();
}
};
// 更新单元列表
const updateUnitList = () => {
unitList.value = [];
if (!activeBuilding.value || !village.value.regions) return;
const region = village.value.regions.find(r => String(r.region_id) === activeBuilding.value);
if (region && region.cells) {
unitList.value = region.cells.map(cell => ({
value: String(cell.cell_id), // 确保单元ID也是字符串类型
label: cell.cell_name
}));
// 默认选中第一个单元
if (unitList.value.length > 0) {
activeUnitId.value = unitList.value[0].value;
console.log('默认选中单元:', activeUnitId.value);
}
} else {
console.log('未找到对应楼栋或单元数据');
}
};
// 监听楼栋变化
watch(activeBuilding, () => {
updateUnitList();
});
// 初始化数据
const initData = async () => {
await getFeeInfo();
// 强制刷新视图
if (unitList.value.length > 0 && !activeUnitId.value) {
// 如果单元列表已加载但没有选中值,再次尝试设置
activeUnitId.value = unitList.value[0].value;
console.log('强制设置默认单元:', activeUnitId.value);
}
// 给视图一点时间渲染
setTimeout(() => {
console.log('当前状态 - 楼栋:', activeBuilding.value, '单元:', activeUnitId.value);
// 最终检查,确保楼栋和单元都有选中值
if (buildingList.value.length > 0 && !activeBuilding.value) {
console.log('检测到楼栋未选中,强制选中第一个楼栋');
activeBuilding.value = buildingList.value[0].id;
updateUnitList();
}
}, 500);
};
// 生命周期钩子
onLoad(() => {
checkRouteStack();
initData();
});
// 小区选择确认
const handleCommunityConfirm = (selected) => {
console.log(selected, 'selected');
// 此处逻辑可以根据实际需求修改
};
// 获取小区列表,扁平化处理
const formattedCommunityList = computed(() => {
// 原始数据是二维数组,需要提取第一层
const flatList = buildingList.value || [];
return flatList.map(item => ({
value: item.id,
label: item.name
}));
});
// 新增的showCommunityPicker
const showCommunityPicker = ref(false);
// 新增的handleUnitSelect
const handleUnitSelect = (value) => {
activeUnitId.value = String(value);
console.log('选中单元:', activeUnitId.value);
};
</script>
<style lang="scss">
page {
background-color: #F7F8FA;
}
.call-page {
min-height: 100vh;
}
.nav-bg-layer {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: calc(var(--status-bar-height) + 88rpx);
background: linear-gradient(180deg, rgba(255, 255, 255, 0.95) 0%, rgba(255, 255, 255, 0.9) 100%);
z-index: 10;
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
}
.content {
padding-bottom: 0;
}
.community-switch {
height: 60rpx;
padding: 0 25rpx;
border-radius: 30rpx;
background-color: rgba(62, 155, 255, 0.1);
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2rpx 8rpx rgba(62, 155, 255, 0.15);
transition: all 0.2s;
&:active {
opacity: 0.8;
transform: scale(0.98);
}
}
.community-switcher {
display: flex;
align-items: center;
background-color: rgba(246, 248, 250, 0.8);
height: 60rpx;
border-radius: 30rpx;
padding: 0 20rpx 0 24rpx;
box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.05);
border: 1px solid rgba(232, 234, 237, 0.8);
.community-name {
font-size: 26rpx;
color: #333;
font-weight: 500;
max-width: 140rpx;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.arrow-icon {
font-size: 28rpx;
color: #666;
margin-left: 6rpx;
}
&:active {
background-color: rgba(242, 244, 246, 0.8);
transform: scale(0.98);
}
}
.selector-trigger {
display: flex;
align-items: center;
height: 60rpx;
padding: 0 20rpx;
background-color: rgba(255, 255, 255, 0.9);
border-radius: 30rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.08);
.location-icon {
font-size: 28rpx;
color: #3e9bff;
margin-right: 6rpx;
}
.trigger-text {
font-size: 28rpx;
color: #3e9bff;
font-weight: 400;
}
&:active {
opacity: 0.85;
transform: scale(0.98);
}
}
.community-card {
border-radius: 20rpx;
overflow: hidden;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
.community-header {
background: linear-gradient(135deg, #3e9bff, #2374e1);
position: relative;
overflow: hidden;
&::before {
content: '';
position: absolute;
top: -50%;
right: -20%;
width: 400rpx;
height: 400rpx;
border-radius: 50%;
background: rgba(255, 255, 255, 0.1);
z-index: 0;
}
&::after {
content: '';
position: absolute;
bottom: -30%;
left: -10%;
width: 300rpx;
height: 300rpx;
border-radius: 50%;
background: rgba(255, 255, 255, 0.05);
z-index: 0;
}
}
.community-footer {
border-radius: 0 0 20rpx 20rpx;
}
}
.building-selector-container {
background-color: #fff;
border-radius: 16rpx;
overflow: hidden;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.05);
margin-bottom: 30rpx;
}
.building-sidebar-layout {
display: flex;
/* 移动端通用适配 */
height: calc(100vh - 400rpx - constant(safe-area-inset-bottom));
height: calc(100vh - 400rpx - env(safe-area-inset-bottom));
/* APP端特殊适配 */
/* #ifdef APP-PLUS */
height: calc(100vh - 400rpx - 50rpx);
margin-bottom: 50rpx;
/* #endif */
/* 非APP端 */
/* #ifndef APP-PLUS */
margin-bottom: calc(constant(safe-area-inset-bottom));
margin-bottom: calc(env(safe-area-inset-bottom));
/* #endif */
}
.sidebar-container {
width: 180rpx;
flex-shrink: 0;
height: 100%;
background-color: #f8f8f8;
overflow-y: auto;
/* APP端特殊适配 */
/* #ifdef APP-PLUS */
-webkit-overflow-scrolling: touch;
/* #endif */
}
.content-container {
flex: 1;
height: 100%;
overflow-y: auto;
padding-bottom: 40rpx;
/* APP端特殊适配 */
/* #ifdef APP-PLUS */
-webkit-overflow-scrolling: touch;
/* #endif */
}
.building-sidebar {
height: 100%;
}
::v-deep .wd-sidebar-item {
font-size: 28rpx;
padding: 30rpx 20rpx;
text-align: center;
}
::v-deep .wd-sidebar-item--active {
background-color: #fff;
color: #3e9bff;
font-weight: bold;
}
.unit-selector {
background-color: #fff;
padding: 30rpx;
}
.unit-grid {
display: flex;
flex-wrap: wrap;
}
.unit-item {
position: relative;
width: 120rpx;
height: 65rpx;
background-color: #f7f8fa;
border-radius: 10rpx;
display: flex;
align-items: center;
justify-content: center;
margin: 0 10rpx 10rpx 0;
&-active {
background: rgba(62, 155, 255, 0.1);
border: 1px solid rgba(62, 155, 255, 0.3);
}
.unit-text {
font-size: 24rpx;
color: #666;
font-weight: 500;
&-active {
color: #3e9bff;
font-weight: bold;
}
}
.unit-badge {
position: absolute;
top: -8rpx;
right: -8rpx;
min-width: 32rpx;
height: 32rpx;
border-radius: 16rpx;
background-color: #ff4d4f;
color: #fff;
font-size: 20rpx;
display: flex;
align-items: center;
justify-content: center;
padding: 0 6rpx;
box-shadow: 0 2rpx 6rpx rgba(255, 77, 79, 0.3);
}
&:active {
opacity: 0.8;
transform: scale(0.98);
}
}
.house-list {
padding: 0 30rpx 50rpx;
}
.floor-item {
background-color: #fff;
border-radius: 16rpx;
overflow: hidden;
/* box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04); */
margin-bottom: 25rpx;
}
.floor-header {
display: flex;
align-items: center;
padding: 20rpx 30rpx;
background: linear-gradient(to right, #f5f7fa, #f9fafc);
border-bottom: 1px solid rgba(0, 0, 0, 0.04);
}
.floor-title {
font-size: 32rpx;
font-weight: 600;
color: #333;
position: relative;
padding-left: 16rpx;
&::before {
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 6rpx;
height: 28rpx;
background: #3e9bff;
border-radius: 3rpx;
}
}
.house-grid {
display: flex;
flex-wrap: wrap;
padding: 20rpx 10rpx;
background-color: #fff;
}
.house-card {
width: 33.33%;
padding: 10rpx;
box-sizing: border-box;
}
.house-card-inner {
position: relative;
background-color: #fff;
border-radius: 12rpx;
padding: 0;
display: flex;
flex-direction: column;
border: 1px solid #fdf9f9;
transition: all 0.25s;
overflow: hidden;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.03);
&:active {
transform: translateY(2rpx);
box-shadow: 0 1rpx 3rpx rgba(0, 0, 0, 0.01);
}
}
.house-number-box {
background-color: #f7f9fc;
padding: 14rpx 10rpx;
text-align: center;
border-bottom: 1px solid #eaedf1;
}
.house-number {
font-size: 28rpx;
font-weight: 600;
color: #333;
}
.house-content {
padding: 14rpx 0;
display: flex;
justify-content: center;
align-items: center;
min-height: 60rpx;
}
.house-unpaid {
display: flex;
align-items: center;
.unpaid-count {
font-size: 30rpx;
font-weight: 600;
color: #ff4d4f;
margin-right: 4rpx;
}
.unpaid-text {
font-size: 24rpx;
color: #ff4d4f;
}
}
.house-paid {
.paid-text {
font-size: 24rpx;
color: #52c41a;
font-weight: 500;
}
}
.house-badge {
position: absolute;
top: 0;
right: 0;
background-color: #ff4d4f;
color: #fff;
font-size: 20rpx;
min-width: 36rpx;
height: 36rpx;
display: flex;
align-items: center;
justify-content: center;
border-radius: 0 12rpx 0 12rpx;
font-weight: bold;
z-index: 2;
box-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.1);
}
.house-has-unpaid {
/* border-color: rgba(255, 77, 79, 0.2); */
background-color: #fff;
}
.empty-state {
padding: 100rpx 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.bottom-safe-area {
height: 0;
width: 100%;
/* #ifdef MP-WEIXIN */
height: constant(safe-area-inset-bottom);
height: env(safe-area-inset-bottom);
/* #endif */
/* #ifdef APP-PLUS */
height: 100rpx;
/* #endif */
/* #ifdef H5 */
height: 80rpx;
/* #endif */
}
.empty-bills {
padding-top: 150rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.house-detail {
height: 100%;
border-radius: 24rpx 24rpx 0 0 !important;
overflow: hidden;
background-color: #fff;
display: flex;
flex-direction: column;
.detail-header {
// padding-top: constant(safe-area-inset-top);
// padding-top: env(safe-area-inset-top);
flex-shrink: 0;
}
.detail-content-scroll {
flex: 1;
height: calc(100% - 120rpx);
}
.detail-content {
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
}
.bill-item {
background-color: #f9f9f9;
border-radius: 16rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
}
.li-bottom-border {
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
}
}
::v-deep .wd-navbar__placeholder {
height: calc(var(--status-bar-height) + 88rpx) !important;
padding-top: constant(safe-area-inset-top) !important;
padding-top: env(safe-area-inset-top) !important;
}
.custom-class-popup {
border-radius: 24rpx 24rpx 0 0 !important;
}
.refresh-btn {
background-color: rgba(255, 255, 255, 0.3);
border-radius: 30rpx;
padding: 8rpx 20rpx;
display: flex;
align-items: center;
justify-content: center;
position: relative;
z-index: 5;
/* 确保在最上层 */
transition: all 0.2s;
border: none;
margin: 0;
font-size: inherit;
color: #fff;
line-height: normal;
/* 清除按钮在小程序中的默认样式 */
&::after {
display: none;
border: none;
}
&:active {
opacity: 0.7;
transform: scale(0.95);
}
}
</style>
<style scoped>
::-webkit-scrollbar {
width: 0 !important;
height: 0 !important;
display: none;
}
</style>