Files
cpzs-frontend-new/src/views/dlt/SurfaceAnalysis.vue

879 lines
22 KiB
Vue
Raw Normal View History

<template>
<div class="surface-analysis">
<div class="header">
<!-- 返回按钮 -->
<div class="back-button-container">
<el-button @click="goBack" icon="ArrowLeft" size="medium">
返回
</el-button>
</div>
<h2>组合性分析</h2>
<p>号球组合分析探寻左姻右缘</p>
</div>
<!-- 分析类型选择 -->
<div class="analysis-buttons">
<el-card
class="analysis-card"
:class="{ active: analysisType === 'front-front' }"
@click="selectAnalysisType('front-front')"
shadow="hover"
>
<div class="btn-icon">
<el-avatar class="red-ball-icon"></el-avatar>
<el-avatar class="red-ball-icon"></el-avatar>
</div>
<div class="btn-text">
<div class="btn-title">前区与前区</div>
<div class="btn-desc">前区组合分析</div>
</div>
</el-card>
<el-card
class="analysis-card"
:class="{ active: analysisType === 'front-back' }"
@click="selectAnalysisType('front-back')"
shadow="hover"
>
<div class="btn-icon">
<el-avatar class="red-ball-icon"></el-avatar>
<el-avatar class="blue-ball-icon"></el-avatar>
</div>
<div class="btn-text">
<div class="btn-title">前区与后区</div>
<div class="btn-desc">前后组合分析</div>
</div>
</el-card>
<el-card
class="analysis-card"
:class="{ active: analysisType === 'back-back' }"
@click="selectAnalysisType('back-back')"
shadow="hover"
>
<div class="btn-icon">
<el-avatar class="blue-ball-icon"></el-avatar>
<el-avatar class="blue-ball-icon"></el-avatar>
</div>
<div class="btn-text">
<div class="btn-title">后区与后区</div>
<div class="btn-desc">后区组合分析</div>
</div>
</el-card>
<el-card
class="analysis-card"
:class="{ active: analysisType === 'back-front' }"
@click="selectAnalysisType('back-front')"
shadow="hover"
>
<div class="btn-icon">
<el-avatar class="blue-ball-icon"></el-avatar>
<el-avatar class="red-ball-icon"></el-avatar>
</div>
<div class="btn-text">
<div class="btn-title">后区与前区</div>
<div class="btn-desc">后前组合分析</div>
</div>
</el-card>
</div>
<!-- 号码选择和分析区域 -->
<el-card v-if="analysisType" class="analysis-container" shadow="never">
<el-alert
v-if="selectionError"
:title="selectionError"
type="warning"
show-icon
@close="selectionError = null"
style="margin-bottom: 20px;"
/>
<div class="number-selection">
<h3>{{ getSelectionTitle() }}</h3>
<!-- 主球选择 -->
<div class="ball-selection-group">
<el-divider>{{ getMasterBallLabel() }}</el-divider>
<div class="ball-grid">
<el-button
v-for="num in getMasterBallRange()"
:key="'master-' + num"
:class="{
active: masterBall === num,
'red-ball': isMasterFront(),
'blue-ball': !isMasterFront()
}"
:type="masterBall === num ? 'primary' : 'default'"
:plain="masterBall !== num"
circle
@click="selectMasterBall(num)"
>
{{ num }}
</el-button>
</div>
</div>
<!-- 随球选择 -->
<div class="ball-selection-group">
<el-divider>{{ getSlaveBallLabel() }}</el-divider>
<div class="ball-grid">
<el-button
v-for="num in getSlaveBallRange()"
:key="'slave-' + num"
:class="{
active: slaveBall === num,
'red-ball': isSlaveFront(),
'blue-ball': !isSlaveFront()
}"
:type="slaveBall === num ? 'primary' : 'default'"
:plain="slaveBall !== num"
circle
@click="selectSlaveBall(num)"
>
{{ num }}
</el-button>
</div>
</div>
<!-- 分析按钮 -->
<div class="analyze-section">
<el-button
type="success"
size="large"
round
:disabled="!canAnalyze || loading"
:loading="loading"
@click="performAnalysis"
>
{{ loading ? '分析中...' : '开始分析' }}
</el-button>
</div>
</div>
<!-- 分析结果 -->
<div v-if="result !== null || error" class="result-container">
<el-alert
v-if="error"
:title="error"
type="error"
show-icon
:closable="false"
style="margin-bottom: 20px;"
>
<template #default>
<el-button @click="clearError" type="primary" size="small">重试</el-button>
</template>
</el-alert>
<el-result
v-else-if="result !== null"
icon="success"
title="组合性分析结果"
>
<template #extra>
<div class="result-details">
<div class="table-wrapper">
<div class="table-title-row">
<div class="table-title-cell">
<span class="highlight-ball" :class="{ 'blue-text': !isMasterFront() }">{{masterBall}}</span>{{isMasterFront() ? '前区' : '后区'}}球与<span class="highlight-ball" :class="{ 'blue-text': !isSlaveFront() }">{{slaveBall}}</span>{{isSlaveFront() ? '前区' : '后区'}}球组合性分析报告
</div>
</div>
<table class="analysis-table">
<tbody>
<tr>
<td class="label-cell">引用数据截至</td>
<td class="value-cell">{{resultData[0]?.latestDrawId || '-'}}</td>
</tr>
<tr>
<td class="label-cell">两号组合系数</td>
<td class="value-cell">{{resultData[0]?.faceCoefficient || '-'}}</td>
</tr>
<tr>
<td class="label-cell">同号组最高系数球号及系数</td>
<td class="value-cell">
<span class="highlight-ball" :class="{ 'blue-text': !isSlaveFront() }">{{resultData[0]?.highestBall || '--'}}</span>
<span class="coefficient-value">{{resultData[0]?.highestCoefficient || '-'}}</span>
</td>
</tr>
<tr>
<td class="label-cell">同号组最低系数球号及系数</td>
<td class="value-cell">
<span class="highlight-ball" :class="{ 'blue-text': !isSlaveFront() }">{{resultData[0]?.lowestBall || '--'}}</span>
<span class="coefficient-value">{{resultData[0]?.lowestCoefficient || '-'}}</span>
</td>
</tr>
<tr>
<td class="label-cell">同号组平均系数</td>
<td class="value-cell">{{ (resultData[0]?.averageCoefficient && Number(resultData[0].averageCoefficient).toFixed(2)) || '-' }}</td>
</tr>
<tr>
<td class="label-cell">建议</td>
<td class="value-cell recommendation">
系数越高表示该此组合概率较高高于平均系数的组合更值得关注同时可尝试寻找关联组合与交叉组合的共性规律
</td>
</tr>
</tbody>
</table>
</div>
<el-button type="primary" @click="resetAnalysis">重新分析</el-button>
</div>
</template>
</el-result>
</div>
</el-card>
<!-- 使用说明 -->
<el-card v-if="!analysisType" class="instruction-container" shadow="hover">
<template #header>
<div class="card-header">
<span><el-icon><InfoFilled /></el-icon> 组合性分析说明</span>
</div>
</template>
<el-collapse accordion>
<el-collapse-item title="前区与前区分析" name="front-front">
<div class="collapse-content">
<p>分析两个前区球号码之间的组合关系计算前区配对的组合系数</p>
</div>
</el-collapse-item>
<el-collapse-item title="前区与后区分析" name="front-back">
<div class="collapse-content">
<p>分析前区与后区球号码的组合关系计算前后配对的组合系数</p>
</div>
</el-collapse-item>
<el-collapse-item title="后区与后区分析" name="back-back">
<div class="collapse-content">
<p>分析两个后区球号码之间的组合关系计算后区配对的组合系数</p>
</div>
</el-collapse-item>
<el-collapse-item title="后区与前区分析" name="back-front">
<div class="collapse-content">
<p>分析后区与前区球号码的组合关系计算后前配对的组合系数</p>
</div>
</el-collapse-item>
</el-collapse>
<el-alert
type="info"
show-icon
:closable="false"
style="margin-top: 20px;"
>
<template #title>
<span>选择分析类型后依次选择主球和随球号码点击"开始分析"获取组合系数值</span>
</template>
</el-alert>
</el-card>
</div>
</template>
<script>
import { dltLotteryApi } from '@/api/dlt'
export default {
name: 'DltSurfaceAnalysis',
data() {
return {
analysisType: '', // 'front-front', 'front-back', 'back-back', 'back-front'
masterBall: null,
slaveBall: null,
loading: false,
result: null,
error: null,
selectionError: null
}
},
computed: {
canAnalyze() {
return this.masterBall !== null && this.slaveBall !== null && this.analysisType
},
resultData() {
if (!this.result) return [];
try {
const data = typeof this.result === 'string' ? JSON.parse(this.result) : this.result;
return [{
latestDrawId: data.latestDrawId || '',
faceCoefficient: data.faceCoefficient || 0,
highestCoefficient: data.highestCoefficient || 0,
lowestCoefficient: data.lowestCoefficient || 0,
averageCoefficient: data.averageCoefficient || 0,
highestBall: data.highestBall || '-',
lowestBall: data.lowestBall || '-'
}];
} catch (e) {
console.error('解析结果数据失败', e);
return [{
latestDrawId: '',
faceCoefficient: 0,
highestCoefficient: 0,
lowestCoefficient: 0,
averageCoefficient: 0,
highestBall: '-',
lowestBall: '-'
}];
}
}
},
methods: {
// 返回上一页
goBack() {
// 获取当前彩票类型,优先使用路由参数,否则使用默认值 'dlt'
const lotteryType = this.$route.query.lotteryType || 'dlt'
this.$router.push({
path: '/data-analysis',
query: { lotteryType: lotteryType }
})
},
selectAnalysisType(type) {
this.analysisType = type
this.masterBall = null
this.slaveBall = null
this.result = null
this.error = null
this.selectionError = null
},
getSelectionTitle() {
const titles = {
'front-front': '前区与前区组合分析(不能重复)',
'front-back': '前区与后区组合分析',
'back-back': '后区与后区组合分析(不能重复)',
'back-front': '后区与前区组合分析'
}
return titles[this.analysisType] || ''
},
getMasterBallLabel() {
const labels = {
'front-front': '主球(前区)',
'front-back': '主球(前区)',
'back-back': '主球(后区)',
'back-front': '主球(后区)'
}
return labels[this.analysisType] || ''
},
getSlaveBallLabel() {
const labels = {
'front-front': '随球(前区)',
'front-back': '随球(后区)',
'back-back': '随球(后区)',
'back-front': '随球(前区)'
}
return labels[this.analysisType] || ''
},
getMasterBallRange() {
if (this.analysisType === 'back-back' || this.analysisType === 'back-front') {
return Array.from({ length: 12 }, (_, i) => i + 1) // 1-12 后区
}
return Array.from({ length: 35 }, (_, i) => i + 1) // 1-35 前区
},
getSlaveBallRange() {
if (this.analysisType === 'front-back' || this.analysisType === 'back-back') {
return Array.from({ length: 12 }, (_, i) => i + 1) // 1-12 后区
}
return Array.from({ length: 35 }, (_, i) => i + 1) // 1-35 前区
},
isMasterFront() {
return this.analysisType === 'front-front' || this.analysisType === 'front-back'
},
isSlaveFront() {
return this.analysisType === 'front-front' || this.analysisType === 'back-front'
},
selectMasterBall(num) {
// 前区与前区、后区与后区不能选择相同号码
if ((this.analysisType === 'front-front' || this.analysisType === 'back-back') && num === this.slaveBall) {
this.selectionError = '主球和随球不能是同一个号码'
return
}
this.masterBall = num
this.result = null
this.error = null
this.selectionError = null
},
selectSlaveBall(num) {
// 前区与前区、后区与后区不能选择相同号码
if ((this.analysisType === 'front-front' || this.analysisType === 'back-back') && num === this.masterBall) {
this.selectionError = '主球和随球不能是同一个号码'
return
}
this.slaveBall = num
this.result = null
this.error = null
this.selectionError = null
},
async performAnalysis() {
if (!this.canAnalyze) return
this.loading = true
this.error = null
this.result = null
try {
let response
switch (this.analysisType) {
case 'front-front':
response = await dltLotteryApi.frontFrontCombinationAnalysis(this.masterBall, this.slaveBall)
break
case 'front-back':
response = await dltLotteryApi.frontBackCombinationAnalysis(this.masterBall, this.slaveBall)
break
case 'back-back':
response = await dltLotteryApi.backBackCombinationAnalysis(this.masterBall, this.slaveBall)
break
case 'back-front':
response = await dltLotteryApi.backFrontCombinationAnalysis(this.masterBall, this.slaveBall)
break
}
if (response.success) {
this.result = response.data
} else {
this.error = response.message || '分析失败'
}
} catch (error) {
console.error('组合系数分析失败:', error)
this.error = '网络请求失败,请重试'
} finally {
this.loading = false
}
},
clearError() {
this.error = null
},
resetAnalysis() {
this.masterBall = null
this.slaveBall = null
this.result = null
this.error = null
}
}
}
</script>
<style scoped>
.surface-analysis {
min-height: 100vh;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
padding: 20px;
}
.header {
text-align: center;
margin-bottom: 30px;
position: relative;
}
/* 返回按钮 */
.back-button-container {
position: absolute;
left: 20px;
top: 0;
}
.header h2 {
color: #2c3e50;
font-size: 28px;
margin-bottom: 10px;
font-weight: 700;
}
.header p {
color: #7f8c8d;
font-size: 16px;
}
/* 分析类型卡片 */
.analysis-buttons {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
margin-bottom: 20px;
max-width: 1000px;
margin-left: auto;
margin-right: auto;
}
.analysis-card {
cursor: pointer;
transition: all 0.3s ease;
display: flex;
flex-direction: column;
align-items: center;
padding: 10px;
}
.analysis-card:hover {
transform: translateY(-5px);
box-shadow: 0 8px 25px rgba(52, 152, 219, 0.15);
border-color: #3498db;
}
.analysis-card.active {
background-color: #eaf5ff;
border-color: #3498db;
box-shadow: 0 8px 25px rgba(52, 152, 219, 0.2);
}
.analysis-card.active :deep(.el-card__body) {
background: transparent;
color: #303133;
}
/* 减少卡片内边距 */
:deep(.el-card__body) {
padding: 10px !important;
}
.btn-icon {
display: flex;
gap: 5px;
margin-bottom: 10px;
}
.red-ball-icon {
background-color: #e74c3c !important;
}
.blue-ball-icon {
background-color: #3498db !important;
}
.btn-title {
font-size: 16px;
font-weight: 600;
margin-bottom: 4px;
}
.btn-desc {
font-size: 14px;
opacity: 0.8;
}
.analysis-card.active .btn-title {
color: #2980b9;
}
.analysis-card.active .btn-desc {
color: #3498db;
}
.number-selection {
padding: 20px 0;
}
.number-selection h3 {
color: #2c3e50;
margin-bottom: 20px;
font-size: 20px;
text-align: center;
}
.ball-selection-group {
margin-bottom: 25px;
}
/* 球号网格 */
.ball-grid {
display: flex;
flex-wrap: wrap;
gap: 10px;
justify-content: center;
margin-top: 15px;
padding: 0 15px;
}
/* 前区球(红球)和后区球(蓝球)按钮样式 */
:deep(.el-button.red-ball.is-plain:not(.is-disabled)) {
color: #e74c3c;
border-color: #e74c3c;
background-color: #fff5f5;
}
:deep(.el-button.red-ball:not(.is-plain):not(.is-disabled)) {
background-color: #e74c3c;
border-color: #c0392b;
}
:deep(.el-button.blue-ball.is-plain:not(.is-disabled)) {
color: #3498db;
border-color: #3498db;
background-color: #f0f8ff;
}
:deep(.el-button.blue-ball:not(.is-plain):not(.is-disabled)) {
background-color: #3498db;
border-color: #2980b9;
}
/* 分析按钮 */
.analyze-section {
text-align: center;
margin-top: 30px;
}
/* 结果容器 */
.result-container {
border-top: 2px solid #ecf0f1;
padding: 20px;
background: #f8f9fa;
}
:deep(.el-result) {
padding: 0px;
}
.result-details {
width: 100%;
max-width: 850px;
margin: 0 auto;
display: flex;
flex-direction: column;
align-items: center;
}
.ball-combo {
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
margin: 15px 0;
}
.combo-label {
font-size: 16px;
color: #2c3e50;
font-weight: 600;
}
.combo-separator {
font-size: 20px;
color: #7f8c8d;
font-weight: bold;
}
.ball-tag {
padding: 8px 12px;
font-weight: 700;
font-size: 16px;
border-radius: 50%;
min-width: 40px;
}
.coefficient-result {
margin: 20px 0;
}
:deep(.el-statistic__head) {
margin-bottom: 10px;
font-size: 16px;
}
:deep(.el-statistic__content) {
font-size: 24px !important;
color: #e74c3c;
}
/* 使用说明 */
.instruction-container {
max-width: 850px;
margin: 0 auto;
}
.card-header {
display: flex;
align-items: center;
gap: 10px;
font-size: 18px;
font-weight: 600;
}
.collapse-content {
padding: 10px;
color: #7f8c8d;
}
.table-wrapper {
width: 100%;
max-width: 500px;
margin: 0 auto 20px;
border-collapse: collapse;
}
.table-title-row {
width: 100%;
text-align: center;
border: 1px solid #000;
}
.table-title-cell {
padding: 8px;
font-weight: normal;
font-size: 15px;
color: #000;
background-color: #fff;
border-bottom: 1px solid #000;
}
.analysis-table {
width: 100%;
border-collapse: collapse;
border: 1px solid #000;
border-top: none;
font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', '微软雅黑', Arial, sans-serif;
}
.analysis-table tr {
border-bottom: 1px solid #000;
}
.analysis-table tr:last-child {
border-bottom: none;
}
.label-cell {
width: 150px;
padding: 8px;
text-align: center;
font-weight: normal;
background-color: #f5f5f5;
border-right: 1px solid #000;
vertical-align: middle;
}
.value-cell {
padding: 8px;
text-align: center;
vertical-align: middle;
}
.value-cell .ball-number {
display: inline-block;
min-width: 30px;
text-align: right;
}
.value-cell .highlight-ball {
display: inline-block;
min-width: 30px;
text-align: left;
color: #e74c3c; /* 红色文字 */
font-weight: bold;
margin-right: 8px;
}
.highlight-ball {
color: #e74c3c; /* 红色文字 */
font-weight: bold;
margin-right: 2px;
}
.highlight-ball.blue-text {
color: #3498db; /* 蓝色文字 */
}
.coefficient-value {
font-weight: normal;
color: #333;
}
.value-cell .coefficient-value {
text-align: left;
display: inline-block;
}
.recommendation {
font-size: 13px;
line-height: 1.5;
color: #333;
text-align: left;
padding: 5px;
white-space: normal;
font-weight: normal;
}
.report-title {
font-size: 18px;
font-weight: bold;
color: #303133;
margin: 20px 0 15px;
text-align: center;
padding-bottom: 10px;
width: 100%;
max-width: 600px;
display: none; /* 隐藏原来的标题,使用表格自身的标题 */
}
/* 响应式设计 */
@media (max-width: 768px) {
.surface-analysis {
padding: 15px;
}
.back-button-container {
position: static;
text-align: left;
margin-bottom: 0px;
}
.header {
margin-bottom: 15px;
}
.analysis-buttons {
grid-template-columns: repeat(2, 1fr);
gap: 10px;
}
.btn-title {
font-size: 14px;
}
.btn-desc {
font-size: 12px;
}
.ball-grid {
gap: 8px;
padding: 0;
}
.table-wrapper {
max-width: 100%;
}
.table-title-cell {
font-size: 14px;
padding: 6px;
}
.label-cell, .value-cell {
padding: 6px;
font-size: 13px;
}
.recommendation {
font-size: 12px;
line-height: 1.4;
}
}
</style>