智慧教务系统
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

512 lines
11 KiB

<!--服务列表页面-->
<template>
<view class="container">
<view class="header">
<view class="search-bar">
<view class="search-input">
<input
placeholder="搜索服务..."
v-model="searchText"
@input="handleSearch"
/>
</view>
<view class="filter-btn" @click="showFilter">
<text>筛选</text>
</view>
</view>
</view>
<view class="service-list">
<view class="service-item"
v-for="(service, index) in filteredServiceList"
:key="index"
@click="goToDetail(service)">
<view class="service-header">
<view class="service-title">{{ service.name }}</view>
<view class="service-badge" :class="[
service.status === '正常' ? 'badge-success' : '',
service.status === '即将到期' ? 'badge-warning' : '',
service.status === '已过期' ? 'badge-danger' : '',
!['正常', '即将到期', '已过期'].includes(service.status) ? 'badge-default' : ''
]">
{{ service.status }}
</view>
</view>
<view class="service-content">
<view class="service-meta">
<view class="meta-item">
<text class="meta-label">类型:</text>
<text class="meta-value">{{ service.type }}</text>
</view>
<view class="meta-item">
<text class="meta-label">时长:</text>
<text class="meta-value">{{ service.duration }}</text>
</view>
</view>
<view class="service-desc">{{ service.description }}</view>
<view class="service-footer">
<view class="service-time">
{{ service.startTime }} - {{ service.endTime }}
</view>
<view class="service-action">
<text class="action-text">查看详情</text>
<text class="action-arrow">></text>
</view>
</view>
</view>
</view>
</view>
<view class="empty-state" v-if="filteredServiceList.length === 0">
<image class="empty-icon" src="/static/icon-img/empty.png"></image>
<view class="empty-text">{{ searchText ? '未找到相关服务' : '暂无服务记录' }}</view>
</view>
<!-- 筛选弹窗 -->
<fui-bottom-popup v-model="showFilterPopup" :zIndex="9999">
<view class="filter-popup">
<view class="popup-header">
<view class="popup-title">筛选条件</view>
<view class="popup-close" @click="showFilterPopup = false"></view>
</view>
<view class="filter-content">
<view class="filter-group">
<view class="filter-title">服务状态</view>
<view class="filter-options">
<view
class="filter-option"
:class="{ active: selectedStatus === '' }"
@click="selectedStatus = ''"
>
全部
</view>
<view
class="filter-option"
:class="{ active: selectedStatus === '正常' }"
@click="selectedStatus = '正常'"
>
正常
</view>
<view
class="filter-option"
:class="{ active: selectedStatus === '即将到期' }"
@click="selectedStatus = '即将到期'"
>
即将到期
</view>
<view
class="filter-option"
:class="{ active: selectedStatus === '已过期' }"
@click="selectedStatus = '已过期'"
>
已过期
</view>
</view>
</view>
</view>
<view class="popup-actions">
<view class="btn btn-reset" @click="resetFilter">重置</view>
<view class="btn btn-confirm" @click="applyFilter">确定</view>
</view>
</view>
</fui-bottom-popup>
</view>
</template>
<script>
import apiRoute from '@/api/apiRoute.js';
export default {
data() {
return {
serviceList: [],
filteredServiceList: [],
searchText: '',
showFilterPopup: false,
selectedStatus: ''
}
},
onLoad() {
this.init();
},
methods: {
async init() {
this.getServiceList();
},
// 获取服务列表
async getServiceList() {
try {
// 模拟数据,实际应该调用API
this.serviceList = [
{
id: 1,
name: '专业体能训练服务',
type: '体能训练',
status: '正常',
duration: '3个月',
startTime: '2024-01-01',
endTime: '2024-03-31',
description: '专业的体能训练指导,包含有氧运动、力量训练等综合项目'
},
{
id: 2,
name: '基础动作指导服务',
type: '技术指导',
status: '即将到期',
duration: '1个月',
startTime: '2024-06-01',
endTime: '2024-06-30',
description: '针对基础动作的专业指导和纠正'
},
{
id: 3,
name: '营养咨询服务',
type: '营养指导',
status: '正常',
duration: '6个月',
startTime: '2024-01-15',
endTime: '2024-07-15',
description: '专业营养师提供个性化营养方案和饮食建议'
},
{
id: 4,
name: '康复训练服务',
type: '康复指导',
status: '已过期',
duration: '2个月',
startTime: '2023-10-01',
endTime: '2023-11-30',
description: '运动损伤康复和预防性训练指导'
}
];
this.filteredServiceList = [...this.serviceList];
// 实际API调用示例:
// let res = await apiRoute.getServiceList({});
// if (res.code === 1) {
// this.serviceList = res.data;
// this.filteredServiceList = [...this.serviceList];
// }
} catch (error) {
console.error('获取服务列表失败:', error);
uni.showToast({
title: '获取数据失败',
icon: 'none'
});
}
},
// 搜索处理
handleSearch() {
this.filterServices();
},
// 筛选服务
filterServices() {
let filtered = [...this.serviceList];
// 按搜索文本筛选
if (this.searchText) {
filtered = filtered.filter(service =>
service.name.includes(this.searchText) ||
service.type.includes(this.searchText) ||
service.description.includes(this.searchText)
);
}
// 按状态筛选
if (this.selectedStatus) {
filtered = filtered.filter(service => service.status === this.selectedStatus);
}
this.filteredServiceList = filtered;
},
// 显示筛选
showFilter() {
this.showFilterPopup = true;
},
// 重置筛选
resetFilter() {
this.selectedStatus = '';
this.filterServices();
},
// 应用筛选
applyFilter() {
this.filterServices();
this.showFilterPopup = false;
},
// 跳转到详情页
goToDetail(service) {
this.$navigateTo({
url: `/pages/coach/my/service_detail?id=${service.id}`
});
}
}
}
</script>
<style lang="less" scoped>
.container {
background: #f5f5f5;
min-height: 100vh;
}
.header {
background: white;
padding: 20rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
.search-bar {
display: flex;
gap: 20rpx;
align-items: center;
}
.search-input {
flex: 1;
background: #f5f5f5;
border-radius: 25rpx;
padding: 15rpx 30rpx;
input {
width: 100%;
font-size: 28rpx;
}
}
.filter-btn {
background: #29d3b4;
color: white;
padding: 15rpx 30rpx;
border-radius: 25rpx;
font-size: 28rpx;
}
.service-list {
padding: 20rpx;
display: flex;
flex-direction: column;
gap: 20rpx;
}
.service-item {
background: white;
border-radius: 16rpx;
padding: 30rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
}
.service-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20rpx;
}
.service-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
flex: 1;
margin-right: 20rpx;
}
.service-badge {
padding: 8rpx 16rpx;
border-radius: 20rpx;
font-size: 24rpx;
&.badge-success {
background: #e8f5e8;
color: #52c41a;
}
&.badge-warning {
background: #fff2e8;
color: #fa8c16;
}
&.badge-danger {
background: #fff1f0;
color: #ff4d4f;
}
&.badge-default {
background: #f0f0f0;
color: #666;
}
}
.service-content {
display: flex;
flex-direction: column;
gap: 15rpx;
}
.service-meta {
display: flex;
gap: 30rpx;
}
.meta-item {
display: flex;
align-items: center;
.meta-label {
color: #666;
font-size: 26rpx;
}
.meta-value {
color: #333;
font-size: 26rpx;
}
}
.service-desc {
color: #666;
font-size: 26rpx;
line-height: 1.5;
}
.service-footer {
display: flex;
justify-content: space-between;
align-items: center;
padding-top: 15rpx;
border-top: 1px solid #f0f0f0;
}
.service-time {
color: #999;
font-size: 24rpx;
}
.service-action {
display: flex;
align-items: center;
color: #29d3b4;
font-size: 26rpx;
.action-arrow {
margin-left: 10rpx;
}
}
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 100rpx 0;
.empty-icon {
width: 120rpx;
height: 120rpx;
margin-bottom: 30rpx;
opacity: 0.3;
}
.empty-text {
color: #999;
font-size: 28rpx;
}
}
// 筛选弹窗样式
.filter-popup {
background: white;
border-radius: 20rpx 20rpx 0 0;
max-height: 80vh;
}
.popup-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx;
border-bottom: 1px solid #f0f0f0;
}
.popup-title {
font-size: 32rpx;
font-weight: bold;
}
.popup-close {
font-size: 36rpx;
color: #999;
}
.filter-content {
padding: 30rpx;
}
.filter-group {
margin-bottom: 40rpx;
}
.filter-title {
font-size: 28rpx;
font-weight: bold;
margin-bottom: 20rpx;
color: #333;
}
.filter-options {
display: flex;
flex-wrap: wrap;
gap: 20rpx;
}
.filter-option {
padding: 15rpx 30rpx;
background: #f5f5f5;
border-radius: 25rpx;
font-size: 26rpx;
color: #666;
&.active {
background: #29d3b4;
color: white;
}
}
.popup-actions {
display: flex;
gap: 20rpx;
padding: 30rpx;
border-top: 1px solid #f0f0f0;
}
.btn {
flex: 1;
padding: 20rpx;
border-radius: 12rpx;
text-align: center;
font-size: 28rpx;
&.btn-reset {
background: #f0f0f0;
color: #333;
}
&.btn-confirm {
background: #29d3b4;
color: white;
}
}
</style>