<template>
  <div class="pc-home-container">

    <div class="hero-section">
      <el-skeleton :loading="isLoading" animated>
        <template #default>
          <div class="main-carousel-wrapper" v-if="banners2 && banners2.length">
            <el-carousel height="100%" class="main-carousel" trigger="click">
              <el-carousel-item v-for="(item, index) in banners2" :key="index">
                <el-image :src="item.image" fit="cover" class="carousel-img" />
              </el-carousel-item>
            </el-carousel>
          </div>

          <div class="sub-banners-wrapper" v-if="banners1 && banners1.length">
            <div class="sub-banner-card" v-for="(item, index) in banners1" :key="index">
              <div class="img-box">
                <el-image :src="item.detail_image" fit="contain" class="sub-img" />
              </div>
              <div class="title-box">
                <span class="sub-title" :title="item.title">{{ item.title }}</span>
              </div>
            </div>
          </div>
        </template>
      </el-skeleton>
    </div>

    <div class="main-split-layout">

      <div class="layout-left-sports">
        <div class="section-header">
          <div class="header-title">
            <div class="decorate-bar"></div>
            <span>{{ t('体育赛事') }}</span>
          </div>
          <el-button link type="primary" class="more-btn" @click="toMoreRollBall('SportsBetting')">
            {{ t('更多体育赛事') }} <el-icon class="ml-1"><ArrowRight /></el-icon>
          </el-button>
        </div>

        <el-skeleton :loading="isLoading" animated>
          <template #template>
            <div class="sports-grid">
              <div class="match-card" v-for="i in 4" :key="i">
                <div class="league-info">
                  <el-skeleton-item variant="text" style="width: 40%;" />
                  <el-skeleton-item variant="text" style="width: 20%;" />
                </div>
                <div class="teams-container">
                  <div class="team-item">
                    <div class="team-info">
                      <el-skeleton-item variant="circle" style="width: 28px; height: 28px; margin-right: 10px; flex-shrink: 0;" />
                      <el-skeleton-item variant="text" style="width: 100px;" />
                    </div>
                  </div>
                  <div class="team-item mt-2">
                    <div class="team-info">
                      <el-skeleton-item variant="circle" style="width: 28px; height: 28px; margin-right: 10px; flex-shrink: 0;" />
                      <el-skeleton-item variant="text" style="width: 120px;" />
                    </div>
                  </div>
                </div>
                <div class="odds-group">
                  <div class="odds-grid-inner">
                    <el-skeleton-item variant="button" class="odds-btn" v-for="j in 3" :key="j" />
                  </div>
                </div>
              </div>
            </div>
          </template>

          <template #default>
            <div class="sports-grid" v-if="gamblingList.length > 0">
              <div class="match-card" v-for="item in gamblingList" :key="item.id" @click="goDetail(item)">

                <div class="league-info">
                  <div class="league-left">
                    <el-icon color="#f8b932" size="16" class="mr-1"><Trophy /></el-icon>
                    <span class="league-name" :title="item.league">{{ item.league }}</span>
                  </div>
                  <div class="match-time-status">
                    <span class="match-score" v-if="[1, 2].includes(item.state)">{{ item.score || '0-0' }}</span>
                    <span class="match-status" :class="{'is-live': item.state === 1}">{{ getStatusText(item.state) }}</span>
                  </div>
                </div>

                <div class="teams-container">
                  <div class="team-item">
                    <div class="team-info">
                      <el-avatar :src="item.home_team_logo" :size="28" class="team-logo"></el-avatar>
                      <span class="team-name" :title="item.home_team">{{ item.home_team }}</span>
                      <el-tag size="small" type="success">{{ t('主') }}</el-tag>
                    </div>
                    <span class="team-score" v-if="item.score && item.score !== '-'">{{ item.score.split('-')[0] }}</span>
                  </div>

                  <div class="team-item mt-2">
                    <div class="team-info">
                      <el-avatar :src="item.guest_team_logo" :size="28" class="team-logo"></el-avatar>
                      <span class="team-name" :title="item.guest_team">{{ item.guest_team }}</span>
                      <el-tag size="small" type="danger">{{ t('客') }}</el-tag>
                    </div>
                    <span class="team-score" v-if="item.score && item.score !== '-'">{{ item.score.split('-')[1] }}</span>
                  </div>
                </div>

                <div class="odds-group" v-if="[0, 1].includes(item.state)">
                  <template v-if="item.odds && item.odds.length > 0 && item.odds[0].values">
                    <div class="odds-grid-inner">
                      <div
                          class="odds-btn"
                          v-for="(opt, optIndex) in getVisibleSportsValues(item.odds[0].values)"
                          :key="optIndex"
                          :class="{
                            'is-locked': isOptionLocked(item, opt),
                            'is-active': isSelected(item.id, item.odds[0].id, opt),
                            'odds-up': isOddsUp(getOddsKey(item.id, item.odds[0].id, opt)) && !isOptionLocked(item, opt),
                            'odds-down': isOddsDown(getOddsKey(item.id, item.odds[0].id, opt)) && !isOptionLocked(item, opt)
                          }"
                      >
                        <div class="odds-name-wrapper">
                          <span class="selection-name" :title="getFormattedSelectionName(item.odds[0].name, opt)">
                            {{ getFormattedSelectionName(item.odds[0].name, opt) }}
                            <span v-if="opt.handicap_text"  class="handicap-val">
                              {{ opt.handicap_text }}
                            </span>
                          </span>
                        </div>
                        <div class="odds-val-wrapper">
                          <span class="odds-val">{{ opt.odd || '-' }}</span>

                          <!-- 3秒闪烁图标 -->
                          <el-icon v-if="isOddsUp(getOddsKey(item.id, item.odds[0].id, opt)) && !isOptionLocked(item, opt)" class="change-icon up">
                            <CaretTop />
                          </el-icon>
                          <el-icon v-else-if="isOddsDown(getOddsKey(item.id, item.odds[0].id, opt)) && !isOptionLocked(item, opt)" class="change-icon down">
                            <CaretBottom />
                          </el-icon>

                          <el-icon v-if="isOptionLocked(item, opt)" class="lock-icon"><Lock /></el-icon>
                        </div>
                      </div>

                      <div
                          class="odds-btn expand-btn"
                          v-if="item.odds_count > 0"
                          @click.stop="goDetail(item)"
                      >
                        <span class="plus-icon">+</span>
                        <span class="remain-count">{{ item.odds_count }}</span>
                      </div>
                    </div>
                  </template>
                </div>

              </div>
            </div>

            <el-empty v-else :description="t('暂无赛事数据')" />
          </template>
        </el-skeleton>
      </div>

      <div class="layout-right-widget">
        <div class="section-header">
          <div class="header-title">
            <div class="decorate-bar"></div>
            <span>{{ t('彩票') }} <span class="count-tag">{{t('加拿大')}}28</span></span>
          </div>
        </div>

        <el-skeleton :loading="isLoading" animated>
          <template #template>
            <div class="pc28-widget-card">
              <div class="widget-top">
                <div class="w-header">
                  <el-skeleton-item variant="text" style="width: 40%;" />
                </div>
                <div class="equation-box">
                  <el-skeleton-item variant="circle" class="calc-circle" />
                  <span class="op">+</span>
                  <el-skeleton-item variant="circle" class="calc-circle" />
                  <span class="op">+</span>
                  <el-skeleton-item variant="circle" class="calc-circle" />
                  <span class="op">=</span>
                  <el-skeleton-item variant="circle" class="calc-circle result" />
                </div>
                <div class="details-list">
                  <el-skeleton-item variant="text" style="width: 100%; margin-bottom: 6px;" />
                  <el-skeleton-item variant="text" style="width: 100%; margin-bottom: 6px;" />
                  <el-skeleton-item variant="text" style="width: 100%;" />
                </div>
              </div>
              <div class="widget-bottom">
                <el-skeleton-item variant="text" style="width: 60%; margin-bottom: 16px;" />
                <div class="timer-box">
                  <el-skeleton-item variant="text" style="width: 80%; height: 30px;" />
                </div>
                <el-skeleton-item variant="button" class="go-bet-btn" />
              </div>
            </div>

            <div class="lhc-widget-card mt-4">
              <div class="widget-top">
                <div class="w-header">
                  <el-skeleton-item variant="text" style="width: 50%;" />
                </div>
                <div class="balls-display-mini">
                  <div class="m-group" v-for="j in 6" :key="'skeln'+j">
                    <el-skeleton-item variant="circle" style="width: 26px; height: 26px;" />
                  </div>
                  <span class="plus"><el-icon><Plus /></el-icon></span>
                  <div class="m-group special">
                    <el-skeleton-item variant="circle" style="width: 30px; height: 30px;" />
                  </div>
                </div>
              </div>
              <div class="widget-bottom">
                <el-skeleton-item variant="text" style="width: 60%; margin-bottom: 16px;" />
                <div class="timer-box">
                  <el-skeleton-item variant="text" style="width: 80%; height: 30px;" />
                </div>
                <el-skeleton-item variant="button" class="go-bet-btn" />
              </div>
            </div>
          </template>

          <template #default>
            <div class="pc28-widget-card" v-if="latestDraw && calcDetails">
              <div class="widget-top" @click="showDetailPopup = true">
                <div class="w-header">
                  <span class="w-issue">{{ latestDraw.issue_no || latestDraw.section }} {{ t('期开奖') }}</span>
                  <el-icon class="w-icon"><DataAnalysis /></el-icon>
                </div>

                <div class="equation-box">
                  <div class="calc-circle">{{ latestDraw.openCode1 }}</div>
                  <span class="op">+</span>
                  <div class="calc-circle">{{ latestDraw.openCode2 }}</div>
                  <span class="op">+</span>
                  <div class="calc-circle">{{ latestDraw.openCode3 }}</div>
                  <span class="op">=</span>
                  <div class="calc-circle result">{{ latestSum }}</div>
                </div>

                <div class="details-list">
                  <div class="d-row"><span class="label">前:</span> <span class="formula">{{ calcDetails.zone1.str }} = {{ calcDetails.zone1.sum }}</span></div>
                  <div class="d-row"><span class="label">中:</span> <span class="formula">{{ calcDetails.zone2.str }} = {{ calcDetails.zone2.sum }}</span></div>
                  <div class="d-row"><span class="label">尾:</span> <span class="formula">{{ calcDetails.zone3.str }} = {{ calcDetails.zone3.sum }}</span></div>
                </div>
              </div>

              <div class="widget-bottom" v-if="countdownInfo">
                <div class="next-title">{{ t('最新') }}: <span class="highlight">{{ countdownInfo.issue_no }}</span> {{ t('期') }}</div>

                <div class="timer-box">
                  <span class="t-label">{{ t('封盘倒计时') }}</span>
                  <div class="time-blocks">
                    <div class="t-box">{{ formatTime(timeLeft).m }}</div>
                    <span class="colon">:</span>
                    <div class="t-box">{{ formatTime(timeLeft).s }}</div>
                  </div>
                </div>

                <el-button type="primary" class="go-bet-btn" @click="router.push({ name: 'Entertainment' })">
                  {{ t('立即去投注') }} <el-icon class="ml-1"><Position /></el-icon>
                </el-button>
              </div>
            </div>

            <div class="lhc-widget-card mt-4" v-if="lhcLastDraw">
              <div class="widget-top">
                <div class="w-header">
                  <span class="w-issue">{{ lhcLastDraw.issue }} {{ t('期开奖') }} ({{ t('澳门六合彩') }})</span>
                </div>

                <div class="balls-display-mini">
                  <div v-for="(b, i) in lhcLastDraw.lottery_codes.slice(0, 6)" :key="i" class="m-group">
                    <span :class="getBgColorClass(b.color)" class="m-ball">
                      <span class="ball-inner">{{ b.code }}</span>
                    </span>
                    <span class="m-zodiac">{{ b.zodiac }}</span>
                  </div>
                  <span class="plus"><el-icon><Plus /></el-icon></span>
                  <div class="m-group special" v-if="lhcLastDraw.lottery_codes[6]">
                    <span :class="getBgColorClass(lhcLastDraw.lottery_codes[6].color)" class="m-ball">
                      <span class="ball-inner">{{ lhcLastDraw.lottery_codes[6].code }}</span>
                    </span>
                    <span class="m-zodiac">{{ lhcLastDraw.lottery_codes[6].zodiac }}</span>
                  </div>
                </div>
              </div>

              <div class="widget-bottom" v-if="lhcNextIssue">
                <div class="next-title">{{ t('最新') }}: <span class="highlight">{{ lhcNextIssue }}</span> {{ t('期') }}</div>

                <div class="timer-box">
                  <span class="t-label">{{ t('距截止下注还有') }}</span>
                  <div class="time-blocks">
                    <div class="t-box">{{ lhcTimeData.hours }}</div>
                    <span class="colon">:</span>
                    <div class="t-box">{{ lhcTimeData.minutes }}</div>
                    <span class="colon">:</span>
                    <div class="t-box">{{ lhcTimeData.seconds }}</div>
                  </div>
                </div>

                <el-button type="primary" class="go-bet-btn" @click="router.push({ name: 'Digital' })">
                  {{ t('立即去投注') }} <el-icon class="ml-1"><Position /></el-icon>
                </el-button>
              </div>
            </div>

            <el-empty v-if="!latestDraw && !lhcLastDraw" :description="t('正在获取开奖数据...')" />
          </template>
        </el-skeleton>
      </div>

    </div>

    <el-dialog
        v-model="showDetailPopup"
        :title="`${latestDraw?.issue_no || latestDraw?.section} ${t('期 开奖详情')}`"
        width="700px"
        center
        custom-class="dark-dialog"
    >
      <div class="dialog-equation" v-if="latestDraw">
        <div class="calc-circle">{{ latestDraw.openCode1 }}</div>
        <span class="op">+</span>
        <div class="calc-circle">{{ latestDraw.openCode2 }}</div>
        <span class="op">+</span>
        <div class="calc-circle">{{ latestDraw.openCode3 }}</div>
        <span class="op">=</span>
        <div class="calc-circle result">{{ latestSum }}</div>
      </div>

      <div class="eighty-grid">
        <div
            class="grid-ball"
            v-for="i in 80"
            :key="i"
            :class="getGridCellClass(i)"
        >
          <div class="ball-inner">{{ i }}</div>
        </div>
      </div>
    </el-dialog>

  </div>
</template>

<script setup>
import { ref, computed, watch, onMounted, onUnmounted } from "vue";
import { useRouter } from "vue-router";
import { useI18n } from "vue-i18n";
import { ArrowRight, Trophy, Lock, DataAnalysis, Position, Calendar, Plus, CaretTop, CaretBottom } from '@element-plus/icons-vue';

import { getActivity, getBanner, getSportSchedule, getLHCInfo, getHowPlay } from "@/request/api.js";
import { useOrderStore } from "@/store/bettingSheet.js";
import socket from '@/utils/websocket.js'
import {formatRange} from "@/utils/index.js";
import { apiUrl } from "@/request/index";

const { t } = useI18n();
const router = useRouter();
const orderStore = useOrderStore();

const isLoading = ref(true);

const banners1 = ref([]);
const banners2 = ref([]);
const gamblingList = ref([]);
const limit = ref(8);
const selectedMap = ref({});

// ====================== 新增：赔率变化闪烁逻辑（3秒） ======================
const oddsChangeMap = ref(new Map())

const getOddsKey = (matchId, marketId, selection) => {
  if (selection.handicap !== null && selection.handicap !== undefined && selection.handicap !== '') {
    return `${matchId}_${marketId}_${selection.value}_${selection.handicap}`
  }
  return `${matchId}_${marketId}_${selection.value}`
}

const isOddsUp = (key) => {
  const change = oddsChangeMap.value.get(key)
  return change?.direction === 'up' && (Date.now() - change.timestamp < 3000)
}

const isOddsDown = (key) => {
  const change = oddsChangeMap.value.get(key)
  return change?.direction === 'down' && (Date.now() - change.timestamp < 3000)
}
// ====================== 新增结束 ======================

const getVisibleSportsValues = (values) => {
  if (!values) return [];
  return values.slice(0, 3);
};

const translateSelection = (valStr) => {
  if (valStr === undefined || valStr === null) return '';
  return String(valStr);
};

const getFormattedSelectionName = (marketName, opt) => {
  const translatedValue = translateSelection(opt.value_text);
  if (!opt.handicap && (translatedValue === '1' || translatedValue === '2' || translatedValue === 'Yes' || translatedValue === 'No')) {
    return `${marketName} - ${translatedValue}`;
  }
  return translatedValue;
};

const getUniqueKey = (matchId, marketId, selection) => {
  if (selection.handicap !== null && selection.handicap !== undefined && selection.handicap !== '') {
    return `${matchId}_${marketId}_${selection.value}_${selection.handicap}`;
  }
  return `${matchId}_${marketId}_${selection.value}`;
};

const checkIsLocked = (item) => {
  if (!item) return true;
  if (Number(item.is_locked) === 1) return true;
  if (item.status !== undefined && Number(item.status) !== 1) return true;
  if (item.state !== undefined && item.state !== 0 && item.state !== 1) return true;
  return false;
};

const isOptionLocked = (item, opt) => {
  if (checkIsLocked(item)) return true;
  if (!opt || !opt.odd || opt.odd === '-' || Number(opt.odd) === 0) return true;
  if (opt.suspended === true || String(opt.suspended).toLowerCase() === 'true') return true;
  if (item.odds && item.odds[0] && item.odds[0].is_findLocked) return true;
  return false;
};

const syncFromStore = () => {
  const map = {};
  if (orderStore.selectOrders && orderStore.selectOrders.length) {
    orderStore.selectOrders.forEach(order => {
      if (order.uniqueKey) map[order.uniqueKey] = true;
    });
  }
  selectedMap.value = map;
};

watch(() => orderStore.selectOrders, () => syncFromStore(), { deep: true, immediate: true });

// ==========================================
// 彩票 PC28 倒计时与开奖状态
// ==========================================
const latestDraw = ref(null);
const countdownInfo = ref(null);
const showDetailPopup = ref(false);
const timeLeft = ref(0);
let pcTimer = null;

const fetchPC28Data = async () => {
  try {
    const [yuanTouRes, countRes] = await Promise.all([
      fetch(`${apiUrl}newPc/yuanTou`).then(r => r.json()).catch(() => null),
      fetch(`${apiUrl}newPc/countdown`).then(r => r.json()).catch(() => null)
    ]);

    if (yuanTouRes?.code === 0 && yuanTouRes.data.length > 0) latestDraw.value = yuanTouRes.data[0];
    if (countRes?.code === 0 && countRes.data) {
      countdownInfo.value = countRes.data;
      startPCCountdown(countRes.data.end_time, countRes.data.current_time);
    }
  } catch (error) {}
};

const startPCCountdown = (endTime, currentTime) => {
  clearInterval(pcTimer);
  const diff = endTime - currentTime;
  timeLeft.value = Math.max(0, diff);

  if (diff > 0) {
    pcTimer = setInterval(() => {
      if (timeLeft.value > 0) timeLeft.value--;
      else clearInterval(pcTimer);
    }, 1000);
  }
};

const latestSum = computed(() => {
  if (!latestDraw.value) return 0;
  return Number(latestDraw.value.openCode1 || 0) + Number(latestDraw.value.openCode2 || 0) + Number(latestDraw.value.openCode3 || 0);
});

const calcDetails = computed(() => {
  if (!latestDraw.value || !latestDraw.value.keno) return null;
  const keno = latestDraw.value.keno.map(Number);
  const getZone = (startIndex) => {
    let nums = [], sum = 0;
    for (let i = 0; i < 6; i++) {
      const val = keno[startIndex + i * 3];
      nums.push(val); sum += val;
    }
    return { str: nums.join(' + '), sum };
  };
  return { zone1: getZone(1), zone2: getZone(2), zone3: getZone(3) };
});

const formatTime = (seconds) => {
  const m = Math.floor(seconds / 60).toString().padStart(2, '0');
  const s = (seconds % 60).toString().padStart(2, '0');
  return { m, s };
};

// ==========================================
// 彩票 六合彩
// ==========================================
const lhcLastDraw = ref(null);
const lhcNextIssue = ref('');
const numberToZodiacMap = ref({});
const lhcTimeData = ref({ hours: '00', minutes: '00', seconds: '00' });
let lhcCountdownTimer = null;
let lhcRemainingSeconds = 0;

const calculateBallColor = (numStr) => {
  const num = parseInt(numStr, 10);
  if (isNaN(num)) return '';
  if ([1, 2, 7, 8, 12, 13, 18, 19, 23, 24, 29, 30, 34, 35, 40, 45, 46].includes(num)) return '红';
  if ([3, 4, 9, 10, 14, 15, 20, 25, 26, 31, 36, 37, 41, 42, 47, 48].includes(num)) return '蓝';
  if ([5, 6, 11, 16, 17, 21, 22, 27, 28, 32, 33, 38, 39, 43, 44, 49].includes(num)) return '绿';
  return '';
};

const getBgColorClass = (colorName) => colorName === '红' ? 'bg-red' : colorName === '蓝' ? 'bg-blue' : colorName === '绿' ? 'bg-green' : 'bg-gray';

const initLhcData = async () => {
  try {
    const [infoRes, playRes] = await Promise.all([getLHCInfo(), getHowPlay()]);
    if (infoRes.code === 1 && infoRes.data) {
      numberToZodiacMap.value = infoRes.data.number_to_zodiac || {};
    }
    if (playRes.code === 1 && playRes.data) {
      lhcNextIssue.value = playRes.data.next_issue || playRes.data.issue;
      if (playRes.data.history_lottery && playRes.data.history_lottery.length > 0) {
        const draw = playRes.data.history_lottery[0];
        lhcLastDraw.value = {
          ...draw,
          lottery_codes: draw.lottery_codes.map(codeStr => ({
            code: codeStr,
            color: calculateBallColor(codeStr),
            zodiac: numberToZodiacMap.value[codeStr] || ''
          }))
        };
      }
      startLhcCountdown(Number(playRes.data.countdown || 0));
    }
  } catch (error) {
    console.error('获取六合彩数据失败', error);
  }
};

const startLhcCountdown = (seconds) => {
  lhcRemainingSeconds = seconds;
  clearInterval(lhcCountdownTimer);
  lhcCountdownTimer = setInterval(() => {
    if (lhcRemainingSeconds > 0) {
      lhcRemainingSeconds--;
      lhcTimeData.value.hours = Math.floor(lhcRemainingSeconds / 3600).toString().padStart(2, '0');
      lhcTimeData.value.minutes = Math.floor((lhcRemainingSeconds % 3600) / 60).toString().padStart(2, '0');
      lhcTimeData.value.seconds = (lhcRemainingSeconds % 60).toString().padStart(2, '0');
    } else {
      clearInterval(lhcCountdownTimer);
      initLhcData();
    }
  }, 1000);
};

// ==========================================
// 核心数据初始化
// ==========================================
const initData = async () => {
  isLoading.value = true;
  try {
    const [resB1, resB2, resGambling] = await Promise.all([
      getActivity({ type: 2 }),
      getBanner({ type: 'pc' }),
      getSportSchedule({ page: 1, limit: limit.value, state: 1, is_rec: 1 })
    ]);

    banners1.value = resB1.data?.list || [];
    banners2.value = resB2.data?.list || [];

    let currentGamblingList = resGambling.data?.list || [];
    if (currentGamblingList.length === 0) {
      const fallback = await getSportSchedule({ page: 1, limit: limit.value, state: 0, is_rec: 1 });
      currentGamblingList = fallback.data?.list || [];
    }

    gamblingList.value = (currentGamblingList || []).map(item => {
      if (typeof item.odds === 'string') {
        try { item.odds = JSON.parse(item.odds); } catch(e) { item.odds = []; }
      }
      if (item.odds && item.odds.length > 0) {
        item.odds.forEach(jtem => {
          if (item.odd_ids_locked && item.odd_ids_locked.find(trim => jtem.id === trim)) {
            jtem.is_findLocked = true;
          }
        });
      }
      return item;
    });

    await Promise.all([fetchPC28Data(), initLhcData()]);
  } catch (error) {
    console.error('首页数据加载失败', error);
  } finally {
    isLoading.value = false;
  }
};

const goDetail = (item) => router.push({ name: 'SportDetail', query: { data_id: item.data_id } });
const toMoreRollBall = (name) => router.push({ name });

const getStatusText = (state) => {
  const states = { 0: t("未开始"), 1: t("进行中"), 2: t("已完场"), 3: t("延期"), 4: t("取消") };
  return states[state] || "";
};

const isSelected = (matchId, marketId, selection) => {
  if (!selection) return false;
  const uniqueKey = getUniqueKey(matchId, marketId, selection);
  return !!selectedMap.value[uniqueKey];
};

// ==========================================
// WebSocket 监听（包含3秒闪烁检测）
// ==========================================
const handleSocketMessage = (e) => {
  try {
    const res = e.detail;
    if (!res) return;

    if (res.type === 'sport_list' && Array.isArray(res.message)) {
      res.message.forEach((newMatch) => {
        const idx = gamblingList.value.findIndex(item => item.data_id === newMatch.data_id);
        if (idx !== -1) {
          const oldMatch = gamblingList.value[idx];

          // === 3秒闪烁检测 ===
          let parsedNewOdds = newMatch.odds;
          if (typeof parsedNewOdds === 'string') {
            try { parsedNewOdds = JSON.parse(parsedNewOdds); } catch(e) { parsedNewOdds = []; }
          }
          if (oldMatch.odds?.[0] && parsedNewOdds?.[0]) {
            const oldMarket = oldMatch.odds[0];
            const newMarket = parsedNewOdds[0];
            if (oldMarket.values && newMarket.values) {
              newMarket.values.forEach(newOpt => {
                const oldOpt = oldMarket.values.find(o =>
                    o.value === newOpt.value &&
                    (o.handicap == newOpt.handicap || (!o.handicap && !newOpt.handicap))
                );
                if (oldOpt?.odd && newOpt?.odd) {
                  const oldNum = parseFloat(oldOpt.odd);
                  const newNum = parseFloat(newOpt.odd);
                  if (!isNaN(oldNum) && !isNaN(newNum) && oldNum !== newNum) {
                    const key = getOddsKey(oldMatch.id, newMarket.id, newOpt);
                    const direction = newNum > oldNum ? 'up' : 'down';
                    oddsChangeMap.value.set(key, { direction, timestamp: Date.now() });
                    setTimeout(() => oddsChangeMap.value.delete(key), 3100);
                  }
                }
              });
            }
          }

          gamblingList.value[idx] = { ...oldMatch, ...newMatch };
          if (typeof orderStore.updateMatchStatus === 'function') {
            orderStore.updateMatchStatus(newMatch.data_id, newMatch);
          }
        }
      });
    }

    if (res.type === 'new_issue' && countdownInfo.value?.issue_no !== res.message) {
      fetchPC28Data();
    }
  } catch (error) {}
};

onMounted(() => {
  syncFromStore();
  initData();
  socket.eventBus.addEventListener('onSocketMessage', handleSocketMessage);
});

onUnmounted(() => {
  socket.eventBus.removeEventListener('onSocketMessage', handleSocketMessage);
  clearInterval(pcTimer);
  clearInterval(lhcCountdownTimer);
});
</script>

<style scoped lang="scss">
$main-color: #f8b932;
$card-bg: var(--el-bg-color-overlay);
$border-color: var(--el-border-color-lighter);
$hover-bg: var(--el-fill-color-light);

.pc-home-container {
  container-type: inline-size;
  min-height: 100%;
  padding: 24px;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  gap: 24px;
  @container (max-width: 1200px) { padding: 16px; gap: 16px; }
  @container (max-width: 800px) { padding: 12px; gap: 12px; }
  @container (max-width: 550px) { padding: 8px; gap: 8px; }
}

/* =======================================
   1. 顶部视界区 (Hero Section)
   ======================================= */
.hero-section {
  display: flex; flex-direction: column; gap: 16px;
  .main-carousel-wrapper {
    width: 100%;
    border-radius: 12px;
    overflow: hidden;
    box-shadow: var(--el-box-shadow-light);
    /* 【核心魔法】直接填入 UI 设计师给你的原图尺寸比例 */
    aspect-ratio: 1920 / 292;
    @media (max-width: 768px) {
      aspect-ratio: 480 / 73;
    }
    .carousel-img {
      width: 100%;
      height: 100%;
    }
    :deep(.el-carousel) { height: 100%; }
    :deep(.el-carousel__container) { height: 100% !important; }
  }
  .sub-banners-wrapper {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 16px;
    @container (max-width: 1350px) { grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); }
    @container (max-width: 992px) { grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); }
    @container (max-width: 550px) { grid-template-columns: repeat(2, 1fr); gap: 10px; }
    .sub-banner-card {
      background-color: $card-bg; border-radius: 8px; border: 1px solid $border-color; overflow: hidden; display: flex; flex-direction: column; box-shadow: 0 2px 8px rgba(0,0,0,0.02); transition: transform 0.2s; cursor: pointer;
      &:hover { transform: translateY(-2px); box-shadow: var(--el-box-shadow-light); }
      .img-box {
        width: 100%; height: 120px;
        @container (max-width: 992px) { height: 90px; }
        @container (max-width: 550px) { height: 70px; }
        .sub-img { width: 100%; height: 100%; }
      }
      .title-box {
        padding: 12px; text-align: center;
        @container (max-width: 800px) { padding: 8px; }
        .sub-title { font-size: 14px; font-weight: bold; color: var(--el-text-color-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: block; @container (max-width: 800px) { font-size: 11px; } }
      }
    }
  }
}

/* =======================================
   2. 主体分栏 (Split Layout)
   ======================================= */
.main-split-layout {
  display: flex;
  flex-wrap: wrap;
  gap: 24px;
  align-items: flex-start;
  width: 100%;
  @container (max-width: 1350px) { gap: 20px; }
  @container (max-width: 992px) { gap: 16px; }
  @container (max-width: 800px) { gap: 10px; }
  @container (max-width: 550px) { gap: 0; }

  /* --- 左侧体育赛事 --- */
  .layout-left-sports {
    flex: 1;
    min-width: 300px;
    @container (max-width: 550px) {
      min-width: 100%;
      margin-bottom: 16px;
    }
    .section-header {
      display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px;
      .header-title { display: flex; align-items: center; font-size: 18px; font-weight: bold; color: var(--el-text-color-primary); @container (max-width: 800px) { font-size: 14px; } .decorate-bar { width: 4px; height: 18px; background-color: $main-color; border-radius: 2px; margin-right: 10px; } }
      .more-btn { font-size: 14px; font-weight: bold; @container (max-width: 800px) { font-size: 12px; } }
    }
    .sports-grid {
      display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px;
      @container (max-width: 1200px) { grid-template-columns: 1fr; }
    }
    .match-card {
      background-color: $card-bg; border-radius: 8px; border: 1px solid $border-color; padding: 16px; box-shadow: 0 2px 8px rgba(0,0,0,0.02); transition: border-color 0.2s; cursor: pointer;
      @container (max-width: 800px) { padding: 12px; }
      @container (max-width: 400px) { padding: 10px; }
      &:hover { border-color: var(--el-border-color); }
      .league-info {
        display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; border-bottom: 1px dashed $border-color; padding-bottom: 12px;
        @container (max-width: 800px) { margin-bottom: 12px; padding-bottom: 8px; }
        .league-left { display: flex; align-items: center; flex: 1; overflow: hidden; .league-name { font-size: 14px; font-weight: bold; color: var(--el-text-color-regular); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; @container (max-width: 800px){ font-size: 12px; } } }
        .match-time-status { font-size: 13px; @container (max-width: 800px){ font-size: 11px; } .match-score { color: var(--el-text-color-secondary); margin-right: 6px; } .match-status { color: var(--el-text-color-regular); &.is-live { color: var(--el-color-danger); font-weight: bold; } } }
      }
      .teams-container {
        display: flex; flex-direction: column; margin-bottom: 16px;
        .team-item {
          display: flex; justify-content: space-between; align-items: center;
          @container (max-width: 400px) { margin-top: 6px; }
          .team-info { display: flex; align-items: center; gap: 10px; flex: 1; overflow: hidden; .team-name { font-size: 15px; font-weight: 500; color: var(--el-text-color-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; @container (max-width: 800px){ font-size: 13px; } } }
          .team-score { font-size: 16px; font-weight: 800; color: var(--el-text-color-primary); }
        }
      }
      .odds-group .odds-grid-inner {
        display: flex; gap: 8px; width: 100%;
        .odds-btn {
          flex: 1; min-width: 0; background-color: var(--el-fill-color); border: 1px solid var(--el-border-color); border-radius: 6px; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 8px 4px; height: 54px; box-sizing: border-box; transition: all 0.2s; cursor: pointer; position: relative; overflow: hidden; gap: 4px;
          @container (max-width: 800px) { height: 44px; padding: 4px; }
          @container (max-width: 400px) { height: 36px; padding: 2px; }
          .odds-name-wrapper {
            display: flex; align-items: center; justify-content: center; width: 100%; z-index: 1;
            .selection-name { font-size: 12px; color: var(--el-text-color-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; @container (max-width: 800px){ font-size: 10px; transform: scale(0.9); } @container (max-width: 400px){ transform: scale(0.8); } }
            .handicap-val { color: var(--el-text-color-primary); font-weight: bold; margin-left: 4px; font-size: 12px; @container (max-width: 800px){ font-size: 10px; transform: scale(0.9); } }
          }
          .odds-val-wrapper {
            display: flex; align-items: center; justify-content: center; gap: 4px; z-index: 1;
            .odds-val { font-size: 15px; font-weight: bold; color: $main-color; @container (max-width: 800px){ font-size: 12px; } @container (max-width: 400px){ font-size: 11px; } }
          }
          &.is-active { background-color: $main-color; border-color: $main-color; .odds-name-wrapper .selection-name, .odds-name-wrapper .handicap-val, .odds-val-wrapper .odds-val { color: #fff; } }
          &.is-locked { cursor: not-allowed; border-color: transparent; .selection-name, .handicap-val, .odds-val { opacity: 0.3; } &::after { content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(0, 0, 0, 0.4); z-index: 2; } .lock-icon { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: #fff; font-size: 16px; z-index: 3; } }
          &.expand-btn { flex-direction: row; background-color: transparent; border: 1px dashed var(--el-border-color-darker); .plus-icon { font-size: 16px; color: var(--el-text-color-secondary); margin-right: 4px; } .remain-count { font-size: 14px; font-weight: bold; color: var(--el-text-color-secondary); } &:hover { border-color: $main-color; .plus-icon, .remain-count { color: $main-color; } } }

          /* 新增：3秒闪烁样式（来自第二段代码） */
          &.odds-up .odds-val { color: #4caf50 !important; transition: color 0.3s; }
          &.odds-down .odds-val { color: #f56c6c !important; transition: color 0.3s; }
          .change-icon {
            margin-left: 4px;
            font-size: 14px;
            &.up { color: #4caf50; }
            &.down { color: #f56c6c; }
          }
          &.odds-up, &.odds-down {
            //animation: oddsFlash 0.6s ease;
          }
        }
      }
    }
  }

  /* --- 右侧悬浮组件区 --- */
  .layout-right-widget {
    position: sticky;
    top: 24px;
    z-index: 10;
    width: 320px;
    flex-shrink: 0;
    @container (max-width: 1600px) { width: 300px; }
    @container (max-width: 1350px) { width: 260px; }
    @container (max-width: 1200px) { width: 250px; }
    @container (max-width: 992px) { width: 230px; }
    @container (max-width: 800px) { width: 210px; }
    @container (max-width: 550px) { width: 100%!important; }
    .section-header {
      display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px;
      .header-title { display: flex; align-items: center; font-size: 18px; font-weight: bold; color: var(--el-text-color-primary); @container (max-width: 800px) { font-size: 14px; } .decorate-bar { width: 4px; height: 18px; background-color: $main-color; border-radius: 2px; margin-right: 10px; } }
    }
    /* PC28 卡片 */
    .pc28-widget-card {
      background: linear-gradient(135deg, #1f2329 0%, #2c323b 100%); border-radius: 12px; overflow: hidden; box-shadow: 0 4px 16px rgba(0,0,0,0.1); border: 1px solid rgba(255,255,255,0.05);
      .widget-top {
        padding: 20px; border-bottom: 1px solid rgba(255,255,255,0.05); cursor: pointer; transition: background 0.2s;
        @container (max-width: 800px) { padding: 12px; }
        @container (max-width: 550px) { padding: 16px; }
        &:hover { background: rgba(255,255,255,0.02); }
        .w-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; @container (max-width: 800px) { margin-bottom: 10px; } .w-issue { font-size: 14px; color: #a1a1aa; @container (max-width: 800px) { font-size: 10px; } @container (max-width: 550px) { font-size: 12px; } } .w-icon { color: $main-color; font-size: 16px; } }
        .equation-box {
          display: flex; align-items: center; justify-content: center; gap: 6px; margin-bottom: 20px;
          @container (max-width: 800px) { gap: 2px; margin-bottom: 12px; }
          @container (max-width: 550px) { gap: 6px; margin-bottom: 16px; }
          .calc-circle {
            width: 36px; height: 36px; border-radius: 50%; border: 1px solid rgba(255,255,255,0.5); display: flex; align-items: center; justify-content: center; font-size: 16px; font-weight: bold; color: #fff;
            @container (max-width: 1200px) { width: 30px; height: 30px; }
            @container (max-width: 800px) { width: 22px; height: 22px; font-size: 11px; }
            @container (max-width: 550px) { width: 32px; height: 32px; font-size: 14px; }
            &.result { background: var(--el-color-danger); border: none; box-shadow: 0 0 10px rgba(245,108,108,0.5); }
          }
          .op { font-size: 18px; color: #fff; font-weight: bold; @container (max-width: 800px) { font-size: 12px; } @container (max-width: 550px) { font-size: 16px; } }
        }
        .details-list {
          display: flex; flex-direction: column; gap: 6px;
          @container (max-width: 550px) { flex-direction: row; justify-content: space-between; }
          .d-row { background: rgba(0,0,0,0.2); padding: 6px 10px; border-radius: 4px; font-size: 12px; color: #cbd5e1; @container (max-width: 800px) { font-size: 9px; padding: 4px; } @container (max-width: 550px) { flex: 1; text-align: center; font-size: 11px; padding: 6px 2px; } .label { color: $main-color; margin-right: 6px; } .formula { font-family: monospace; } }
        }
      }
      .widget-bottom {
        padding: 20px; background: rgba(0,0,0,0.15); display: flex; flex-direction: column; align-items: center;
        @container (max-width: 800px) { padding: 12px; }
        @container (max-width: 550px) { padding: 16px; }
        .next-title { font-size: 14px; color: #f8fafc; margin-bottom: 16px; @container (max-width: 800px) { font-size: 10px; margin-bottom: 10px; } @container (max-width: 550px) { font-size: 13px; margin-bottom: 12px; } .highlight { color: var(--el-color-danger); font-size: 16px; font-weight: bold; margin: 0 4px; @container (max-width: 800px) { font-size: 12px; margin: 0 2px;} } }
        .timer-box {
          background: rgba(0,0,0,0.3); padding: 12px 20px; border-radius: 8px; text-align: center; width: 100%; box-sizing: border-box; margin-bottom: 20px;
          @container (max-width: 800px) { padding: 8px; margin-bottom: 12px; }
          @container (max-width: 550px) { padding: 12px; margin-bottom: 16px; }
          .t-label { display: block; font-size: 12px; color: #94a3b8; margin-bottom: 8px; @container (max-width: 800px){ font-size: 9px; margin-bottom: 4px; } @container (max-width: 550px){ font-size: 11px; margin-bottom: 6px; } }
          .time-blocks { display: flex; justify-content: center; align-items: center; gap: 8px; @container (max-width: 800px){ gap: 4px; } @container (max-width: 550px){ gap: 8px; } .t-box { background: #d35400; color: #fff; font-size: 24px; font-weight: bold; padding: 4px 10px; border-radius: 4px; box-shadow: inset 0 -2px 0 rgba(0,0,0,0.3); @container (max-width: 800px){ font-size: 14px; padding: 2px 4px;} @container (max-width: 550px){ font-size: 18px; padding: 4px 8px;} } .colon { font-size: 20px; font-weight: bold; color: #94a3b8; @container (max-width: 800px){ font-size: 12px; } } }
        }
        .go-bet-btn { width: 100%; height: 44px; font-weight: bold; font-size: 15px; color: #000; @container (max-width: 800px){ height: 32px; font-size: 11px; } @container (max-width: 550px){ height: 38px; font-size: 14px; } }
      }
    }
    /* 六合彩 卡片 */
    .lhc-widget-card {
      background: linear-gradient(135deg, #1f2329 0%, #2c323b 100%); border-radius: 12px; overflow: hidden; box-shadow: 0 4px 16px rgba(0,0,0,0.1); border: 1px solid rgba(255,255,255,0.05);
      .widget-top {
        padding: 20px; border-bottom: 1px solid rgba(255,255,255,0.05);
        @container (max-width: 800px) { padding: 12px; }
        @container (max-width: 550px) { padding: 16px; }
        .w-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; @container (max-width: 800px) { margin-bottom: 10px; } .w-issue { font-size: 14px; color: #a1a1aa; @container (max-width: 800px) { font-size: 10px; } @container (max-width: 550px) { font-size: 12px; } } .w-icon { color: $main-color; font-size: 16px; } }
        /* 六合彩特有球体布局 */
        .balls-display-mini {
          display: flex; align-items: center; justify-content: space-between; gap: 2px;
          .m-group {
            display: flex; flex-direction: column; align-items: center; gap: 4px;
            .m-ball {
              width: 26px; height: 26px; border-radius: 50%; display: flex; align-items: center; justify-content: center;
              background-size: 100% 100%; background-position: center; background-repeat: no-repeat;
              &.bg-red { background: linear-gradient(135deg, #ff416c 0%, #ff4b2b 100%); }
              &.bg-blue { background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); }
              &.bg-green { background: linear-gradient(135deg, #0ba360 0%, #3cba92 100%); }
              &.bg-gray { background: #555; }
              .ball-inner { width: 80%; height: 80%; background: #fff; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: bold; color: #333; }
            }
            .m-zodiac { font-size: 11px; color: #999; transform: scale(0.9); }
            &.special .m-ball { transform: scale(1.15); }
          }
          .plus { color: #666; font-size: 14px; margin-top: -16px; }
        }
      }
      .widget-bottom {
        padding: 20px; background: rgba(0,0,0,0.15); display: flex; flex-direction: column; align-items: center;
        @container (max-width: 800px) { padding: 12px; }
        @container (max-width: 550px) { padding: 16px; }
        .next-title { font-size: 14px; color: #f8fafc; margin-bottom: 16px; @container (max-width: 800px) { font-size: 10px; margin-bottom: 10px; } @container (max-width: 550px) { font-size: 13px; margin-bottom: 12px; } .highlight { color: var(--el-color-danger); font-size: 16px; font-weight: bold; margin: 0 4px; @container (max-width: 800px) { font-size: 12px; margin: 0 2px;} } }
        .timer-box {
          background: rgba(0,0,0,0.3); padding: 12px 20px; border-radius: 8px; text-align: center; width: 100%; box-sizing: border-box; margin-bottom: 20px;
          @container (max-width: 800px) { padding: 8px; margin-bottom: 12px; }
          @container (max-width: 550px) { padding: 12px; margin-bottom: 16px; }
          .t-label { display: block; font-size: 12px; color: #94a3b8; margin-bottom: 8px; @container (max-width: 800px){ font-size: 9px; margin-bottom: 4px; } @container (max-width: 550px){ font-size: 11px; margin-bottom: 6px; } }
          .time-blocks { display: flex; justify-content: center; align-items: center; gap: 8px; @container (max-width: 800px){ gap: 4px; } @container (max-width: 550px){ gap: 8px; } .t-box { background: #0e86e3; color: #fff; font-size: 24px; font-weight: bold; padding: 4px 10px; border-radius: 4px; box-shadow: inset 0 -2px 0 rgba(0,0,0,0.3); @container (max-width: 800px){ font-size: 14px; padding: 2px 4px;} @container (max-width: 550px){ font-size: 18px; padding: 4px 8px;} } .colon { font-size: 20px; font-weight: bold; color: #94a3b8; @container (max-width: 800px){ font-size: 12px; } } }
        }
        .go-bet-btn { width: 100%; height: 44px; font-weight: bold; font-size: 15px; color: #000; @container (max-width: 800px){ height: 32px; font-size: 11px; } @container (max-width: 550px){ height: 38px; font-size: 14px; } }
      }
    }
  }
}

/* 弹窗及通用样式 */
.dialog-equation { display: flex; justify-content: center; align-items: center; margin-bottom: 30px; .calc-circle { width: 54px; height: 54px; border-radius: 50%; border: 2px solid var(--el-border-color-darker); display: flex; align-items: center; justify-content: center; font-size: 22px; font-weight: bold; color: var(--el-text-color-primary); background-color: var(--el-fill-color-darker); &.result { background-color: var(--el-color-danger); border: none; color: #fff; box-shadow: 0 4px 15px rgba(245, 108, 108, 0.5); } } .op { font-size: 26px; color: var(--el-text-color-regular); font-weight: bold; margin: 0 16px; } }
.eighty-grid { display: grid; grid-template-columns: repeat(10, 1fr); gap: 12px; background-color: var(--el-fill-color-darker); padding: 24px; border-radius: 12px; box-shadow: inset 0 2px 10px rgba(0,0,0,0.2); .grid-ball { aspect-ratio: 1; border-radius: 50%; display: flex; align-items: center; justify-content: center; background-color: var(--el-fill-color); border: 1px solid var(--el-border-color-darker); box-shadow: inset 0 -2px 0 rgba(0,0,0,0.1); .ball-inner { font-size: 15px; font-weight: bold; color: var(--el-text-color-placeholder); } &.bg-red { background: linear-gradient(135deg, #ff4b2b 0%, #ff416c 100%); border: none; box-shadow: 0 3px 8px rgba(255, 65, 108, 0.4), inset 0 2px 0 rgba(255,255,255,0.3); .ball-inner { color: #fff; text-shadow: 0 1px 2px rgba(0,0,0,0.3); } } &.bg-blue { background: linear-gradient(135deg, #00f2fe 0%, #4facfe 100%); border: none; box-shadow: 0 3px 8px rgba(79, 172, 254, 0.4), inset 0 2px 0 rgba(255,255,255,0.3); .ball-inner { color: #fff; text-shadow: 0 1px 2px rgba(0,0,0,0.3); } } } }
.mr-1 { margin-right: 4px; } .mt-2 { margin-top: 8px; } .ml-1 { margin-left: 4px; } .mt-4 { margin-top: 16px; }
:deep(.el-avatar) { @container (max-width: 800px) { width: 22px !important; height: 22px !important; } @container (max-width: 400px) { width: 18px !important; height: 18px !important; } }

@keyframes oddsFlash {
  0% { transform: scale(1); }
  50% { transform: scale(1.08); }
  100% { transform: scale(1); }
}
</style>
