423 lines
8.7 KiB
Vue
423 lines
8.7 KiB
Vue
<template>
|
|
<view class="project-list-container">
|
|
<!-- 页面标题区域 -->
|
|
<view class="header-section">
|
|
<view class="header-title" style="display: flex; align-items: center; justify-content: space-between;">
|
|
<text class="title">项目列表</text>
|
|
<text class="subtitle">{{ projects.length }}个项目</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 项目列表 -->
|
|
<view class="projects-section">
|
|
<view v-if="projects.length === 0" class="empty-state">
|
|
<view class="empty-icon">
|
|
<u-icon name="list" size="64" color="#ddd"></u-icon>
|
|
</view>
|
|
<text class="empty-text">暂无项目</text>
|
|
<text class="empty-desc">点击下方按钮创建第一个项目</text>
|
|
</view>
|
|
|
|
<view v-else class="projects-list">
|
|
<view v-for="(project, index) in projects" :key="project.planId" class="project-card"
|
|
@click="viewProjectDetail(project)">
|
|
<view class="project-delete" @click.stop="deleteProject(project, index)">
|
|
<u-icon name="trash" size="18" color="#ff4d4f"></u-icon>
|
|
</view>
|
|
|
|
<view class="project-info">
|
|
<view class="project-title-row">
|
|
<text class="project-name">{{ project.name }}</text>
|
|
<view class="project-mode" :class="getModeClass(project.mode)">
|
|
<text class="mode-text">{{ project.mode }}</text>
|
|
</view>
|
|
</view>
|
|
<view class="project-stats">
|
|
<view class="stat-badge">
|
|
<u-icon name="account" size="14" color="#1890ff"></u-icon>
|
|
<text class="badge-text">{{ project.users.length }}位学员</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="project-footer">
|
|
<view class="">
|
|
|
|
</view>
|
|
<view class="project-time">
|
|
<u-icon name="clock" size="14" color="#999"></u-icon>
|
|
<text class="time-text">{{ Service.formatDate(project.addTime,1) }}</text>
|
|
</view>
|
|
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { onShow, onLoad, onReachBottom } from "@dcloudio/uni-app"
|
|
import { Service } from '@/Service/Service'
|
|
import { PlanService } from '@/Service/swimming/PlanService'
|
|
import { ref } from "vue"
|
|
|
|
|
|
// 分页相关
|
|
let page = ref(1)
|
|
let status = ref('loadmore')
|
|
|
|
// 项目列表数据
|
|
const projects = ref<Array<any>>([])
|
|
|
|
onLoad(() => {
|
|
getData()
|
|
})
|
|
|
|
onReachBottom(() => {
|
|
getList()
|
|
})
|
|
|
|
// 获取模式对应的样式类
|
|
const getModeClass = (mode : string) : string => {
|
|
const classMap : Record<string, string> = {
|
|
'计时': 'mode-timing',
|
|
'包干': 'mode-package',
|
|
'分段': 'mode-segment'
|
|
}
|
|
return classMap[mode] || ''
|
|
}
|
|
|
|
// 查看项目详情
|
|
const viewProjectDetail = (project : any) => {
|
|
Service.Msg(`查看「${project.name}」详情`)
|
|
}
|
|
|
|
// 删除项目
|
|
const deleteProject = (project : any, index : number) => {
|
|
Service.Confirm(`确定要删除「${project.name}」吗?`, () => {
|
|
PlanService.DeletePlan(project.planId).then(res => {
|
|
if (res.code == 0) {
|
|
getData()
|
|
Service.Msg('删除成功')
|
|
} else {
|
|
Service.Msg(res.msg)
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
// 获取项目列表数据
|
|
const getData = () => {
|
|
projects.value = []
|
|
page.value = 1
|
|
status.value = 'loadmore'
|
|
getList()
|
|
}
|
|
|
|
// 获取项目列表
|
|
const getList = () => {
|
|
if (status.value == 'loading' || status.value == 'nomore') {
|
|
return
|
|
}
|
|
status.value = 'loading'
|
|
PlanService.GetPlanList( '', page.value.toString()).then(res => {
|
|
if (res.code == 0) {
|
|
projects.value = [...projects.value, ...res.data]
|
|
status.value = res.data.length == 10 ? 'loadmore' : 'nomore'
|
|
page.value++
|
|
} else {
|
|
Service.Msg(res.msg)
|
|
}
|
|
})
|
|
}
|
|
|
|
// 添加项目
|
|
const addProject = () => {
|
|
Service.GoPage('/pages/userFunc/setCourse')
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
page {
|
|
background-color: #f5f5f5;
|
|
}
|
|
|
|
.project-list-container {
|
|
min-height: 100vh;
|
|
padding: 20rpx;
|
|
padding-bottom: 180rpx;
|
|
}
|
|
|
|
/* 页面标题区域 */
|
|
.header-section {
|
|
margin-bottom: 24rpx;
|
|
|
|
.header-title {
|
|
.title {
|
|
font-size: 36rpx;
|
|
font-weight: 700;
|
|
color: #333;
|
|
display: block;
|
|
margin-bottom: 8rpx;
|
|
}
|
|
|
|
.subtitle {
|
|
font-size: 24rpx;
|
|
color: #999;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* 项目列表区域 */
|
|
.projects-section {
|
|
.section-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 20rpx;
|
|
|
|
.section-title {
|
|
font-size: 30rpx;
|
|
font-weight: 600;
|
|
color: #333;
|
|
}
|
|
|
|
.section-count {
|
|
font-size: 24rpx;
|
|
color: #999;
|
|
background-color: #f5f5f5;
|
|
padding: 6rpx 16rpx;
|
|
border-radius: 16rpx;
|
|
}
|
|
}
|
|
|
|
.empty-state {
|
|
background-color: #fff;
|
|
border-radius: 24rpx;
|
|
padding: 100rpx 40rpx;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
|
|
|
|
.empty-icon {
|
|
margin-bottom: 24rpx;
|
|
opacity: 0.6;
|
|
}
|
|
|
|
.empty-text {
|
|
font-size: 30rpx;
|
|
font-weight: 600;
|
|
color: #666;
|
|
margin-bottom: 12rpx;
|
|
}
|
|
|
|
.empty-desc {
|
|
font-size: 24rpx;
|
|
color: #999;
|
|
}
|
|
}
|
|
}
|
|
|
|
.projects-list {
|
|
.project-card {
|
|
background-color: #fff;
|
|
border-radius: 20rpx;
|
|
padding: 28rpx 24rpx;
|
|
margin-bottom: 16rpx;
|
|
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
|
|
transition: all 0.3s ease;
|
|
position: relative;
|
|
overflow: hidden;
|
|
|
|
&::before {
|
|
content: '';
|
|
position: absolute;
|
|
left: 0;
|
|
top: 0;
|
|
bottom: 0;
|
|
width: 6rpx;
|
|
background: linear-gradient(180deg, #1890ff 0%, #096dd9 100%);
|
|
opacity: 0;
|
|
transition: opacity 0.3s ease;
|
|
}
|
|
|
|
&:active {
|
|
transform: scale(0.98);
|
|
box-shadow: 0 1rpx 6rpx rgba(0, 0, 0, 0.04);
|
|
|
|
&::before {
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
.project-delete {
|
|
position: absolute;
|
|
top: 20rpx;
|
|
right: 20rpx;
|
|
width: 44rpx;
|
|
height: 44rpx;
|
|
border-radius: 50%;
|
|
background: linear-gradient(135deg, #fff1f0 0%, #ffccc7 100%);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
box-shadow: 0 4rpx 12rpx rgba(255, 77, 79.3);
|
|
transition: all 0.3s ease;
|
|
z-index: 2;
|
|
|
|
&:active {
|
|
transform: scale(0.9);
|
|
background: linear-gradient(135deg, #ffccc7 0%, #ffa39e 100%);
|
|
}
|
|
}
|
|
|
|
.project-info {
|
|
padding-right: 80rpx;
|
|
|
|
.project-title-row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12rpx;
|
|
margin-bottom: 16rpx;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.project-name {
|
|
font-size: 32rpx;
|
|
font-weight: 600;
|
|
color: #333;
|
|
}
|
|
|
|
.project-mode {
|
|
padding: 6rpx 14rpx;
|
|
border-radius: 12rpx;
|
|
font-size: 22rpx;
|
|
font-weight: 600;
|
|
flex-shrink: 0;
|
|
|
|
&.mode-timing {
|
|
background-color: #e6f7ff;
|
|
color: #1890ff;
|
|
}
|
|
|
|
&.mode-package {
|
|
background-color: #fff7e6;
|
|
color: #faad14;
|
|
}
|
|
|
|
&.mode-segment {
|
|
background-color: #f6ffed;
|
|
color: #52c41a;
|
|
}
|
|
|
|
.mode-text {
|
|
font-size: 22rpx;
|
|
font-weight: 600;
|
|
}
|
|
}
|
|
|
|
.project-stats {
|
|
display: flex;
|
|
gap: 12rpx;
|
|
flex-wrap: wrap;
|
|
|
|
.stat-badge {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6rpx;
|
|
padding: 8rpx 14rpx;
|
|
background-color: #f5f5f5;
|
|
border-radius: 12rpx;
|
|
|
|
&.record-badge {
|
|
background-color: #f6ffed;
|
|
}
|
|
|
|
.badge-text {
|
|
font-size: 22rpx;
|
|
color: #666;
|
|
font-weight: 500;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.project-footer {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
margin-top: 16rpx;
|
|
padding-top: 16rpx;
|
|
border-top: 1rpx solid #f0f0f0;
|
|
|
|
.project-time {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6rpx;
|
|
|
|
.time-text {
|
|
font-size: 22rpx;
|
|
color: #999;
|
|
}
|
|
}
|
|
|
|
.project-arrow {
|
|
width: 48rpx;
|
|
height: 48rpx;
|
|
border-radius: 50%;
|
|
background-color: rgba(0, 0, 0, 0.04);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
transition: all 0.3s ease;
|
|
}
|
|
}
|
|
|
|
&:active .project-arrow {
|
|
transform: translateX(6rpx);
|
|
background-color: rgba(24, 144, 255, 0.1);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* 底部添加按钮 */
|
|
.bottom-add-btn {
|
|
position: fixed;
|
|
bottom: 0;
|
|
left: 0;
|
|
right: 0;
|
|
background-color: #fff;
|
|
padding: 20rpx 30rpx;
|
|
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
|
|
border-top: 1rpx solid #f0f0f0;
|
|
box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.08);
|
|
z-index: 100;
|
|
|
|
.add-btn {
|
|
width: 100%;
|
|
height: 96rpx;
|
|
background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%);
|
|
border-radius: 20rpx;
|
|
border: none;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 12rpx;
|
|
box-shadow: 0 8rpx 24rpx rgba(24, 144, 255, 0.4);
|
|
transition: all 0.3s ease;
|
|
|
|
&:active {
|
|
transform: scale(0.97);
|
|
box-shadow: 0 4rpx 12rpx rgba(24, 144, 255, 0.3);
|
|
}
|
|
|
|
.btn-text {
|
|
font-size: 32rpx;
|
|
color: #fff;
|
|
font-weight: 700;
|
|
}
|
|
}
|
|
}
|
|
</style> |