staff/pagesB/complaint/index.vue

451 lines
12 KiB
Vue

<template>
<view class="complaint-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>
</wd-navbar>
<!-- 导航栏背景 -->
<view class="nav-bg-layer"></view>
<!-- 搜索栏 -->
<view class="li-w-90% li-mx-auto li-mt-30">
<wd-search placeholderStyle="color:#d9d9d9" v-model="searchText" placeholder="搜索投诉内容/编号" hide-cancel
placeholder-left @search="handleSearch"></wd-search>
</view>
<!-- 状态筛选 -->
<view class="li-flex li-items-center li-mx-auto li-w-96% li-mt-20 li-pl-30">
<text v-for="(item, index) in statusList" :key="index"
:class="activeStatus === item.value ? 'status-tag active' : 'status-tag'"
@click="handleStatusChange(item.value)">
{{item.label}}
</text>
</view>
<!-- 投诉列表 -->
<view class="li-w-92% li-mx-auto li-mt-30 li-pb-30">
<view v-if="complaintList.length > 0">
<view v-for="(item, index) in complaintList" :key="index" @click="toPages({type:'detail', value:item})"
class="complaint-card li-bg-white li-rd-20 li-px-30 li-py-25 li-mb-20 li-shadow-sm">
<!-- 投诉头部 -->
<view
class="complaint-header li-flex li-items-center li-justify-between li-pb-15 li-bottom-border2">
<view class="li-flex li-items-center">
<text class="ri-error-warning-line li-text-34 li-mr-10 li-text-#999999"></text>
<text class="li-text-30">{{item.complaint_no}}</text>
</view>
<view class="status-badge" :style="{
backgroundColor: getStatusBgColor(item.status),
color: getStatusColor(item.status)
}">
{{getStatusText(item.status)}}
</view>
</view>
<!-- 投诉内容 -->
<view class="complaint-content li-mt-20">
<view class="li-flex li-items-start li-mb-15">
<text class="content-label li-text-28 li-text-#9a9a9a li-w-160">投诉内容</text>
<text
class="content-text li-text-28 li-text-#333 li-flex-1 li-line-clamp-2">{{item.content}}</text>
</view>
<view class="li-flex li-items-center li-mb-15">
<text class="content-label li-text-28 li-text-#9a9a9a li-w-160">小区信息</text>
<text class="content-text li-text-28 li-text-#333">{{item.village_name}}</text>
</view>
<view class="li-flex li-items-center li-mb-15">
<text class="content-label li-text-28 li-text-#9a9a9a li-w-160">投诉人</text>
<text class="content-text li-text-28 li-text-#333">{{item.user_name}}</text>
<text class="ri-phone-line li-text-28 li-text-#0070F0 li-ml-20"
@click.stop="callPhone(item.user_mobile)"></text>
</view>
<view class="li-flex li-items-center">
<text class="content-label li-text-28 li-text-#9a9a9a li-w-160">提交时间</text>
<text class="content-text li-text-28 li-text-#999">{{item.create_time}}</text>
</view>
<!-- 标签 -->
<view class="li-flex li-items-center li-flex-wrap li-mt-15"
v-if="item.tags && item.tags.length">
<wd-tag v-for="(tag, idx) in item.tags" :key="idx" color="#0083ff" bg-color="#d0e8ff"
custom-class="li-mr-10 li-mb-10">
{{tag}}
</wd-tag>
</view>
<!-- 附件图片预览 -->
<view class="li-flex li-mt-15" v-if="item.images && item.images.length">
<image v-for="(img, imgIdx) in item.images.slice(0, 3)" :key="imgIdx" :src="img"
mode="aspectFill" class="preview-image li-mr-10"
@click.stop="previewImage(item.images, imgIdx)">
</image>
<text v-if="item.images.length > 3" class="more-image-text li-text-28 li-text-#0070F0">
+{{item.images.length - 3}}
</text>
</view>
</view>
</view>
</view>
<!-- 空状态 -->
<view v-else class="li-mt-100">
<wd-status-tip :image="uni.$globalData?.RESOURCE_URL+'tip/search.png'" tip="暂无投诉记录" />
</view>
<!-- 加载状态 -->
<view v-if="loading" class="li-flex-center li-mt-30">
<wd-loading color="#0070F0" />
</view>
<!-- 底部提示 -->
<view v-if="!loading && finished && complaintList.length > 0"
class="li-text-center li-text-26 li-text-#999 li-py-20">
-- 没有更多数据了 --
</view>
</view>
</view>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue';
import { onLoad, onPullDownRefresh, onReachBottom } from '@dcloudio/uni-app';
import { useNavigation } from '@/hooks/useNavigation';
import { useToast } from '@/uni_modules/wot-design-uni';
const Toast = useToast();
// 使用导航composable
const {
hasMultiplePages,
isTabBarPage,
checkRouteStack
} = useNavigation();
// 状态管理
const searchText = ref('');
const activeStatus = ref('ALL');
const loading = ref(false);
const finished = ref(false);
const page = ref(1);
const pageSize = ref(10);
// 状态筛选选项
const statusList = ref([
{ label: '全部', value: 'ALL' },
{ label: '待处理', value: 0 },
{ label: '处理中', value: 1 },
{ label: '已处理', value: 2 },
{ label: '已关闭', value: 3 }
]);
// 模拟数据 - 实际项目中应该是通过API获取
const complaintList = ref([
// {
// complaint_id: 1,
// complaint_no: 'TS20240607001',
// content: '楼道灯已经坏了三天,晚上上下楼很不方便,希望物业尽快解决!',
// village_name: '阳光花园小区',
// user_name: '张三',
// user_mobile: '13800138000',
// create_time: '2024-06-07 10:23',
// status: 0,
// urgency: 2,
// tags: ['公共设施', '照明'],
// images: [
// 'https://img.yzcdn.cn/vant/cat.jpeg',
// 'https://img.yzcdn.cn/vant/tree.jpeg'
// ]
// },
// {
// complaint_id: 2,
// complaint_no: 'TS20240606001',
// content: '小区北门停车场有人乱停车,导致通道被堵,请物业及时处理。',
// village_name: '阳光花园小区',
// user_name: '李四',
// user_mobile: '13900139000',
// create_time: '2024-06-06 16:45',
// status: 1,
// urgency: 1,
// tags: ['停车管理', '安全隐患'],
// images: [
// 'https://img.yzcdn.cn/vant/cat.jpeg',
// 'https://img.yzcdn.cn/vant/cat.jpeg',
// 'https://img.yzcdn.cn/vant/cat.jpeg',
// 'https://img.yzcdn.cn/vant/tree.jpeg'
// ]
// },
// {
// complaint_id: 3,
// complaint_no: 'TS20240605001',
// content: '小区垃圾分类做得不到位,希望加强宣传和管理。',
// village_name: '阳光花园小区',
// user_name: '王五',
// user_mobile: '13700137000',
// create_time: '2024-06-05 09:12',
// status: 2,
// urgency: 1,
// tags: ['环境卫生', '垃圾分类'],
// images: []
// }
]);
// 状态颜色配置
const getStatusColor = (status) => {
const colorMap = {
0: '#ff9d00', // 待处理
1: '#37A5FF', // 处理中
2: '#00b42a', // 已处理
3: '#999999' // 已关闭
};
return colorMap[status] || '#666666';
};
// 状态背景色配置
const getStatusBgColor = (status) => {
const bgColorMap = {
0: '#fff6e9', // 待处理
1: '#e8f4ff', // 处理中
2: '#e8ffea', // 已处理
3: '#f5f5f5' // 已关闭
};
return bgColorMap[status] || '#f5f5f5';
};
// 状态文字配置
const getStatusText = (status) => {
const textMap = {
0: '待处理',
1: '处理中',
2: '已处理',
3: '已关闭'
};
return textMap[status] || '未知状态';
};
// 处理状态切换
const handleStatusChange = (status) => {
activeStatus.value = status;
resetList();
loadComplaintList();
};
// 搜索处理
const handleSearch = () => {
resetList();
loadComplaintList();
};
// 重置列表
const resetList = () => {
page.value = 1;
finished.value = false;
complaintList.value = [];
};
// 加载投诉列表数据
const loadComplaintList = async () => {
if (loading.value || finished.value) return;
try {
// loading.value = true;
// 这里应该调用实际的API接口获取数据
// const params = {
// page: page.value,
// page_size: pageSize.value,
// keyword: searchText.value,
// status: activeStatus.value !== 'ALL' ? activeStatus.value : ''
// };
// const res = await getComplaintList(params);
// 模拟加载延迟
await new Promise(resolve => setTimeout(resolve, 1000));
// 模拟数据加载完成的情况
if (page.value > 1) {
// finished.value = true;
} else {
page.value++;
}
loading.value = false;
} catch (error) {
console.error('加载投诉列表失败', error);
Toast.fail('加载失败,请重试');
loading.value = false;
}
};
// 页面跳转
const toPages = (item) => {
switch (item.type) {
case 'nav':
uni.navigateBack({
delta: 1
});
break;
case 'home':
uni.switchTab({
url: '/pages/index/index'
});
break;
case 'detail':
uni.navigateTo({
url: `/pagesB/complaint/detail?id=${item.value.complaint_id}`
});
break;
default:
break;
}
};
// 拨打电话
const callPhone = (phone) => {
uni.makePhoneCall({
phoneNumber: phone,
success: () => {
console.log('拨打电话成功');
},
fail: (err) => {
console.log('拨打电话失败', err);
}
});
};
// 预览图片
const previewImage = (images, current) => {
uni.previewImage({
urls: images,
current: images[current]
});
};
// 生命周期钩子
onLoad(() => {
checkRouteStack();
loadComplaintList();
});
// 下拉刷新
onPullDownRefresh(() => {
resetList();
loadComplaintList().then(() => {
uni.stopPullDownRefresh();
});
});
// 上拉加载
onReachBottom(() => {
loadComplaintList();
});
</script>
<style lang="scss">
page {
background-color: #F7F8FA;
}
.complaint-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: -1;
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
}
.status-tag {
padding: 8rpx 24rpx;
border-radius: 30rpx;
font-size: 28rpx;
color: #666;
background: #f5f5f5;
margin-right: 16rpx;
transition: all 0.3s;
}
.status-tag.active {
color: #0070F0;
background: rgba(0, 112, 240, 0.1);
font-weight: 500;
}
.complaint-card {
transition: all 0.3s;
&:active {
transform: scale(0.98);
opacity: 0.9;
}
}
.complaint-header {
.status-badge {
padding: 4rpx 20rpx;
border-radius: 20rpx;
font-size: 24rpx;
}
}
.li-bottom-border2 {
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
}
.preview-image {
width: 120rpx;
height: 120rpx;
border-radius: 8rpx;
object-fit: cover;
}
.more-image-text {
display: flex;
align-items: center;
justify-content: center;
width: 120rpx;
height: 120rpx;
background-color: #f8f8f8;
border-radius: 8rpx;
}
/* 覆盖组件样式 */
::v-deep .wd-search {
background-color: transparent !important;
padding: 0 !important;
border-radius: 10rpx !important;
}
::v-deep .wd-search__block {
background-color: rgba(255, 255, 255, 0.8) !important;
padding: 8rpx !important;
border-radius: 10rpx !important;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.015);
}
::v-deep .wd-status-tip__text {
margin-top: 30rpx !important;
color: #999 !important;
}
</style>