# 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 |
# 注意事项
# 使用建议
- 队伍头像:建议为队伍头像设置默认占位图,避免加载失败时显示空白
- 操作图标:确保操作图标类名在项目中已定义,建议使用统一的图标库
- 比赛状态:根据实际比赛状态动态更新
statusText和status字段 - 操作权限:在实际使用中应根据用户权限控制可用的操作选项
- 响应式适配:在小屏幕设备上,建议适当调整相关尺寸变量
# 性能优化
- 使用
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%) | 标题裁剪路径 |