# MatchOperationPopup 比赛操作弹窗

比赛操作弹窗组件,用于显示比赛信息并提供操作选项,支持重置比赛、改判比分等功能。

# 特性

  • 🎮 比赛信息展示 - 清晰展示比赛标题、队伍信息、游戏模式等
  • ⚙️ 操作管理 - 支持多种比赛操作,如重置比赛、改判比分
  • 🏷️ 状态显示 - 实时显示比赛状态信息
  • 🎨 自定义样式 - 丰富的CSS变量支持主题定制
  • 🔧 插槽支持 - 支持自定义操作按钮
  • 轻量高效 - 优化的代码结构,性能出色

# 适用场景

  • 电竞比赛管理操作
  • 在线游戏对战管理
  • 体育赛事操作控制
  • 比赛裁判系统

# 引入

import PressMatchOperationPopup from 'press-next/press-match-operation-popup/press-match-operation-popup';

# 代码演示

# 基础用法

<template>
  <PressMatchOperationPopup
    :show="showPopup"
    :title="title"
    :match-info="matchInfo"
    :operations="operations"
    @close="handleClose"
    @operation-click="handleOperationClick"
  />
</template>

<script setup>
import { ref } from 'vue';
import PressMatchOperationPopup from 'press-next/press-match-operation-popup/press-match-operation-popup.vue';
import { getMockData } from './demo-data';

// 使用模拟数据
const componentProps = getMockData();

const showPopup = ref(false);
const title = ref('对局操作');
const matchInfo = ref(componentProps.matchInfo);
const operations = ref(componentProps.operations);

// 事件处理
const handleClose = () => {
  showPopup.value = false;
};

const handleOperationClick = (operation) => {
  console.log('操作点击:', operation);
  // 处理具体操作逻辑
};
</script>

# 自定义比赛信息

<template>
  <PressMatchOperationPopup
    :show="true"
    :title="'比赛管理'"
    :match-info="customMatchInfo"
    :operations="operations"
    @close="handleClose"
    @operation-click="handleOperationClick"
  />
</template>

<script setup>
import { ref } from 'vue';

const customMatchInfo = ref({
  id: 1,
  title: '决赛 BO5',
  gameMode: '竞技模式',
  mapName: '训练场',
  playerCount: '五人',
  status: 'in-progress',
  statusText: '进行中',
  leftTeam: {
    id: 1,
    name: '王者战队',
    avatar: 'https://placehold.co/144x144'
  },
  rightTeam: {
    id: 2,
    name: '冠军战队',
    avatar: 'https://placehold.co/144x144'
  }
});

const operations = ref([
  {
    id: 'pause',
    name: '暂停比赛',
    icon: 'pmg-icon-pause',
    action: 'pause'
  },
  {
    id: 'end',
    name: '结束比赛',
    icon: 'pmg-icon-end',
    action: 'end'
  }
]);

const handleClose = () => {
  console.log('关闭弹窗');
};

const handleOperationClick = (operation) => {
  console.log('执行操作:', operation.action);
};
</script>

# 自定义操作按钮

<template>
  <PressMatchOperationPopup
    :show="showPopup"
    :title="title"
    :match-info="matchInfo"
    :operations="customOperations"
    @close="handleClose"
    @operation-click="handleOperationClick"
  />
</template>

<script setup>
import { ref } from 'vue';

const customOperations = ref([
  {
    id: 'reset',
    name: '重置比赛',
    icon: 'pmg-icon-reset',
    action: 'reset'
  },
  {
    id: 'change-score',
    name: '改判比分',
    icon: 'pmg-icon-rejudge',
    action: 'change-score'
  },
  {
    id: 'export',
    name: '导出数据',
    icon: 'pmg-icon-export',
    action: 'export'
  },
  {
    id: 'settings',
    name: '比赛设置',
    icon: 'pmg-icon-settings',
    action: 'settings'
  }
]);

const handleOperationClick = (operation) => {
  switch (operation.action) {
    case 'reset':
      console.log('重置比赛');
      break;
    case 'change-score':
      console.log('改判比分');
      break;
    case 'export':
      console.log('导出数据');
      break;
    case 'settings':
      console.log('比赛设置');
      break;
  }
};
</script>

# 自定义样式

<template>
  <PressMatchOperationPopup
    :show="showPopup"
    :title="title"
    :match-info="matchInfo"
    :operations="operations"
    :custom-class="'custom-operation-popup'"
    @close="handleClose"
    @operation-click="handleOperationClick"
  />
</template>

<script setup>
import { ref } from 'vue';

// 组件数据...
</script>

<style>
.custom-operation-popup {
  --op-match-card-bg: #f8f9fa;
  --op-title-bg: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  --op-title-color: #ffffff;
  --op-operation-icon-color: #667eea;
  --op-operation-text-color: #333333;
}
</style>

# API

# Props

参数 说明 类型 默认值
custom-class 自定义样式类 string ''
z-index 弹窗层级 number 100
title 弹窗标题 string '对局操作'
show 是否显示弹窗 boolean false
match-info 比赛信息 MatchInfo {}
operations 操作列表 OperationItem[] []

# MatchInfo 数据结构

interface TeamInfo {
  id: string | number; // 队伍ID
  name: string; // 队伍名称
  avatar?: string; // 队伍头像URL
}

interface MatchInfo {
  id: string | number; // 比赛ID
  title: string; // 比赛标题,如 "16进8 BO3"
  gameMode: string; // 游戏模式,如 "经典(第三人称)"
  mapName: string; // 地图名称,如 "度假岛"
  playerCount: string; // 人数,如 "四人"
  status: 'not-started' | 'in-progress' | 'finished'; // 比赛状态
  statusText: string; // 状态文本,如 "未开始"
  leftTeam: TeamInfo; // 左队信息
  rightTeam: TeamInfo; // 右队信息
}

# OperationItem 数据结构

interface OperationItem {
  id: string; // 操作ID
  name: string; // 操作名称
  icon: string; // 操作图标类名
  action: string; // 操作标识
}

# Slots

名称 说明
title 自定义比赛标题
vs 自定义VS区域
operations 自定义操作按钮

插槽使用说明

  • title 插槽用于替换默认的比赛标题区域,可以自定义标题样式和内容
  • vs 插槽用于替换默认的VS区域,可以自定义对战显示效果
  • operations 插槽用于替换默认的操作按钮列表,需要自行处理点击事件
  • 插槽内容会完全替换默认内容,请确保提供合适的交互元素

# 自定义插槽用法

<template>
  <div class="demo-wrap">
    <h3>自定义插槽用法</h3>
    <PressButton @click="showSlotPopup = true">
      显示自定义插槽弹窗
    </PressButton>

    <PressMatchOperationPopup
      :show="showSlotPopup"
      :match-info="matchInfo"
      :operations="operations"
      @close="onSlotClose"
      @operation-click="onSlotOperationClick"
    >
      <!-- 自定义标题 -->
      <template #title>
        <div class="custom-title">
          <div class="custom-title-icon">
            <div class="pmg-iconfont pmg-icon-trophy" />
          </div>
          <div class="custom-title-text">
            {{ matchInfo.title }}
          </div>
          <div class="custom-title-badge">
            决赛
          </div>
        </div>
      </template>

      <!-- 自定义VS区域 -->
      <template #vs>
        <div class="custom-vs">
          <div class="custom-vs-icon">
            <div class="pmg-iconfont pmg-icon-vs" />
          </div>
          <div class="custom-vs-status">
            <div class="custom-vs-status-text">
              {{ matchInfo.statusText }}
            </div>
            <div class="custom-vs-time">
              15:30 开始
            </div>
          </div>
        </div>
      </template>

      <!-- 自定义操作按钮 -->
      <template #operations>
        <div class="custom-operations">
          <div
            v-for="operation in operations"
            :key="operation.id"
            class="custom-operation-item"
            @click="onSlotOperationClick(operation)"
          >
            <div class="custom-operation-icon">
              <div :class="`pmg-iconfont ${operation.icon}`" />
            </div>
            <div class="custom-operation-content">
              <div class="custom-operation-name">
                {{ operation.name }}
              </div>
              <div class="custom-operation-desc">
                点击执行{{ operation.name }}操作
              </div>
            </div>
            <div class="custom-operation-arrow">
              <div class="pmg-iconfont pmg-icon-arrow-right" />
            </div>
          </div>
        </div>
      </template>
    </PressMatchOperationPopup>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import PressButton from 'press-ui/press-button/press-button.vue';
import { getMockData } from './demo-data';

const componentProps = getMockData();
const showSlotPopup = ref(false);

// 自定义插槽事件处理
const onSlotClose = () => {
  console.log('插槽用法 - 关闭弹窗');
  showSlotPopup.value = false;
};

const onSlotOperationClick = (operation) => {
  console.log('插槽用法 - 操作点击:', operation);
  showSlotPopup.value = false;
};
</script>

<style scoped>
.custom-title {
  display: flex;
  align-items: center;
  padding: 16px 20px;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  border-radius: 8px 8px 0 0;
}

.custom-title-icon {
  margin-right: 12px;
}

.custom-title-icon .pmg-iconfont {
  font-size: 20px;
  color: #ffd700;
}

.custom-title-text {
  flex: 1;
  font-size: 16px;
  font-weight: 600;
  color: #ffffff;
}

.custom-title-badge {
  padding: 4px 12px;
  background: rgba(255, 255, 255, 0.2);
  border-radius: 12px;
  font-size: 12px;
  color: #ffffff;
}

.custom-vs {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 16px;
  background: linear-gradient(45deg, #ff6b6b, #ee5a24);
  border-radius: 50%;
  width: 80px;
  height: 80px;
  justify-content: center;
}

.custom-vs-icon .pmg-iconfont {
  font-size: 24px;
  color: #ffffff;
  font-weight: bold;
}

.custom-vs-status {
  text-align: center;
}

.custom-vs-status-text {
  font-size: 10px;
  color: #ffffff;
  font-weight: 600;
}

.custom-vs-time {
  font-size: 8px;
  color: rgba(255, 255, 255, 0.8);
}

.custom-operations {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 20px;
}

.custom-operation-item {
  display: flex;
  align-items: center;
  padding: 16px;
  background: #ffffff;
  border-radius: 12px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  cursor: pointer;
  transition: all 0.3s ease;
}

.custom-operation-item:hover {
  transform: translateY(-2px);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
}

.custom-operation-icon {
  width: 40px;
  height: 40px;
  border-radius: 8px;
  background: linear-gradient(135deg, #1890ff, #096dd9);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-right: 16px;
}

.custom-operation-icon .pmg-iconfont {
  font-size: 18px;
  color: #ffffff;
}

.custom-operation-content {
  flex: 1;
}

.custom-operation-name {
  font-size: 16px;
  font-weight: 600;
  color: #333333;
  margin-bottom: 4px;
}

.custom-operation-desc {
  font-size: 12px;
  color: #999999;
}

.custom-operation-arrow .pmg-iconfont {
  font-size: 14px;
  color: #cccccc;
}
</style>

# Events

事件名 说明 参数
close 关闭弹窗时触发 -
operation-click 点击操作按钮时触发 operation: OperationItem

# 注意事项

# 使用建议

  1. 队伍头像:建议为队伍头像设置默认占位图,避免加载失败时显示空白
  2. 操作图标:确保操作图标类名在项目中已定义,建议使用统一的图标库
  3. 比赛状态:根据实际比赛状态动态更新 statusTextstatus 字段
  4. 操作权限:在实际使用中应根据用户权限控制可用的操作选项
  5. 响应式适配:在小屏幕设备上,建议适当调整相关尺寸变量

# 性能优化

  • 使用 v-show 控制弹窗显示,避免频繁创建销毁
  • 操作列表较多时建议使用虚拟滚动
  • 头像图片建议使用 CDN 加速

# 兼容性

  • 支持 Vue 3.0+
  • 兼容现代浏览器(Chrome 60+, Firefox 60+, Safari 12+)
  • 支持微信小程序、支付宝小程序等平台

# 主题定制

# 样式变量

组件提供了下列 CSS 变量,可用于自定义样式,使用方法请参考 ConfigProvider 组件

# 尺寸属性 (Width/Height)

名称 默认值 描述
--op-match-card-height 3.62rem 比赛卡片高度
--op-title-texture-width 100% 标题纹理宽度
--op-title-texture-height .065rem 标题纹理高度
--op-content-height 100% 内容区域高度
--op-teams-width 100% 队伍区域宽度
--op-team-max-width 1.68rem 单个队伍最大宽度
--op-team-name-width 100% 队伍名称宽度
--op-team-avatar-size 1.44rem 队伍头像尺寸
--op-vs-width 1.72rem VS区域宽度
--op-operation-item-width .8rem 操作项宽度
--op-operation-item-height .76rem 操作项高度
--op-operation-icon-size .4rem 操作图标尺寸

# 间距属性 (Margin/Padding/Gap)

名称 默认值 描述
--op-title-padding .06rem .48rem 标题内边距
--op-content-padding .8rem $spacing-lg $spacing-lg 内容区域内边距
--op-status-padding .03rem .16rem 状态标签内边距
--op-team-avatar-margin-bottom $spacing-sm 队伍头像下边距
--op-teams-gap $spacing-lg 队伍间距
--op-vs-gap $spacing-sm VS区域间距
--op-operations-margin-top $spacing-md 操作区域上边距
--op-operations-gap 1.6rem 操作项间距
--op-operation-icon-margin-bottom .06rem 操作图标下边距

# 颜色属性 (Color/Background)

名称 默认值 描述
--op-match-card-bg $color-surface-default 比赛卡片背景色
--op-title-bg #d9e2ff 标题背景色
--op-title-color $color-text-primary 标题文字颜色
--op-team-name-color $color-text-primary 队伍名称颜色
--op-vs-color $color-text-primary VS文字颜色
--op-status-bg #eceff2 状态标签背景色
--op-status-color $color-text-secondary 状态文字颜色
--op-game-info-color #a3abb4 游戏信息颜色
--op-operation-icon-color #000915 操作图标颜色
--op-operation-text-color #212124 操作文字颜色

# 字体属性 (Font)

名称 默认值 描述
--op-title-font-size $font-size-md 标题字体大小
--op-title-font-weight $font-weight-bold 标题字体粗细
--op-team-name-font-size $font-size-sm 队伍名称字体大小
--op-team-name-font-weight $font-weight-bold 队伍名称字体粗细
--op-vs-font-size .8rem VS文字大小
--op-vs-font-weight $font-weight-bold VS文字粗细
--op-vs-line-height 1 VS文字行高
--op-status-font-size $font-size-xs 状态文字大小
--op-game-info-font-size $font-size-xs 游戏信息字体大小
--op-operation-text-font-size $font-size-xs 操作文字大小

# 边框属性 (Border/Border-Radius)

名称 默认值 描述
--op-team-avatar-border .01rem solid $color-divider-light 队伍头像边框
--op-match-card-radius $border-radius-sm 比赛卡片圆角
--op-team-avatar-radius $border-radius-circle 队伍头像圆角
--op-operation-icon-radius $border-radius-xs 操作图标圆角

# 阴影属性 (Box-Shadow)

名称 默认值 描述
--op-match-card-shadow 0 .08rem .08rem 0 #ebeff2 比赛卡片底边阴影

# 定位属性 (Position/Top/Left/Z-Index)

名称 默认值 描述
--op-title-section-top 0 标题区域顶部位置
--op-title-section-left 50% 标题区域左侧位置
--op-title-texture-top 0 标题纹理顶部位置
--op-title-texture-left 50% 标题纹理左侧位置
--op-title-z-index 2 标题层级

# 变换属性 (Transform)

名称 默认值 描述
--op-title-section-transform translateX(-50%) 标题区域变换
--op-title-texture-transform translateX(-50%) 标题纹理变换
--op-operation-active-scale .95 操作项激活缩放

# 过渡属性 (Transition)

名称 默认值 描述
--op-operation-transition transform .2s ease 操作项过渡效果

# 布局属性 (Flex)

名称 默认值 描述
--op-team-flex 1 队伍flex属性

# 其他属性 (Others)

名称 默认值 描述
--op-title-texture-content '' 标题纹理内容
--op-title-clip-path polygon(0% 0%, 100% 0%, 95% 100%, 5% 100%) 标题裁剪路径