修复bug

This commit is contained in:
zhouyanli
2026-08-14 16:22:44 +08:00
parent 9e8f5d6acc
commit 53ea3996a0
17 changed files with 164 additions and 76 deletions

View File

@@ -2,8 +2,8 @@
"name" : "花开物业", "name" : "花开物业",
"appid" : "__UNI__29C3D60", "appid" : "__UNI__29C3D60",
"description" : "智慧社区居民端面向小区业主使用,支持注册、验证码、账号密码多种登录方式,提供密码找回功能,账号使用安全便捷。支持多小区切换,首页设有轮播 banner、社区公告集成远程开门、生活缴费、在线报修、访客邀请、社区活动常用服务。全服务板块统一涵盖门禁开门、线上缴费、报修申报、访客预约、投诉反馈、问卷调研、活动报名、社区公示、一键联系物业功能。个人中心可管理房屋、住户、车位、车辆信息支持更换手机号、修改密码、消息通知设置、版本更新及账号退出一站式满足业主居家生活、社区服务、房产车辆管理需求实现社区生活数字化、便捷化。", "description" : "智慧社区居民端面向小区业主使用,支持注册、验证码、账号密码多种登录方式,提供密码找回功能,账号使用安全便捷。支持多小区切换,首页设有轮播 banner、社区公告集成远程开门、生活缴费、在线报修、访客邀请、社区活动常用服务。全服务板块统一涵盖门禁开门、线上缴费、报修申报、访客预约、投诉反馈、问卷调研、活动报名、社区公示、一键联系物业功能。个人中心可管理房屋、住户、车位、车辆信息支持更换手机号、修改密码、消息通知设置、版本更新及账号退出一站式满足业主居家生活、社区服务、房产车辆管理需求实现社区生活数字化、便捷化。",
"versionName" : "1.1.2", "versionName" : "1.1.3",
"versionCode" : 125, "versionCode" : 126,
"transformPx" : false, "transformPx" : false,
"uniCloud" : { "uniCloud" : {
"provider" : "aliyun", "provider" : "aliyun",

View File

@@ -177,8 +177,8 @@
取消报名 取消报名
</button> </button>
<!-- 活动实况页显示添加实况按钮 --> <!-- 活动实况页显示添加实况按钮活动开始之后结束之前显示 -->
<button class="action-btn add-status-btn" v-if="hasSigned && isActivityStarted && !isActivityEnded && activeTab === 'status'" @click="liveClick">添加实况</button> <button class="action-btn add-status-btn" v-if="isActivityStarted && !isActivityEndedByTime && activeTab === 'status'" @click="liveClick">添加实况</button>
</view> </view>
<!-- 报名确认模态框 --> <!-- 报名确认模态框 -->
@@ -257,6 +257,12 @@ const isActivityStarted = computed(() => {
return moment().isSameOrAfter(moment(activityConent.value.startTime)) return moment().isSameOrAfter(moment(activityConent.value.startTime))
}) })
// 判断活动是否已到结束时间
const isActivityEndedByTime = computed(() => {
if (!activityConent.value.endTime) return false
return moment().isAfter(moment(activityConent.value.endTime))
})

View File

@@ -119,7 +119,7 @@ export const getQueryRepair = (data) =>{
} }
// 获取房屋列表 // 获取房屋列表
export const getHouseList = (data) =>{ export const getHouseList = (data) =>{
return get('/api/resident/my/house/list',data) return get('/repairOrder/certifiedHouseList',data)
} }
// 报修详情 // 报修详情
export const getRepairDetail = (data) =>{ export const getRepairDetail = (data) =>{

View File

@@ -2,8 +2,8 @@ import { navigateToLogin } from '@/common/checkLogin.js'
let baseUrl = ''; let baseUrl = '';
if (process.env.NODE_ENV === 'development') { if (process.env.NODE_ENV === 'development') {
// baseUrl = 'http://192.168.1.6:8080'; // 开发环境 baseUrl = 'http://192.168.1.6:8080'; // 开发环境
baseUrl = 'http://192.168.1.222:8080'; // baseUrl = 'http://192.168.1.222:8080';
} else { } else {
baseUrl = 'https://wuyeapi.ckdzkj.com'; // 生产环境 baseUrl = 'https://wuyeapi.ckdzkj.com'; // 生产环境
} }

View File

@@ -1,6 +1,6 @@
// 服务器地址(与 request.js 保持一致) // 服务器地址(与 request.js 保持一致)
const baseUrl = 'https://wuyeapi.ckdzkj.com'; const baseUrl = 'https://wuyeapi.ckdzkj.com';
// const baseUrl = "http://192.168.1.222:8080" // const baseUrl = "http://192.168.1.6:8080"
/** /**
* 图片上传 Hook * 图片上传 Hook

View File

@@ -21,31 +21,16 @@
<view class="text-item">巡检点{{ detail.pointNames }}</view> <view class="text-item">巡检点{{ detail.pointNames }}</view>
</view> </view>
<!-- 第二块巡检结果 -->
<view class="card">
<view class="card-subtitle">巡检结果</view>
<view class="text-item">巡检人{{ detail.inspectorName }}</view>
<view class="text-item">手机号码{{ detail.phoneNumber }}</view>
<view class="text-item">巡检时间{{ detail.inspectTime }}</view>
<view class="text-item">巡检结果</view>
<view class="result-desc">
<text v-for="(r, idx) in detail.results" :key="idx">{{ idx + 1 }}.{{ r }}</text>
</view>
<view class="text-item">巡检照片</view>
<view class="img-wrap">
<view class="img-box" v-for="(img, idx) in detail.photos" :key="idx" @click="previewImage(img)">
<image class="img" :src="img" mode="aspectFill"></image>
</view>
<view class="empty-img-tip" v-if="!detail.photos || detail.photos.length === 0">暂无照片</view>
</view>
</view>
<!-- 第三块巡检明细列表 --> <!-- 第三块巡检明细列表 -->
<view class="card" v-for="(sub, idx) in detail.details" :key="sub.id"> <view class="card" v-for="(sub, idx) in detail.details" :key="sub.id">
<view class="card-subtitle">{{ sub.pointName }}</view> <view class="card-subtitle">巡检结果</view>
<view class="text-item">巡检点{{ sub.pointName }}</view>
<view class="text-item">巡检人{{ detail.inspectorName }}</view>
<view class="text-item">手机号码{{ detail.phoneNumber }}</view>
<view class="text-item">巡检时间{{ sub.checkTime }}</view> <view class="text-item">巡检时间{{ sub.checkTime }}</view>
<view class="text-item">巡检状态{{ getXunJianStatus(sub.status) }}</view>
<view class="text-item">巡检结果{{ sub.checkResult }}</view> <view class="text-item">巡检结果{{ sub.checkResult }}</view>
<view class="text-item" v-if="sub.remark">备注{{ sub.remark }}</view> <!-- <view class="text-item" v-if="sub.remark">备注{{ sub.remark }}</view> -->
<view class="text-item" v-if="sub.photos">巡检照片</view> <view class="text-item" v-if="sub.photos">巡检照片</view>
<view class="img-wrap" v-if="sub.photos"> <view class="img-wrap" v-if="sub.photos">
<view class="img-box" v-for="(img, i) in sub.photos.split(',')" :key="i" @click="previewImage(img)"> <view class="img-box" v-for="(img, i) in sub.photos.split(',')" :key="i" @click="previewImage(img)">
@@ -83,6 +68,15 @@
} }
}) })
// 巡检状态字段映射 0正常1异常
function getXunJianStatus(status){
const staMap = {
"0":'正常',
"1":"异常"
}
return staMap[status]
}
const fetchDetail = async () => { const fetchDetail = async () => {
if (!recordId) return if (!recordId) return
loading.value = true loading.value = true

View File

@@ -37,7 +37,7 @@
</view> </view>
<view class="info-row"> <view class="info-row">
<text class="info-label">业主</text> <text class="info-label">业主</text>
<text class="info-value">{{form.ownerName}}</text> <text class="info-value">{{form.name}}</text>
</view> </view>
<view class="info-row"> <view class="info-row">
<text class="info-label">房间状态</text> <text class="info-label">房间状态</text>
@@ -58,7 +58,7 @@
</view> </view>
<view class="info-row"> <view class="info-row">
<text class="info-label">住户</text> <text class="info-label">住户</text>
<text class="info-value">{{form.name}}</text> <text class="info-value">{{form.residentName}}</text>
</view> </view>
<view class="info-row"> <view class="info-row">
<text class="info-label">房间号</text> <text class="info-label">房间号</text>
@@ -220,6 +220,10 @@
id: id.value id: id.value
}).then(res => { }).then(res => {
if (res.code === 200) { if (res.code === 200) {
// 删除后清空小区缓存,避免首页仍显示已删除的小区
uni.setStorageSync('needReloadUserInfo', true)
uni.removeStorageSync('currentVillageId')
uni.removeStorageSync('home_cache_' + (uni.getStorageSync('userId') || ''))
uni.showToast({ uni.showToast({
title: '删除成功', title: '删除成功',
icon: 'success' icon: 'success'

View File

@@ -162,7 +162,7 @@
min-height: 0; min-height: 0;
height: 0; height: 0;
overflow-y: auto; overflow-y: auto;
padding: 0px 40rpx; padding: 0px 40rpx 140rpx;
box-sizing: border-box; box-sizing: border-box;
} }
@@ -183,9 +183,15 @@
} }
.bottom-btn { .bottom-btn {
padding: 20rpx 30rpx 40rpx; position: fixed;
left: 0;
right: 0;
bottom: 0;
padding: 20rpx 30rpx;
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
flex-shrink: 0; flex-shrink: 0;
background-color: #f5f7fa; background-color: #f5f7fa;
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.05);
} }
.car-item { .car-item {

View File

@@ -2,6 +2,11 @@
<view class="contentStyle" style=""> <view class="contentStyle" style="">
<scroll-view class="page" scroll-y :refresher-enabled="true" :refresher-triggered="isRefreshing" @refresherrefresh="onRefresh" @scrolltolower="loadMore"> <scroll-view class="page" scroll-y :refresher-enabled="true" :refresher-triggered="isRefreshing" @refresherrefresh="onRefresh" @scrolltolower="loadMore">
<!-- 空状态 -->
<view v-if="houseList.length === 0" class="empty-state">
<uni-icons type="info" size="30" color="#ccc"></uni-icons>
<text class="empty-text">暂无数据</text>
</view>
<!-- 房屋列表 v-for 渲染 --> <!-- 房屋列表 v-for 渲染 -->
<view class="house-list"> <view class="house-list">
<view class="house-card" v-for="(item, index) in houseList" :key="index" @click="tapHouse(item)"> <view class="house-card" v-for="(item, index) in houseList" :key="index" @click="tapHouse(item)">
@@ -218,6 +223,24 @@
box-sizing: border-box; box-sizing: border-box;
} }
/* 空状态 */
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
min-height: 500rpx;
color: #ccc;
}
.empty-text {
font-size: 32rpx;
color: #999;
margin-top: 20rpx;
margin-bottom: 10rpx;
}
/* 列表 */ /* 列表 */
.house-list { .house-list {
} }

View File

@@ -196,7 +196,7 @@
.page { .page {
flex: 1; flex: 1;
overflow-y: auto; overflow-y: auto;
padding: 0px 40rpx; padding: 0px 40rpx 140rpx;
box-sizing: border-box; box-sizing: border-box;
} }
@@ -217,7 +217,14 @@
} }
.bottom-btn { .bottom-btn {
padding: 20rpx 30rpx 40rpx; position: fixed;
left: 0;
right: 0;
bottom: 0;
padding: 20rpx 30rpx;
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
background: #f5f7fa;
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.05);
} }
.parkingSpace-card { .parkingSpace-card {

View File

@@ -24,7 +24,7 @@
<view class="info-card"> <view class="info-card">
<view class="card-title"> <view class="card-title">
<view class="title-line"></view> <view class="title-line"></view>
房屋信息 车位信息
</view> </view>
<view class="info-row"> <view class="info-row">
<text class="info-label">小区</text> <text class="info-label">小区</text>

View File

@@ -26,6 +26,9 @@
ref, ref,
onMounted onMounted
} from 'vue' } from 'vue'
import {
onUnload
} from '@dcloudio/uni-app'
import { import {
getResidentCarAreaManageAreaListByVillageId, getResidentCarAreaManageAreaListByVillageId,
getResidentCarAreaManageParkingListByAreaId getResidentCarAreaManageParkingListByAreaId
@@ -37,6 +40,8 @@
const selectedParkingLot = ref(uni.getStorageSync('parkingLotId')) const selectedParkingLot = ref(uni.getStorageSync('parkingLotId'))
const selectedParkingSpace = ref(uni.getStorageSync('parkingSpaceId')) const selectedParkingSpace = ref(uni.getStorageSync('parkingSpaceId'))
const isSubmitting = ref(false) const isSubmitting = ref(false)
let navTimer = null
let lockTimer = null
onMounted(() => { onMounted(() => {
checkType.value = uni.getStorageSync('checkType') checkType.value = uni.getStorageSync('checkType')
@@ -94,37 +99,38 @@
} }
const selectedParking = (item) => { const selectedParking = (item) => {
// 防重复点击锁:处理中直接返回,避免重复选择/重复跳转
if (isSubmitting.value) return if (isSubmitting.value) return
isSubmitting.value = true isSubmitting.value = true
console.log(item);
try {
if (checkType.value == '停车场') { if (checkType.value == '停车场') {
selectedParkingLot.value = item.id selectedParkingLot.value = item.id
} else if (checkType.value == '车位编号') {
selectedParkingSpace.value = item.id
}
setTimeout(() => {
uni.showToast({
title: '选择成功',
icon: 'success'
})
console.log(checkType.value);
if (checkType.value == '停车场') {
uni.setStorageSync('parkingLotId', item.id) uni.setStorageSync('parkingLotId', item.id)
uni.setStorageSync('parkingLotName', item.name) uni.setStorageSync('parkingLotName', item.name)
uni.removeStorageSync('parkingSpaceId') uni.removeStorageSync('parkingSpaceId')
uni.removeStorageSync('parkingSpaceName') uni.removeStorageSync('parkingSpaceName')
uni.setStorageSync('checkType', '车位编号') uni.setStorageSync('checkType', '车位编号')
} else if (checkType.value == '车位编号') { } else if (checkType.value == '车位编号') {
console.log(item.id); selectedParkingSpace.value = item.id
uni.setStorageSync('parkingSpaceId', item.id) uni.setStorageSync('parkingSpaceId', item.id)
uni.setStorageSync('parkingSpaceName', item.name) uni.setStorageSync('parkingSpaceName', item.name)
} }
}, 1000)
setTimeout(() => { uni.showToast({
title: '选择成功',
icon: 'success'
})
navTimer = setTimeout(() => {
goFreash() goFreash()
}, 2500) }, 1500)
} finally {
// 正常跳转后页面会销毁,防止异常时锁死
lockTimer = setTimeout(() => {
isSubmitting.value = false
}, 1500)
}
} }
const goFreash = () => { const goFreash = () => {
@@ -149,6 +155,18 @@
} }
uni.navigateBack() uni.navigateBack()
} }
// 页面销毁时清理定时器,避免手势返回后延迟跳转仍触发
onUnload(() => {
if (navTimer) {
clearTimeout(navTimer)
navTimer = null
}
if (lockTimer) {
clearTimeout(lockTimer)
lockTimer = null
}
})
</script> </script>
<style lang="scss"> <style lang="scss">

View File

@@ -372,14 +372,20 @@
.page { .page {
flex: 1; flex: 1;
overflow-y: auto; overflow-y: auto;
padding: 0 40rpx; padding: 0 40rpx 140rpx;
box-sizing: border-box; box-sizing: border-box;
background-color: #fff; background-color: #fff;
} }
.bottom-btn { .bottom-btn {
padding: 20rpx 30rpx 40rpx; position: fixed;
left: 0;
right: 0;
bottom: 0;
padding: 20rpx 30rpx;
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
background-color: #fff; background-color: #fff;
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.05);
} }
</style> </style>

View File

@@ -29,7 +29,7 @@
<view class="form-item-wenti"> <view class="form-item-wenti">
<text class="label">问题描述</text> <text class="label">问题描述</text>
<view class="textarea-wrap"> <view class="textarea-wrap">
<textarea v-model="form.desc" placeholder="请描述你的问题最多200字" maxlength="200" class="desc-textarea" /> <textarea v-model="form.desc" placeholder="请描述你的问题或位置最多200字" maxlength="200" class="desc-textarea" />
<text class="char-count">{{ form.desc.length }}/200</text> <text class="char-count">{{ form.desc.length }}/200</text>
</view> </view>
<!-- <uni-easyinput v-model="form.desc" placeholder="请描述你的问题" type="textarea" maxlength="200"></uni-easyinput> --> <!-- <uni-easyinput v-model="form.desc" placeholder="请描述你的问题" type="textarea" maxlength="200"></uni-easyinput> -->

View File

@@ -22,7 +22,7 @@
<view class="form-item-wenti"> <view class="form-item-wenti">
<text class="label">问题描述</text> <text class="label">问题描述</text>
<view class="textarea-wrap"> <view class="textarea-wrap">
<textarea v-model="form.desc" placeholder="请描述你的问题最多200字" maxlength="200" class="desc-textarea" /> <textarea v-model="form.desc" placeholder="请描述你的问题或位置最多200字" maxlength="200" class="desc-textarea" />
<text class="char-count">{{ form.desc.length }}/200</text> <text class="char-count">{{ form.desc.length }}/200</text>
</view> </view>
</view> </view>

View File

@@ -27,9 +27,11 @@
</view> </view>
<!-- 确认按钮 --> <!-- 确认按钮固定底部不随内容滚动 -->
<view class="confirm-bar">
<button class="confirm-btn" @click="confirmSelect">确认</button> <button class="confirm-btn" @click="confirmSelect">确认</button>
</view> </view>
</view>
</template> </template>
<script setup> <script setup>
@@ -55,7 +57,7 @@ const fetchHouseList = async () => {
try { try {
const res = await getHouseList({ pageNum: pageNum.value, pageSize: pageSize.value }) const res = await getHouseList({ pageNum: pageNum.value, pageSize: pageSize.value })
if (res.code === 200) { if (res.code === 200) {
const list = res.rows || [] const list = res.data || []
houseList.value = list houseList.value = list
// 仅当从表单页带入了房屋ID时自动选中对应房屋否则不默认选择 // 仅当从表单页带入了房屋ID时自动选中对应房屋否则不默认选择
if (preSelectedHouseId.value) { if (preSelectedHouseId.value) {
@@ -106,15 +108,12 @@ const confirmSelect = () => {
padding: 15px; padding: 15px;
height: 100vh; height: 100vh;
box-sizing: border-box; box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: space-between;
background: #f9f9f9; background: #f9f9f9;
} }
.house-list { .house-list {
flex: 1; height: 100%;
min-height: 0;
overflow-y: auto; overflow-y: auto;
padding-bottom: 120rpx;
} }
.house-item { .house-item {
display: flex; display: flex;
@@ -145,6 +144,17 @@ const confirmSelect = () => {
color: #666; color: #666;
margin-top: 4px; margin-top: 4px;
} }
.confirm-bar {
position: fixed;
left: 0;
right: 0;
bottom: 0;
padding: 20rpx 30rpx;
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
background: #f9f9f9;
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.05);
}
.confirm-btn { .confirm-btn {
width: 100%; width: 100%;
height: 44px; height: 44px;
@@ -153,8 +163,6 @@ const confirmSelect = () => {
color: #fff; color: #fff;
border-radius: 8px; border-radius: 8px;
font-size: 28rpx; font-size: 28rpx;
margin-top: 20px;
margin-bottom: 20rpx;
} }
/* 空状态 */ /* 空状态 */
.empty-state { .empty-state {

View File

@@ -272,16 +272,27 @@
dataLoaded.value = false dataLoaded.value = false
} }
const getCurrentCommunityData = () => { const getCurrentCommunityData = (reloadedVillageId) => {
// 删除房屋后 reloadUserInfo 会返回 currentVillageId=0
// 此时直接清空,避免再请求可能返回过期数据的 /village/current 导致小区名残留
if (reloadedVillageId === 0 || reloadedVillageId === '0') {
currentCommunity.value = '请绑定房屋'
currentVillageId.value = ''
uni.removeStorageSync('currentVillageId')
saveHomeCache()
return Promise.resolve()
}
return getCurrentVillage().then(res => { return getCurrentVillage().then(res => {
if (res.code === 200 && res.data && res.data.villageId) { if (res.code === 200 && res.data && res.data.villageId) {
currentCommunity.value = res.data.villageName || '未命名小区' currentCommunity.value = res.data.villageName
saveHomeCache() saveHomeCache()
currentVillageId.value = res.data.villageId currentVillageId.value = res.data.villageId
uni.setStorageSync('currentVillageId', res.data.villageId) uni.setStorageSync('currentVillageId', res.data.villageId)
} else { } else {
currentCommunity.value = '请绑定房屋' currentCommunity.value = '请绑定房屋'
currentVillageId.value = '' currentVillageId.value = ''
uni.removeStorageSync('currentVillageId')
saveHomeCache()
} }
}).catch(err => { }).catch(err => {
// 有 token 才提示错误(无 token 用户正常浏览首页API 401 属于预期行为) // 有 token 才提示错误(无 token 用户正常浏览首页API 401 属于预期行为)
@@ -317,20 +328,23 @@
const token = uni.getStorageSync('token') || '' const token = uni.getStorageSync('token') || ''
dataLoaded.value = true dataLoaded.value = true
const needReload = uni.getStorageSync('needReloadUserInfo') const needReload = uni.getStorageSync('needReloadUserInfo')
// 重新加载用户信息时,拿到权威的 currentVillageId删除房屋后会变成 0
let reloadedVillageId = null
if (token && needReload) { if (token && needReload) {
uni.removeStorageSync('needReloadUserInfo') uni.removeStorageSync('needReloadUserInfo')
getReloadUserInfo().then(res => { try {
const res = await getReloadUserInfo()
if (res.code === 200 && res.data) { if (res.code === 200 && res.data) {
if (res.data.userId) uni.setStorageSync('userId', res.data.userId) if (res.data.userId) uni.setStorageSync('userId', res.data.userId)
const reloadedVillageId = res.data.currentVillageId || 0 reloadedVillageId = res.data.currentVillageId || 0
uni.setStorageSync('currentVillageId', reloadedVillageId) uni.setStorageSync('currentVillageId', reloadedVillageId)
} }
}).catch(err => { } catch (err) {
console.error('重新加载用户信息失败', err) console.error('重新加载用户信息失败', err)
}) }
} }
// 先获取小区信息,确保 villageId 已更新,再请求依赖 villageId 的接口 // 先获取小区信息,确保 villageId 已更新,再请求依赖 villageId 的接口
await getCurrentCommunityData() await getCurrentCommunityData(reloadedVillageId)
getNoticeData() getNoticeData()
getNewActivityList() getNewActivityList()
getbannarData() getbannarData()
@@ -361,12 +375,14 @@
onShow(() => { onShow(() => {
const currentUserId = uni.getStorageSync('userId') || '' const currentUserId = uni.getStorageSync('userId') || ''
const userIdChanged = lastUserId.value !== currentUserId const userIdChanged = lastUserId.value !== currentUserId
const needReload = uni.getStorageSync('needReloadUserInfo')
refreshing.value = false refreshing.value = false
if (userIdChanged) { if (userIdChanged) {
resetPageData() resetPageData()
refreshAllData() refreshAllData()
} else if (!dataLoaded.value) { } else if (!dataLoaded.value || needReload) {
// 首次进入且之前因无 token 跳过了 API现在有 token 则补拉 // 首次进入且之前因无 token 跳过了 API现在有 token 则补拉
// 或房屋/小区信息有变更(如删除房屋后),需要重新拉取
refreshAllData() refreshAllData()
} }
lastUserId.value = currentUserId lastUserId.value = currentUserId