| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396 |
- <script setup>
- import { Tooltip } from 'ant-design-vue';
- import { ref, computed } from 'vue';
- import dayjs from 'dayjs';
- import MatchCard from './match_card.vue';
- const props = defineProps({
- serial: {
- type: Number,
- },
- id: {
- type: Number,
- required: true
- },
- mk: {
- type: Number,
- required: true
- },
- rel: {
- type: Object,
- required: true
- },
- solutions: {
- type: Array,
- required: true
- },
- selected: {
- type: Boolean,
- default: false
- }
- });
- const emit = defineEmits(['toggle']);
- const selectedIndex = ref(0);
- const parseIorKey = (iorKey) => {
- const iorKeyMatch = iorKey.match(/^ior_(r|ou|m|wm|ot|os)(a?)(h|c|n)?(_([\d-]+))?$/);
- if (!iorKeyMatch) {
- console.log('no iorKeyMatch', iorKey);
- return null;
- }
- const [, type, accept, side, , ratioString] = iorKeyMatch;
- 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'],
- ['-3', 'ior_rh_35', 'ior_wmh_3', 'ior_rac_25'],
- ['-4', 'ior_rh_45', 'ior_wmh_4', 'ior_rac_35'],
- ['-5', 'ior_rh_55', 'ior_wmh_5', 'ior_rac_45'],
- ['+1', 'ior_rah_05', 'ior_wmc_1', 'ior_rc_15'],
- ['+2', 'ior_rah_15', 'ior_wmc_2', 'ior_rc_25'],
- ['+3', 'ior_rah_25', 'ior_wmc_3', 'ior_rc_35'],
- ['+4', 'ior_rah_35', 'ior_wmc_4', 'ior_rc_45'],
- ['+5', 'ior_rah_45', 'ior_wmc_5', 'ior_rc_55'],
- ['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 fixFloat = (number, x = 2) => {
- return parseFloat(number.toFixed(x));
- }
- 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 formatEvents = (events) => {
- const eventsMap = {};
- Object.keys(events).forEach(key => {
- const { type, side, ratio } = parseIorKey(key) ?? {};
- if (!type) {
- return;
- }
- 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 === 'ot') {
- ratioKey = `ot_${ratio}`;
- index = 1;
- }
- if (typeof (ratioKey) == 'number') {
- if (ratioKey > 0) {
- ratioKey = `+${ratioKey}`;
- }
- 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;
- const qualified = events[key]?.q ?? 1;
- eventsMap[ratioKey][index] = { key, value, origin, qualified };
- });
- return Object.keys(eventsMap).sort((a, b) => a.localeCompare(b)).map(key => {
- return [key, ...eventsMap[key]];
- });
- }
- const toggleSolution = () => {
- const id = props.id;
- const sid = currentSolution.value.sid;
- emit('toggle', { id, sid });
- };
- const switchSolution = (index) => {
- if (index == selectedIndex.value) {
- return;
- }
- selectedIndex.value = index;
- if (!props.selected) {
- return;
- }
- toggleSolution();
- };
- const currentIndex = computed(() => {
- const index = selectedIndex.value;
- if (props.solutions[index]) {
- return index;
- }
- return 0;
- });
- const currentSolution = computed(() => {
- return props.solutions[currentIndex.value];
- });
- const currentRelation = computed(() => {
- const cpr = currentSolution.value.cpr;
- const rel = props.rel;
- const { ps: { eventId, leagueName, timestamp, stage, retime, score } } = rel;
- const dateTime = dayjs(timestamp).format('YYYY-MM-DD HH:mm:ss');
- const relation = { id: eventId, leagueName, timestamp, dateTime, stage, retime, score };
- Object.keys(rel).forEach(platform => {
- const { eventId, teamHomeName, teamAwayName, events, special } = rel[platform] ?? {};
- if (!relation.rel) {
- relation.rel = {};
- }
- const mergedEvents = { ...events, ...special };
- const formattedEvents = platform === 'ps' ? formatPsEvents(mergedEvents) : formatEvents(mergedEvents);
- relation.rel[platform] = { eventId, teamHomeName, teamAwayName, events: formattedEvents };
- });
- cpr.forEach(item => {
- const { k, p } = item;
- if (!relation.rel[p]['selected']) {
- relation.rel[p]['selected'] = [];
- }
- relation.rel[p]['selected'].push(k);
- });
- return relation;
- });
- const isHalf = computed(() => {
- return currentRelation.value.id < 0;
- });
- const ps = computed(() => {
- return currentRelation.value.rel.ps;
- });
- const hg = computed(() => {
- return currentRelation.value.rel.hg;
- });
- const ob = computed(() => {
- return currentRelation.value.rel.ob;
- });
- const im = computed(() => {
- return currentRelation.value.rel.im;
- });
- </script>
- <template>
- <div class="solution-item" :class="{ 'selected': selected }">
- <div class="solution-header">
- <div class="serial-number" v-if="serial">{{ serial }}.</div>
- <div class="stage" v-if="currentRelation.stage">[{{ currentRelation.stage }}{{ currentRelation.retime ? ` ${currentRelation.retime}` : '' }}]</div>
- <div class="score" v-if="currentRelation.stage">[{{ currentRelation.score }}]</div>
- <div class="league-name">{{ currentRelation.leagueName }}</div>
- <div class="period-half" v-if="isHalf">[上半场]</div>
- <div class="date-time">{{ currentRelation.dateTime }}</div>
- <div class="switch-btns" v-if="solutions.length">
- <Tooltip v-for="({sol}, index) in solutions" :key="index"
- class="switch-btn-item"
- :class="{ 'selected': index === currentIndex }"
- :title="`${sol.win_profit_rate}% (${sol.cross_type})`"
- @click="switchSolution(index)">{{ sol.win_average_rate }}</Tooltip>
- </div>
- </div>
- <div class="solution-content">
- <MatchCard platform="ps" :eventId="ps.eventId" :teamHomeName="ps.teamHomeName"
- :teamAwayName="ps.teamAwayName" :dateTime="ps.dateTime" :events="ps.events ?? []"
- :selected="ps.selected ?? []" />
- <MatchCard platform="ob" :eventId="ob.eventId" :teamHomeName="ob.teamHomeName"
- :teamAwayName="ob.teamAwayName" :dateTime="ob.dateTime" :events="ob.events ?? []"
- :selected="ob.selected ?? []" />
- <MatchCard platform="hg" :eventId="hg.eventId" :teamHomeName="hg.teamHomeName"
- :teamAwayName="hg.teamAwayName" :dateTime="hg.dateTime" :events="hg.events ?? []"
- :selected="hg.selected ?? []" />
- <MatchCard platform="im" :eventId="im.eventId" :teamHomeName="im.teamHomeName"
- :teamAwayName="im.teamAwayName" :dateTime="im.dateTime" :events="im.events ?? []"
- :selected="im.selected ?? []" />
- <!-- <div class="solution-profit" @click="toggleSolution()">
- <p>{{ currentSolution.sol.win_average_rate }}%</p>
- <p>{{ currentSolution.sol.win_profit_rate }}%</p>
- <p>{{ currentSolution.sol.cross_type }}</p>
- </div> -->
- </div>
- </div>
- </template>
- <style lang="scss" scoped>
- .solution-item {
- display: flex;
- flex-direction: column;
- border-radius: 10px;
- background-color: hsl(var(--card));
- &.selected {
- background-color: hsl(var(--primary) / 0.15);
- }
- &:not(:last-child) {
- margin-bottom: 20px;
- }
- }
- .solution-header {
- display: flex;
- align-items: center;
- height: 40px;
- padding: 0 15px;
- border-bottom: 1px solid hsl(var(--border));
- .serial-number {
- margin-right: 5px;
- font-size: 16px;
- font-weight: 400;
- color: hsl(var(--foreground) / 0.7);
- }
- .score, .stage {
- text-align: center;
- font-size: 16px;
- font-weight: 400;
- }
- .score {
- color: hsl(var(--primary));
- }
- .stage {
- color: hsl(var(--destructive));
- }
- .league-name {
- margin-right: 10px;
- font-size: 16px;
- font-weight: 400;
- }
- .period-half {
- margin-right: 10px;
- color: hsl(var(--primary));
- }
- .date-time {
- text-align: right;
- font-size: 14px;
- color: hsl(var(--foreground) / 0.7);
- }
- }
- .switch-btns {
- display: flex;
- align-items: center;
- justify-content: flex-end;
- flex: 1;
- :deep(.switch-btn-item) {
- display: block;
- height: 20px;
- line-height: 20px;
- padding: 0 5px;
- border-radius: 4px;
- cursor: pointer;
- &:hover {
- color: hsl(var(--primary));
- }
- &.selected {
- color: hsl(var(--primary-foreground));
- background-color: hsl(var(--primary));
- cursor: default;
- }
- &:not(:last-child) {
- margin-right: 5px;
- }
- }
- }
- .solution-content {
- display: flex;
- .match-card {
- flex: 1;
- }
- .match-card:not(:last-child) {
- border-right: 1px solid hsl(var(--border));
- }
- }
- /*
- .solution-profit {
- display: flex;
- flex-direction: column;
- width: 80px;
- align-items: center;
- justify-content: center;
- }
- */
- </style>
|