..
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user