Compare commits
2
Commits
b46bd6001f
...
f7ffe317ac
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f7ffe317ac | ||
|
|
0b327121fe |
+4
-2
@@ -13,8 +13,10 @@
|
||||
export const appConfig = {
|
||||
appName: '充值自动化',
|
||||
appVersion: '0.1.0',
|
||||
baseUrl: 'http://10.0.2.2:8111',
|
||||
wsBaseUrl: 'ws://10.0.2.2:8111',
|
||||
// baseUrl: 'http://10.0.2.2:8111',
|
||||
// wsBaseUrl: 'ws://10.0.2.2:8111',
|
||||
baseUrl: 'http://192.168.10.2:8111',
|
||||
wsBaseUrl: 'ws://192.168.10.2:8111',
|
||||
rechargeUrl: 'https://www.douyin.com/pay',
|
||||
primaryColor: '#007aff',
|
||||
dryRun: false
|
||||
|
||||
+2
-1
@@ -3,6 +3,7 @@
|
||||
{
|
||||
"path": "pages/login/index",
|
||||
"style": {
|
||||
"navigationStyle": "custom",
|
||||
"navigationBarTitleText": "登录",
|
||||
"navigationBarTextStyle": "black",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
@@ -12,7 +13,7 @@
|
||||
{
|
||||
"path": "pages/home/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "首页",
|
||||
"navigationBarTitleText": "工作台",
|
||||
"navigationBarTextStyle": "black",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"backgroundColor": "#f2f2f7"
|
||||
|
||||
+72
-55
@@ -1,57 +1,28 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="page-header">
|
||||
<view class="page-title">工作台</view>
|
||||
<view class="page-subtitle">登录后自动绑定账号设备,持续心跳并在空闲时拉取分发任务。</view>
|
||||
</view>
|
||||
|
||||
<view class="section">
|
||||
<view class="section-title">基础状态</view>
|
||||
<view class="summary-grid">
|
||||
<view class="summary-item">
|
||||
<view class="summary-label">当前账号</view>
|
||||
<view class="summary-value">{{ userName }}</view>
|
||||
</view>
|
||||
<view class="summary-item">
|
||||
<view class="summary-label">设备编号</view>
|
||||
<view class="summary-value">{{ deviceInfo.deviceCode || '--' }}</view>
|
||||
</view>
|
||||
<view class="summary-item">
|
||||
<view class="summary-label">App 版本</view>
|
||||
<view class="summary-value">{{ deviceInfo.appVersion || '--' }}</view>
|
||||
</view>
|
||||
<view class="summary-item">
|
||||
<view class="summary-label">系统版本</view>
|
||||
<view class="summary-value">{{ deviceInfo.systemVersion || '--' }}</view>
|
||||
<view class="page home-page">
|
||||
<view class="section profile-card">
|
||||
<view class="profile-row">
|
||||
<view class="profile-label">当前账号</view>
|
||||
<view class="profile-value">{{ userName }}</view>
|
||||
</view>
|
||||
<view class="profile-row">
|
||||
<view class="profile-label">设备编号</view>
|
||||
<view class="profile-device">{{ deviceInfo.deviceCode || '--' }}</view>
|
||||
</view>
|
||||
<view class="profile-row">
|
||||
<view class="profile-label">设备在线状态</view>
|
||||
<view class="profile-status">
|
||||
<view class="tag">{{ onlineStatusText }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="section">
|
||||
<view class="section-title">运行状态</view>
|
||||
<view class="list-item">
|
||||
<view class="row">
|
||||
<view class="row-left">
|
||||
<view class="row-title">设备在线状态</view>
|
||||
<view class="row-desc">依据绑定和心跳刷新</view>
|
||||
</view>
|
||||
<view class="tag">{{ onlineStatusText }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="list-item">
|
||||
<view class="row">
|
||||
<view class="row-left">
|
||||
<view class="row-title">账号设备绑定状态</view>
|
||||
<view class="row-desc">登录后自动调用 register</view>
|
||||
</view>
|
||||
<view class="tag">{{ registerStatus }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="list-item">
|
||||
<view class="row">
|
||||
<view class="row-left">
|
||||
<view class="row-title">工作状态</view>
|
||||
<view class="row-desc">设备主动控制是否允许开始接单</view>
|
||||
</view>
|
||||
<view class="tag">{{ workStatusText }}</view>
|
||||
</view>
|
||||
@@ -60,7 +31,6 @@
|
||||
<view class="row">
|
||||
<view class="row-left">
|
||||
<view class="row-title">当前任务状态</view>
|
||||
<view class="row-desc">工作状态为可工作时轮询 pull,收到后自动接收并开始执行</view>
|
||||
</view>
|
||||
<view class="tag">{{ taskStatusText }}</view>
|
||||
</view>
|
||||
@@ -69,7 +39,6 @@
|
||||
<view class="row">
|
||||
<view class="row-left">
|
||||
<view class="row-title">当前任务号</view>
|
||||
<view class="row-desc">收到任务后将自动进入充值执行页</view>
|
||||
</view>
|
||||
<view class="field-value">{{ currentTaskNo }}</view>
|
||||
</view>
|
||||
@@ -78,7 +47,6 @@
|
||||
<view class="row">
|
||||
<view class="row-left">
|
||||
<view class="row-title">订单号</view>
|
||||
<view class="row-desc">分发任务里携带的订单信息</view>
|
||||
</view>
|
||||
<view class="field-value">{{ currentOrderNo }}</view>
|
||||
</view>
|
||||
@@ -87,7 +55,6 @@
|
||||
<view class="row">
|
||||
<view class="row-left">
|
||||
<view class="row-title">充值金额</view>
|
||||
<view class="row-desc">用于首页快速确认任务内容</view>
|
||||
</view>
|
||||
<view class="field-value">{{ currentAmount }}</view>
|
||||
</view>
|
||||
@@ -96,7 +63,6 @@
|
||||
<view class="row">
|
||||
<view class="row-left">
|
||||
<view class="row-title">充值账号</view>
|
||||
<view class="row-desc">任务指定充值目标账号</view>
|
||||
</view>
|
||||
<view class="field-value">{{ currentRechargeAccount }}</view>
|
||||
</view>
|
||||
@@ -105,7 +71,6 @@
|
||||
<view class="row">
|
||||
<view class="row-left">
|
||||
<view class="row-title">最近心跳时间</view>
|
||||
<view class="row-desc">心跳上报成功后刷新</view>
|
||||
</view>
|
||||
<view class="field-value">{{ lastHeartbeatTime }}</view>
|
||||
</view>
|
||||
@@ -119,12 +84,6 @@
|
||||
:disabled="workStatusUpdating"
|
||||
@tap="toggleWorkStatus"
|
||||
>{{ workStatusButtonText }}</button>
|
||||
<button
|
||||
class="button-primary button-space"
|
||||
:disabled="!canStartRecharge"
|
||||
@tap="startRecharge"
|
||||
>开始充值</button>
|
||||
<button class="button-secondary button-space" :disabled="!canPullTask" @tap="manualPullTask">立即拉取任务</button>
|
||||
<button class="button-secondary button-space" @tap="goTask">任务列表</button>
|
||||
<button class="button-secondary button-space" @tap="goLog">接收日志</button>
|
||||
<button class="button-secondary button-space" @tap="goRecharge">配置账号</button>
|
||||
@@ -615,3 +574,61 @@ export default {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.home-page {
|
||||
padding-top: 20rpx;
|
||||
}
|
||||
|
||||
.profile-card {
|
||||
padding: 20rpx 24rpx;
|
||||
border: 1rpx solid rgba(60, 60, 67, 0.06);
|
||||
border-radius: 24rpx;
|
||||
background: #ffffff;
|
||||
box-shadow: 0 12rpx 28rpx rgba(15, 23, 42, 0.05);
|
||||
}
|
||||
|
||||
.profile-row + .profile-row {
|
||||
margin-top: 16rpx;
|
||||
padding-top: 16rpx;
|
||||
border-top: 1rpx solid rgba(60, 60, 67, 0.08);
|
||||
}
|
||||
|
||||
.profile-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
column-gap: 24rpx;
|
||||
}
|
||||
|
||||
.profile-label {
|
||||
font-size: 24rpx;
|
||||
color: #5b6472;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.profile-value {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #111827;
|
||||
line-height: 1.4;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.profile-device {
|
||||
font-size: 24rpx;
|
||||
font-weight: 500;
|
||||
color: #111827;
|
||||
line-height: 1.4;
|
||||
word-break: break-all;
|
||||
text-align: right;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.profile-status {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
+148
-12
@@ -1,12 +1,17 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="page-header">
|
||||
<view class="page-title">充值自动化</view>
|
||||
<view class="page-subtitle">使用 RuoYi 账号登录后进入首页,页面样式保持 iOS 风格。</view>
|
||||
<view class="page login-page">
|
||||
<view class="login-bg">
|
||||
<view class="bg-orb bg-orb-left"></view>
|
||||
<view class="bg-orb bg-orb-right"></view>
|
||||
</view>
|
||||
|
||||
<view class="section">
|
||||
<view class="section-title">登录</view>
|
||||
<view class="page-header login-header">
|
||||
<view class="page-title">欢迎登录</view>
|
||||
<view class="page-subtitle">输入账号信息后继续进入工作台</view>
|
||||
</view>
|
||||
|
||||
<view class="section login-card">
|
||||
<view class="card-caption">Account</view>
|
||||
<view class="field">
|
||||
<view class="field-label">用户名</view>
|
||||
<input
|
||||
@@ -38,7 +43,7 @@
|
||||
placeholder="请输入验证码"
|
||||
/>
|
||||
<view class="captcha-box" @tap="refreshCaptcha">
|
||||
<image v-if="captchaImg" class="captcha-image" :src="captchaImg" mode="aspectFill" />
|
||||
<image v-if="captchaImg" class="captcha-image" :src="captchaImg" mode="aspectFit" />
|
||||
<view v-else class="captcha-placeholder">点击刷新</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -46,7 +51,7 @@
|
||||
<view class="row remember-row">
|
||||
<view class="row-left">
|
||||
<view class="row-title">记住账号</view>
|
||||
<view class="row-desc">下次打开时自动预填用户名</view>
|
||||
<view class="row-desc">仅保留用户名</view>
|
||||
</view>
|
||||
<switch :checked="rememberAccount" color="#007aff" @change="onRememberChange" />
|
||||
</view>
|
||||
@@ -177,6 +182,88 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.login-page {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
padding: 32rpx 32rpx 48rpx;
|
||||
background:
|
||||
radial-gradient(circle at top left, rgba(138, 180, 248, 0.32), transparent 34%),
|
||||
radial-gradient(circle at right 20%, rgba(255, 255, 255, 0.9), transparent 30%),
|
||||
linear-gradient(180deg, #eef4ff 0%, #f6f8fc 48%, #f4f5f7 100%);
|
||||
}
|
||||
|
||||
.login-bg {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.bg-orb {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
filter: blur(16rpx);
|
||||
}
|
||||
|
||||
.bg-orb-left {
|
||||
top: 20rpx;
|
||||
left: -80rpx;
|
||||
width: 280rpx;
|
||||
height: 280rpx;
|
||||
background: rgba(138, 180, 248, 0.28);
|
||||
}
|
||||
|
||||
.bg-orb-right {
|
||||
top: 240rpx;
|
||||
right: -100rpx;
|
||||
width: 360rpx;
|
||||
height: 360rpx;
|
||||
background: rgba(255, 255, 255, 0.72);
|
||||
}
|
||||
|
||||
.login-header {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
margin-bottom: 36rpx;
|
||||
padding: 8rpx 8rpx 0;
|
||||
}
|
||||
|
||||
.login-card {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
padding: 28rpx;
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.6);
|
||||
border-radius: 32rpx;
|
||||
background: rgba(255, 255, 255, 0.68);
|
||||
box-shadow: 0 24rpx 60rpx rgba(83, 104, 141, 0.12);
|
||||
backdrop-filter: blur(24rpx);
|
||||
}
|
||||
|
||||
.card-caption {
|
||||
margin-bottom: 24rpx;
|
||||
font-size: 22rpx;
|
||||
color: rgba(17, 24, 39, 0.45);
|
||||
letter-spacing: 6rpx;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.field {
|
||||
margin-bottom: 22rpx;
|
||||
}
|
||||
|
||||
.field-label {
|
||||
margin-bottom: 12rpx;
|
||||
color: #5f6b7a;
|
||||
}
|
||||
|
||||
.input {
|
||||
height: 92rpx;
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.7);
|
||||
border-radius: 24rpx;
|
||||
background: rgba(255, 255, 255, 0.72);
|
||||
box-shadow: inset 0 1rpx 0 rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
.captcha-input {
|
||||
flex: 1;
|
||||
margin-right: 16rpx;
|
||||
@@ -184,10 +271,15 @@ export default {
|
||||
|
||||
.captcha-box {
|
||||
width: 220rpx;
|
||||
height: 88rpx;
|
||||
border-radius: 20rpx;
|
||||
height: 92rpx;
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.72);
|
||||
border-radius: 24rpx;
|
||||
overflow: hidden;
|
||||
background: #f7f7fa;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: rgba(255, 255, 255, 0.72);
|
||||
box-shadow: 0 12rpx 32rpx rgba(83, 104, 141, 0.08);
|
||||
}
|
||||
|
||||
.captcha-image,
|
||||
@@ -196,6 +288,10 @@ export default {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.captcha-image {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.captcha-placeholder {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -205,6 +301,46 @@ export default {
|
||||
}
|
||||
|
||||
.remember-row {
|
||||
margin-top: 12rpx;
|
||||
margin-top: 8rpx;
|
||||
padding: 10rpx 4rpx 4rpx;
|
||||
}
|
||||
|
||||
.row-title {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.row-desc {
|
||||
margin-top: 6rpx;
|
||||
color: #7b8794;
|
||||
}
|
||||
|
||||
.button-primary {
|
||||
height: 92rpx;
|
||||
line-height: 92rpx;
|
||||
border-radius: 24rpx;
|
||||
font-weight: 600;
|
||||
background: linear-gradient(135deg, #4f8cff 0%, #2f6bff 100%);
|
||||
box-shadow: 0 18rpx 36rpx rgba(47, 107, 255, 0.22);
|
||||
}
|
||||
|
||||
.button-space {
|
||||
margin-top: 22rpx;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
font-size: 52rpx;
|
||||
font-weight: 700;
|
||||
letter-spacing: 1rpx;
|
||||
}
|
||||
|
||||
.page-subtitle {
|
||||
margin-top: 14rpx;
|
||||
font-size: 26rpx;
|
||||
color: #6c7a89;
|
||||
}
|
||||
|
||||
.section-title::before,
|
||||
.section-title::after {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
+9
-1
@@ -4,6 +4,14 @@ function isAppPlus() {
|
||||
return typeof plus !== 'undefined' && !!plus.webview
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算页面原生导航栏占位,避免子 WebView 从顶端铺开后遮住标题栏。
|
||||
*/
|
||||
function getNavigationOffset() {
|
||||
const info = uni.getSystemInfoSync ? uni.getSystemInfoSync() : {}
|
||||
return `${(info.statusBarHeight || 0) + 44}px`
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开充值 WebView,后续自动化流程复用同一个容器。
|
||||
*/
|
||||
@@ -26,7 +34,7 @@ export function openRechargeWebview(url, parentWebview) {
|
||||
}
|
||||
|
||||
rechargeWebview = plus.webview.create(url, 'recharge-webview', {
|
||||
top: '0px',
|
||||
top: getNavigationOffset(),
|
||||
bottom: '0px'
|
||||
})
|
||||
currentWebview.append(rechargeWebview)
|
||||
|
||||
@@ -12,6 +12,14 @@ function isAppPlus() {
|
||||
return typeof plus !== 'undefined' && !!plus.webview
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算页面原生导航栏占位,避免自动执行页的子 WebView 被顶部标题栏遮挡。
|
||||
*/
|
||||
function getNavigationOffset() {
|
||||
const info = uni.getSystemInfoSync ? uni.getSystemInfoSync() : {}
|
||||
return `${(info.statusBarHeight || 0) + 44}px`
|
||||
}
|
||||
|
||||
function resolveWebviewLoadWaiters(loaded) {
|
||||
const waiters = webviewLoadWaiters.slice()
|
||||
webviewLoadWaiters = []
|
||||
@@ -89,7 +97,7 @@ export function openWebview(url, parentWebview) {
|
||||
}
|
||||
|
||||
webviewInstance = plus.webview.create(url, 'recharge-webview', {
|
||||
top: '0px',
|
||||
top: getNavigationOffset(),
|
||||
bottom: '0px'
|
||||
})
|
||||
webviewLoaded = false
|
||||
|
||||
@@ -30,6 +30,7 @@ export default new Vuex.Store({
|
||||
logs: [],
|
||||
executionState: getExecutionStateStorage(),
|
||||
workStatus: getWorkStatusStorage(),
|
||||
cooldownUntil: '',
|
||||
currentStepIndex: -1,
|
||||
currentStepCode: '',
|
||||
stepLogs: [],
|
||||
@@ -108,6 +109,9 @@ export default new Vuex.Store({
|
||||
state.workStatus = value || 'NOT_READY'
|
||||
setWorkStatusStorage(state.workStatus)
|
||||
},
|
||||
setCooldownUntil(state, value) {
|
||||
state.cooldownUntil = value || ''
|
||||
},
|
||||
setCurrentStepIndex(state, index) {
|
||||
state.currentStepIndex = index
|
||||
},
|
||||
@@ -139,6 +143,7 @@ export default new Vuex.Store({
|
||||
state.logs = []
|
||||
state.executionState = 'IDLE'
|
||||
state.workStatus = 'NOT_READY'
|
||||
state.cooldownUntil = ''
|
||||
state.currentStepIndex = -1
|
||||
state.currentStepCode = ''
|
||||
state.stepLogs = []
|
||||
|
||||
Reference in New Issue
Block a user