flyzto před 4 měsíci
rodič
revize
f2171e698a

+ 43 - 8
server/models/GamesPs.js

@@ -58,7 +58,13 @@ const fixFloat = (number, x=2) => {
  * 获取市场类型
  */
 const getMarketType = (mk) => {
-  return mk == 0 ? 'early' : 'today';
+  if (mk == 0) {
+    return 'early';
+  }
+  else if (mk == 2) {
+    return 'rollball';
+  }
+  return 'today';
 }
 
 /**
@@ -135,8 +141,11 @@ const syncGamesList = ({ platform, mk, games }) => {
  */
 const syncBaseList = ({ marketType, games }) => {
   const baseList = GAMES.Baselist;
+
+  // 直接创建新列表
   if (!baseList[marketType]) {
     baseList[marketType] = games;
+    return;
   }
 
   const newMap = new Map(games.map(item => [item.eventId, item]));
@@ -156,6 +165,7 @@ const syncBaseList = ({ marketType, games }) => {
       baseList[marketType].push(game);
     }
   });
+
 }
 
 /**
@@ -193,6 +203,7 @@ const submitOdds = ({ platform, mk, games }) => {
  * 同步基准盘口
  */
 const syncBaseEvents = ({ mk, games, outrights }) => {
+
   const marketType = getMarketType(mk);
   const baseList = GAMES.Baselist;
   if (!baseList[marketType]) {
@@ -202,9 +213,13 @@ const syncBaseEvents = ({ mk, games, outrights }) => {
   const baseMap = new Map(baseList[marketType].map(item => [item.eventId, item]));
 
   games?.forEach(game => {
-    const { eventId, evtime, events } = game;
+    const { eventId, originId, stage, score, wm, evtime, events } = game;
     const baseGame = baseMap.get(eventId);
     if (baseGame) {
+      baseGame.originId = originId;
+      baseGame.stage = stage;
+      baseGame.score = score;
+      baseGame.wm = wm;
       baseGame.evtime = evtime;
       baseGame.events = events;
     }
@@ -217,6 +232,14 @@ const syncBaseEvents = ({ mk, games, outrights }) => {
       baseGame.sptime = sptime;
       baseGame.special = special;
     }
+    else {
+      const originBaseMap = new Map(baseList[marketType].map(item => [item.originId, item]));
+      const originBaseGame = originBaseMap.get(parentId);
+      if (originBaseGame) {
+        originBaseGame.sptime = sptime;
+        originBaseGame.special = special;
+      }
+    }
   });
 
   if (games?.length) {
@@ -239,7 +262,8 @@ const syncBaseEvents = ({ mk, games, outrights }) => {
           else {
             return {
               key,
-              value: odds[key] ?? 0
+              value: odds[key]?.v ?? 0,
+              origin: odds[key]?.r
             }
           }
         });
@@ -272,17 +296,23 @@ const syncBaseEvents = ({ mk, games, outrights }) => {
     const relatedMap = new Map(relatedGames.map(item => [item.eventId, item]));
 
     gamesList?.forEach(game => {
-      const { eventId, matches, uptime } = game;
+      const { eventId, matches, uptime, stage, score, wm } = game;
       const relatedGame = relatedMap.get(eventId);
       if (relatedGame) {
         const events = {};
         matches.forEach(({ label, match }) => {
-          match.forEach(({ key, value }) => {
-            events[key] = value;
+          match.forEach(({ key, value, origin }) => {
+            events[key] = {
+              v: value,
+              r: origin
+            };
           });
         });
         relatedGame.evtime = uptime;
         relatedGame.events = events;
+        relatedGame.stage = stage;
+        relatedGame.score = score;
+        relatedGame.wm = wm;
         update ++;
       }
     });
@@ -314,11 +344,15 @@ const updateGamesEvents = ({ platform, mk, games, outrights }) => {
     const relatedMap = new Map(relatedGames.map(item => [item.eventId, item]));
 
     games?.forEach(game => {
-      const { eventId, evtime, events } = game;
+      const { eventId, evtime, events, stage, score, wm } = game;
       const relatedGame = relatedMap.get(eventId);
       if (relatedGame) {
         relatedGame.evtime = evtime;
         relatedGame.events = events;
+        relatedGame.stage = stage;
+        relatedGame.score = score;
+        relatedGame.wm = wm;
+
         updateCount.update ++;
       }
     });
@@ -329,6 +363,7 @@ const updateGamesEvents = ({ platform, mk, games, outrights }) => {
       if (relatedGame) {
         relatedGame.sptime = sptime;
         relatedGame.special = special;
+
         updateCount.update ++;
       }
     });
@@ -479,7 +514,7 @@ const updateGamesRelation = () => {
     const baseList = {};
     gamesRelation.map(item => {
       const baseGame = item.rel?.['ps'] ?? {};
-      return { ...baseGame };
+      return { ...baseGame, mk: item.mk };
     }).forEach(item => {
       const marketType = getMarketType(item.mk);
       if (!baseList[marketType]) {

+ 3 - 3
server/triangle/eventsMatch.js

@@ -86,7 +86,7 @@ const extractOdds = ({ evtime, events, sptime, special }) => {
     odds = { ...odds, ...special };
   }
   Object.keys(odds).forEach(ior => {
-    if (odds[ior] <= 0) {
+    if (!odds[ior]?.v || odds[ior].v <= 0) {
       delete odds[ior];
     }
   });
@@ -112,12 +112,12 @@ const eventMatch = () => {
       const eventsMap = {};
       const oddsMap = {};
       Object.keys(rel).forEach(platform => {
-        const { leagueName, teamHomeName, teamAwayName, timestamp, evtime, events, sptime, special } = rel[platform];
+        const { leagueName, teamHomeName, teamAwayName, timestamp, stage, score, evtime, events, sptime, special } = rel[platform];
         if (!events && !special) {
           return;
         }
         if (platform == 'ps') {
-          eventsMap.info = { leagueName, teamHomeName, teamAwayName, id, timestamp };
+          eventsMap.info = { leagueName, teamHomeName, teamAwayName, id, timestamp, stage, score };
         }
         const odds = extractOdds({ evtime, events, sptime, special });
         Object.keys(odds).forEach(ior => {

+ 13 - 11
server/triangle/trangleCalc.js

@@ -26,7 +26,7 @@ function getOptimalSelections(odds, rules) {
         const key = rule[j];
         let item = odds[key];
         if (key == '-') {
-          item = { no: 1};
+          item = { no: { v: 1 } };
         }
         if (!item) {
           isValid = false;
@@ -40,8 +40,9 @@ function getOptimalSelections(odds, rules) {
           selection.push({
             k: key,
             p: 'ps',
-            v: item.ps,
-            o: item,
+            v: item.ps.v,
+            r: item.ps.r,
+            o: item
           });
         }
         else {
@@ -52,8 +53,8 @@ function getOptimalSelections(odds, rules) {
           }
           // Logs.out('candidates', candidates)
           const best = candidates.reduce((a, b) => {
-            const aValue = (item[a]-1)*rebateMap[a];
-            const bValue = (item[b]-1)*rebateMap[b];
+            const aValue = (item[a].v-1)*rebateMap[a];
+            const bValue = (item[b].v-1)*rebateMap[b];
             const seletcted = aValue > bValue ? a : b;
             return seletcted;
           });
@@ -61,8 +62,9 @@ function getOptimalSelections(odds, rules) {
           selection.push({
             k: key,
             p: best,
-            v: item[best],
-            o: item,
+            v: item[best].v,
+            r: item[best].r,
+            o: item
           });
         }
       }
@@ -125,7 +127,7 @@ const attachRebate = (ior) => {
   else if (p == 'hg') {
     rebate = hgRebateRatio;
   }
-  return { ...ior, r: rebate };
+  return { ...ior, b: rebate };
 }
 
 const eventsCombination = (passableEvents) => {
@@ -155,9 +157,9 @@ const eventsCombination = (passableEvents) => {
           odds_side_a: fixFloat(oddsSideA.v - 1),
           odds_side_b: fixFloat(oddsSideB.v - 1),
           odds_side_c: fixFloat(oddsSideC.v - 1),
-          rebate_side_a: parseFloat((oddsSideA.r / 100).toFixed(4)),
-          rebate_side_b: parseFloat((oddsSideB.r / 100).toFixed(4)),
-          rebate_side_c: parseFloat((oddsSideC.r / 100).toFixed(4)),
+          rebate_side_a: parseFloat((oddsSideA.b / 100).toFixed(4)),
+          rebate_side_b: parseFloat((oddsSideB.b / 100).toFixed(4)),
+          rebate_side_c: parseFloat((oddsSideC.b / 100).toFixed(4)),
         };
         const sol = eventSolutions(betInfo, true);
         if (cpr[2].k == '-') {

+ 35 - 7
web/apps/web-antd/src/views/match/components/match_card.vue

@@ -49,6 +49,14 @@ defineProps({
   selected: {
     type: Array,
     required: false
+  },
+  stage: {
+    type: String,
+    required: false
+  },
+  score: {
+    type: String,
+    required: false
   }
 })
 </script>
@@ -56,21 +64,30 @@ defineProps({
 <template>
   <div class="match-card">
     <div class="card-header">
-      <div class="league-name"><strong v-if="matchNumStr">[{{ matchNumStr }}]</strong>{{ leagueName }}</div>
+      <div class="league-name"><strong v-if="stage && platform == 'ps'">[{{ stage }}]</strong>{{ leagueName }}</div>
       <div class="date-time">{{ dateTime }}</div>
     </div>
     <div class="team-name">
       <span class="home-name">{{ teamHomeName }}</span>
-      <em>VS</em>
+      <em v-if="stage">{{ score }}</em><em v-else>VS</em>
       <span class="away-name">{{ teamAwayName }}</span>
     </div>
     <div class="events-list" :class="{'list-row2': events.length <= 2}">
       <table>
         <tr v-for="item in events">
           <th>{{ parseEventKey(item[0]) }}</th>
-          <td><span :class="{'selected': selected.includes(item[1]?.key)}">{{ item[1]?.value ? item[1].value : '-' }}</span></td>
-          <td><span :class="{'selected': selected.includes(item[2]?.key)}">{{ item[2]?.value ? item[2].value : '-' }}</span></td>
-          <td><span :class="{'selected': selected.includes(item[3]?.key)}">{{ item[3]?.value ? item[3].value : '-' }}</span></td>
+          <td>
+            <span :class="{'selected': selected.includes(item[1]?.key)}">{{ item[1]?.value ? item[1].value : '-' }}</span>
+            <em v-if="item[1]?.origin">{{ item[1].origin }}</em>
+          </td>
+          <td>
+            <span :class="{'selected': selected.includes(item[2]?.key)}">{{ item[2]?.value ? item[2].value : '-' }}</span>
+            <em v-if="item[2]?.origin">{{ item[2].origin }}</em>
+          </td>
+          <td>
+            <span :class="{'selected': selected.includes(item[3]?.key)}">{{ item[3]?.value ? item[3].value : '-' }}</span>
+            <em v-if="item[3]?.origin">{{ item[3].origin }}</em>
+          </td>
         </tr>
       </table>
     </div>
@@ -146,7 +163,7 @@ defineProps({
     border-spacing: 0;
     table-layout: fixed;
     th, td {
-      height: 30px;
+      padding: 5px;
       border: 1px solid hsl(var(--border));
       text-align: center;
     }
@@ -156,19 +173,30 @@ defineProps({
     }
     td {
       width: calc((100% - 64px) / 2);
+      font-size: 0;
     }
     span {
       display: inline-block;
       height: 20px;
+      padding: 0 5px;
       line-height: 20px;
       vertical-align: middle;
-      padding: 0 5px;
+      font-size: 14px;
       &.selected {
         border-radius: 4px;
         background-color: hsl(var(--primary));
         color: hsl(var(--primary-foreground));
       }
     }
+    em {
+      display: block;
+      height: 18px;
+      margin-top: -3px;
+      line-height: 18px;
+      font-style: normal;
+      font-size: 12px;
+      color: hsl(var(--foreground) / 0.5);
+    }
   }
   &.list-row2 {
     table {

+ 19 - 47
web/apps/web-antd/src/views/match/solutions/index.vue

@@ -14,11 +14,6 @@ const selectedSolutions = reactive([]);
 const totalProfit = ref({});
 const loopActive = ref(false);
 
-const psOptions = reactive({
-  bet: 10000,
-  rebate: 0,
-});
-
 const totalProfitVisible = ref(false);
 
 const fixFloat = (number, x = 2) => {
@@ -40,21 +35,6 @@ const totalProfitValue = computed(() => {
   const sol1 = formatSolution(preSolution, gamesEvents);
   const sol2 = formatSolution(subSolution, gamesEvents);
 
-  const psScale = psOptions.bet / profit.ps_base ?? 10000;
-  const psRebate = psOptions.bet * psOptions.rebate / 100;
-  const profitInfo = {};
-  Object.keys(profit).forEach(key => {
-    if (key == 'win_diff') {
-      return;
-    }
-    if (key.startsWith('gold')) {
-      profitInfo[key] = fixFloat(profit[key] * psScale);
-    }
-    else if (key.startsWith('win_')) {
-      profitInfo[key] = fixFloat(profit[key] * psScale + psRebate);
-    }
-  });
-
   const psInfo = [];
   const outPreSol = [];
   const outSubSol = [];
@@ -108,19 +88,9 @@ const solutionsList = computed(() => {
   return solutions.value.map(item => {
     const selected = selectedSolutions.findIndex(sol => sol.sid === item.sid) >= 0;
     const disabled = false && !selected && (item.info.ps.timestamp < startTimestamp + 1000 * 60 * 60 * 2);
-    const currentSol = { ...item.sol };
-
-    const psScale = psOptions.bet / currentSol.inner_base;
-    const psRebate = psOptions.bet * psOptions.rebate / 100;
-
-    Object.keys(currentSol).forEach(key => {
-      if (key.startsWith('gold_')) {
-        currentSol[key] = fixFloat(currentSol[key] * psScale);
-      }
-      else if (key.startsWith('win_')) {
-        currentSol[key] = fixFloat(currentSol[key] * psScale + psRebate);
-      }
-    });
+    const { sol: { inner_base, win_average } } = item;
+    const win_average_rate = fixFloat(win_average / inner_base * 100);
+    const currentSol = { ...item.sol, win_average_rate };
     return { ...item, sol: currentSol, selected, disabled };
   });
 });
@@ -140,7 +110,7 @@ const getSolutions = async () => {
 const calcTotalProfit = async () => {
   const sids = selectedSolutions.map(item => item.sid);
   try {
-    const totalProfit = await requestClient.post('/pstery/calc_total_profit', [...sids, psOptions.bet]);
+    const totalProfit = await requestClient.post('/pstery/calc_total_profit', [...sids]);
     return totalProfit;
   }
   catch (error) {
@@ -176,7 +146,8 @@ const formatPsEvents = (events) => {
   return PS_IOR_KEYS.map(([label, ...keys]) => {
     const match = keys.map(key => ({
       key,
-      value: events[key] ?? 0
+      value: events[key]?.v ?? 0,
+      origin: events[key]?.r
     }));
     return {
       label,
@@ -295,8 +266,9 @@ const formatEvents = (events, cprKeys) => {
       eventsMap[ratioKey] = new Array(3).fill(undefined);
     }
 
-    const value = events[key] ?? 0;
-    eventsMap[ratioKey][index] = { key, value };
+    const value = events[key]?.v ?? 0;
+    const origin = events[key]?.r;
+    eventsMap[ratioKey][index] = { key, value, origin };
   });
 
   return Object.keys(eventsMap).sort((a, b) => a.localeCompare(b)).map(key => {
@@ -398,16 +370,16 @@ onUnmounted(() => {
   <div class="solution-container">
 
     <div class="contents-header transition-all duration-200" :style="headerStyle">
-      <div class="solution-options">
+      <!-- <div class="solution-options">
         <Form layout="inline">
           <Form.Item label="PS 投注">
             <InputNumber size="small" placeholder="PS投注" min="1000" v-model:value="psOptions.bet" />
           </Form.Item>
-          <!-- <Form.Item label="PS 返点">
+          <Form.Item label="PS 返点">
             <InputNumber size="small" placeholder="PS返点" min="0" v-model:value="psOptions.rebate" />
-          </Form.Item> -->
+          </Form.Item>
         </Form>
-      </div>
+      </div> -->
       <div class="solution-header">
         <span>PS</span>
         <span>OB</span>
@@ -418,22 +390,22 @@ onUnmounted(() => {
 
     <div class="solution-list">
       <div class="solution-item"
-        v-for="{ sid, sol: { win_average, win_profit_rate, cross_type }, info: { ps, ob, hg }, selected, disabled } in solutionsList" :key="sid"
+        v-for="{ sid, sol: { win_average_rate, win_profit_rate, cross_type }, info: { ps, ob, hg }, selected, disabled } in solutionsList" :key="sid"
         :class="{ 'selected': selected, 'disabled': disabled }">
         <MatchCard platform="ps" :eventId="ps.eventId" :leagueName="ps.leagueName" :teamHomeName="ps.teamHomeName"
           :teamAwayName="ps.teamAwayName" :dateTime="ps.dateTime" :eventInfo="ps.eventInfo" :events="ps.events ?? []"
-          :matchNumStr="ps.matchNumStr" :selected="ps.selected ?? []" />
+          :matchNumStr="ps.matchNumStr" :selected="ps.selected ?? []" :stage="ps.stage" :score="ps.score" />
 
         <MatchCard platform="ob" :eventId="ob.eventId" :leagueName="ob.leagueName" :teamHomeName="ob.teamHomeName"
           :teamAwayName="ob.teamAwayName" :dateTime="ob.dateTime" :events="ob.events ?? []"
-          :selected="ob.selected ?? []" />
+          :selected="ob.selected ?? []" :stage="ob.stage" :score="ob.score" />
 
         <MatchCard platform="hg" :eventId="hg.eventId" :leagueName="hg.leagueName" :teamHomeName="hg.teamHomeName"
           :teamAwayName="hg.teamAwayName" :dateTime="hg.dateTime" :events="hg.events ?? []"
-          :selected="hg.selected ?? []" />
+          :selected="hg.selected ?? []" :stage="hg.stage" :score="hg.score" />
 
         <div class="solution-profit" @click="!disabled && toggleSolution(sid, ps.timestamp)">
-          <p>{{ win_average }}</p>
+          <p>{{ win_average_rate }}%</p>
           <p>{{ win_profit_rate }}%</p>
           <p>{{ cross_type }}</p>
         </div>
@@ -541,7 +513,7 @@ onUnmounted(() => {
 }
 
 .solution-container {
-  padding-top: 74px;
+  padding-top: 31px;
 }
 
 .solution-item {