|
|
@@ -1,664 +0,0 @@
|
|
|
-<script setup>
|
|
|
-import { requestClient } from '#/api/request';
|
|
|
-import { Button, message, Form, InputNumber, RadioGroup, Radio, Drawer } from 'ant-design-vue';
|
|
|
-import { ref, reactive, computed, watch, onMounted, onUnmounted } from 'vue';
|
|
|
-import dayjs from 'dayjs';
|
|
|
-
|
|
|
-import MatchCard from '../components/match_card.vue';
|
|
|
-
|
|
|
-import { useContentsPositionStore } from '@vben/stores';
|
|
|
-const contentsPositionStore = useContentsPositionStore();
|
|
|
-
|
|
|
-const solutions = ref([]);
|
|
|
-const markCount = ref({ all: 0, rollball: 0, today: 0, early: 0 });
|
|
|
-const selectedSolutions = reactive([]);
|
|
|
-const totalProfit = ref({});
|
|
|
-const loopActive = ref(false);
|
|
|
-const loopTimer = ref(null);
|
|
|
-const updateTimer = ref(null);
|
|
|
-const minProfitRate = ref(2);
|
|
|
-const marketType = ref(-1);
|
|
|
-const updateLoaderHide = ref(null);
|
|
|
-
|
|
|
-const totalProfitVisible = ref(false);
|
|
|
-
|
|
|
-const fixFloat = (number, x = 2) => {
|
|
|
- return parseFloat(number.toFixed(x));
|
|
|
-}
|
|
|
-
|
|
|
-const headerStyle = computed(() => {
|
|
|
- return {
|
|
|
- position: contentsPositionStore.position,
|
|
|
- top: contentsPositionStore.top,
|
|
|
- left: contentsPositionStore.left,
|
|
|
- width: contentsPositionStore.width,
|
|
|
- paddingLeft: contentsPositionStore.paddingLeft,
|
|
|
- }
|
|
|
-});
|
|
|
-
|
|
|
-// const totalProfitValue = computed(() => {
|
|
|
-// const { profit = {}, preSolution = {}, subSolution = {}, gamesEvents = {} } = totalProfit.value;
|
|
|
-// const sol1 = formatSolution(preSolution, gamesEvents);
|
|
|
-// const sol2 = formatSolution(subSolution, gamesEvents);
|
|
|
-
|
|
|
-// const psInfo = [];
|
|
|
-// const outPreSol = [];
|
|
|
-// const outSubSol = [];
|
|
|
-
|
|
|
-// const solutions = [sol1, sol2].filter(item => item);
|
|
|
-// solutions.forEach((item, index) => {
|
|
|
-// const { sol: { ps_index }, cpr } = item;
|
|
|
-// const newCpr = [...cpr];
|
|
|
-// const ps_info = newCpr.splice(ps_index, 1);
|
|
|
-// psInfo.push({ ...ps_info[0] });
|
|
|
-// newCpr.forEach((c, i) => {
|
|
|
-// let side = '';
|
|
|
-// if (ps_index == 0) {
|
|
|
-// if (i == 0) {
|
|
|
-// side = "B"
|
|
|
-// }
|
|
|
-// else {
|
|
|
-// side = "M";
|
|
|
-// }
|
|
|
-// }
|
|
|
-// else if (ps_index == 1) {
|
|
|
-// if (i == 0) {
|
|
|
-// side = "A";
|
|
|
-// }
|
|
|
-// else {
|
|
|
-// side = "M";
|
|
|
-// }
|
|
|
-// }
|
|
|
-// else {
|
|
|
-// if (i == 0) {
|
|
|
-// side = "A";
|
|
|
-// }
|
|
|
-// else {
|
|
|
-// side = "B";
|
|
|
-// }
|
|
|
-// }
|
|
|
-// if (index == 0) {
|
|
|
-// outPreSol.push({ ...c, g: profitInfo[`gold${side}${index+1}`] });
|
|
|
-// }
|
|
|
-// else {
|
|
|
-// outSubSol.push({ ...c, g: profitInfo[`gold${side}${index+1}`] });
|
|
|
-// }
|
|
|
-// })
|
|
|
-// });
|
|
|
-
|
|
|
-// return { solutions, profit: profitInfo, psInfo, outPreSol, outSubSol };
|
|
|
-// });
|
|
|
-
|
|
|
-const solutionsList = computed(() => {
|
|
|
- const startTimestamp = selectedSolutions[0]?.timestamp ?? 0;
|
|
|
- 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 { 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 };
|
|
|
- });
|
|
|
-});
|
|
|
-
|
|
|
-const getSolutions = async () => {
|
|
|
- try {
|
|
|
- const win_min = minProfitRate.value * 100;
|
|
|
- const mk = marketType.value;
|
|
|
- const with_events = true;
|
|
|
- const data = await requestClient.get('/pstery/get_solutions', { params: { win_min, mk, with_events } });
|
|
|
- return data;
|
|
|
- }
|
|
|
- catch (error) {
|
|
|
- console.error('Failed to fetch solutions:', error);
|
|
|
- message.error('获取中单方案失败');
|
|
|
- return [];
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-const calcTotalProfit = async () => {
|
|
|
- const sids = selectedSolutions.map(item => item.sid);
|
|
|
- try {
|
|
|
- const totalProfit = await requestClient.post('/pstery/calc_total_profit', [...sids]);
|
|
|
- return totalProfit;
|
|
|
- }
|
|
|
- catch (error) {
|
|
|
- console.error('Failed to calc total profit:', error);
|
|
|
- message.error('计算综合利润失败');
|
|
|
- return {};
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-const parseIorKey = (iorKey) => {
|
|
|
- const [, type, accept, side, , ratioString] = iorKey.match(/^ior_(r|ou|m|wm|ot|os)(a?)(h|c|n)?(_([\d-]+))?$/);
|
|
|
- let ratio = 0;
|
|
|
- if (type === 'ot' || type === 'os') {
|
|
|
- ratio = ratioString;
|
|
|
- }
|
|
|
- else if (ratioString) {
|
|
|
- ratio = `${ratioString[0]}.${ratioString.slice(1)}` * (accept ? 1 : -1);
|
|
|
- }
|
|
|
- return { type, side, ratio };
|
|
|
-}
|
|
|
-
|
|
|
-const PS_IOR_KEYS = [
|
|
|
- ['0', 'ior_mh', 'ior_mn', 'ior_mc'],
|
|
|
- ['-1', 'ior_rh_15', 'ior_wmh_1', 'ior_rac_05'],
|
|
|
- ['-2', 'ior_rh_25', 'ior_wmh_2', 'ior_rac_15'],
|
|
|
- ['+1', 'ior_rah_05', 'ior_wmc_1', 'ior_rc_15'],
|
|
|
- ['+2', 'ior_rah_15', 'ior_wmc_2', 'ior_rc_25'],
|
|
|
- // ['0-1', 'ior_ot_0', 'ior_os_0-1', 'ior_ot_1'],
|
|
|
- // ['2-3', 'ior_ot_2', 'ior_os_2-3', 'ior_ot_3'],
|
|
|
- ['ot_1', '-', 'ior_ot_1', '-'],
|
|
|
- ['ot_2', '-', 'ior_ot_2', '-'],
|
|
|
- ['ot_3', '-', 'ior_ot_3', '-'],
|
|
|
- ['ot_4', '-', 'ior_ot_4', '-'],
|
|
|
- ['ot_5', '-', 'ior_ot_5', '-'],
|
|
|
- ['ot_6', '-', 'ior_ot_6', '-'],
|
|
|
- ['ot_7', '-', 'ior_ot_7', '-'],
|
|
|
-];
|
|
|
-
|
|
|
-const formatPsEvents = (events) => {
|
|
|
- return PS_IOR_KEYS.map(([label, ...keys]) => {
|
|
|
- const match = keys.map(key => ({
|
|
|
- key,
|
|
|
- value: events[key]?.v ?? 0,
|
|
|
- origin: events[key]?.r
|
|
|
- }));
|
|
|
- return {
|
|
|
- label,
|
|
|
- match
|
|
|
- };
|
|
|
- })
|
|
|
- // .filter(item => item.match.every(entry => entry.value !== 0))
|
|
|
- .map(({label, match}) => [label, ...match]);
|
|
|
-}
|
|
|
-
|
|
|
-// const rivalIor = (ior) => {
|
|
|
-// const map = {
|
|
|
-// "ior_rh": "ior_rac",
|
|
|
-// "ior_rc": "ior_rah",
|
|
|
-// "ior_rac": "ior_rh",
|
|
|
-// "ior_rah": "ior_rc",
|
|
|
-// "ior_wmh": "ior_wmc",
|
|
|
-// "ior_wmc": "ior_wmh",
|
|
|
-// "ior_wmh_2": "ior_wmc_2",
|
|
|
-// "ior_wmc_2": "ior_wmh_2"
|
|
|
-// };
|
|
|
-// const iorInfos = ior.split('_');
|
|
|
-// const iorStart = iorInfos.slice(0, 2).join('_');
|
|
|
-// if (!map[iorStart]) {
|
|
|
-// return ior;
|
|
|
-// }
|
|
|
-// return `${map[iorStart]}_${iorInfos[2]}`;
|
|
|
-// }
|
|
|
-
|
|
|
-const formatEvents = (events, cprKeys) => {
|
|
|
- const eventsMap = {};
|
|
|
- Object.keys(events).forEach(key => {
|
|
|
- const { type, side, ratio } = parseIorKey(key);
|
|
|
- let ratioKey, index;
|
|
|
- if (type === 'r') {
|
|
|
- if (side === 'h') {
|
|
|
- ratioKey = ratio;
|
|
|
- index = 0;
|
|
|
- }
|
|
|
- else if (side === 'c') {
|
|
|
- ratioKey = -ratio;
|
|
|
- index = 2;
|
|
|
- }
|
|
|
- }
|
|
|
- else if (type === 'm') {
|
|
|
- ratioKey = 'm';
|
|
|
- if (side == 'h') {
|
|
|
- index = 0;
|
|
|
- }
|
|
|
- else if (side == 'c') {
|
|
|
- index = 2;
|
|
|
- }
|
|
|
- else {
|
|
|
- index = 1;
|
|
|
- }
|
|
|
- }
|
|
|
- else if (type === 'wm') {
|
|
|
- ratioKey = `wm_${Math.abs(ratio)}`;
|
|
|
- if (side === 'h') {
|
|
|
- index = 0;
|
|
|
- }
|
|
|
- else if (side === 'c') {
|
|
|
- index = 2;
|
|
|
- }
|
|
|
- }
|
|
|
- else if (type === 'ou') {
|
|
|
- ratioKey = `ou_${Math.abs(ratio)}`;
|
|
|
- if (side === 'c') {
|
|
|
- index = 0;
|
|
|
- }
|
|
|
- else if (side === 'h') {
|
|
|
- index = 2;
|
|
|
- }
|
|
|
- }
|
|
|
- // else if (type === 'os') {
|
|
|
- // ratioKey = ratio;
|
|
|
- // index = 1;
|
|
|
- // }
|
|
|
- else if (type === 'ot') {
|
|
|
- ratioKey = `ot_${ratio}`;
|
|
|
- index = 1;
|
|
|
- // switch (ratio) {
|
|
|
- // case '0':
|
|
|
- // ratioKey = '0-1';
|
|
|
- // index = 0;
|
|
|
- // break;
|
|
|
- // case '1':
|
|
|
- // ratioKey = '0-1';
|
|
|
- // index = 2;
|
|
|
- // break;
|
|
|
- // case '2':
|
|
|
- // ratioKey = '2-3';
|
|
|
- // index = 0;
|
|
|
- // break;
|
|
|
- // case '3':
|
|
|
- // ratioKey = '2-3';
|
|
|
- // index = 2;
|
|
|
- // break;
|
|
|
- // }
|
|
|
- }
|
|
|
- if (typeof (ratioKey) == 'number') {
|
|
|
- if (ratioKey > 0) {
|
|
|
- ratioKey = `+${ratioKey}`;
|
|
|
- }
|
|
|
- // else if (ratioKey === 0) {
|
|
|
- // ratioKey = '-0';
|
|
|
- // }
|
|
|
- else {
|
|
|
- ratioKey = `${ratioKey}`;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (!ratioKey) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (!eventsMap[ratioKey]) {
|
|
|
- eventsMap[ratioKey] = new Array(3).fill(undefined);
|
|
|
- }
|
|
|
-
|
|
|
- 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 => {
|
|
|
- return [key, ...eventsMap[key]];
|
|
|
- });
|
|
|
-}
|
|
|
-
|
|
|
-const formatSolution = (solution, eventsList) => {
|
|
|
- const { cpr, info } = solution;
|
|
|
- if (!cpr || !info) {
|
|
|
- return null;
|
|
|
- }
|
|
|
-
|
|
|
- const cprKeys = cpr.map(item => item.k);
|
|
|
-
|
|
|
- const psEvents = eventsList.ps?.[info.ps.eventId] ?? {};
|
|
|
- const obEvents = eventsList.ob?.[info.ob.eventId] ?? {};
|
|
|
- const hgEvents = eventsList.hg?.[info.hg.eventId] ?? {};
|
|
|
-
|
|
|
- info.ps.events = formatPsEvents(psEvents);
|
|
|
- info.ob.events = formatEvents(obEvents, cprKeys);
|
|
|
- info.hg.events = formatEvents(hgEvents, cprKeys);
|
|
|
-
|
|
|
- info.ps.dateTime = dayjs(info.ps.timestamp).format('YYYY-MM-DD HH:mm:ss');
|
|
|
- info.ob.dateTime = dayjs(info.ob.timestamp).format('YYYY-MM-DD HH:mm:ss');
|
|
|
- info.hg.dateTime = dayjs(info.hg.timestamp).format('YYYY-MM-DD HH:mm:ss');
|
|
|
-
|
|
|
- cpr.forEach(item => {
|
|
|
- const { k, p } = item;
|
|
|
- if (!info[p]['selected']) {
|
|
|
- info[p]['selected'] = [];
|
|
|
- }
|
|
|
- info[p]['selected'].push(k);
|
|
|
- });
|
|
|
-
|
|
|
- return solution;
|
|
|
-}
|
|
|
-
|
|
|
-const updateSolutions = async (showLoading=false) => {
|
|
|
- clearTimeout(loopTimer.value);
|
|
|
- if (showLoading && !updateLoaderHide.value) {
|
|
|
- updateLoaderHide.value = message.loading('数据加载中...', 0);
|
|
|
- }
|
|
|
- getSolutions()
|
|
|
- .then(({ solutions: solutionsList, gamesEvents: eventsList, mkCount: mkCountData }) => {
|
|
|
- solutions.value = solutionsList?.map(solution => formatSolution(solution, eventsList)) ?? [];
|
|
|
- markCount.value = mkCountData;
|
|
|
- })
|
|
|
- .catch(error => {
|
|
|
- console.error('Failed to update solutions:', error);
|
|
|
- message.error('获取中单方案失败');
|
|
|
- })
|
|
|
- .finally(() => {
|
|
|
- updateLoaderHide.value?.();
|
|
|
- updateLoaderHide.value = null;
|
|
|
- if (loopActive.value) {
|
|
|
- loopTimer.value = setTimeout(() => {
|
|
|
- updateSolutions();
|
|
|
- }, 1000 * 10);
|
|
|
- }
|
|
|
- });
|
|
|
-}
|
|
|
-
|
|
|
-const showTotalProfit = async () => {
|
|
|
- totalProfit.value = await calcTotalProfit();
|
|
|
- totalProfitVisible.value = true;
|
|
|
- const { profit } = totalProfit.value;
|
|
|
- console.log('profit', profit);
|
|
|
-};
|
|
|
-
|
|
|
-const closeTotalProfit = () => {
|
|
|
- totalProfitVisible.value = false;
|
|
|
- selectedSolutions.length = 0;
|
|
|
- totalProfit.value = {};
|
|
|
-};
|
|
|
-
|
|
|
-const toggleSolution = (sid, timestamp) => {
|
|
|
- const findIndex = selectedSolutions.findIndex(item => item.sid === sid);
|
|
|
- if (findIndex >= 0) {
|
|
|
- selectedSolutions.splice(findIndex, 1);
|
|
|
- }
|
|
|
- else if (selectedSolutions.length < 2) {
|
|
|
- selectedSolutions.push({ sid, timestamp });
|
|
|
- }
|
|
|
- else {
|
|
|
- selectedSolutions.splice(1, 1, { sid, timestamp });
|
|
|
- }
|
|
|
- if (selectedSolutions.length == 2) {
|
|
|
- showTotalProfit();
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-const setLocalStorage = (key, value) => {
|
|
|
- localStorage.setItem(key, JSON.stringify(value));
|
|
|
-}
|
|
|
-
|
|
|
-const getLocalStorage = (key) => {
|
|
|
- const value = localStorage.getItem(key);
|
|
|
- return value ? JSON.parse(value) : null;
|
|
|
-}
|
|
|
-
|
|
|
-watch(minProfitRate, (newVal) => {
|
|
|
- clearTimeout(updateTimer.value);
|
|
|
- updateTimer.value = setTimeout(() => {
|
|
|
- setLocalStorage('minProfitRate', newVal);
|
|
|
- updateSolutions();
|
|
|
- }, 1000);
|
|
|
-});
|
|
|
-
|
|
|
-watch(marketType, (newVal) => {
|
|
|
- if (!updateLoaderHide.value) {
|
|
|
- updateLoaderHide.value = message.loading('数据更新中...', 0);
|
|
|
- }
|
|
|
- clearTimeout(updateTimer.value);
|
|
|
- updateTimer.value = setTimeout(() => {
|
|
|
- setLocalStorage('marketType', newVal);
|
|
|
- updateSolutions();
|
|
|
- }, 1000);
|
|
|
-});
|
|
|
-
|
|
|
-onMounted(() => {
|
|
|
- loopActive.value = true;
|
|
|
- const min_win_rate = getLocalStorage('minProfitRate');
|
|
|
- const mk = getLocalStorage('marketType');
|
|
|
- if (min_win_rate !== null) {
|
|
|
- minProfitRate.value = min_win_rate;
|
|
|
- }
|
|
|
- if (mk !== null) {
|
|
|
- marketType.value = mk;
|
|
|
- }
|
|
|
- setTimeout(() => {
|
|
|
- updateSolutions(true);
|
|
|
- }, 100);
|
|
|
-});
|
|
|
-
|
|
|
-onUnmounted(() => {
|
|
|
- loopActive.value = false;
|
|
|
-});
|
|
|
-
|
|
|
-
|
|
|
-</script>
|
|
|
-
|
|
|
-<template>
|
|
|
- <div class="solution-container">
|
|
|
-
|
|
|
- <div class="contents-header transition-all duration-200" :style="headerStyle">
|
|
|
- <div class="solution-options">
|
|
|
- <Form layout="inline" class="sol-opt-container">
|
|
|
- <Form.Item label="盘口类型" class="sol-opt-item">
|
|
|
- <RadioGroup v-model:value="marketType">
|
|
|
- <Radio :value="-1">全部({{ markCount.all ?? 0 }})</Radio>
|
|
|
- <Radio :value="2">滚球({{ markCount.rollball ?? 0 }})</Radio>
|
|
|
- <Radio :value="1">今日({{ markCount.today ?? 0 }})</Radio>
|
|
|
- <Radio :value="0">早盘({{ markCount.early ?? 0 }})</Radio>
|
|
|
- </RadioGroup>
|
|
|
- </Form.Item>
|
|
|
- <Form.Item label="最小利润率(%)" class="sol-opt-item">
|
|
|
- <InputNumber style="width: 60px" size="small" max="100" min="-100" step="0.1" placeholder="最小利润率(%)" v-model:value="minProfitRate"/>
|
|
|
- </Form.Item>
|
|
|
- </Form>
|
|
|
- </div>
|
|
|
- <div class="solution-header">
|
|
|
- <span>PS</span>
|
|
|
- <span>OB</span>
|
|
|
- <span>HG</span>
|
|
|
- <em>利润</em>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="solution-list">
|
|
|
- <div class="solution-item"
|
|
|
- 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 ?? []" :stage="ps.stage" :retime="ps.retime" :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 ?? []" :stage="ob.stage" :retime="ob.retime" :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 ?? []" :stage="hg.stage" :retime="hg.retime" :score="hg.score" />
|
|
|
-
|
|
|
- <div class="solution-profit" @click="!disabled && toggleSolution(sid, ps.timestamp)">
|
|
|
- <p>{{ win_average_rate }}%</p>
|
|
|
- <p>{{ win_profit_rate }}%</p>
|
|
|
- <p>{{ cross_type }}</p>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="list-empty" v-if="!solutionsList.length">暂无数据</div>
|
|
|
-
|
|
|
- <!-- <Drawer
|
|
|
- title="综合利润方案"
|
|
|
- placement="bottom"
|
|
|
- height="600"
|
|
|
- :visible="totalProfitVisible"
|
|
|
- @close="closeTotalProfit"
|
|
|
- >
|
|
|
- <div class="solution-total-profit" v-if="totalProfitValue.solutions.length">
|
|
|
- <div class="solution-item"
|
|
|
- v-for="{ sid, info: { ps, ob, hg } } in totalProfitValue.solutions" :key="sid">
|
|
|
- <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 ?? []" />
|
|
|
-
|
|
|
- <MatchCard platform="ob" :eventId="ob.eventId" :leagueName="ob.leagueName" :teamHomeName="ob.teamHomeName"
|
|
|
- :teamAwayName="ob.teamAwayName" :dateTime="ob.dateTime" :events="ob.events ?? []"
|
|
|
- :selected="ob.selected ?? []" />
|
|
|
-
|
|
|
- <MatchCard platform="hg" :eventId="hg.eventId" :leagueName="hg.leagueName" :teamHomeName="hg.teamHomeName"
|
|
|
- :teamAwayName="hg.teamAwayName" :dateTime="hg.dateTime" :events="hg.events ?? []"
|
|
|
- :selected="hg.selected ?? []" />
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="profit-info">
|
|
|
- <table>
|
|
|
- <tr>
|
|
|
- <th></th>
|
|
|
- <td>PS</td>
|
|
|
- <td colspan="2">第一场</td>
|
|
|
- <td colspan="2">第二场</td>
|
|
|
- </tr>
|
|
|
- <tr>
|
|
|
- <th>赔率</th>
|
|
|
- <td>{{ totalProfitValue.psInfo[0]?.v }}: {{ totalProfitValue.psInfo[1]?.v }}</td>
|
|
|
- <td>{{ totalProfitValue.outPreSol[0]?.p }}: {{ totalProfitValue.outPreSol[0]?.v }}</td>
|
|
|
- <td>{{ totalProfitValue.outPreSol[1]?.p }}: {{ totalProfitValue.outPreSol[1]?.v }}</td>
|
|
|
- <td>{{ totalProfitValue.outSubSol[0]?.p }}: {{ totalProfitValue.outSubSol[0]?.v }}</td>
|
|
|
- <td>{{ totalProfitValue.outSubSol[1]?.p }}: {{ totalProfitValue.outSubSol[1]?.v }}</td>
|
|
|
- </tr>
|
|
|
- <tr>
|
|
|
- <th>下注</th>
|
|
|
- <td>{{ psOptions.bet }}</td>
|
|
|
- <td>{{ totalProfitValue.outPreSol[0]?.g }}</td>
|
|
|
- <td>{{ totalProfitValue.outPreSol[1]?.g }}</td>
|
|
|
- <td>{{ totalProfitValue.outSubSol[0]?.g }}</td>
|
|
|
- <td>{{ totalProfitValue.outSubSol[1]?.g }}</td>
|
|
|
- </tr>
|
|
|
- <tr>
|
|
|
- <th>利润</th>
|
|
|
- <td>{{ totalProfitValue.profit.win_ps }}</td>
|
|
|
- <td colspan="2">{{ totalProfitValue.profit.win_target }}</td>
|
|
|
- <td colspan="2">{{ totalProfitValue.profit.win_target }}</td>
|
|
|
- </tr>
|
|
|
- </table>
|
|
|
- </div>
|
|
|
- </Drawer> -->
|
|
|
-
|
|
|
- </div>
|
|
|
-</template>
|
|
|
-
|
|
|
-<style lang="scss" scoped>
|
|
|
-.contents-header {
|
|
|
- position: fixed;
|
|
|
- top: 0;
|
|
|
- left: 0;
|
|
|
- z-index: 201;
|
|
|
- width: 100%;
|
|
|
- border-bottom: 1px solid hsl(var(--border));
|
|
|
- background-color: hsl(var(--background));
|
|
|
-}
|
|
|
-
|
|
|
-.solution-options {
|
|
|
- position: relative;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- padding: 5px 20px;
|
|
|
- border-bottom: 1px solid hsl(var(--border));
|
|
|
-}
|
|
|
-
|
|
|
-.sol-opt-container {
|
|
|
- flex-grow: 1;
|
|
|
- justify-content: space-between;
|
|
|
-}
|
|
|
-
|
|
|
-.sol-opt-item:last-child {
|
|
|
- margin-inline-end: 0 !important;
|
|
|
-}
|
|
|
-
|
|
|
-.solution-header {
|
|
|
- position: relative;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- height: 30px;
|
|
|
- padding: 0 20px;
|
|
|
- span,
|
|
|
- em {
|
|
|
- display: block;
|
|
|
- text-align: center;
|
|
|
- }
|
|
|
-
|
|
|
- span {
|
|
|
- flex: 1;
|
|
|
- }
|
|
|
-
|
|
|
- em {
|
|
|
- width: 80px;
|
|
|
- font-style: normal;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-.solution-container {
|
|
|
- padding-top: 74px;
|
|
|
-}
|
|
|
-
|
|
|
-.solution-item {
|
|
|
- display: flex;
|
|
|
- .match-card {
|
|
|
- flex: 1;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-.solution-list {
|
|
|
- padding: 20px;
|
|
|
- overflow: hidden;
|
|
|
-
|
|
|
- .solution-item {
|
|
|
- border-radius: 10px;
|
|
|
- background-color: hsl(var(--card));
|
|
|
-
|
|
|
- &.selected {
|
|
|
- background-color: hsl(var(--primary) / 0.15);
|
|
|
- }
|
|
|
-
|
|
|
- &.disabled {
|
|
|
- opacity: 0.5;
|
|
|
- cursor: not-allowed;
|
|
|
- }
|
|
|
-
|
|
|
- &:not(:last-child) {
|
|
|
- margin-bottom: 20px;
|
|
|
- }
|
|
|
-
|
|
|
- .match-card {
|
|
|
- border-right: 1px solid hsl(var(--border));
|
|
|
- }
|
|
|
-
|
|
|
- .solution-profit {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- width: 80px;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-.profit-info {
|
|
|
- table {
|
|
|
- width: 100%;
|
|
|
- border-collapse: collapse;
|
|
|
- border-spacing: 0;
|
|
|
- table-layout: fixed;
|
|
|
- th, td {
|
|
|
- height: 30px;
|
|
|
- border: 1px solid hsl(var(--border));
|
|
|
- text-align: center;
|
|
|
- }
|
|
|
- th {
|
|
|
- width: 64px;
|
|
|
- font-weight: normal;
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-.list-empty {
|
|
|
- text-align: center;
|
|
|
- padding: 10px;
|
|
|
- font-size: 18px;
|
|
|
- color: hsl(var(--foreground) / 0.7);
|
|
|
-}
|
|
|
-</style>
|