333 lines
7.1 KiB
Vue
333 lines
7.1 KiB
Vue
<template>
|
||
<view class="grid" @click="handleCardClick">
|
||
<view class="grid-item">
|
||
<view style="height: 251rpx;">
|
||
<view class="nine-grid-container">
|
||
<view></view>
|
||
<view class="item">
|
||
<view class="item-avatar">
|
||
<image src="@@:app/static/add.png" class="avatar-img" mode="aspectFit">
|
||
</image>
|
||
</view>
|
||
</view>
|
||
<view></view>
|
||
<view class="item">
|
||
<view class="item-avatar">
|
||
<image src="@@:app/static/add.png" class="avatar-img" mode="aspectFit">
|
||
</image>
|
||
</view>
|
||
</view>
|
||
<view></view>
|
||
<view class="item">
|
||
<view class="item-avatar">
|
||
<image src="@@:app/static/add.png" class="avatar-img" mode="aspectFit">
|
||
</image>
|
||
</view>
|
||
</view>
|
||
<view></view>
|
||
<view class="item">
|
||
<view class="item-avatar">
|
||
<image src="@@:app/static/add.png" class="avatar-img" mode="aspectFit">
|
||
</image>
|
||
</view>
|
||
</view>
|
||
<view></view>
|
||
</view>
|
||
</view>
|
||
<view style="width: 100%;display: flex;align-items: center;justify-content: center;">
|
||
<view style="width: 90%;">
|
||
<view
|
||
style="color: #000000;font-family: PingFang SC, PingFang SC;font-weight: 500;font-size: 28rpx;text-align: left;font-style: normal;text-transform: none;">
|
||
{{item.description}}
|
||
</view>
|
||
<view
|
||
style="font-family: PingFang SC, PingFang SC;font-weight: 400;font-size: 18rpx;color: #575757;text-align: left;font-style: normal;text-transform: none;">
|
||
{{item.time}}
|
||
</view>
|
||
<view
|
||
style="font-family: PingFang SC, PingFang SC;font-weight: 400;font-size: 18rpx;color: #575757;text-align: left;font-style: normal;text-transform: none;">
|
||
{{item.room}}
|
||
</view>
|
||
<view
|
||
style="font-family: PingFang SC, PingFang SC;font-weight: 400;font-size: 18rpx;color: #575757;text-align: left;font-style: normal;text-transform: none;">
|
||
{{item.requirements}}
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import {
|
||
defineProps,
|
||
defineEmits,
|
||
computed
|
||
} from 'vue'
|
||
|
||
// 定义 props
|
||
const props = defineProps({
|
||
item: {
|
||
type: Object,
|
||
required: true,
|
||
default: () => ({
|
||
id: '',
|
||
status: '',
|
||
description: '',
|
||
time: '',
|
||
room: '',
|
||
requirements: '',
|
||
personCount: 4, //总人数
|
||
joinPerson: [{
|
||
id: 1,
|
||
name: '张三',
|
||
avatar: '',
|
||
phone: '',
|
||
}], //已加入人
|
||
})
|
||
}
|
||
})
|
||
|
||
// 定义 emits
|
||
const emit = defineEmits(['click', 'join'])
|
||
|
||
// 计算属性:获取玩家位置布局
|
||
const playerPositions = computed(() => {
|
||
const {
|
||
personCount,
|
||
joinPerson
|
||
} = props.item
|
||
const joinedCount = joinPerson.length
|
||
|
||
// 根据总人数确定布局
|
||
if (personCount === 2) {
|
||
// 2人局:第二行左边和右边
|
||
return {
|
||
positions: [null, joinPerson[0] || null, joinPerson[1] || null, null],
|
||
joinPositions: [null, !joinPerson[0], !joinPerson[1], null]
|
||
}
|
||
} else if (personCount === 3) {
|
||
// 3人局:第一行中间、第二行左边和右边
|
||
return {
|
||
positions: [joinPerson[2] || null, joinPerson[0] || null, joinPerson[1] || null, null],
|
||
joinPositions: [!joinPerson[2], !joinPerson[0], !joinPerson[1], null]
|
||
}
|
||
} else {
|
||
// 4人局:标准布局(上、左、右、下)
|
||
return {
|
||
positions: [
|
||
joinPerson[2] || null, // 第一行中间
|
||
joinPerson[0] || null, // 第二行左边
|
||
joinPerson[1] || null, // 第二行右边
|
||
joinPerson[3] || null // 第三行中间
|
||
],
|
||
joinPositions: [
|
||
!joinPerson[2], // 第一行中间
|
||
!joinPerson[0], // 第二行左边
|
||
!joinPerson[1], // 第二行右边
|
||
!joinPerson[3] // 第三行中间
|
||
]
|
||
}
|
||
}
|
||
})
|
||
|
||
// 获取指定位置的玩家
|
||
const getPlayerAtPosition = (position) => {
|
||
return playerPositions.value.positions[position]
|
||
}
|
||
|
||
// 判断指定位置是否可以加入
|
||
const canJoinAtPosition = (position) => {
|
||
const {
|
||
personCount,
|
||
joinPerson
|
||
} = props.item
|
||
const joinedCount = joinPerson.length
|
||
|
||
// 如果已满员,不能加入
|
||
if (joinedCount >= personCount) {
|
||
return false
|
||
}
|
||
|
||
// 直接使用计算属性中的 joinPositions
|
||
return playerPositions.value.joinPositions[position]
|
||
}
|
||
|
||
// 获取单元格样式类
|
||
const getCellClass = (position) => {
|
||
if (getPlayerAtPosition(position)) {
|
||
return 'player-cell'
|
||
} else if (canJoinAtPosition(position)) {
|
||
return 'join-cell'
|
||
}
|
||
return ''
|
||
}
|
||
|
||
// 处理卡片点击事件
|
||
const handleCardClick = () => {
|
||
emit('click', props.item)
|
||
}
|
||
|
||
// 处理加入按钮点击事件
|
||
const handleJoin = () => {
|
||
emit('join', props.item)
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.grid {
|
||
width: 100%;
|
||
display: flex;
|
||
align-content: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.grid-item {
|
||
width: 320rpx;
|
||
height: 400rpx;
|
||
background: #FFFFFF;
|
||
box-shadow: -4rpx 12rpx 7rpx 0rpx rgba(0, 0, 0, 0.25);
|
||
border-radius: 27rpx 27rpx 27rpx 27rpx;
|
||
border: 4rpx solid #006C1A
|
||
}
|
||
|
||
.item-content {
|
||
height: 540rpx;
|
||
color: white;
|
||
border-radius: 10rpx;
|
||
font-size: 32rpx;
|
||
}
|
||
|
||
.item {
|
||
display: flex;
|
||
align-content: center;
|
||
justify-content: center;
|
||
align-items: center;
|
||
}
|
||
|
||
.item-avatar {
|
||
width: 60rpx;
|
||
height: 60rpx;
|
||
background-color: #60AA72;
|
||
border-radius: 50rpx;
|
||
}
|
||
|
||
.mahjong-table {
|
||
width: 100%;
|
||
background-color: #D4D4D4;
|
||
border-radius: 10rpx 10rpx 0 0;
|
||
display: flex;
|
||
justify-content: center;
|
||
}
|
||
|
||
.status-tag {
|
||
position: absolute;
|
||
left: 15rpx;
|
||
top: 15rpx;
|
||
font-size: 16rpx;
|
||
color: black;
|
||
z-index: 10;
|
||
}
|
||
|
||
/* 九宫格容器 */
|
||
.nine-grid-container {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr 1fr;
|
||
grid-template-rows: 1fr 1fr 1fr;
|
||
width: 100%;
|
||
height: 100%;
|
||
box-sizing: border-box;
|
||
background: url('@@:app/static/index_logo.png') no-repeat center center;
|
||
background-size: 50%;
|
||
}
|
||
|
||
/* 网格单元格 */
|
||
.grid-cell {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
position: relative;
|
||
}
|
||
|
||
/* 玩家头像单元格 */
|
||
.player-cell {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
/* 中心单元格(麻将桌) */
|
||
.center-cell {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
/* 加入按钮单元格 */
|
||
.join-cell {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
/* 麻将桌背景图 */
|
||
.table-bg {
|
||
width: 80rpx;
|
||
height: 80rpx;
|
||
}
|
||
|
||
/* 玩家头像 */
|
||
.player-avatar {
|
||
width: 60rpx;
|
||
height: 60rpx;
|
||
background-color: white;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
.avatar-img {
|
||
|
||
border-radius: 50%;
|
||
width: 60rpx;
|
||
height: 60rpx;
|
||
}
|
||
|
||
/* 加入按钮 */
|
||
.join-button {
|
||
width: 60rpx;
|
||
height: 60rpx;
|
||
background-color: white;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.join-button:hover {
|
||
transform: scale(1.1);
|
||
background-color: #f0f0f0;
|
||
}
|
||
|
||
.join-text {
|
||
color: black;
|
||
font-size: 24rpx;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.info-section {
|
||
padding: 10rpx;
|
||
}
|
||
|
||
.info-text {
|
||
font-size: 24rpx;
|
||
color: black;
|
||
display: block;
|
||
}
|
||
</style> |