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
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>
|