feat:新增登录验证

This commit is contained in:
吉浩茹
2025-10-31 18:24:56 +08:00
parent 2b5dff94af
commit 20a3fe0b51
4 changed files with 250 additions and 123 deletions

View File

@ -7,68 +7,68 @@
<!-- 内容区域 --> <!-- 内容区域 -->
<view class="tabbar-content"> <view class="tabbar-content">
<!-- 环境参数详情 --> <!-- 环境参数详情 -->
<view class="parameter-details"> <view class="parameter-details">
<!-- 温度卡片 --> <!-- 温度卡片 -->
<view class="detail-card temperature-detail-card"> <view class="detail-card temperature-detail-card" @click="navigateToParameterRecord">
<view class="detail-header"> <view class="detail-header">
<view class="detail-icon-container"> <view class="detail-icon-container">
<view class="detail-icon temperature-icon">🌡</view> <view class="detail-icon temperature-icon">🌡</view>
<text class="detail-label">温度</text> <text class="detail-label">温度</text>
</view>
<view class="detail-value-container">
<text class="detail-value">{{ temperature }}°C</text>
<view class="detail-status" :class="temperature > 0 ? 'active' : 'inactive'"></view>
</view>
</view>
<view class="detail-progress-bar">
<view class="detail-progress-fill temperature-progress" :style="{ width: temperatureProgress + '%' }"></view>
</view>
<!-- <view class="detail-range">
<text class="detail-range-text">{{ 0 }}°C - {{ 100 }}°C</text>
</view> -->
</view> </view>
<view class="detail-value-container">
<!-- 湿度卡片 --> <text class="detail-value">{{ temperature }}°C</text>
<view class="detail-card humidity-detail-card"> <view class="detail-status" :class="temperature > 0 ? 'active' : 'inactive'"></view>
<view class="detail-header">
<view class="detail-icon-container">
<view class="detail-icon humidity-icon">💧</view>
<text class="detail-label">湿度</text>
</view>
<view class="detail-value-container">
<text class="detail-value">{{ humidity }}%</text>
<view class="detail-status" :class="humidity > 0 ? 'active' : 'inactive'"></view>
</view>
</view>
<view class="detail-progress-bar">
<view class="detail-progress-fill humidity-progress" :style="{ width: humidityProgress + '%' }"></view>
</view>
<!-- <view class="detail-range">
<text class="detail-range-text">{{ 0 }}% - {{ 100 }}%</text>
</view> -->
</view>
<!-- 洁净度卡片 -->
<view class="detail-card cleanliness-detail-card">
<view class="detail-header">
<view class="detail-icon-container">
<view class="detail-icon cleanliness-icon"></view>
<text class="detail-label">洁净度</text>
</view>
<view class="detail-value-container">
<text class="detail-value">{{ cleanliness > 0 ? cleanliness + 'μg/m³' : '-μg/m³' }}</text>
<view class="detail-status" :class="cleanliness > 0 ? 'active' : 'inactive'"></view>
</view>
</view>
<view class="detail-progress-bar">
<view class="detail-progress-fill cleanliness-progress" :style="{ width: cleanlinessProgress + '%' }"></view>
</view>
<!-- <view class="detail-range">
<text class="detail-range-text">{{ 0 }}% - {{ 100 }}%</text>
</view> -->
</view> </view>
</view> </view>
<view class="detail-progress-bar">
<view class="detail-progress-fill temperature-progress" :style="{ width: temperatureProgress + '%' }"></view>
</view>
<!-- <view class="detail-range">
<text class="detail-range-text">{{ 0 }}°C - {{ 100 }}°C</text>
</view> -->
</view>
<!-- 湿度卡片 -->
<view class="detail-card humidity-detail-card" @click="navigateToParameterRecord">
<view class="detail-header">
<view class="detail-icon-container">
<view class="detail-icon humidity-icon">💧</view>
<text class="detail-label">湿度</text>
</view>
<view class="detail-value-container">
<text class="detail-value">{{ humidity }}%</text>
<view class="detail-status" :class="humidity > 0 ? 'active' : 'inactive'"></view>
</view>
</view>
<view class="detail-progress-bar">
<view class="detail-progress-fill humidity-progress" :style="{ width: humidityProgress + '%' }"></view>
</view>
<!-- <view class="detail-range">
<text class="detail-range-text">{{ 0 }}% - {{ 100 }}%</text>
</view> -->
</view>
<!-- 洁净度卡片 -->
<view class="detail-card cleanliness-detail-card" @click="navigateToParameterRecord">
<view class="detail-header">
<view class="detail-icon-container">
<view class="detail-icon cleanliness-icon"></view>
<text class="detail-label">洁净度</text>
</view>
<view class="detail-value-container">
<text class="detail-value">{{ cleanliness > 0 ? cleanliness + 'μg/m³' : '-μg/m³' }}</text>
<view class="detail-status" :class="cleanliness > 0 ? 'active' : 'inactive'"></view>
</view>
</view>
<view class="detail-progress-bar">
<view class="detail-progress-fill cleanliness-progress" :style="{ width: cleanlinessProgress + '%' }"></view>
</view>
<!-- <view class="detail-range">
<text class="detail-range-text">{{ 0 }}% - {{ 100 }}%</text>
</view> -->
</view>
</view>
<!-- 空调设置 --> <!-- 空调设置 -->
<view class="air-conditioner-settings"> <view class="air-conditioner-settings">
@ -385,6 +385,13 @@ export default {
this.loadWsdSettings() this.loadWsdSettings()
// 注意:定时器在 onShow 中启动,避免重复启动 // 注意:定时器在 onShow 中启动,避免重复启动
}, },
navigateToParameterRecord() {
try {
uni.switchTab({ url: '/pages/parameter/index' })
} catch (e) {
uni.showToast({ title: '页面跳转失败', icon: 'none' })
}
},
// 首次进入系统时创建启动事件 // 首次进入系统时创建启动事件
async createStartupEventIfNeeded() { async createStartupEventIfNeeded() {
// 检查是否已经创建过启动事件 // 检查是否已经创建过启动事件

View File

@ -16,15 +16,32 @@
<text class="title-text">上动物联</text> <text class="title-text">上动物联</text>
</view> </view>
</view> </view>
<!-- 下部区域按钮和版本号 --> <!-- 登录表单账号密码 -->
<view class="bottom-section"> <view class="form-section">
<!-- 进入系统按钮 --> <!-- <view class="form-item">
<text class="form-label">账号</text>
<input class="form-input" v-model="username" placeholder="请输入账号" placeholder-class="placeholder" confirm-type="next" />
</view> -->
<view class="form-item">
<text class="form-label">密码</text>
<input class="form-input" v-model="password" password placeholder="请输入密码" placeholder-class="placeholder" confirm-type="done" />
</view>
<view class="action-container"> <view class="action-container">
<button class="enter-button" @click="navigateToTabBar"> <button class="enter-button" @click="navigateToTabBar">
<text class="button-text">进入系统 </text> <text class="button-text">进入系统 </text>
</button> </button>
</view> </view>
</view>
<!-- 下部区域按钮和版本号 -->
<view class="bottom-section">
<!-- 进入系统按钮 -->
<!-- <view class="action-container">
<button class="enter-button" @click="navigateToTabBar">
<text class="button-text">进入系统 </text>
</button>
</view> -->
<!-- 版本号 --> <!-- 版本号 -->
<view class="version-container"> <view class="version-container">
@ -37,84 +54,141 @@
<script> <script>
import { manualReconnect } from '@/utils/sendMqtt.js' import { manualReconnect } from '@/utils/sendMqtt.js'
import { authApi } from '@/utils/api.js'
export default { export default {
data() { data() {
return { return {
title: 'Hello', title: 'Hello',
username: '',
password: '',
}
},
computed: {
canLogin() {
// return this.username && this.username.trim().length > 0 && this.password && this.password.trim().length > 0
return this.password && this.password.trim().length > 0
} }
}, },
onLoad() {}, onLoad() {},
methods: { methods: {
navigateToTabBar() { async navigateToTabBar() {
console.log('🔧 用户点击进入系统开始MQTT重连...') if (!this.canLogin) {
uni.showToast({
// 立即显示连接提示 title: '请输入密码',
uni.showLoading({ icon: 'none',
title: '正在连接MQTT...', duration: 1200
// mask: true })
}) return
}
// 调用MQTT重连函数 console.log('🔒 开始登录...')
// 先登录
try { try {
manualReconnect() uni.showLoading({ title: '正在登录...' })
console.log('✅ MQTT重连函数已调用') const loginRes = await authApi.login({
username: this.username || 'admin',
// 延迟跳转给MQTT连接一些时间 password: this.password
setTimeout(() => { })
// 更新loading文本
console.log('🔒 登录结果:', loginRes)
if (loginRes.success) {
// 可选:如果返回 token保存以备后续请求使用
if (loginRes && loginRes.token) {
const token = loginRes.token;
try {
uni.setStorageSync('auth_token', token)
} catch (e) {}
}
uni.hideLoading()
uni.showToast({ title: '登录成功', icon: 'success', duration: 800 })
// 立即显示连接提示
uni.showLoading({ uni.showLoading({
title: '正在跳转系统...', title: '正在连接MQTT...',
// mask: true // mask: true
}) })
uni.hideLoading()
// 跳转到tabbar的第一个页面环境参数页面 // 调用MQTT重连函数
uni.switchTab({ try {
url: '/pages/environment/index', manualReconnect()
success: () => { console.log('✅ MQTT重连函数已调用')
console.log('✅ 成功跳转到环境参数页面')
uni.showToast({ // 延迟跳转给MQTT连接一些时间
title: '系统连接成功', setTimeout(() => {
icon: 'success', // 更新loading文本
duration: 1000 uni.showLoading({
title: '正在跳转系统...',
// mask: true
}) })
}, uni.hideLoading()
fail: (err) => { // 跳转到tabbar的第一个页面环境参数页面
console.error('❌ 跳转到tabbar失败:', err); uni.switchTab({
// 如果失败尝试使用redirectTo
uni.redirectTo({
url: '/pages/environment/index', url: '/pages/environment/index',
success: () => { success: () => {
console.log('✅ 使用redirectTo成功跳转') console.log('✅ 成功跳转到环境参数页面')
uni.showToast({ uni.showToast({
title: '系统连接成功', title: '系统连接成功',
icon: 'success', icon: 'success',
duration: 1000 duration: 1000
}) })
}, },
fail: (redirectErr) => { fail: (err) => {
console.error('❌ redirectTo也失败:', redirectErr) console.error('❌ 跳转到tabbar失败:', err);
uni.showToast({ // 如果失败尝试使用redirectTo
title: '页面跳转失败', uni.redirectTo({
icon: 'error', url: '/pages/environment/index',
duration: 1000 success: () => {
}) console.log('✅ 使用redirectTo成功跳转')
uni.showToast({
title: '系统连接成功',
icon: 'success',
duration: 1000
})
},
fail: (redirectErr) => {
console.error('❌ redirectTo也失败:', redirectErr)
uni.showToast({
title: '页面跳转失败',
icon: 'error',
duration: 1000
})
}
});
} }
}); })
}
}, 300) // 1秒后开始跳转
} catch (error) {
console.error('❌ MQTT重连失败:', error)
uni.hideLoading()
uni.showToast({
title: 'MQTT连接失败',
icon: 'error',
duration: 1000
})
}
} else {
uni.hideLoading()
uni.showToast({
title: loginRes?.message || '登录失败',
icon: 'none',
duration: 1500
}) })
return
}, 300) // 1秒后开始跳转 }
} catch (e) {
} catch (error) {
console.error('❌ MQTT重连失败:', error)
uni.hideLoading() uni.hideLoading()
uni.showToast({ uni.showToast({
title: 'MQTT连接失败', title: e?.message || '登录失败',
icon: 'error', icon: 'none',
duration: 1000 duration: 1500
}) })
return
} }
console.log('🔧 用户点击进入系统开始MQTT重连...')
} }
}, },
} }
@ -193,6 +267,7 @@ export default {
/* 进入系统按钮 */ /* 进入系统按钮 */
.action-container { .action-container {
margin-bottom: 40rpx; margin-bottom: 40rpx;
margin-top: 40px;
} }
.enter-button { .enter-button {
@ -210,6 +285,42 @@ export default {
font-weight: 500; font-weight: 500;
} }
/* 表单样式 */
.form-section {
width: 100%;
max-width: 640rpx;
margin-top: 40rpx;
}
.form-item {
display: flex;
align-items: center;
background: #f7f8fa;
border-radius: 12rpx;
padding: 20rpx 24rpx;
margin-bottom: 24rpx;
}
.form-label {
width: 120rpx;
font-size: 28rpx;
color: #333333;
}
.form-input {
flex: 1;
font-size: 28rpx;
color: #111111;
}
.placeholder {
color: #999999;
}
.enter-button:disabled {
opacity: 0.5;
}
/* 版本号 */ /* 版本号 */
.version-text { .version-text {

View File

@ -5,6 +5,15 @@
import httpService from './http.js' import httpService from './http.js'
// 认证接口
export const authApi = {
// 登录
login(data) {
// 约定字段username、password
return httpService.post('/api/auth/login', data)
}
}
// 数据历史接口 // 数据历史接口
export const dataHistoryApi = { export const dataHistoryApi = {
// 获取历史数据 // 获取历史数据

View File

@ -282,11 +282,11 @@ const sendMqttData = (data) => {
}); });
} else { } else {
console.log('✅ MQTT数据发送成功'); console.log('✅ MQTT数据发送成功');
uni.showToast({ // uni.showToast({
title: '数据发送成功', // title: '数据发送成功',
icon: 'success', // icon: 'success',
duration: 1500 // duration: 1500
}); // });
} }
}); });
@ -334,11 +334,11 @@ const sendMqttDataRecall = (data) => {
duration: 2000 duration: 2000
}); });
} else { } else {
uni.showToast({ // uni.showToast({
title: '数据发送成功', // title: '数据发送成功',
icon: 'success', // icon: 'success',
duration: 1500 // duration: 1500
}); // });
} }
}); });