mahjong_group/components/index/MahjongCard.vue
2025-09-06 20:17:36 +08:00

310 lines
7.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="grid-item" @click="handleCardClick">
<uni-card margin="0px" padding="0px" spacing="0px">
<view
style="position:absolute;top:0;right:0;width:100%; background: linear-gradient(to bottom, rgba(255, 108, 0, 0.9), rgba(255, 108, 0, 0.7));box-shadow: 0 2px 8px rgba(235,135,58, 0.3);z-index:999;border-radius:4px 4px 0 0;font-size:24rpx;color:#fff;font-weight: 500; opacity: 0.7;">
<text style="padding-left:10rpx;">{{ item.status }}</text>
</view>
<view class="item-content column">
<!-- 麻将桌区域 -->
<view class="mahjong-table">
<!-- 九宫格布局 -->
<view style="width:300rpx;height: 300rpx;">
<view class="nine-grid-container">
<!-- 第一行 -->
<view class="grid-cell"></view>
<view class="grid-cell" :class="getCellClass(0)">
<view v-if="getPlayerAtPosition(0)" class="player-avatar">
<image :src="getPlayerAtPosition(0).avatar || ''" class="avatar-img"></image>
</view>
<view v-else-if="canJoinAtPosition(0)" class="join-button" @click.stop="handleJoin">
<text class="join-text">+</text>
</view>
</view>
<view class="grid-cell"></view>
<!-- 第二行 -->
<view class="grid-cell" :class="getCellClass(1)">
<view v-if="getPlayerAtPosition(1)" class="player-avatar">
<image :src="getPlayerAtPosition(1).avatar || ''" class="avatar-img"></image>
</view>
<view v-else-if="canJoinAtPosition(1)" class="join-button" @click.stop="handleJoin">
<text class="join-text">+</text>
</view>
</view>
<view class="grid-cell center-cell">
<!-- 麻将桌背景图 -->
<image src="/static/9.png" class="table-bg" mode=""></image>
</view>
<view class="grid-cell" :class="getCellClass(2)">
<view v-if="getPlayerAtPosition(2)" class="player-avatar">
<image :src="getPlayerAtPosition(2).avatar || ''" class="avatar-img"></image>
</view>
<view v-else-if="canJoinAtPosition(2)" class="join-button" @click.stop="handleJoin">
<text class="join-text">+</text>
</view>
</view>
<!-- 第三行 -->
<view class="grid-cell"></view>
<view class="grid-cell" :class="getCellClass(3)">
<view v-if="getPlayerAtPosition(3)" class="player-avatar">
<image :src="getPlayerAtPosition(3).avatar || ''" class="avatar-img"></image>
</view>
<view v-else-if="canJoinAtPosition(3)" class="join-button" @click.stop="handleJoin">
<text class="join-text">+</text>
</view>
</view>
<view class="grid-cell"></view>
</view>
</view>
</view>
<!-- 信息区域 -->
<view class="info-section">
<text class="info-text" style="font-size: 26rpx;font-weight: 600;color: #FA690B;">{{
item.description }}</text>
<text class="info-text" style="margin-top: -7rpx;">{{ item.room }}</text>
<text class="info-text" style="font-size: 22rpx;font-weight: 600;line-height:28rpx;">2025-09-06</text>
<text class="info-text" style="font-size: 22rpx;font-weight: 600;line-height:28rpx;">{{ item.time }}</text>
<text class="info-text" style="color:#FA690B;line-height:30rpx;margin-top:6rpx;">{{ item.requirements }}</text>
</view>
</view>
</uni-card>
</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>
.item-content {
height: 540rpx;
color: white;
border-radius: 10rpx;
font-size: 32rpx;
}
.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%;
padding: 20rpx;
box-sizing: border-box;
}
/* 网格单元格 */
.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 {
width: 100%;
height: 100%;
background-color: aqua;
border-radius: 50%;
}
/* 加入按钮 */
.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>