瀏覽代碼

新增返水类型支持

flyzto 2 月之前
父節點
當前提交
4fef1f810b

+ 12 - 4
server/models/GamesPs.js

@@ -1096,20 +1096,30 @@ const getTotalProfitWithBetInfo = async (betInfo1, betInfo2, fixed=false, inner_
  * 同步Qboss平台配置
  */
 const syncQbossConfig = () => {
+  const setting = getSetting();
+  if (!setting.syncSettingEnabled) {
+    // Logs.outDev('syncQbossConfig disabled');
+    return setTimeout(syncQbossConfig, 1000*5);
+  }
   axios.get(`${BASE_API_URL}/p/QbossSystemConfig`, { proxy: false })
   .then(res => {
     const { data } = res;
     if (!data?.data) {
       throw new Error('syncQbossConfig data is empty');
     }
-    const setting = getSetting();
     const {
       qboss_return_ratio,
+      ob_return_ratio, ob_return_type,
+      hg_return_ratio, hg_return_type,
       qboss_jq_add_odds, qboss_jq_add_hours,
       qboss_gq_add_dy_odds, qboss_gq_add_jq_odds,
      } = data.data;
     const qbossSetting = {
       innerRebateRatio: +qboss_return_ratio,
+      obRebateRatio: +ob_return_ratio,
+      obRebateType: +ob_return_type,
+      hgRebateRatio: +hg_return_ratio,
+      hgRebateType: +hg_return_type,
       subsidyTime: +qboss_jq_add_hours,
       subsidyAmount: +qboss_jq_add_odds,
       subsidyRbWmAmount: +qboss_gq_add_dy_odds,
@@ -1135,9 +1145,7 @@ const syncQbossConfig = () => {
     Logs.out('syncQbossConfig error', err.message);
   })
   .finally(() => {
-    setTimeout(() => {
-      syncQbossConfig();
-    }, 1000*15);
+    setTimeout(syncQbossConfig, 1000*15);
   });
 }
 syncQbossConfig();

+ 19 - 4
server/models/Setting.js

@@ -31,15 +31,20 @@ const systemSettingSchema = new Schema({
     required: true,
     default: 0
   },
+  obRebateType: {
+    type: Number,
+    required: true,
+    default: 0
+  },
   hgRebateRatio: {
     type: Number,
     required: true,
     default: 0
   },
-  runWorkerEnabled: {
-    type: Boolean,
+  hgRebateType: {
+    type: Number,
     required: true,
-    default: false
+    default: 0
   },
   expireTimeEvents: {
     type: Number,
@@ -70,7 +75,17 @@ const systemSettingSchema = new Schema({
     type: Number,
     required: true,
     default: 0
-  }
+  },
+  syncSettingEnabled: {
+    type: Boolean,
+    required: true,
+    default: false
+  },
+  runWorkerEnabled: {
+    type: Boolean,
+    required: true,
+    default: false
+  },
 }, {
   toJSON: {
     transform(doc, ret) {

+ 15 - 7
server/triangle/eventSolutions.js

@@ -27,6 +27,9 @@ const triangleProfitCalc = (betInfo) => {
     rebate_side_a: A = 0,
     rebate_side_b: B = 0,
     rebate_side_c: C = 0,
+    rebate_type_side_a: TA = 0,
+    rebate_type_side_b: TB = 0,
+    rebate_type_side_c: TC = 0,
   } = betInfo;
 
   /**
@@ -50,11 +53,11 @@ const triangleProfitCalc = (betInfo) => {
     inner_rebate_value = z * inner_rebate;
   }
 
-  const k1 = a * (1 + A);
+  const k1 = TA == 1 ? a + A : a * (1 + A);
   const k2 = 1 - A;
-  const k3 = b * (1 + B);
+  const k3 = TB == 1 ? b + B : b * (1 + B);
   const k4 = 1 - B;
-  const k5 = c * (1 + C);
+  const k5 = TC == 1 ? c + C : c * (1 + C);
   const k6 = 1 - C;
 
   let win_side_a = 0, win_side_b = 0, win_side_c = 0;
@@ -111,15 +114,18 @@ const triangleGoldCalc = (betInfo) => {
     rebate_side_a: A = 0,
     rebate_side_b: B = 0,
     rebate_side_c: C = 0,
+    rebate_type_side_a: TA = 0,
+    rebate_type_side_b: TB = 0,
+    rebate_type_side_c: TC = 0,
   } = betInfo;
   if (typeof a !== 'number' || typeof b !== 'number' || typeof c !== 'number') {
     return;
   }
-  const k1 = a * (1 + A);
+  const k1 = TA == 1 ? a + A : a * (1 + A);
   const k2 = 1 - A;
-  const k3 = b * (1 + B);
+  const k3 = TB == 1 ? b + B : b * (1 + B);
   const k4 = 1 - B;
-  const k5 = c * (1 + C);
+  const k5 = TC == 1 ? c + C : c * (1 + C);
   const k6 = 1 - C;
   let x = inner_base;
   let y = (k1 + k2) * x / (k3 + k4);
@@ -188,7 +194,8 @@ const eventSolutions = (betInfo, showGolds=false) => {
   const {
     cross_type, inner_index, inner_rebate, inner_base,
     odds_side_a, odds_side_b, odds_side_c,
-    rebate_side_a,rebate_side_b, rebate_side_c,
+    rebate_side_a, rebate_side_b, rebate_side_c,
+    rebate_type_side_a, rebate_type_side_b, rebate_type_side_c,
   } = betInfo;
 
   const win_average_rate = fixFloat(win_average / inner_base * 100);
@@ -197,6 +204,7 @@ const eventSolutions = (betInfo, showGolds=false) => {
   let result = {
     odds_side_a, odds_side_b, odds_side_c,
     rebate_side_a, rebate_side_b, rebate_side_c,
+    rebate_type_side_a, rebate_type_side_b, rebate_type_side_c,
     win_average, win_average_rate, win_profit_rate, cross_type,
     inner_index, inner_base, inner_rebate,
   }

+ 7 - 4
server/triangle/settings.js

@@ -6,14 +6,17 @@ const SETTING = {
   minShowAmount: 0,
   innerRebateRatio: 0,
   obRebateRatio: 0,
+  obRebateType: 0,
   hgRebateRatio: 0,
-  runWorkerEnabled: false,
-  expireTimeEvents: 45000,
-  expireTimeSpecial: 60000,
+  hgRebateType: 0,
   subsidyTime: 0,
   subsidyAmount: 0,
   subsidyRbWmAmount: 0,
-  subsidyRbOtAmount: 0
+  subsidyRbOtAmount: 0,
+  expireTimeEvents: 45000,
+  expireTimeSpecial: 60000,
+  syncSettingEnabled: false,
+  runWorkerEnabled: false,
 }
 
 const getSetting = (key) => {

+ 40 - 8
server/triangle/totalProfitCalc.js

@@ -19,7 +19,11 @@ const fixFloat = (number, x = 2) => {
  */
 const CROSS_TYPE_MAP = { w: -1, l: 1, a: 1, h: 0.5, d: 0, r: 0, v: 0 };
 const lossProportion = (sol) => {
-  const { cross_type, odds_side_a, odds_side_b, rebate_side_a, rebate_side_b } = sol;
+  const {
+    cross_type, odds_side_a, odds_side_b,
+    rebate_side_a, rebate_side_b,
+    rebate_type_side_a, rebate_type_side_b,
+  } = sol;
   const typeList = cross_type.split('_').map(part => {
     return part.split('').map(key => CROSS_TYPE_MAP[key]);
   }).map(([a, b])=> a * b);
@@ -29,14 +33,24 @@ const lossProportion = (sol) => {
     loss_proportion_a = typeList[0] * (1 - rebate_side_a);
   }
   else {
-    loss_proportion_a = typeList[0] * odds_side_a * (1 + rebate_side_a);
+    if (rebate_type_side_a == 1) {
+      loss_proportion_a = typeList[0] * (odds_side_a + rebate_side_a);
+    }
+    else {
+      loss_proportion_a = typeList[0] * odds_side_a * (1 + rebate_side_a);
+    }
   }
 
   if (typeList[1] >= 0) {
     loss_proportion_b = typeList[1] * (1 - rebate_side_b);
   }
   else {
-    loss_proportion_b = typeList[1] * odds_side_b * (1 + rebate_side_b);
+    if (rebate_type_side_b == 1) {
+      loss_proportion_b = typeList[1] * (odds_side_b + rebate_side_b);
+    }
+    else {
+      loss_proportion_b = typeList[1] * odds_side_b * (1 + rebate_side_b);
+    }
   }
 
   return { loss_proportion_a, loss_proportion_b };
@@ -46,13 +60,13 @@ const lossProportion = (sol) => {
  * 不同组合的金额计算
  */
 const HandicapCalc = function (data) {
-  const { i, g, a, b, c, A, B, C, w, l } = data;
+  const { i, g, a, b, c, A, B, C, TA, TB, TC, w, l } = data;
   const t = w + l;
-  const k1 = a * (1 + A);
+  const k1 = TA == 1 ? a + A : a * (1 + A);
   const k2 = 1 - A;
-  const k3 = b * (1 + B);
+  const k3 = TB == 1 ? b + B : b * (1 + B);
   const k4 = 1 - B;
-  const k5 = c * (1 + C);
+  const k5 = TC == 1 ? c + C : c * (1 + C);
   const k6 = 1 - C;
 
   const calcTemplate = (handlers) => {
@@ -210,12 +224,15 @@ const calcGoldsWithTarget = (data) => {
     rebate_side_a: A,
     rebate_side_b: B,
     rebate_side_c: C,
+    rebate_type_side_a: TA,
+    rebate_type_side_b: TB,
+    rebate_type_side_c: TC,
     inner_index: i,
     cross_type: t,
     win_target: w,
     loss_out: l = 0,
   } = data;
-  const calc = new HandicapCalc({ i, g, a, b, c, A, B, C, w, l });
+  const calc = new HandicapCalc({ i, g, a, b, c, A, B, C, TA, TB, TC, w, l });
   const { x, y, z } = calc?.[t]() ?? {};
   return {
     gold_side_a: fixFloat(x),
@@ -237,6 +254,9 @@ const calcWinResultWithTarget = (data) => {
     rebate_side_a: rebateA1,
     rebate_side_b: rebateB1,
     rebate_side_c: rebateC1,
+    rebate_type_side_a: rebateTypeA1,
+    rebate_type_side_b: rebateTypeB1,
+    rebate_type_side_c: rebateTypeC1,
     inner_index: inner_index_1,
   } = sol1;
   const {
@@ -272,6 +292,9 @@ const calcWinResultWithTarget = (data) => {
     rebate_side_a: rebateA2,
     rebate_side_b: rebateB2,
     rebate_side_c: rebateC2,
+    rebate_type_side_a: rebateTypeA2,
+    rebate_type_side_b: rebateTypeB2,
+    rebate_type_side_c: rebateTypeC2,
     inner_index: inner_index_2,
   } = sol2;
   const {
@@ -321,6 +344,9 @@ const calcWinResultWithTarget = (data) => {
         rebate_side_a: rebateA1,
         rebate_side_b: rebateB1,
         rebate_side_c: rebateC1,
+        rebate_type_side_a: rebateTypeA1,
+        rebate_type_side_b: rebateTypeB1,
+        rebate_type_side_c: rebateTypeC1,
         inner_index: inner_index_1,
       },
       {
@@ -334,6 +360,9 @@ const calcWinResultWithTarget = (data) => {
         rebate_side_a: rebateA2,
         rebate_side_b: rebateB2,
         rebate_side_c: rebateC2,
+        rebate_type_side_a: rebateTypeA2,
+        rebate_type_side_b: rebateTypeB2,
+        rebate_type_side_c: rebateTypeC2,
         inner_index: inner_index_2,
       }
     ],
@@ -439,6 +468,9 @@ const calcTotalProfitWithFixedFirst = (betInfo1, betInfo2, inner_base, inner_reb
     rebate_side_a: rebateA1,
     rebate_side_b: rebateB1,
     rebate_side_c: rebateC1,
+    rebate_type_side_a: rebateTypeA1,
+    rebate_type_side_b: rebateTypeB1,
+    rebate_type_side_c: rebateTypeC1,
   } = betInfo1;
 
   let loss_out_1 = 0, inner_ref_value = 0, inner_odds_1 = 0;

+ 22 - 11
server/triangle/trangleCalc.js

@@ -7,13 +7,17 @@ const { eventSolutions } = require('./eventSolutions');
 /**
  * 筛选最优赔率
  */
-function getOptimalSelections(odds, rules) {
+const oddRebateValue = (odds, platform) => {
+  const setting = getSetting();
+  const rebateRatio = setting[`${platform}RebateRatio`] ?? 0;
+  const rebateType = setting[`${platform}RebateType`] ?? 0;
+  if (rebateType == 0) {
+    return odds * (1 + rebateRatio / 100);
+  }
+  return odds + rebateRatio / 100;
+}
+const getOptimalSelections = (odds, rules) => {
   const results = [];
-  const { obRebateRatio, hgRebateRatio } = getSetting();
-  const rebateMap = {
-    ob: 1 + obRebateRatio / 100,
-    hg: 1 + hgRebateRatio / 100,
-  };
 
   rules.forEach((rule, ruleIndex) => {
     let validOptions = [];
@@ -54,8 +58,8 @@ function getOptimalSelections(odds, rules) {
           }
           // Logs.out('candidates', candidates)
           const best = candidates.reduce((a, b) => {
-            const aValue = (item[a].v-1)*rebateMap[a];
-            const bValue = (item[b].v-1)*rebateMap[b];
+            const aValue = oddRebateValue(item[a].v-1, a);
+            const bValue = oddRebateValue(item[b].v-1, b);
             const seletcted = aValue > bValue ? a : b;
             return seletcted;
           });
@@ -65,6 +69,7 @@ function getOptimalSelections(odds, rules) {
             p: best,
             v: item[best].v,
             r: item[best].r,
+            s: item[best].s,
             o: item
           });
         }
@@ -116,19 +121,22 @@ const sortCpr = (cpr) => {
  * 添加返佣
  */
 const attachRebate = (ior) => {
-  const { obRebateRatio, hgRebateRatio } = getSetting();
+  const { obRebateRatio, obRebateType, hgRebateRatio, hgRebateType } = getSetting();
   const { p } = ior;
-  let rebate = 0;
+  let rebate = 0, rebateType = 0;
   if (p == 'ps') {
     rebate = 0;
+    rebateType = -1;
   }
   else if (p == 'ob') {
     rebate = obRebateRatio;
+    rebateType = obRebateType;
   }
   else if (p == 'hg') {
     rebate = hgRebateRatio;
+    rebateType = hgRebateType;
   }
-  return { ...ior, b: rebate };
+  return { ...ior, b: rebate, t: rebateType };
 }
 
 const eventsCombination = (passableEvents) => {
@@ -159,8 +167,11 @@ const eventsCombination = (passableEvents) => {
           odds_side_b: fixFloat(oddsSideB.v - 1),
           odds_side_c: fixFloat(oddsSideC.v - 1),
           rebate_side_a: parseFloat((oddsSideA.b / 100).toFixed(4)),
+          rebate_type_side_a: oddsSideA.t,
           rebate_side_b: parseFloat((oddsSideB.b / 100).toFixed(4)),
+          rebate_type_side_b: oddsSideB.t,
           rebate_side_c: parseFloat((oddsSideC.b / 100).toFixed(4)),
+          rebate_type_side_c: oddsSideC.t,
         };
         const sol = eventSolutions(betInfo, true);
         if (cpr[2].k == '-') {

+ 1 - 0
web/apps/web-antd/src/router/routes/modules/system.ts

@@ -11,6 +11,7 @@ const routes: RouteRecordRaw[] = [
     },
     name: 'System',
     path: '/system',
+    redirect: '/system/parameter',
     children: [
       {
         name: 'UserManagement',

+ 58 - 5
web/apps/web-antd/src/views/system/parameter/index.vue

@@ -1,7 +1,7 @@
 <script setup>
 import { Page } from '@vben/common-ui';
 import { requestClient } from '#/api/request';
-import { Button, message, Form, InputNumber, Drawer, Switch } from 'ant-design-vue';
+import { Button, message, Form, InputNumber, RadioGroup, Radio, Drawer, Switch } from 'ant-design-vue';
 import { ref, reactive, computed, onMounted, onUnmounted, watch } from 'vue';
 
 const initialFormState = {
@@ -10,10 +10,17 @@ const initialFormState = {
   minShowAmount: 0,
   innerRebateRatio: 0,
   obRebateRatio: 0,
+  obRebateType: 0,
   hgRebateRatio: 0,
-  runWorkerEnabled: false,
+  hgRebateType: 0,
+  subsidyTime: 0,
+  subsidyAmount: 0,
+  subsidyRbWmAmount: 0,
+  subsidyRbOtAmount: 0,
   expireTimeEvents: 0,
-  expireTimeSpecial: 0
+  expireTimeSpecial: 0,
+  syncSettingEnabled: false,
+  runWorkerEnabled: false,
 };
 
 const formState = reactive({ ...initialFormState });
@@ -133,6 +140,7 @@ onUnmounted(() => {
         name="innerRebateRatio"
       >
         <InputNumber
+          :disabled="formState.syncSettingEnabled"
           v-model:value="formState.innerRebateRatio"
           :min="0"
           :max="100"
@@ -146,12 +154,17 @@ onUnmounted(() => {
         name="obRebateRatio"
       >
         <InputNumber
+          :disabled="formState.syncSettingEnabled"
           v-model:value="formState.obRebateRatio"
           :min="0"
           :max="100"
           :step="0.1"
-          style="width: 200px"
+          style="width: 200px; vertical-align: middle;"
         />
+        <RadioGroup :disabled="formState.syncSettingEnabled" style="margin-left: 10px; vertical-align: middle;" v-model:value="formState.obRebateType">
+          <Radio :value="0">结算</Radio>
+          <Radio :value="1">本金</Radio>
+        </RadioGroup>
       </Form.Item>
 
       <Form.Item
@@ -159,12 +172,45 @@ onUnmounted(() => {
         name="hgRebateRatio"
       >
         <InputNumber
+          :disabled="formState.syncSettingEnabled"
           v-model:value="formState.hgRebateRatio"
           :min="0"
           :max="100"
           :step="0.1"
-          style="width: 200px"
+          style="width: 200px; vertical-align: middle;"
         />
+        <RadioGroup :disabled="formState.syncSettingEnabled" style="margin-left: 10px; vertical-align: middle;" v-model:value="formState.hgRebateType">
+          <Radio :value="0">结算</Radio>
+          <Radio :value="1">本金</Radio>
+        </RadioGroup>
+      </Form.Item>
+
+      <Form.Item
+        label="早盘补水时间(-h)"
+        name="subsidyTime"
+      >
+        <InputNumber :disabled="formState.syncSettingEnabled" v-model:value="formState.subsidyTime" :min="0" :step="48" style="width: 200px" />
+      </Form.Item>
+
+      <Form.Item
+        label="早盘补水比例"
+        name="subsidyAmount"
+      >
+        <InputNumber :disabled="formState.syncSettingEnabled" v-model:value="formState.subsidyAmount" :min="0" :step="0.01" style="width: 200px" />
+      </Form.Item>
+
+      <Form.Item
+        label="滚球补水(净胜)"
+        name="subsidyRbWmAmount"
+      >
+        <InputNumber :disabled="formState.syncSettingEnabled" v-model:value="formState.subsidyRbWmAmount" :min="0" :step="0.01" style="width: 200px" />
+      </Form.Item>
+
+      <Form.Item
+        label="滚球补水(进球)"
+        name="subsidyRbOtAmount"
+      >
+        <InputNumber :disabled="formState.syncSettingEnabled" v-model:value="formState.subsidyRbOtAmount" :min="0" :step="0.01" style="width: 200px" />
       </Form.Item>
 
       <Form.Item
@@ -181,6 +227,13 @@ onUnmounted(() => {
         <InputNumber v-model:value="formState.expireTimeSpecial" :min="0" :step="1000" style="width: 200px" />
       </Form.Item>
 
+      <Form.Item
+        label="同步 Qboss 配置"
+        name="syncSettingEnabled"
+      >
+        <Switch v-model:checked="formState.syncSettingEnabled" />
+      </Form.Item>
+
       <Form.Item
         label="后台 Worker 开关"
         name="runWorkerEnabled"

File diff suppressed because it is too large
+ 168 - 431
web/pnpm-lock.yaml


Some files were not shown because too many files changed in this diff