# MatchChangeScorePopup 改分弹窗

比赛改分弹窗组件,用于裁判或管理员修改比赛分数,支持双队比分调整和双方判负功能。

# 特性

  • 🎯 分数调整 - 支持增减双方队伍比分,范围0-999
  • 👥 双队显示 - 清晰展示两支队伍信息和当前比分
  • ⚖️ 双方判负 - 一键设置双方判负功能
  • 🎨 自定义样式 - 丰富的CSS变量支持主题定制
  • 🔧 插槽支持 - 支持自定义确认按钮和双败按钮插槽
  • 🔒 数据验证 - 自动限制分数范围,防止异常输入
  • 轻量高效 - 优化的代码结构,性能出色

# 适用场景

  • 电竞比赛分数修正
  • 体育赛事比分调整
  • 在线游戏对战结果修改
  • 比赛管理系统

# 引入

import PressMatchChangeScorePopup from 'press-next/press-match-change-score-popup/press-match-change-score-popup';

# 代码演示

# 基础用法

<template>
  <div class="demo-wrap">
    <h3>基础用法</h3>
    <PressButton @click="showBasicPopup = true">
      显示基础改判比分弹窗
    </PressButton>

    <PressMatchChangeScorePopup
      :show="showBasicPopup"
      :z-index="componentProps.zIndex"
      :left-team="componentProps.leftTeam"
      :right-team="componentProps.rightTeam"
      :initial-left-score="componentProps.initialLeftScore"
      :initial-right-score="componentProps.initialRightScore"
      :custom-class="componentProps.customClass"
      @close="onBasicClose"
      @confirm="onBasicConfirm"
      @both-lose="onBasicBothLose"
    />
  </div>
</template>

<script setup>
import { ref } from 'vue';
import PressButton from 'press-ui/press-button/press-button.vue';
import PressMatchChangeScorePopup from 'press-next/press-match-change-score-popup/press-match-change-score-popup.vue';
import { getMockData } from './demo-data';

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

// 弹窗显示状态
const showBasicPopup = ref(false);

// 基础用法事件处理
const onBasicConfirm = (leftScore, rightScore) => {
  console.log('基础用法 - 确认改判:', { leftScore, rightScore });
  showBasicPopup.value = false;
};

const onBasicClose = () => {
  console.log('基础用法 - 关闭弹窗');
  showBasicPopup.value = false;
};

const onBasicBothLose = (leftScore, rightScore) => {
  console.log('基础用法 - 双方判负:', { leftScore, rightScore });
  showBasicPopup.value = false;
};
</script>

# 自定义插槽用法

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

    <PressMatchChangeScorePopup
      :show="showSlotPopup"
      :z-index="componentProps.zIndex"
      :left-team="componentProps.leftTeam"
      :right-team="componentProps.rightTeam"
      :initial-left-score="componentProps.initialLeftScore"
      :initial-right-score="componentProps.initialRightScore"
      @close="onSlotClose"
      @confirm="onSlotConfirm"
      @both-lose="onSlotBothLose"
    >
      <!-- 自定义确认按钮 -->
      <template #confirm-btn>
        <PressButton
          :class="`${prefix}__custom-confirm`"
          size="small"
          type="primary"
          @click="onSlotConfirm"
        >
          自定义确认
        </PressButton>
      </template>
      
      <!-- 自定义双方判负按钮 -->
      <template #bothLoseBtn>
        <div :class="`${prefix}__custom-both-lose`" @click="onSlotBothLose">
          <div class="pmg-iconfont pmg-icon-warning" />
          <div :class="`${prefix}__custom-both-lose-text`">
            自定义双败
          </div>
        </div>
      </template>
    </PressMatchChangeScorePopup>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import PressButton from 'press-ui/press-button/press-button.vue';
import PressMatchChangeScorePopup from 'src/packages/press-match-change-score-popup/press-match-change-score-popup.vue';
import { getMockData } from 'src/packages/press-match-change-score-popup/demo-data';

const prefix = 'pm-change-score-popup';

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

// 弹窗显示状态
const showSlotPopup = ref(false);

// 自定义插槽事件处理
const onSlotConfirm = (leftScore, rightScore) => {
  if (leftScore !== undefined && rightScore !== undefined) {
    console.log('插槽用法 - 确认改判:', { leftScore, rightScore });
  } else {
    console.log('插槽用法 - 自定义确认按钮点击');
  }
  showSlotPopup.value = false;
};

const onSlotClose = () => {
  console.log('插槽用法 - 关闭弹窗');
  showSlotPopup.value = false;
};

const onSlotBothLose = (leftScore, rightScore) => {
  if (leftScore !== undefined && rightScore !== undefined) {
    console.log('插槽用法 - 双方判负:', { leftScore, rightScore });
  } else {
    console.log('插槽用法 - 自定义双败按钮点击');
  }
  showSlotPopup.value = false;
};
</script>

<style scoped lang="scss">
.pm-change-score-popup {
  &__custom-confirm {
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    border: none;
  }

  &__custom-both-lose {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 8px 16px;
    background: rgba(255, 107, 107, 0.1);
    border-radius: 8px;
    cursor: pointer;
    transition: all 0.3s ease;

    &:hover {
      background: rgba(255, 107, 107, 0.2);
    }

    .pmg-iconfont {
      color: #ff6b6b;
      font-size: 16px;
    }
  }

  &__custom-both-lose-text {
    color: #ff6b6b;
    font-size: 14px;
    font-weight: 500;
  }
}
</style>

# 自定义样式

<template>
  <PressMatchChangeScorePopup
    :show="showPopup"
    :left-team="leftTeam"
    :right-team="rightTeam"
    :initial-left-score="1"
    :initial-right-score="2"
    custom-class="custom-score-popup"
    @close="handleClose"
    @confirm="handleConfirm"
  />
</template>

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

const showPopup = ref(true);
const leftTeam = ref({ name: '红队', avatar: '' });
const rightTeam = ref({ name: '蓝队', avatar: '' });

const handleClose = () => {
  showPopup.value = false;
};

const handleConfirm = (leftScore, rightScore) => {
  console.log('比分确认:', leftScore, rightScore);
};
</script>

<style>
.custom-score-popup {
  --csp-popup-bg: #f8f9fa;
  --csp-score-btn-bg: #007bff;
  --csp-team-info-name-color: #333;
}
</style>

# API

# Props

参数 说明 类型 默认值
custom-class 自定义样式类 string ''
z-index 弹窗层级 number 100
title 弹窗标题 string '改判比分'
show 是否显示弹窗 boolean false
left-team 左队信息 TeamInfo { name: '战队名称A' }
right-team 右队信息 TeamInfo { name: '战队名称A' }
initial-left-score 初始左队比分 number 0
initial-right-score 初始右队比分 number 5
slot-confirm-btn 是否使用确认按钮插槽 boolean false
slot-both-lose-btn 是否使用双败按钮插槽 boolean false

# TeamInfo 数据结构

interface TeamInfo {
  name: string; // 队伍名称
  avatar?: string; // 队伍头像URL,可选
}

# Events

事件名 说明 参数
close 关闭弹窗时触发 -
confirm 确认改分时触发 leftScore: number, rightScore: number
both-lose 双方判负时触发 leftScore: number, rightScore: number

# Slots

插槽名 说明 参数
confirm-btn 自定义确认按钮 -
bothLoseBtn 自定义双方判负按钮 -

插槽使用说明

  • confirm-btn 插槽用于替换默认的确认按钮,需要自行处理点击事件
  • bothLoseBtn 插槽用于替换默认的双方判负按钮,需要自行处理点击事件
  • 插槽内容会完全替换默认按钮,请确保提供合适的交互元素

# 注意事项

# 使用建议

  1. 分数范围:组件自动限制分数范围在0-999之间,超出范围会自动调整
  2. 队伍头像:建议为队伍头像设置默认占位图,避免加载失败时显示空白
  3. 弹窗层级:在复杂页面中使用时,注意调整 z-index 避免层级冲突
  4. 事件处理:确保正确处理 confirmboth-lose 事件,更新业务数据
  5. 插槽使用:使用自定义插槽时,插槽内容会完全替换默认按钮,请确保自行处理点击事件
  6. 响应式适配:在小屏幕设备上,建议适当调整相关尺寸变量

# 性能优化

  • 使用 v-show 控制弹窗显示,避免频繁创建销毁
  • 合理使用 computed 优化数据计算
  • 避免在弹窗内进行复杂的数据处理

# 兼容性

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

# 主题定制

# 样式变量

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

# 尺寸属性 (Width/Height)

名称 默认值 描述
--csp-head-confirm-width 1.4rem 确认按钮宽度
--csp-head-confirm-height .56rem 确认按钮高度
--csp-content-team-min-height 1.12rem 队伍内容最小高度
--csp-team-info-avatar-size .8rem 队伍头像尺寸
--csp-content-team-score-width 2rem 比分区域宽度
--csp-content-team-score-height .44rem 比分区域高度
--csp-score-number-width 1.14rem 分数数字宽度
--csp-score-number-height .44rem 分数数字高度
--csp-score-btn-size .44rem 分数按钮尺寸
--csp-score-btn-sub-width .272rem 减分按钮宽度
--csp-score-btn-sub-height .04rem 减分按钮高度
--csp-warning-height .96rem 警告区域高度

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

名称 默认值 描述
--csp-popup-head-padding-top $spacing-md 弹窗头部上内边距
--csp-popup-head-margin-bottom $spacing-lg 弹窗头部下外边距
--csp-content-team-padding .32rem 0 .16rem 队伍内容内边距
--csp-popup-content-margin-bottom .4rem 弹窗内容下外边距
--csp-team-info-avatar-margin-right $spacing-sm 队伍头像右外边距
--csp-content-team-score-margin auto 0 比分区域外边距
--csp-content-team-score-gap 0 比分区域间距
--csp-warning-padding-bottom .28rem 警告区域下内边距
--csp-warning-gap $spacing-xs 警告区域间距

# 颜色属性 (Color/Background)

名称 默认值 描述
--csp-popup-bg $color-surface-default 弹窗背景色
--csp-score-btn-bg $color-icon-dark 分数按钮背景色
--csp-score-btn-disabled-bg $color-surface-secondary 禁用按钮背景色
--csp-score-btn-sub-bg $color-text-primary 减分按钮背景色
--csp-score-number-bg rgba(247, 249, 250, 1) 分数数字背景色
--csp-score-btn-color $color-text-invert-light 分数按钮文字颜色
--csp-score-number-color $color-text-primary 分数数字颜色
--csp-team-info-name-color $color-text-primary 队伍名称颜色
--csp-warning-icon-color $color-icon-dark 警告图标颜色
--csp-warning-text-color $color-text-primary 警告文字颜色

# 字体属性 (Font)

名称 默认值 描述
--csp-head-confirm-font-size $font-size-sm 确认按钮字体大小
--csp-team-info-name-font-size $font-size-lg 队伍名称字体大小
--csp-score-number-font-size $font-size-md 分数数字字体大小
--csp-score-number-font-weight $font-weight-bold 分数数字字体粗细
--csp-score-btn-icon-font-size .38rem 分数按钮图标大小
--csp-warning-text-font-size .32rem 警告文字字体大小
--csp-warning-icon-font-size $font-size-xl 警告图标字体大小

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

名称 默认值 描述
--csp-content-team-border-bottom .02rem solid #eaeff2 队伍内容下边框
--csp-team-info-avatar-border-radius $border-radius-circle 队伍头像圆角
--csp-score-btn-sub-border-radius $border-radius-xs 减分按钮圆角

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

名称 默认值 描述
--csp-popup-position relative 弹窗定位
--csp-popup-head-position relative 弹窗头部定位

# 布局属性 (Flex)

名称 默认值 描述
--csp-team-info-flex 1 队伍信息flex值
--csp-score-btn-flex-shrink 0 分数按钮收缩值

# 其他属性 (Others)

名称 默认值 描述
--csp-team-info-avatar-object-fit cover 队伍头像适应方式