# MatchOperationPopup
A match operation popup component for displaying match information and providing operation options, supporting functions like match reset and score adjustment.
# Features
- 🎮 Match Information Display - Clearly display match title, team information, game mode, etc.
- ⚙️ Operation Management - Support various match operations like match reset and score adjustment
- 🏷️ Status Display - Real-time display of match status information
- 🎨 Custom Styles - Rich CSS variables for theme customization
- 🔧 Slot Support - Support custom operation buttons
- ⚡ Lightweight & Efficient - Optimized code structure with excellent performance
# Use Cases
- E-sports match management operations
- Online game battle management
- Sports event operation control
- Match referee system
# Import
import PressMatchOperationPopup from 'press-next/press-match-operation-popup/press-match-operation-popup';
# Code Demo
# Basic Usage
<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';
// Use mock data
const componentProps = getMockData();
const showPopup = ref(false);
const title = ref('Match Operations');
const matchInfo = ref(componentProps.matchInfo);
const operations = ref(componentProps.operations);
// Event handlers
const handleClose = () => {
showPopup.value = false;
};
const handleOperationClick = (operation) => {
console.log('Operation clicked:', operation);
// Handle specific operation logic
};
</script>
# Custom Match Information
<template>
<PressMatchOperationPopup
:show="true"
:title="'Match Management'"
:match-info="customMatchInfo"
:operations="operations"
@close="handleClose"
@operation-click="handleOperationClick"
/>
</template>
<script setup>
import { ref } from 'vue';
const customMatchInfo = ref({
id: 1,
title: 'Finals BO5',
gameMode: 'Competitive Mode',
mapName: 'Training Ground',
playerCount: 'Five Players',
status: 'in-progress',
statusText: 'In Progress',
leftTeam: {
id: 1,
name: 'King Team',
avatar: 'https://placehold.co/144x144'
},
rightTeam: {
id: 2,
name: 'Champion Team',
avatar: 'https://placehold.co/144x144'
}
});
const operations = ref([
{
id: 'pause',
name: 'Pause Match',
icon: 'pmg-icon-pause',
action: 'pause'
},
{
id: 'end',
name: 'End Match',
icon: 'pmg-icon-end',
action: 'end'
}
]);
const handleClose = () => {
console.log('Close popup');
};
const handleOperationClick = (operation) => {
console.log('Execute operation:', operation.action);
};
</script>
# Custom Operation Buttons
<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: 'Reset Match',
icon: 'pmg-icon-reset',
action: 'reset'
},
{
id: 'change-score',
name: 'Adjust Score',
icon: 'pmg-icon-rejudge',
action: 'change-score'
},
{
id: 'export',
name: 'Export Data',
icon: 'pmg-icon-export',
action: 'export'
},
{
id: 'settings',
name: 'Match Settings',
icon: 'pmg-icon-settings',
action: 'settings'
}
]);
const handleOperationClick = (operation) => {
switch (operation.action) {
case 'reset':
console.log('Reset match');
break;
case 'change-score':
console.log('Adjust score');
break;
case 'export':
console.log('Export data');
break;
case 'settings':
console.log('Match settings');
break;
}
};
</script>
# Custom Styles
<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';
// Component data...
</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
| Attribute | Description | Type | Default |
|---|---|---|---|
| custom-class | Custom CSS class | string | '' |
| z-index | PopupPlus z-index | number | 100 |
| title | PopupPlus title | string | 'Match Operations' |
| show | Whether to show popup | boolean | false |
| match-info | Match information | MatchInfo | {} |
| operations | Operations list | OperationItem[] | [] |
# MatchInfo Data Structure
interface TeamInfo {
id: string | number; // Team ID
name: string; // Team name
avatar?: string; // Team avatar URL
}
interface MatchInfo {
id: string | number; // Match ID
title: string; // Match title, e.g., "Round of 16 BO3"
gameMode: string; // Game mode, e.g., "Classic (Third Person)"
mapName: string; // Map name, e.g., "Resort Island"
playerCount: string; // Player count, e.g., "Four Players"
status: 'not-started' | 'in-progress' | 'finished'; // Match status
statusText: string; // Status text, e.g., "Not Started"
leftTeam: TeamInfo; // Left team information
rightTeam: TeamInfo; // Right team information
}
# OperationItem Data Structure
interface OperationItem {
id: string; // Operation ID
name: string; // Operation name
icon: string; // Operation icon class name
action: string; // Operation identifier
}
# Slots
| Name | Description |
|---|---|
| title | Custom match title |
| vs | Custom VS area |
| operations | Custom operation buttons |
Slot Usage Notes:
- The
titleslot replaces the default match title area, allowing custom title styles and content - The
vsslot replaces the default VS area, allowing custom battle display effects - The
operationsslot replaces the default operation button list, you need to handle click events yourself - Slot content completely replaces the default content, please ensure proper interactive elements are provided
# Custom Slots Usage
<template>
<div class="demo-wrap">
<h3>Custom Slots Usage</h3>
<PressButton @click="showSlotPopup = true">
Show Custom Slots Popup
</PressButton>
<PressMatchOperationPopup
:show="showSlotPopup"
:match-info="matchInfo"
:operations="operations"
@close="onSlotClose"
@operation-click="onSlotOperationClick"
>
<!-- Custom title -->
<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">
Final
</div>
</div>
</template>
<!-- Custom VS area -->
<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">
Start at 15:30
</div>
</div>
</div>
</template>
<!-- Custom operation buttons -->
<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">
Click to execute {{ operation.name }} operation
</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);
// Custom slots event handling
const onSlotClose = () => {
console.log('Slots usage - Close popup');
showSlotPopup.value = false;
};
const onSlotOperationClick = (operation) => {
console.log('Slots usage - Operation click:', 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
| Event | Description | Parameters |
|---|---|---|
| close | Triggered when popup is closed | - |
| operation-click | Triggered when operation button clicked | operation: OperationItem |
# Notes
# Usage Recommendations
- Team Avatars: It is recommended to set default placeholder images for team avatars to avoid blank display when loading fails
- Operation Icons: Ensure operation icon class names are defined in the project, recommend using a unified icon library
- Match Status: Dynamically update
statusTextandstatusfields according to actual match status - Operation Permissions: In actual use, control available operation options based on user permissions
- Responsive Adaptation: On small screen devices, it's recommended to appropriately adjust related size variables
# Performance Optimization
- Use
v-showto control popup display, avoid frequent creation and destruction - Recommend using virtual scrolling for large operation lists
- Avatar images are recommended to use CDN acceleration
# Compatibility
- Support Vue 3.0+
- Compatible with modern browsers (Chrome 60+, Firefox 60+, Safari 12+)
- Support WeChat Mini Program, Alipay Mini Program and other platforms
# Theme Customization
# CSS Variables
The component provides the following CSS variables, which can be used to customize styles. For usage, please refer to ConfigProvider component.
# Size Properties (Width/Height)
| Name | Default Value | Description |
|---|---|---|
| --op-match-card-height | 3.62rem | Match card height |
| --op-title-texture-width | 100% | Title texture width |
| --op-title-texture-height | .065rem | Title texture height |
| --op-content-height | 100% | Content area height |
| --op-teams-width | 100% | Teams area width |
| --op-team-max-width | 1.68rem | Single team max width |
| --op-team-name-width | 100% | Team name width |
| --op-team-avatar-size | 1.44rem | Team avatar size |
| --op-vs-width | 1.72rem | VS area width |
| --op-operation-item-width | .8rem | Operation item width |
| --op-operation-item-height | .76rem | Operation item height |
| --op-operation-icon-size | .4rem | Operation icon size |
# Spacing Properties (Margin/Padding/Gap)
| Name | Default Value | Description |
|---|---|---|
| --op-title-padding | .06rem .48rem | Title padding |
| --op-content-padding | .8rem $spacing-lg $spacing-lg | Content area padding |
| --op-status-padding | .03rem .16rem | Status label padding |
| --op-team-avatar-margin-bottom | $spacing-sm | Team avatar bottom margin |
| --op-teams-gap | $spacing-lg | Teams gap |
| --op-vs-gap | $spacing-sm | VS area gap |
| --op-operations-margin-top | $spacing-md | Operations area top margin |
| --op-operations-gap | 1.6rem | Operation items gap |
| --op-operation-icon-margin-bottom | .06rem | Operation icon bottom margin |
# Color Properties (Color/Background)
| Name | Default Value | Description |
|---|---|---|
| --op-match-card-bg | $color-surface-default | Match card background |
| --op-title-bg | #d9e2ff | Title background |
| --op-title-color | $color-text-primary | Title text color |
| --op-team-name-color | $color-text-primary | Team name color |
| --op-vs-color | $color-text-primary | VS text color |
| --op-status-bg | #eceff2 | Status label background |
| --op-status-color | $color-text-secondary | Status text color |
| --op-game-info-color | #a3abb4 | Game info color |
| --op-operation-icon-color | #000915 | Operation icon color |
| --op-operation-text-color | #212124 | Operation text color |
# Font Properties (Font)
| Name | Default Value | Description |
|---|---|---|
| --op-title-font-size | $font-size-md | Title font size |
| --op-title-font-weight | $font-weight-bold | Title font weight |
| --op-team-name-font-size | $font-size-sm | Team name font size |
| --op-team-name-font-weight | $font-weight-bold | Team name font weight |
| --op-vs-font-size | .8rem | VS text size |
| --op-vs-font-weight | $font-weight-bold | VS text weight |
| --op-vs-line-height | 1 | VS text line height |
| --op-status-font-size | $font-size-xs | Status text size |
| --op-game-info-font-size | $font-size-xs | Game info font size |
| --op-operation-text-font-size | $font-size-xs | Operation text size |
# Border Properties (Border/Border-Radius)
| Name | Default Value | Description |
|---|---|---|
| --op-team-avatar-border | .01rem solid $color-divider-light | Team avatar border |
| --op-match-card-radius | $border-radius-sm | Match card border radius |
| --op-team-avatar-radius | $border-radius-circle | Team avatar border radius |
| --op-operation-icon-radius | $border-radius-xs | Operation icon border radius |
# Shadow Properties (Box-Shadow)
| Name | Default Value | Description |
|---|---|---|
| --op-match-card-shadow | 0 .08rem .08rem 0 #ebeff2 | Match card bottom shadow |
# Position Properties (Position/Top/Left/Z-Index)
| Name | Default Value | Description |
|---|---|---|
| --op-title-section-top | 0 | Title section top position |
| --op-title-section-left | 50% | Title section left position |
| --op-title-texture-top | 0 | Title texture top position |
| --op-title-texture-left | 50% | Title texture left position |
| --op-title-z-index | 2 | Title z-index |
# Transform Properties (Transform)
| Name | Default Value | Description |
|---|---|---|
| --op-title-section-transform | translateX(-50%) | Title section transform |
| --op-title-texture-transform | translateX(-50%) | Title texture transform |
| --op-operation-active-scale | .95 | Operation item active scale |
# Transition Properties (Transition)
| Name | Default Value | Description |
|---|---|---|
| --op-operation-transition | transform .2s ease | Operation item transition |
# Layout Properties (Flex)
| Name | Default Value | Description |
|---|---|---|
| --op-team-flex | 1 | Team flex property |
# Other Properties (Others)
| Name | Default Value | Description |
|---|---|---|
| --op-title-texture-content | '' | Title texture content |
| --op-title-clip-path | polygon(0% 0%, 100% 0%, 95% 100%, 5% 100%) | Title clip path |