فهرست منبع

修改赔率记录

flyzto 1 هفته پیش
والد
کامیت
3924f59b0f
2فایلهای تغییر یافته به همراه58 افزوده شده و 95 حذف شده
  1. 7 10
      server/models/OddsHistory.js
  2. 51 85
      web/apps/web-antd/src/views/match/odds-curve/index.vue

+ 7 - 10
server/models/OddsHistory.js

@@ -2,18 +2,10 @@ import mongoose from 'mongoose';
 const { Schema } = mongoose;
 
 const TRACKED_IOR_KEYS = [
-  'ior_mn',
-  'ior_wmh_1',
-  'ior_wmh_2',
-  'ior_wmh_3',
-  'ior_wmc_1',
-  'ior_wmc_2',
-  'ior_wmc_3',
   'ior_ot_1',
   'ior_ot_2',
   'ior_ot_3',
   'ior_ot_4',
-  'ior_ot_5',
 ];
 
 const TRACKED_IOR_SET = new Set(TRACKED_IOR_KEYS);
@@ -145,9 +137,13 @@ const getGameOddsHistory = async (eventId) => {
   if (!history) {
     return null;
   }
+  const markets = Object.fromEntries(
+    Object.entries(history.markets ?? {})
+    .filter(([key, points]) => isTrackedKey(key) && points?.length),
+  );
   return {
     ...history,
-    markets: history.markets ? Object.fromEntries(Object.entries(history.markets)) : {},
+    markets,
   };
 }
 
@@ -193,7 +189,8 @@ const getOddsHistoryGames = async ({ page = 1, pageSize = 50, status = -1, keywo
     teamAwayName: history.teamAwayName,
     startTime: history.startTime,
     endTime: history.endTime,
-    marketCount: Object.values(history.markets ?? {}).filter(points => points?.length).length,
+    marketCount: Object.entries(history.markets ?? {})
+    .filter(([key, points]) => isTrackedKey(key) && points?.length).length,
     updatedAt: history.updatedAt,
   }));
 

+ 51 - 85
web/apps/web-antd/src/views/match/odds-curve/index.vue

@@ -14,6 +14,7 @@ import {
   Pagination,
   Radio,
   RadioGroup,
+  Switch,
   Spin,
 } from 'ant-design-vue';
 import dayjs from 'dayjs';
@@ -55,50 +56,15 @@ type HistoryGamesResponse = {
   total: number;
 };
 
-const MARKET_GROUPS = [
-  {
-    keys: [
-      'ior_mn',
-      'ior_wmh_1',
-      'ior_wmh_2',
-      'ior_wmh_3',
-      'ior_wmc_1',
-      'ior_wmc_2',
-      'ior_wmc_3',
-    ],
-    label: '让平盘',
-  },
-  {
-    keys: ['ior_ot_1', 'ior_ot_2', 'ior_ot_3', 'ior_ot_4', 'ior_ot_5'],
-    label: '进球数',
-  },
-];
+const MARKET_KEYS = ['ior_ot_1', 'ior_ot_2', 'ior_ot_3', 'ior_ot_4'];
 
 const MARKET_LABELS: Record<string, string> = {
-  ior_mn: '和局',
   ior_ot_1: '总进球 1',
   ior_ot_2: '总进球 2',
   ior_ot_3: '总进球 3',
   ior_ot_4: '总进球 4',
-  ior_ot_5: '总进球 5',
-  ior_wmc_1: '客胜 1 球',
-  ior_wmc_2: '客胜 2 球',
-  ior_wmc_3: '客胜 3 球',
-  ior_wmh_1: '主胜 1 球',
-  ior_wmh_2: '主胜 2 球',
-  ior_wmh_3: '主胜 3 球',
 };
 
-const DEFAULT_MARKET_KEYS = [
-  'ior_mn',
-  'ior_wmh_1',
-  'ior_wmh_2',
-  'ior_wmh_3',
-  'ior_wmc_1',
-  'ior_wmc_2',
-  'ior_wmc_3',
-];
-
 const chartRef = ref<EchartsUIType>();
 const { renderEcharts } = useEcharts(chartRef);
 
@@ -108,6 +74,7 @@ const selectedEventId = ref<number>();
 const selectedMarkets = ref<string[]>([]);
 const loadingGames = ref(false);
 const loadingHistory = ref(false);
+const isMultiSelect = ref(false);
 const marketType = ref(-1);
 const pageSize = 50;
 const currentPage = ref(1);
@@ -117,7 +84,7 @@ const totalGames = ref(0);
 
 const availableMarketKeys = computed(() => {
   const markets = history.value?.markets ?? {};
-  return Object.keys(markets).filter((key) => markets[key]?.length);
+  return MARKET_KEYS.filter((key) => markets[key]?.length);
 });
 
 const hasChartData = computed(() => !!history.value && availableMarketKeys.value.length > 0);
@@ -140,25 +107,18 @@ const isHalfEvent = (eventId?: number) => {
 
 const marketOptions = computed(() => {
   const available = new Set(availableMarketKeys.value);
-  return MARKET_GROUPS.map((group) => ({
-    ...group,
-    availableKeys: group.keys.filter((key) => available.has(key)),
-    options: group.keys
-      .filter((key) => available.has(key))
-      .map((key) => ({
-        label: MARKET_LABELS[key] ?? key,
-        value: key,
-      })),
-  })).filter((group) => group.options.length);
+  return MARKET_KEYS.filter((key) => available.has(key)).map((key) => ({
+    label: MARKET_LABELS[key] ?? key,
+    value: key,
+  }));
 });
 
-const isGroupSelected = (keys: string[]) => {
-  return keys.length > 0 && keys.every((key) => selectedMarkets.value.includes(key));
-};
-
-const selectMarketGroup = (keys: string[]) => {
-  selectedMarkets.value = isGroupSelected(keys) ? [] : [...keys];
-};
+const selectedMarket = computed({
+  get: () => selectedMarkets.value[0],
+  set: (key?: string) => {
+    selectedMarkets.value = key ? [key] : [];
+  },
+});
 
 const formatTime = (time?: number) => {
   return time ? dayjs(time).format('MM-DD HH:mm:ss') : '-';
@@ -321,8 +281,8 @@ const fetchHistory = async (eventId: number) => {
       params: { event_id: eventId },
     });
     history.value = data;
-    const keys = Object.keys(data?.markets ?? {}).filter((key) => data?.markets?.[key]?.length);
-    selectedMarkets.value = DEFAULT_MARKET_KEYS.filter((key) => keys.includes(key));
+    const firstKey = MARKET_KEYS.find((key) => data?.markets?.[key]?.length);
+    selectedMarkets.value = firstKey ? [firstKey] : [];
     await nextTick();
     setTimeout(renderChart);
   }
@@ -366,6 +326,13 @@ watch(currentPage, () => {
 
 watch(selectedMarkets, () => {
   renderChart();
+}, { deep: true });
+
+watch(isMultiSelect, (multiSelect) => {
+  if (!multiSelect && selectedMarkets.value.length > 1) {
+    selectedMarkets.value = [selectedMarkets.value[0]!];
+  }
+  renderChart();
 });
 
 onMounted(() => {
@@ -435,16 +402,21 @@ onMounted(() => {
       </div>
 
       <div class="market-selector" v-if="marketOptions.length">
-        <div v-for="group in marketOptions" :key="group.label" class="market-group">
-          <button
-            class="market-group-label"
-            :class="{ active: isGroupSelected(group.availableKeys) }"
-            type="button"
-            @click="selectMarketGroup(group.availableKeys)"
-          >
-            {{ group.label }}
-          </button>
-          <CheckboxGroup v-model:value="selectedMarkets" :options="group.options" />
+        <div class="market-mode">
+          <span>盘口选择</span>
+          <Switch
+            v-model:checked="isMultiSelect"
+            checked-children="多选"
+            un-checked-children="单选"
+          />
+        </div>
+        <div class="market-options">
+          <CheckboxGroup
+            v-if="isMultiSelect"
+            v-model:value="selectedMarkets"
+            :options="marketOptions"
+          />
+          <RadioGroup v-else v-model:value="selectedMarket" :options="marketOptions" />
         </div>
       </div>
 
@@ -577,34 +549,23 @@ onMounted(() => {
 }
 
 .market-selector {
-  display: grid;
-  gap: 8px;
+  display: flex;
+  align-items: center;
+  gap: 16px;
   padding: 12px 16px;
   border-bottom: 1px solid hsl(var(--border));
 }
 
-.market-group {
+.market-mode {
   display: flex;
-  align-items: flex-start;
-  gap: 12px;
-}
-
-.market-group-label {
-  width: 64px;
-  flex: none;
-  padding: 0;
-  border: 0;
-  background: transparent;
+  align-items: center;
+  gap: 8px;
   color: hsl(var(--foreground) / 0.66);
-  cursor: pointer;
   font-size: 13px;
-  line-height: 24px;
-  text-align: left;
 }
 
-.market-group-label.active,
-.market-group-label:hover {
-  color: hsl(var(--primary));
+.market-options {
+  min-width: 0;
 }
 
 .chart-wrap {
@@ -637,5 +598,10 @@ onMounted(() => {
   .chart-wrap {
     height: 420px;
   }
+
+  .market-selector {
+    align-items: flex-start;
+    flex-direction: column;
+  }
 }
 </style>