staff/pagesB/questionnaire/list.vue

475 lines
12 KiB
Vue

<template>
<view class="questionnaire-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-flex-center li-mr-200" @click="createQuestionnaire">
<text class="ri-add-line li-text-52"></text>
</view>
</template>
<!-- #endif -->
<!-- #ifndef MP-WEIXIN -->
<template #right>
<view class="li-flex-center li-mr-25" @click="createQuestionnaire">
<text class="ri-add-line li-text-52"></text>
</view>
</template>
<!-- #endif -->
</wd-navbar>
<!-- 导航栏背景 -->
<view class="nav-bg-layer"></view>
<!-- 筛选区域 -->
<view class="filter-section li-w-92% li-mx-auto li-mt-30">
<!-- 问卷状态筛选 -->
<view class="li-flex li-items-center li-flex-wrap">
<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>
<!-- 问卷列表 -->
<view class="li-w-92% li-mx-auto li-mt-30 li-pb-30">
<view v-if="questionnaireList.length > 0">
<view v-for="(item, index) in questionnaireList" :key="index"
class="questionnaire-card li-bg-white li-rd-20 li-p-30 li-mb-20 li-shadow-sm"
@click="toPages({type:'detail', value:item})">
<!-- 问卷标题 -->
<view class="li-flex li-items-center li-justify-between li-pb-20 li-bottom-border2">
<view class="li-flex li-items-center">
<text class="ri-questionnaire-line li-text-40 li-mr-15 li-text-#0070F0"></text>
<text class="li-text-32 li-font-bold">{{item.title}}</text>
</view>
<view class="status-badge" :style="{
backgroundColor: getStatusBgColor(item.status),
color: getStatusColor(item.status)
}">
{{getStatusText(item.status)}}
</view>
</view>
<!-- 问卷信息 -->
<view class="li-mt-20">
<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>
<wd-tag color="#0083ff" bg-color="#d0e8ff">{{item.type}}</wd-tag>
</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.participant_count}}人</text>
</view>
<!-- 修改有效期和操作按钮的布局 -->
<view class="li-flex li-flex-col">
<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.start_time}} ~
{{item.end_time}}</text>
</view>
<view class="li-flex li-items-center li-justify-between" @click.stop>
<view></view>
<view class="li-flex li-items-center ">
<wd-button type="primary" size="small" plain custom-class="action-btn"
@click="handleEdit(item)">编辑</wd-button>
<wd-button type="danger" size="small" plain custom-class="action-btn"
@click="handleDelete(item)">删除</wd-button>
</view>
</view>
</view>
</view>
</view>
</view>
<!-- 空状态 -->
<view v-else class="empty-state li-mt-100">
<image src="https://img.yzcdn.cn/vant/empty-image-default.png" mode="aspectFit" class="empty-image">
</image>
<text class="li-text-28 li-text-#999 li-mt-20">暂无问卷数据</text>
</view>
<!-- 加载状态 -->
<view v-if="loading" class="li-flex-center li-mt-30">
<wd-loading color="#0070F0" />
</view>
<!-- 底部提示 -->
<view v-if="!loading && finished && questionnaireList.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, watch } 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 hasPermission = ref(true); // 实际项目中应该从用户信息或权限系统中获取
// 状态管理
const selectedVillage = ref('1'); // 设置默认选中的小区
const activeStatus = ref('ALL');
const loading = ref(false);
const finished = ref(false);
const page = ref(1);
const pageSize = ref(10);
// 小区列表
const villageList = ref([
{ value: '1', label: '阳光花园小区' },
{ value: '2', label: '翠湖庭院' },
{ value: '3', label: '金色家园' }
]);
// 状态筛选选项
const statusList = ref([
{ label: '全部', value: 'ALL' },
{ label: '未开始', value: 0 },
{ label: '进行中', value: 1 },
{ label: '已结束', value: 2 }
]);
// 模拟问卷列表数据
const questionnaireList = ref([
{
id: 1,
title: '2024年度物业服务满意度调查',
village_name: '阳光花园小区',
type: '满意度调查',
participant_count: 156,
start_time: '2024-06-01',
end_time: '2024-06-30',
status: 1
},
{
id: 2,
title: '小区环境改造意见征集',
village_name: '阳光花园小区',
type: '意见征集',
participant_count: 89,
start_time: '2024-07-01',
end_time: '2024-07-15',
status: 0
},
{
id: 3,
title: '业主委员会换届选举投票',
village_name: '阳光花园小区',
type: '投票选举',
participant_count: 245,
start_time: '2024-05-01',
end_time: '2024-05-15',
status: 2
},
{
id: 3,
title: '业主委员会换届选举投票',
village_name: '阳光花园小区',
type: '投票选举',
participant_count: 245,
start_time: '2024-05-01',
end_time: '2024-05-15',
status: 2
},
{
id: 3,
title: '业主委员会换届选举投票',
village_name: '阳光花园小区',
type: '投票选举',
participant_count: 245,
start_time: '2024-05-01',
end_time: '2024-05-15',
status: 2
}
]);
// 状态颜色配置
const getStatusColor = (status) => {
const colorMap = {
0: '#ff9d00', // 未开始
1: '#0070F0', // 进行中
2: '#999999' // 已结束
};
return colorMap[status] || '#666666';
};
// 状态背景色配置
const getStatusBgColor = (status) => {
const bgColorMap = {
0: '#fff6e9', // 未开始
1: '#e8f4ff', // 进行中
2: '#f5f5f5' // 已结束
};
return bgColorMap[status] || '#f5f5f5';
};
// 状态文字配置
const getStatusText = (status) => {
const textMap = {
0: '未开始',
1: '进行中',
2: '已结束'
};
return textMap[status] || '未知状态';
};
// 处理状态切换
const handleStatusChange = (status) => {
activeStatus.value = status;
resetList();
loadQuestionnaireList();
};
// 重置列表
const resetList = () => {
page.value = 1;
finished.value = false;
questionnaireList.value = [];
};
// 加载问卷列表数据
const loadQuestionnaireList = async () => {
if (loading.value || finished.value) return;
try {
loading.value = true;
// 实际项目中这里应该调用API
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 createQuestionnaire = () => {
uni.navigateTo({
url: '/pagesB/questionnaire/edit'
});
};
// 编辑问卷
const handleEdit = (item) => {
uni.navigateTo({
url: `/pagesB/questionnaire/edit?id=${item.id}`
});
};
// 删除问卷
const handleDelete = (item) => {
uni.showModal({
title: '提示',
content: '确定要删除该问卷吗?',
success: async (res) => {
if (res.confirm) {
Toast.loading('删除中...');
// 实际项目中这里应该调用API
await new Promise(resolve => setTimeout(resolve, 800));
Toast.success('删除成功');
loadQuestionnaireList();
}
}
});
};
// 页面跳转
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/questionnaire/detail?id=${item.value.id}`
});
break;
default:
break;
}
};
// 生命周期钩子
onLoad(() => {
checkRouteStack();
loadQuestionnaireList();
});
// 下拉刷新
onPullDownRefresh(() => {
resetList();
loadQuestionnaireList().then(() => {
uni.stopPullDownRefresh();
});
});
// 上拉加载
onReachBottom(() => {
loadQuestionnaireList();
});
// 监听小区选择变化
watch(selectedVillage, (newVal) => {
resetList();
loadQuestionnaireList();
});
</script>
<style lang="scss">
page {
background-color: #F7F8FA;
}
.questionnaire-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);
}
.filter-section {
border-radius: 20rpx;
padding: 20rpx;
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
}
.status-tag {
padding: 8rpx 24rpx;
border-radius: 30rpx;
font-size: 28rpx;
color: #666;
background: #f5f5f5;
margin-right: 16rpx;
margin-bottom: 16rpx;
transition: all 0.3s;
}
.status-tag.active {
color: #0070F0;
background: rgba(0, 112, 240, 0.1);
font-weight: 500;
}
.questionnaire-card {
transition: all 0.3s;
&:active {
transform: scale(0.98);
opacity: 0.9;
}
.status-badge {
padding: 4rpx 20rpx;
border-radius: 20rpx;
font-size: 24rpx;
}
}
.li-bottom-border2 {
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
}
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.empty-image {
width: 240rpx;
height: 240rpx;
}
}
.action-btn {
width: 100rpx !important;
margin-left: 15rpx !important;
}
::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;
}
::v-deep .wd-select {
background-color: transparent !important;
margin-bottom: 0 !important;
.wd-select__value {
color: #333 !important;
}
.wd-select__label {
margin-right: 20rpx !important;
}
}
::v-deep .wd-select__right-icon {
color: #666 !important;
}
</style>