This commit is contained in:
那些花儿
2025-04-28 15:32:41 +08:00
parent cb3bcb57bc
commit 12c3afb4a6
42 changed files with 3272 additions and 1627 deletions
@@ -0,0 +1,442 @@
<template>
<view class="page-container">
<t-dropdown-menu class="top-dropdown">
<t-dropdown-item :options="actOptions" :value="selectActId"/>
</t-dropdown-menu>
<view class="content-container">
<view class="page-header">
<text class="page-title">团队报名</text>
<text class="page-subtitle">选择您感兴趣的项目进行报名</text>
</view>
<!-- 项目列表 -->
<view class="project-cards">
<view
v-for="project in itemOptions"
:key="project.id"
class="project-card"
:class="{'project-card--registered': registrationStatus[project.id]?.length}"
@click="selectProject(project.id)"
>
<view class="project-card__content">
<view class="project-card__title">{{ project.name }}</view>
<view class="project-card__desc">{{ project.description }}</view>
</view>
<view class="project-card__status">
<t-tag v-if="registrationStatus[project.id]?.length" theme="success" variant="light-outline">
已报名 {{ registrationStatus[project.id]?.length }}人
</t-tag>
<view v-else class="project-card__action">
<t-icon name="chevron-right" color="#999"/>
</view>
</view>
<view v-if="registrationStatus[project.id]?.length" class="project-card__checkmark">
<t-icon name="check" color="#52c41a"/>
</view>
</view>
</view>
</view>
<t-popup v-model:visible="showMemberPicker" placement="bottom" destroy-on-close>
<view class="member-picker">
<view class="picker-header">
<text class="picker-title">选择项目参与成员</text>
<t-icon name="close" @click="showMemberPicker = false"/>
</view>
<view class="picker-subtitle" v-if="selectedItemId">
{{ itemOptions.find(p => p.id === selectedItemId)?.name }}
</view>
<view class="member-list">
<t-checkbox-group v-model="selectedMemberIds">
<view
v-for="member in teamMembers"
:key="member.id"
>
<t-checkbox
:value="member.id"
:label="member.userName"
:content="member.unitName"
:disabled="registrationStatus[selectedItemId]?.includes(member.id)"
icon-size="20px"
/>
<view class="member-status" v-if="registrationStatus[selectedItemId]?.includes(member.id)">
已报名
</view>
</view>
</t-checkbox-group>
</view>
<view class="picker-footer">
<t-button block theme="primary" @click="submitRegistration" :disabled="!selectedMemberIds.length">
确认报名 ({{ selectedMemberIds.length }}人)
</t-button>
</view>
</view>
</t-popup>
</view>
</template>
<script setup>
import {ref, onMounted, computed} from 'vue';
import {useRequest} from '@/utils/request';
import {Dialog, Toast} from 'tdesign-mobile-vue';
import {onLoad} from '@dcloudio/uni-app';
const request = useRequest();
// 活动数据
const actOptions = ref([])
// 选中的活动ID
const selectActId = ref(null);
// 项目列表数据
const itemOptions = ref([
{
id: 1,
name: '篮球比赛',
description: '3v3篮球友谊赛'
},
{
id: 2,
name: '足球比赛',
description: '5人制足球赛'
},
{
id: 3,
name: '羽毛球比赛',
description: '双打友谊赛'
}
]);
// 选中的项目ID
const selectedItemId = ref(null);
// 团队成员列表
const teamMembers = ref([]);
onLoad((option) => {
if (option.id) {
selectActId.value = option.id;
}
});
onMounted(async () => {
await listActs()
await listItems();
listTeamUser()
// fetchRegistrationStatus();
});
// 选中的团队成员
const selectedMemberIds = ref([]);
// 成员选择弹窗显示状态
const showMemberPicker = ref(false);
// 当前项目的报名状态
const registrationStatus = ref({});
// 获取活动列表
async function listActs() {
try {
const {data, code, msg} = await request.get('/client/activity/list-mine-act')
if (code === 0) {
actOptions.value = data && data.map(item => {
return {
value: item.id,
label: item.title
}
})
if(selectActId.value === null && data.length){
selectActId.value = data[0].id
}
} else {
Toast.error(msg)
}
} catch (e) {
console.error(e)
Toast.error(e.message)
}
}
// 获取项目列表
async function listItems() {
try {
const {code, data, msg} = await request.get('/client/item/list/' + selectActId.value)
if (code === 0) {
itemOptions.value = data;
}
} catch (e) {
console.error(e)
}
}
// 获取团队成员
async function listTeamUser(){
try {
const {code, data, msg} = await request.get('/client/item/list-team-user/'+selectActId.value)
if (code === 0) {
teamMembers.value = data;
}else{
Toast.error(msg)
}
}catch (e){
Toast.error(msg)
console.error(e)
}
}
// 获取报名状态 - 使用静态数据
const fetchRegistrationStatus = async () => {
};
// 选择项目
const selectProject = (projectId) => {
selectedItemId.value = projectId;
selectedMemberIds.value = [];
showMemberPicker.value = true;
};
// 提交报名 - 使用静态数据模拟
const submitRegistration = async () => {
if (!selectedMemberIds.value.length) {
Toast.warning('请选择团队成员');
return;
}
try {
console.log(selectedMemberIds.value)
console.log(selectedItemId.value)
console.log(selectActId.value)
const teamUser = teamMembers.value.filter(v=>selectedMemberIds.value.includes(v.id))
// const {code, msg} = await request.post('/client/item/sign-up', {
// activityId: selectActId.value,
// itemId: selectedItemId.value,
// userList: selectedMemberIds.value
// })
// if (code === 0) {
// Toast.success('报名成功')
// showMemberPicker.value = false;
// selectedMemberIds.value = []
// }else{
// Toast.error(msg)
// }
}catch (e){
Toast.error(e.message)
console.error(e)
}
};
</script>
<style scoped lang="less">
.top-dropdown {
flex-shrink: 0;
z-index: 10;
position: relative;
}
.content-container {
padding: 15px;
z-index: 9;
position: relative;
}
.page-header {
margin-bottom: 24px;
padding: 0 4px;
.page-title {
font-size: 24px;
font-weight: 600;
color: #333;
margin-bottom: 8px;
display: block;
}
.page-subtitle {
font-size: 14px;
color: #999;
display: block;
}
}
.project-cards {
display: flex;
flex-direction: column;
gap: 16px;
margin-bottom: 24px;
}
.project-card {
background-color: #fff;
border-radius: 12px;
padding: 16px;
display: flex;
align-items: center;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
transition: all 0.3s ease;
position: relative;
overflow: hidden;
&:active {
transform: scale(0.98);
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
}
&--registered {
background: #fff;
.project-card__title,
.project-card__desc {
color: #333;
}
}
&__content {
flex: 1;
min-width: 0;
}
&__title {
font-size: 16px;
font-weight: 500;
color: #333;
margin-bottom: 4px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
&__desc {
font-size: 14px;
color: #666;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
&__status {
margin-left: 12px;
}
&__action {
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
}
&__checkmark {
position: absolute;
top: 16px;
right: 16px;
color: #52c41a;
}
}
.member-picker {
background-color: #fff;
border-radius: 16px 16px 0 0;
padding: 20px;
.picker-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
.picker-title {
font-size: 18px;
font-weight: 600;
color: #333;
}
}
.picker-subtitle {
font-size: 14px;
color: #ff5f5c;
margin-bottom: 20px;
padding-bottom: 12px;
border-bottom: 1px solid #f0f0f0;
}
.member-list {
max-height: 50vh;
overflow-y: auto;
margin-bottom: 20px;
padding: 0 4px;
}
.member-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 0;
border-bottom: 1px solid #f5f5f5;
&:last-child {
border-bottom: none;
}
&--disabled {
opacity: 0.7;
}
.member-status {
font-size: 12px;
color: #52c41a;
}
:deep(.t-checkbox) {
margin: 0;
}
}
.picker-footer {
padding-top: 12px;
}
}
// 添加动画效果
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.project-card {
animation: fadeIn 0.3s ease-out;
animation-fill-mode: both;
}
.project-card:nth-child(1) {
animation-delay: 0.05s;
}
.project-card:nth-child(2) {
animation-delay: 0.1s;
}
.project-card:nth-child(3) {
animation-delay: 0.15s;
}
.project-card:nth-child(4) {
animation-delay: 0.2s;
}
.project-card:nth-child(5) {
animation-delay: 0.25s;
}
</style>