451 lines
12 KiB
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> |