添加投注定时器脚本

This commit is contained in:
2026-01-23 12:31:57 +08:00
parent 70f2a71df8
commit 15b0fff86d
4 changed files with 437 additions and 97 deletions

BIN
bocai.db

Binary file not shown.

View File

@@ -7,15 +7,21 @@ import * as echarts from 'echarts';
const input1 = ref('');
const input2 = ref('');
// 登录模态框数据
const loginDialogVisible = ref(false);
const isLoggedIn = ref(false);
const username = ref('用户名');
const accountBalance = ref('账户余额');
const loginForm = ref({
username: '',
password: '',
loginUrl: 'https://4701268539-esh.qdk63ayw8g.com'
});
const loginLoading = ref(false);
const loginError = ref('');
// 表格数据
const tableData = ref([
{ id: 1, name: '项目1', value: 120, status: '正常' },
{ id: 2, name: '项目2', value: 230, status: '警告' },
{ id: 3, name: '项目3', value: 180, status: '正常' },
{ id: 4, name: '项目4', value: 90, status: '异常' },
{ id: 5, name: '项目5', value: 320, status: '正常' },
{ id: 6, name: '项目6', value: 270, status: '警告' },
]);
const tableData = ref([]);
const tableLoading = ref(false);
const tableError = ref('');
@@ -34,21 +40,34 @@ const chart2 = ref(null);
// 初始化ECharts图表
function initCharts() {
console.log('开始初始化图表');
console.log('chart1Ref.value:', chart1Ref.value);
console.log('chart2Ref.value:', chart2Ref.value);
// 初始化图表1
if (chart1Ref.value) {
console.log('初始化图表1');
chart1.value = echarts.init(chart1Ref.value);
updateChart1();
}
// 初始化图表2
if (chart2Ref.value) {
console.log('初始化图表2');
chart2.value = echarts.init(chart2Ref.value);
updateChart2();
}
console.log('图表初始化完成');
}
// 更新图表1
function updateChart1() {
console.log('更新图表1');
console.log('chart1.value:', chart1.value);
console.log('chartData1.value:', chartData1.value);
console.log('chartLabels.value:', chartLabels.value);
if (!chart1.value) return;
const option = {
@@ -107,11 +126,18 @@ function updateChart1() {
]
};
console.log('设置图表1选项');
chart1.value.setOption(option);
console.log('图表1更新完成');
}
// 更新图表2
function updateChart2() {
console.log('更新图表2');
console.log('chart2.value:', chart2.value);
console.log('chartData2.value:', chartData2.value);
console.log('chartLabels.value:', chartLabels.value);
if (!chart2.value) return;
const option = {
@@ -170,7 +196,9 @@ function updateChart2() {
]
};
console.log('设置图表2选项');
chart2.value.setOption(option);
console.log('图表2更新完成');
}
// 监听窗口大小变化
@@ -181,31 +209,54 @@ function handleResize() {
// 从后端获取折线图数据
async function fetchChartData() {
console.log('开始获取图表数据');
loading.value = true;
error.value = '';
try {
// 获取折线图1数据
console.log('获取折线图1数据');
const response1 = await axios.get('http://localhost:8080/api/charts/line1');
console.log('折线图1数据响应:', response1.data);
if (response1.data) {
chartData1.value = response1.data.data;
chartLabels.value = response1.data.labels;
chartData1.value = response1.data.data || chartData1.value;
chartLabels.value = response1.data.labels || chartLabels.value;
}
// 获取折线图2数据
console.log('获取折线图2数据');
const response2 = await axios.get('http://localhost:8080/api/charts/line2');
console.log('折线图2数据响应:', response2.data);
if (response2.data) {
chartData2.value = response2.data.data;
chartData2.value = response2.data.data || chartData2.value;
}
console.log('图表数据获取完成');
console.log('chartData1.value:', chartData1.value);
console.log('chartData2.value:', chartData2.value);
console.log('chartLabels.value:', chartLabels.value);
// 更新图表
nextTick(() => {
console.log('更新图表数据');
updateChart1();
updateChart2();
});
} catch (err) {
console.error('获取图表数据失败:', err);
error.value = '获取图表数据失败,请刷新页面重试';
console.error('Error fetching chart data:', err);
// 使用默认数据
console.log('使用默认数据');
console.log('默认 chartData1.value:', chartData1.value);
console.log('默认 chartData2.value:', chartData2.value);
console.log('默认 chartLabels.value:', chartLabels.value);
// 更新图表
nextTick(() => {
console.log('使用默认数据更新图表');
updateChart1();
updateChart2();
});
} finally {
loading.value = false;
}
@@ -243,6 +294,145 @@ onMounted(() => {
window.addEventListener('resize', handleResize);
});
// 处理登录
async function handleLogin() {
loginError.value = '';
loginLoading.value = true;
try {
console.log('登录信息:', loginForm.value);
// 验证表单
if (!loginForm.value.username || !loginForm.value.password || !loginForm.value.loginUrl) {
loginError.value = '请填写完整登录信息';
return;
}
// 构建登录API地址
const loginApiUrl = `http://localhost:8080/api/ocr/saveUserInfo`;
console.log('登录API地址:', loginApiUrl);
// 调用登录API
const response = await axios.post(loginApiUrl, {
username: loginForm.value.username,
password: loginForm.value.password
});
// 处理登录结果
if (response.data && response.data.code === 1) {
// 登录成功
loginLoading.value = false;
loginDialogVisible.value = false;
isLoggedIn.value = true;
// 更新用户名和账户余额
username.value = loginForm.value.username;
accountBalance.value = response.data.balance || '¥10000.00';
// 保存登录信息(可选)
if (response.data.token) {
localStorage.setItem('token', response.data.token);
}
// 重置表单
loginForm.value = {
username: '',
password: '',
loginUrl: 'https://4701268539-esh.qdk63ayw8g.com'
};
console.log('登录成功:', response.data);
} else {
// 登录失败
loginError.value = response.data.message || '登录失败,请检查输入信息';
console.error('登录失败:', response.data);
}
} catch (err) {
loginError.value = '登录失败,请检查网络连接或登录地址';
console.error('登录失败:', err);
} finally {
loginLoading.value = false;
}
}
// 处理退出登录
function handleLogout() {
console.log('退出登录');
isLoggedIn.value = false;
// 重置用户名和账户余额
username.value = '用户名';
accountBalance.value = '账户余额';
// 清除登录状态
localStorage.removeItem('token');
// 这里可以添加其他清理逻辑
// 1. 清除用户信息
// 2. 重置相关数据
// 3. 调用退出登录API可选
}
// 处理确认按钮点击
async function handleConfirm() {
console.log('确认按钮点击,止盈点:', input1.value, '止亏点:', input2.value);
// 验证输入
if (!input1.value || !input2.value) {
alert('请填写完整的止盈止亏点');
return;
}
try {
// 构建提交数据
const submitData = {
winNum: input1.value,
loseNum: input2.value
};
console.log('提交数据:', submitData);
// 调用后端API
const response = await axios.post('http://localhost:8080/api/ocr/saveUserInfo', submitData);
// 处理响应结果
if (response.data && response.data.code === 1) {
console.log('提交成功:', response.data);
alert('设置保存成功');
} else {
console.error('提交失败:', response.data);
alert('设置保存失败: ' + (response.data.message || '未知错误'));
}
} catch (err) {
console.error('提交失败:', err);
alert('设置保存失败,请检查网络连接');
}
}
// 处理停止按钮点击
async function handleStop() {
console.log('停止按钮点击');
try {
// 调用后端停止API
const response = await axios.post('http://localhost:8080/api/ocr/saveUserInfo', {
onOff: 0
});
// 处理响应结果
if (response.data && response.data.code === 1) {
console.log('停止成功:', response.data);
alert('停止操作成功');
} else {
console.error('停止失败:', response.data);
alert('停止操作失败: ' + (response.data.message || '未知错误'));
}
} catch (err) {
console.error('停止失败:', err);
alert('停止操作失败,请检查网络连接');
}
}
onUnmounted(() => {
// 销毁图表
chart1.value?.dispose();
@@ -261,28 +451,65 @@ onUnmounted(() => {
<div class="account-info">
<div class="account-avatar">👤</div>
<div class="account-details">
<div class="account-name">用户名</div>
<div class="account-role">账户余额</div>
<div class="account-name">{{ username }}</div>
<div class="account-role">{{ accountBalance }}</div>
</div>
<div class="account-actions">
<button type="button" class="login-button">登录</button>
<button type="button" class="logout-button">退出</button>
<button v-if="!isLoggedIn" type="button" class="login-button" @click="loginDialogVisible = true">登录</button>
<button v-else type="button" class="logout-button" @click="handleLogout">退出</button>
</div>
</div>
<!-- 登录模态框 -->
<div v-if="loginDialogVisible" class="modal-overlay">
<div class="modal-content" @click.stop>
<div class="modal-header">
<h3>登录</h3>
<button type="button" class="modal-close" @click="loginDialogVisible = false">×</button>
</div>
<div class="modal-body">
<div v-if="loginError" class="modal-error">
{{ loginError }}
</div>
<form @submit.prevent="handleLogin">
<div class="form-group">
<label for="username">账号</label>
<input type="text" id="username" v-model="loginForm.username" placeholder="请输入账号" required>
</div>
<div class="form-group">
<label for="password">密码</label>
<input type="password" id="password" v-model="loginForm.password" placeholder="请输入密码" required>
</div>
<div class="form-group">
<label for="loginUrl">登录地址</label>
<input type="url" id="loginUrl" v-model="loginForm.loginUrl" placeholder="请输入登录地址" required>
</div>
<div class="form-actions">
<button type="button" class="cancel-button" @click="loginDialogVisible = false">取消</button>
<button type="submit" class="submit-button" :disabled="loginLoading">
<span v-if="loginLoading">登录中...</span>
<span v-else>登录</span>
</button>
</div>
</form>
</div>
</div>
</div>
<!-- 顶部输入框区域 -->
<div class="top-inputs">
<div class="input-group">
<label for="input1">输入1</label>
<div class="input-with-button">
<input type="text" id="input1" v-model="input1" placeholder="请输入内容">
<input type="text" id="input1" v-model="input1" placeholder="请输入止盈点">
</div>
</div>
<div class="input-group">
<label for="input2">输入2</label>
<div class="input-with-button">
<input type="text" id="input2" v-model="input2" placeholder="请输入内容">
<button type="button" class="confirm-button">确认</button>
<input type="text" id="input2" v-model="input2" placeholder="请输入止亏点">
<div class="button-group">
<button type="button" class="confirm-button" @click="handleConfirm">确认</button>
<button type="button" class="stop-button" @click="handleStop">停止</button>
</div>
</div>
</div>
</div>
@@ -354,7 +581,7 @@ onUnmounted(() => {
display: flex;
gap: 20px;
width: 100%;
height: 100%;
min-height: 100vh;
padding: 20px;
box-sizing: border-box;
}
@@ -369,7 +596,6 @@ onUnmounted(() => {
flex-direction: column;
gap: 20px;
height: 100%;
min-height: 100%;
box-sizing: border-box;
}
@@ -512,6 +738,35 @@ onUnmounted(() => {
transform: translateY(1px);
}
/* 按钮组 */
.button-group {
display: flex;
gap: 8px;
}
/* 停止按钮 */
.stop-button {
padding: 10px 16px;
background-color: #f44336;
color: white;
border: none;
border-radius: 4px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: background-color 0.2s ease;
white-space: nowrap;
}
.stop-button:hover {
background-color: #d32f2f;
}
.stop-button:active {
background-color: #b71c1c;
transform: translateY(1px);
}
/* 表格区域 */
.table-container {
flex: 1;
@@ -528,18 +783,16 @@ onUnmounted(() => {
display: flex;
flex-direction: column;
gap: 30px;
height: 100%;
min-height: 100%;
min-height: 700px;
box-sizing: border-box;
}
/* 图表区域 */
.chart-container {
flex: 1;
display: flex;
flex-direction: column;
gap: 15px;
min-height: 0;
height: 300px;
}
.input-group label {
@@ -685,6 +938,158 @@ onUnmounted(() => {
overflow: hidden;
}
/* 登录模态框 */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
}
.modal-content {
background-color: white;
border-radius: 8px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
width: 90%;
max-width: 450px;
max-height: 80vh;
overflow-y: auto;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px;
border-bottom: 1px solid #e0e0e0;
}
.modal-header h3 {
margin: 0;
color: #333;
font-size: 18px;
font-weight: 600;
}
.modal-close {
background: none;
border: none;
font-size: 24px;
color: #999;
cursor: pointer;
padding: 0;
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 4px;
transition: all 0.2s ease;
}
.modal-close:hover {
background-color: #f5f5f5;
color: #666;
}
.modal-body {
padding: 20px;
}
.modal-error {
background-color: #ffebee;
color: #c62828;
padding: 12px;
border-radius: 4px;
margin-bottom: 20px;
font-size: 14px;
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: 600;
color: #333;
font-size: 14px;
}
.form-group input {
width: 100%;
padding: 10px 12px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
transition: border-color 0.2s ease;
box-sizing: border-box;
}
.form-group input:focus {
outline: none;
border-color: #2196F3;
box-shadow: 0 0 0 2px rgba(33, 150, 243, 0.1);
}
.form-actions {
display: flex;
justify-content: flex-end;
gap: 12px;
margin-top: 30px;
padding-top: 20px;
border-top: 1px solid #e0e0e0;
}
.cancel-button {
padding: 10px 20px;
background-color: #f5f5f5;
color: #333;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
}
.cancel-button:hover {
background-color: #e0e0e0;
}
.submit-button {
padding: 10px 20px;
background-color: #2196F3;
color: white;
border: none;
border-radius: 4px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: background-color 0.2s ease;
}
.submit-button:hover:not(:disabled) {
background-color: #1976D2;
}
.submit-button:active:not(:disabled) {
background-color: #1565C0;
transform: translateY(1px);
}
.submit-button:disabled {
background-color: #bdbdbd;
cursor: not-allowed;
}
/* 响应式布局 */
@media (max-width: 768px) {
.main-container {
@@ -702,5 +1107,10 @@ onUnmounted(() => {
.chart-container {
min-height: 300px;
}
.modal-content {
width: 95%;
margin: 20px;
}
}
</style>

View File

@@ -1,32 +0,0 @@
package com.tem.bocai.controller;
import com.tem.bocai.entity.LotteryResult;
import com.tem.bocai.repository.LotteryResultRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/lottery")
public class LotteryResultController {
@Autowired
private LotteryResultRepository lotteryResultRepository;
// 获取所有彩票开奖结果
@GetMapping("/results")
public List<LotteryResult> getAllLotteryResults() {
return lotteryResultRepository.findAll();
}
// 根据期号获取彩票开奖结果
@GetMapping("/results/{issue}")
public LotteryResult getLotteryResultByIssue(@PathVariable String issue) {
return lotteryResultRepository.findAll()
.stream()
.filter(result -> result.getIssue().equals(issue))
.findFirst()
.orElse(null);
}
}

View File

@@ -1,38 +0,0 @@
package com.tem.bocai.controller;
import com.tem.bocai.util.ImageOcrService;
import net.sourceforge.tess4j.TesseractException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
@RestController
public class TestController {
private final ImageOcrService imageOcrService;
@Autowired
public TestController(ImageOcrService imageOcrService) {
this.imageOcrService = imageOcrService;
}
@GetMapping("/ocr/local")
public ResponseEntity<String> ocrLocalImage(String imagePath) throws IOException, TesseractException {
imagePath = "b.jpg";
String result = imageOcrService.ocrLocalImage(imagePath);
return ResponseEntity.ok(result);
}
@GetMapping("/ocr/remote")
public ResponseEntity<String> ocrRemoteImage(String imageUrl) throws IOException, TesseractException, InterruptedException {
imageUrl = "https://4701268539-esh.qdk63ayw8g.com/code";
String result = imageOcrService.ocrRemoteImage();
System.out.println("++++"+result);
return ResponseEntity.ok(result);
}
}