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
+317 -221
View File
@@ -1,112 +1,116 @@
<template>
<view class="page-container">
<t-dropdown-menu @menu-opened="handleMenuOpened" @menu-closed="handleMenuClosed">
<t-dropdown-item :options="actOptions" :value="pageForm.actId" @change="actChange" />
</t-dropdown-menu>
<view class="page-container" :style="{ backgroundColor: '#f7f7f9' }">
<t-sticky>
<t-dropdown-menu class="top-dropdown-menu">
<t-dropdown-item :options="actOptions" :value="pageForm.actId" @change="actChange" />
</t-dropdown-menu>
</t-sticky>
<!-- 团队卡片 -->
<div class="content-area">
<!-- 团队信息卡片 -->
<div class="team-card">
<div class="team-banner">
<div class="team-header">
<div class="team-logo">
<i class="bi bi-people-fill" v-if="!team.logoUrl"></i>
<img :src="team.logoUrl" alt="团队logo" v-if="team.logoUrl">
</div>
<div class="team-info">
<div class="team-basic-info">
<div class="team-name">{{ team.name }}</div>
<div class="team-meta">创建于 {{ team.createdDate }}</div>
<div class="team-id">团队ID: {{ team.id }}</div>
</div>
<div class="event-name">{{ team.eventName }}</div>
</div>
<div class="team-detail">
<div class="team-stat-row">
<div class="team-stat-item">
<div class="team-stat-value">{{ team.memberCount }}</div>
<div class="team-stat-label">团队成员</div>
</div>
<div class="team-stat-item">
<div class="team-stat-value">{{ team.rank }}</div>
<div class="team-stat-label">当前排名</div>
</div>
<div class="team-stat-item">
<div class="team-stat-value">{{ team.score }}</div>
<div class="team-stat-label">团队积分</div>
<div class="team-stats">
<div class="stat-item">
<div class="stat-icon"><i class="bi bi-people"></i></div>
<div class="stat-content">
<div class="stat-value">{{ team.memberCount }}</div>
<div class="stat-label">成员</div>
</div>
</div>
<div style="font-size: 14px; color: #666; line-height: 1.6;">
{{ team.description }}
<div class="stat-divider"></div>
<div class="stat-item">
<div class="stat-icon"><i class="bi bi-trophy"></i></div>
<div class="stat-content">
<div class="stat-value">{{ team.rank }}</div>
<div class="stat-label">排名</div>
</div>
</div>
</div>
<div v-if="team.description" class="team-desc-toggle" @click="showDesc = !showDesc">
<span>团队介绍</span>
<i class="bi" :class="showDesc ? 'bi-chevron-up' : 'bi-chevron-down'"></i>
</div>
<div v-if="showDesc && team.description" class="team-desc">
<i class="bi bi-quote"></i>
{{ team.description }}
</div>
</div>
<!-- 团队成员 -->
<div class="team-section">
<!-- 项目报名按钮 -->
<div class="action-section">
<t-button block theme="danger" size="large" class="register-btn" @click="goToEventRegistration">
参与项目报名
</t-button>
</div>
<!-- 团队成员列表 -->
<div class="members-section">
<div class="section-header">
<div class="section-title">
<i class="bi bi-people"></i>团队成员
<i class="bi bi-people-fill"></i>
团队成员
</div>
<div class="section-badge">{{ team.memberCount }}</div>
</div>
<div class="member-list">
<div class="member-item" v-for="member in team.members" :key="member.id">
<div class="member-avatar">
<img :src="member.avatar" :alt="member.name" onerror="this.src='data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iI2YwZjBmMCIvPjx0ZXh0IHg9IjUwJSIgeT0iNTAlIiBmb250LXNpemU9IjIwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBhbGlnbm1lbnQtYmFzZWxpbmU9Im1pZGRsZSIgZm9udC1mYW1pbHk9IkFyaWFsLCBzYW5zLXNlcmlmIiBmaWxsPSIjNTU1Ij57eyBtZW1iZXIubmFtZS5jaGFyQXQoMCkgfX08L3RleHQ+PC9zdmc+'">
<div class="member-grid">
<div class="member-grid-item" v-for="member in team.members" :key="member.id">
<div class="member-name">
{{ member.name }}
<t-tag theme="danger" size="small" v-if="member.role === 'leader'">队长</t-tag>
</div>
<div class="member-info">
<div class="member-name">
{{ member.name }}
<span class="member-role" v-if="member.role === 'leader'">队长</span>
</div>
<div class="member-detail">
<div class="member-detail-item">
<i class="bi bi-gender-ambiguous"></i>
<span>{{ member.gender }}</span>
</div>
<div class="member-detail-item">
<i class="bi bi-building"></i>
<span>{{ member.organization }}</span>
</div>
</div>
</div>
<div class="member-actions">
<i class="bi bi-three-dots-vertical"></i>
<div class="member-details">
<span><i class="bi bi-gender-ambiguous"></i> {{ member.gender }}</span>
<span><i class="bi bi-building"></i> {{ member.organization }}</span>
</div>
</div>
</div>
<!-- 当前角色与申请队长 -->
<div v-if="currentUserRole !== 'leader'">
<div class="role-notice">
<i class="bi bi-info-circle"></i>
您当前是普通成员身份
<div class="role-section">
<div class="role-card" v-if="currentUserRole === 'leader'">
<div class="role-icon">
<i class="bi bi-trophy"></i>
</div>
<div class="role-info">
<div class="role-title">您是队长</div>
<div class="role-desc">拥有团队所有管理权限</div>
</div>
</div>
<div v-else>
<div class="role-card">
<div class="role-icon">
<i class="bi bi-person"></i>
</div>
<div class="role-info">
<div class="role-title">您是普通成员</div>
<div class="role-desc">申请成为队长可获得更多权限</div>
</div>
</div>
<t-button block
class="leader-apply-btn"
theme="danger"
variant="outline"
@click="leaderConfirmVisible = true">
申请成为队长
</t-button>
</div>
<t-button block
theme="primary"
variant="outline"
size="large"
shape="round"
@click="leaderConfirmVisible = true">
<i class="bi bi-award"></i>申请成为队长
</t-button>
</div>
<div class="role-notice" v-else>
<i class="bi bi-check-circle"></i>
您当前是队长身份,拥有团队所有权限
</div>
</div>
<!-- 项目报名按钮 -->
<div class="team-section">
<t-button block
theme="primary"
size="large"
shape="round" @click="goToEventRegistration">
<i class="bi bi-calendar-check"></i>
项目报名
</t-button>
</div>
</div>
</view>
@@ -120,18 +124,24 @@
@cancel="leaderConfirmVisible = false"
>
<template #content>
<p>申请成为队长前,请确认您已与团队其他成员商议并达成一致意见。</p>
<p>一个团队仅能有一名队长,作为队长,您可以帮助队员一键报名项目。</p>
<div class="dialog-content">
<div class="dialog-icon">
<i class="bi bi-info-circle"></i>
</div>
<div class="dialog-text">
<p>申请成为队长前,请确认您已与团队其他成员商议并达成一致意见。</p>
<p>一个团队仅能有一名队长,作为队长,您可以帮助队员一键报名项目。</p>
</div>
</div>
</template>
</t-dialog>
</template>
<script setup>
import {ref,reactive} from "vue";
import {ref, reactive} from "vue";
const actOptions = ref([])
const showDesc = ref(false)
const pageForm = reactive({
actId: null,
@@ -216,45 +226,54 @@ function onLeaderConfirm(){
}
function goToEventRegistration(){}
</script>
<style scoped lang="less">
/* 主体内容区 */
:deep(.top-dropdown-menu) {
background-color: #fff;
padding: 10px 0;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
z-index: 999;
}
.content-area {
padding: 0 16px 24px;
}
/* 团队信息卡片 */
/* 团队卡片 */
.team-card {
background-color: white;
margin: 15px;
border-radius: 12px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
background-color: #fff;
border-radius: 16px;
overflow: hidden;
box-shadow: 0 4px 16px rgba(255, 95, 92, 0.08);
margin: 12px 0 20px;
}
.team-banner {
position: relative;
height: 120px;
background: linear-gradient(135deg, #e74c3c, #ff7675);
.team-header {
display: flex;
align-items: center;
padding: 20px;
padding: 16px;
background: linear-gradient(to right, rgba(255, 95, 92, 0.05), rgba(255, 95, 92, 0.02));
border-bottom: 1px solid rgba(255, 95, 92, 0.1);
}
.team-logo {
width: 80px;
height: 80px;
border-radius: 50%;
width: 48px;
height: 48px;
border-radius: 12px;
background-color: white;
display: flex;
justify-content: center;
align-items: center;
margin-right: 15px;
border: 2px solid rgba(255, 255, 255, 0.8);
box-shadow: 0 2px 15px rgba(0, 0, 0, 0.1);
border: 2px solid #fff;
box-shadow: 0 2px 8px rgba(255, 95, 92, 0.15);
overflow: hidden;
flex-shrink: 0;
}
.team-logo i {
font-size: 24px;
color: #ff5f5c;
}
.team-logo img {
@@ -263,93 +282,137 @@ function goToEventRegistration(){}
object-fit: cover;
}
.team-logo i {
font-size: 40px;
color: #e74c3c;
}
.team-info {
.team-basic-info {
margin-left: 12px;
flex: 1;
color: white;
}
.team-name {
font-size: 20px;
font-size: 18px;
font-weight: 600;
margin-bottom: 6px;
text-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
color: #333;
margin-bottom: 4px;
}
.team-meta {
font-size: 13px;
opacity: 0.95;
}
.team-id {
display: inline-block;
background-color: rgba(255, 255, 255, 0.2);
padding: 2px 8px;
border-radius: 10px;
margin-top: 6px;
font-size: 12px;
color: #999;
}
.event-name {
position: absolute;
bottom: 10px;
right: 15px;
background-color: rgba(0, 0, 0, 0.2);
padding: 3px 10px;
border-radius: 15px;
font-size: 12px;
color: white;
}
/* 团队详情内容 */
.team-detail {
padding: 15px;
}
.team-stat-row {
.team-stats {
display: flex;
margin-bottom: 15px;
border-bottom: 1px solid #f0f0f0;
padding-bottom: 15px;
padding: 12px 16px;
}
.team-stat-item {
.stat-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
padding: 5px 0;
}
.team-stat-value {
font-size: 22px;
.stat-icon {
width: 36px;
height: 36px;
border-radius: 18px;
background-color: rgba(255, 95, 92, 0.1);
display: flex;
align-items: center;
justify-content: center;
margin-right: 10px;
color: #ff5f5c;
font-size: 18px;
}
.stat-content {
display: flex;
flex-direction: column;
}
.stat-divider {
width: 1px;
height: 36px;
background-color: #f0f0f0;
margin: 0 16px;
}
.stat-value {
font-size: 18px;
font-weight: 600;
color: #e74c3c;
margin-bottom: 5px;
color: #333;
line-height: 1.2;
}
.team-stat-label {
font-size: 13px;
.stat-label {
font-size: 12px;
color: #999;
}
.team-desc-toggle {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 16px;
font-size: 14px;
color: #666;
background-color: #f9f9f9;
border-top: 1px solid #f0f0f0;
cursor: pointer;
}
.team-desc-toggle i {
font-size: 12px;
color: #999;
}
/* 团队成员列表 */
.team-section {
.team-desc {
padding: 12px 16px;
font-size: 14px;
color: #666;
line-height: 1.5;
position: relative;
background-color: #fff8f8;
border-top: 1px solid #f0f0f0;
}
.team-desc i {
color: #ffdddd;
font-size: 18px;
position: absolute;
top: 8px;
left: 10px;
}
/* 操作按钮 */
.action-section {
margin-bottom: 20px;
}
.register-btn {
height: 48px;
font-size: 16px;
background-color: #ff5f5c;
border-color: #ff5f5c;
box-shadow: 0 6px 16px rgba(255, 95, 92, 0.2);
}
/* 成员列表 */
.members-section {
background-color: #fff;
border-radius: 16px;
overflow: hidden;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.04);
}
.section-header {
display: flex;
align-items: center;
margin-bottom: 15px;
justify-content: space-between;
padding: 16px;
border-bottom: 1px solid #f5f5f5;
}
.section-title {
font-size: 17px;
font-size: 16px;
font-weight: 600;
color: #333;
display: flex;
@@ -358,105 +421,138 @@ function goToEventRegistration(){}
.section-title i {
margin-right: 8px;
color: #e74c3c;
font-size: 20px;
color: #ff5f5c;
font-size: 18px;
}
.member-list {
background: white;
overflow: hidden;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
}
.member-item {
.section-badge {
display: flex;
padding: 15px;
border-bottom: 1px solid #f0f0f0;
align-items: center;
justify-content: center;
min-width: 24px;
height: 24px;
background-color: #fff0f0;
color: #ff5f5c;
border-radius: 12px;
font-size: 13px;
font-weight: 500;
padding: 0 8px;
}
.member-item:last-child {
border-bottom: none;
.member-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 8px;
padding: 12px;
}
.member-avatar {
width: 50px;
height: 50px;
border-radius: 50%;
background-color: #f0f0f0;
margin-right: 15px;
overflow: hidden;
flex-shrink: 0;
}
.member-avatar img {
width: 100%;
height: 100%;
object-fit: cover;
}
.member-info {
flex: 1;
.member-grid-item {
background-color: #f9f9f9;
border-radius: 8px;
padding: 10px;
}
.member-name {
font-size: 16px;
font-size: 14px;
font-weight: 500;
color: #333;
margin-bottom: 5px;
margin-bottom: 2px;
display: flex;
align-items: center;
justify-content: space-between;
}
.member-role {
display: inline-block;
.member-details {
display: flex;
flex-direction: column;
font-size: 12px;
background-color: #e74c3c;
color: white;
padding: 1px 6px;
border-radius: 4px;
margin-left: 8px;
color: #999;
}
.member-detail {
display: flex;
font-size: 13px;
color: #666;
}
.member-detail-item {
.member-details span {
display: flex;
align-items: center;
margin-right: 15px;
margin-top: 2px;
}
.member-detail-item i {
.member-details i {
margin-right: 4px;
font-size: 14px;
color: #999;
font-size: 12px;
color: #ccc;
}
.member-actions {
color: #999;
padding: 5px;
border-radius: 5px;
/* 角色相关 */
.role-section {
padding: 16px;
}
.role-notice {
background-color: #f8f9fa;
padding: 12px 15px;
border-radius: 8px;
margin-top: 15px;
font-size: 13px;
color: #666;
.role-card {
display: flex;
align-items: center;
background-color: #fff8f8;
border-radius: 12px;
padding: 16px;
margin-bottom: 16px;
box-shadow: 0 4px 12px rgba(255, 95, 92, 0.05);
}
.role-notice i {
color: #ffa63f;
margin-right: 8px;
font-size: 16px;
.role-icon {
width: 40px;
height: 40px;
border-radius: 20px;
background: linear-gradient(120deg, #ff5f5c, #ff8c8a);
display: flex;
align-items: center;
justify-content: center;
margin-right: 12px;
box-shadow: 0 4px 12px rgba(255, 95, 92, 0.2);
}
.role-icon i {
font-size: 20px;
color: white;
}
.role-info {
flex: 1;
}
.role-title {
font-size: 15px;
font-weight: 500;
color: #333;
margin-bottom: 2px;
}
.role-desc {
font-size: 13px;
color: #666;
}
.leader-apply-btn {
margin-top: 8px;
border-radius: 12px;
height: 48px;
border-color: #ff5f5c;
color: #ff5f5c;
}
/* 弹窗内容样式 */
.dialog-content {
display: flex;
padding: 16px 0;
}
.dialog-icon {
margin-right: 16px;
font-size: 24px;
color: #ff9800;
}
.dialog-text p {
margin: 0 0 8px;
font-size: 14px;
color: #666;
line-height: 1.6;
}
</style>