Files
property-manager-side/wuye-manager-uniapp/pageSubPack/ticket/hall.vue
2026-06-23 08:12:17 +08:00

465 lines
11 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="report-record-page page_padding">
<!-- 顶部导航栏 -->
<navBar @clickLeft="navBack" title="工单大厅"></navBar>
<view class="hall_body flex flex-col">
<view class="bgaction"> </view>
<!-- 状态筛选标签 -->
<TabsComponents
:tabslist="statusTabs"
:activeValue="activeStatus"
:options="{ label: 'label', value: 'value' }"
@update="switchStatus"
></TabsComponents>
<!-- 类型筛选标签 -->
<view class="type-tabs">
<view
v-for="item in typeTabs"
:key="item.value"
class="type-tab-item"
:class="{ active: activeType === item.value }"
@tap="switchType(item.value)"
>
{{ item.label }}
</view>
</view>
<!-- 上报记录列表 -->
<scroll-view
ref="scrollRef"
class="record-list"
scroll-y
lower-threshold="60"
@scrolltolower="scrolltolower"
>
<!-- 空状态 -->
<view v-if="reportRecords.length === 0" class="empty-state">
<uni-icons type="empty" size="60" color="#ccc"></uni-icons>
<text class="empty-text">暂无上报记录</text>
</view>
<!-- 记录卡片 -->
<view
v-for="(record, index) in reportRecords"
:key="index"
class="record-card"
@tap="handleMain(record.id)"
>
<!-- 标题 + 状态标签 -->
<view class="card-header">
<text class="card-title">{{ record.item }}</text>
<view
class="status-tag"
:class="{
pending: record.problemStatus === statusMap.pending,
processing: record.problemStatus === statusMap.processing,
completed: record.problemStatus === statusMap.completed
}"
>
{{ getStatusText(record.problemStatus) }}
</view>
</view>
<!-- 类型标签 -->
<view class="tag-group" v-if="record.maintenanceItemName || record.projectTypeStr">
<view class="tag-item" v-if="record.projectTypeStr">{{ record.projectTypeStr }}</view>
<view class="tag-item" v-if="record.maintenanceItemName">{{
record.maintenanceItemName
}}</view>
</view>
<!-- 内容 -->
<view class="card-content">
{{ record.problem }}
</view>
<!-- 工单图片 -->
<view class="card-image" v-if="record.repairImageUrlList.length > 0">
<image
lazy-load
v-for="(item, index) in record.repairImageUrlList"
:key="index"
:src="item"
class="images"
@tap="handlePrivew(record.repairImageUrlList, index)"
mode="scaleToFill"
></image>
</view>
<!-- 底部信息 -->
<view class="card-footer">
<text class="create-time">{{ record.createTime }}</text>
<text v-if="record.problemStatus === statusMap.processing" class="repairman"
>维修师傅:{{ record.repairName }}</text
>
<view class="share" v-if="record.problemStatus === statusMap.pending">
<text>分配</text>
</view>
</view>
</view>
</scroll-view>
</view>
</view>
</template>
<script setup>
import { ref, computed, nextTick } from 'vue'
import { onReady, onShow } from '@dcloudio/uni-app'
import TabsComponents from '@/components/tabs/tabs.vue'
import NavBar from '@/components/navbar/navbar.vue'
import { getTicketHallList } from '@/api/ticket.js'
// 导航栏/标签高度(适配不同设备)
// 筛选状态
const activeStatus = ref(-1) // 全部/待分配/待解决/已完成
const activeType = ref(-1) // 全部/公共报修/个人报修
// 0 已提交 1已分配 2维修完成
// 状态筛选选项
const statusTabs = ref([
{ label: '全部', value: -1 },
{ label: '待分配', value: 0 },
{ label: '待解决', value: 1 },
{ label: '已完成', value: 2 }
])
// 类型筛选选项
const typeTabs = ref([
{ label: '全部', value: -1 },
{ label: '公共报修', value: 0 },
{ label: '个人报修', value: 1 }
])
// 模拟上报记录数据(实际项目替换为接口请求)
const reportRecords = ref([])
const queryParmas = ref({
pageNum: 1,
pageSize: 5,
itemType: undefined, // -1 全部/ 0 公共报修/ 1 个人报修
problemStatus: undefined // 0 已提交 1已分配 2维修完成
})
const isLoading = ref(false) // 加载锁
const hasMore = ref(true) // 是否还有更多数据
const total = ref(0)
function scrolltolower() {
// 必须加这两个判断!
if (isLoading.value || !hasMore.value) return
queryParmas.value.pageNum += 1
getlist()
}
function getlist() {
if (isLoading.value || !hasMore.value) return
isLoading.value = true
getTicketHallList(queryParmas.value)
.then(res => {
const list = res.rows.map(item => ({
...item,
repairImageUrlList: item.repairImageUrl
? item.repairImageUrl.split(',').filter(Boolean)
: []
}))
if (queryParmas.value.pageNum === 1) {
reportRecords.value = list
} else {
reportRecords.value.push(...list)
}
total.value = res.total
hasMore.value = reportRecords.value.length < total.value
})
.catch(err => {
if (err.code === 500 && err.msg === '您没有权限访问') {
uni.showToast({
icon: 'error',
title: '没有权限'
})
} else {
uni.showToast({
icon: 'error',
title: '网络异常'
})
}
})
.finally(() => {
isLoading.value = false
})
}
onShow(() => {
getlist()
})
function resetList() {
reportRecords.value = []
queryParmas.value.pageNum = 1
queryParmas.value.pageSize = 5
hasMore.value = true
getlist()
}
// 切换状态(全部/待分配/待解决/已完成)筛选
const switchStatus = value => {
activeStatus.value = value
if (value === -1) {
queryParmas.value.problemStatus = undefined
} else {
queryParmas.value.problemStatus = value
}
resetList()
}
// 切换类型(公共/个人)筛选
const switchType = value => {
activeType.value = value
if (value === -1) {
queryParmas.value.itemType = undefined
} else {
queryParmas.value.itemType = value
}
resetList()
}
const statusMap = {
已提交: '待分配',
已分配: '待解决',
已完成: '已完成',
pending: '已提交',
processing: '已分配',
completed: '已完成'
}
// 获取状态文本
const getStatusText = status => {
return statusMap[status] || ''
}
// 返回上一页
const navBack = () => {
uni.navigateBack()
}
/* 0 待分配,1待解决 2已完成*/
function handleMain(id) {
const find = reportRecords.value.find(item => item.id === id)
if (find) {
const status = find.repairStatus
if (status === 2) {
uni.navigateTo({
url: `/pageSubPack/ticket/repairMain?id=${id}&showbtn=${false}&path=hall`
})
} else {
uni.navigateTo({
url: `/pageSubPack/ticket/repairMain?id=${id}&showbtn=${false}&path=hall`
})
}
}
}
/* 预览图片 */
function handlePrivew(items, index) {
if (items.length <= 0) return
uni.previewImage({
urls: items,
current: index
})
}
</script>
<style scoped>
.bgaction {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: -1;
/* 禁止拦截滚动/点击事件 */
pointer-events: none;
background: linear-gradient(225deg, #e2f0ff 0%, #f9f9f9 25%);
}
/* 根页面:固定满屏、纵向弹性布局、禁止自身滚动 */
.report-record-page {
height: 100vh;
overflow: hidden;
display: flex;
flex-direction: column;
background: linear-gradient(225deg, #e2f0ff 0%, #f9f9f9 25.71%);
}
/* 主体容器:占满剩余高度、纵向排列、禁止滚动 */
.hall_body {
flex: 1;
display: flex;
flex-direction: column;
padding: 0 40rpx;
overflow: hidden;
position: relative;
}
/* 状态标签栏(固定高度,正常占位) */
.status-tabs {
display: flex;
height: 88rpx;
align-items: center;
}
/* 类型标签栏(固定高度,正常占位) */
.type-tabs {
display: flex;
height: 48rpx;
margin: 20rpx 0;
justify-content: flex-start;
}
.type-tabs > .type-tab-item:not(:last-child) {
margin-right: 20rpx;
}
.type-tab-item {
width: 142rpx;
height: 48rpx;
border-radius: 24rpx;
border: 2rpx solid #999999;
font-size: 28rpx;
color: #999999;
line-height: 48rpx;
text-align: center;
}
.type-tab-item.active {
color: #4d5dfa;
border: 2rpx solid #4d5dfa;
}
/* ========== 核心修复:scroll-view 滚动区域 ========== */
/* 放弃 calc 固定计算,改用 flex 自适应,首屏高度永远正常 */
.record-list {
flex: 1;
height: 0;
overflow-y: auto;
padding-bottom: 40rpx;
}
/* 空状态 */
.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;
}
/* 卡片样式(原有逻辑保留,仅修正冗余 height) */
.record-card {
background-color: #fff;
border-radius: 16rpx;
padding: 34rpx 32rpx;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
}
.card-header {
display: flex;
justify-content: flex-start;
align-items: center;
margin-bottom: 20rpx;
}
.card-title {
margin-right: 20rpx;
font-size: 32rpx;
color: #222222;
line-height: 40rpx;
}
/* 状态标签 */
.status-tag {
width: 82rpx;
height: 30rpx;
border-radius: 15rpx;
font-size: 20rpx;
color: #ffffff;
line-height: 30rpx;
text-align: center;
}
.status-tag.pending {
background-color: #e34d59;
}
.status-tag.processing {
background-color: #09c2bd;
}
.status-tag.completed {
background-color: #4d5dfa;
}
/* 类型标签组 */
.tag-group {
display: flex;
margin-bottom: 20rpx;
}
.tag-group > .tag-item:not(:last-child) {
margin-right: 20rpx;
}
.tag-item {
height: 42rpx;
padding: 0 10rpx;
border-radius: 8rpx;
border: 1rpx solid #999999;
font-size: 24rpx;
color: #999999;
line-height: 42rpx;
text-align: center;
}
/* 内容 */
.card-content {
margin-bottom: 20rpx;
letter-spacing: 2rpx;
font-size: 28rpx;
color: #666666;
line-height: 40rpx;
}
/* 图片区域 */
.card-image {
display: grid;
grid-template-columns: repeat(3, 1fr);
min-height: 104rpx;
margin-bottom: 20rpx;
}
.card-image > .images:not(:last-child) {
margin-right: 20rpx;
}
.images {
width: 186rpx;
height: 104rpx;
}
/* 底部信息 */
.card-footer {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 28rpx;
color: #999;
}
.create-time,
.repairman {
font-size: 28rpx;
color: #999999;
line-height: 40rpx;
}
.share {
width: 127rpx;
height: 44rpx;
background: #4d5dfa;
border-radius: 22rpx;
font-size: 28rpx;
color: #ffffff;
line-height: 44rpx;
text-align: center;
}
</style>