增量提交

This commit is contained in:
zqm
2026-04-21 13:46:20 +08:00
parent f64209cb04
commit 09eb6fb1bd
44 changed files with 4411 additions and 931 deletions

View File

@@ -1,224 +1,322 @@
// 首页逻辑
// 首页逻辑 - 深色主题信息流
const app = getApp()
Page({
data: {
userInfo: null,
// 用户信息
hasUserInfo: false,
canIUse: wx.canIUse('button.open-type.getUserInfo'),
openId: '',
phoneNumber: '',
unionId: '',
locationInfo: null,
deviceInfo: null,
systemInfo: null,
networkType: '',
wxVersion: '',
accountInfo: null,
clipboardData: null,
// 时间显示
currentTime: '',
yesterdayTime: '',
// 轮播Banner数据 - 蓝色主题
banners: [
{ id: 1, tag: '健康科普', title: '在多才和多艺之间\n我选择了多肉~', desc: '医生,我喝水都要胖,咋个整?', image: '' },
{ id: 2, tag: '专家讲座', title: '春季养生指南:\n中医教你调理身体', desc: '', image: '' }
],
// 轮播Banner数据 - 红色喜报主题
redBanners: [
{ id: 1, title: '四川省人民医院高质量发展跃上新台阶,成功迈入全国公立医院第一方阵!', image: '' }
],
websocketConnected: false,
version: app.globalData.version
version: app.globalData.version || '1.0.0',
socketTask: null,
},
onLoad() {
if (app.globalData.userInfo) {
this.setData({
userInfo: app.globalData.userInfo,
hasUserInfo: true
})
} else if (this.data.canIUse) {
// 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
// 所以此处加入 callback 以防止这种情况
app.userInfoReadyCallback = res => {
this.setData({
userInfo: res.userInfo,
hasUserInfo: true
})
}
} else {
// 在没有 open-type=getUserInfo 版本的兼容处理
wx.getUserInfo({
success: res => {
app.globalData.userInfo = res.userInfo
this.setData({
userInfo: res.userInfo,
hasUserInfo: true
})
}
})
this.updateTimeDisplay()
this.loadStoredInfo()
this.initWebSocketSafe()
},
onShow() {
this.updateTimeDisplay()
this.setTabBarActive()
if (this.data.hasUserInfo) this.loadStoredInfo()
},
// ==============================================
// 加载本地存储的信息
// ==============================================
loadStoredInfo() {
const openId = wx.getStorageSync('openId') || ''
const phoneNumber = wx.getStorageSync('phoneNumber') || ''
const deviceInfo = app.getDeviceInfo?.() || null
this.setData({ openId, phoneNumber, deviceInfo })
if (openId) {
this.setData({ hasUserInfo: true })
}
// 获取网络状态
app.getNetworkType?.((networkType) => {
if (networkType) this.setData({ networkType })
})
// 获取位置(需要授权)
app.getLocation?.((locationInfo) => {
if (locationInfo) this.setData({ locationInfo })
})
// 获取小程序信息
try {
const accountInfo = wx.getAccountInfoSync()
this.setData({ accountInfo })
} catch (error) {
console.error('获取小程序信息失败:', error)
this.setData({ accountInfo: null })
}
// 获取剪贴板信息(需要授权)
wx.getClipboardData({
success: (res) => {
this.setData({ clipboardData: res.data })
},
fail: (error) => {
console.error('获取剪贴板信息失败:', error)
this.setData({ clipboardData: null })
}
})
// 获取微信版本信息
try {
const systemInfo = wx.getSystemInfoSync()
this.setData({ wxVersion: systemInfo.version, systemInfo })
} catch (error) {
console.error('获取微信版本信息失败:', error)
this.setData({ wxVersion: null, systemInfo: null })
}
// 获取UnionID个人小程序无法获取
this.setData({ unionId: '无法获取(需企业资质)' })
// 获取手机号(个人小程序无法获取)
if (!phoneNumber) {
this.setData({ phoneNumber: '无法获取(需企业资质)' })
}
// 初始化WebSocket连接
this.initWebSocket()
},
getUserProfile(e) {
// 推荐使用wx.getUserProfile获取用户信息开发者每次通过该接口获取用户个人信息均需用户确认
wx.getUserProfile({
desc: '展示用户信息', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
// ==============================================
// 登录:通过 WebSocket 发 wechat_login收到 openid 后存本地
// ==============================================
onLogin() {
// 确保 WebSocket 已连接
if (!this.data.socketTask || !this.data.websocketConnected) {
// 先重连
this.initWebSocketSafe()
setTimeout(() => this._doLogin(), 1500)
return
}
this._doLogin()
},
_doLogin() {
if (!this.data.websocketConnected) {
wx.showToast({ title: '连接中...', icon: 'none' })
return
}
wx.login({
success: (res) => {
app.globalData.userInfo = res.userInfo
this.setData({
userInfo: res.userInfo,
hasUserInfo: true
if (!res.code) {
wx.showToast({ title: '微信登录失败', icon: 'none' })
return
}
// 记录待处理登录(收到 wechat_login_ret 时判断)
this._pendingLogin = true
this.data.socketTask.send({
data: JSON.stringify({
type: 'wechat_login',
data: { code: res.code }
}),
fail: () => {
this._pendingLogin = false
wx.showToast({ title: '发送失败', icon: 'none' })
}
})
// 发送用户信息到服务器
this.sendUserInfoToServer(res.userInfo)
},
fail:
// ==============================================
// 获取手机号button open-type="getPhoneNumber"
// ==============================================
onGetPhoneNumber(e) {
// 检查是否有加密数据(旧版方式,个人小程序可用)
const { encryptedData, iv, code } = e.detail
if (!encryptedData || !iv) {
wx.showToast({ title: '请允许授权', icon: 'none' })
return
}
// 必须先登录有 openid
const openid = this.data.openId || wx.getStorageSync('openId')
if (!openid) {
wx.showToast({ title: '请先登录', icon: 'none' })
return
}
// 确保 WebSocket 连接
if (!this.data.websocketConnected) {
wx.showToast({ title: '连接中...', icon: 'none' })
this.initWebSocketSafe()
setTimeout(() => {
this._sendPhoneDecrypt(openid, encryptedData, iv)
}, 1500)
return
}
this._sendPhoneDecrypt(openid, encryptedData, iv)
},
_sendPhoneDecrypt(openid, encryptedData, iv) {
if (!this.data.websocketConnected) {
wx.showToast({ title: 'WebSocket 未连接', icon: 'none' })
return
}
this._pendingPhone = true
this.data.socketTask.send({
data: JSON.stringify({
type: 'wechat_decrypt_phone',
data: { openid, encryptedData, iv }
}),
fail: () => {
this._pendingPhone = false
wx.showToast({ title: '发送失败', icon: 'none' })
}
})
},
getUserInfo(e) {
// 不推荐使用getUserInfo获取用户信息预计自2021年4月13日起getUserInfo将不再弹出弹窗并直接返回匿名的用户个人信息
app.globalData.userInfo = e.detail.userInfo
// ==============================================
// 时间显示
// ==============================================
updateTimeDisplay() {
const now = new Date()
const m = now.getMonth() + 1
const d = now.getDate()
const h = now.getHours()
const mm = String(now.getMinutes()).padStart(2, '0')
const period = h >= 12 ? '下午' : '上午'
const displayH = h > 12 ? h - 12 : h
this.setData({
userInfo: e.detail.userInfo,
hasUserInfo: true
})
// 发送用户信息到服务器
this.sendUserInfoToServer(e.detail.userInfo)
},
// 发送用户信息到服务器
sendUserInfoToServer(userInfo) {
wx.request({
url: `${app.globalData.apiBase}/user/info`,
method: 'POST',
data: {
userInfo: userInfo,
deviceId: app.globalData.systemInfo.model
},
header: {
'content-type': 'application/json'
},
success: (res) => {
console.log('用户信息上传成功', res.data)
},
fail: (err) => {
console.error('用户信息上传失败', err)
}
currentTime: `${m}${d}${period}${displayH}:${mm}`,
yesterdayTime: `昨天 晚上8:36`
})
},
// 初始化WebSocket连接
initWebSocket() {
const socket = wx.connectSocket({
url: app.globalData.websocketUrl,
header: {
'content-type': 'application/json'
}
})
// ==============================================
// TabBar 选中
// ==============================================
setTabBarActive() {
if (this.getTabBar) this.getTabBar()?.setData({ currentTab: 0 })
},
// ==============================================
// 新闻点击
// ==============================================
onNewsTap(e) {
const id = e.currentTarget.dataset.id
console.log('点击新闻:', id)
wx.showToast({ title: '加载中...', icon: 'none' })
},
// ==============================================
// WebSocket 安全版(防重复连接、防崩溃)
// ==============================================
initWebSocketSafe() {
if (this.data.socketTask) return
const socket = wx.connectSocket({ url: app.globalData.websocketUrl })
this.setData({ socketTask: socket })
socket.onOpen(() => {
console.log('WebSocket连接已打开')
this.setData({
websocketConnected: true
})
// 发送认证信息
this.setData({ websocketConnected: true })
socket.send({
data: JSON.stringify({
type: 'auth',
userId: app.globalData.userInfo ? app.globalData.userInfo.nickName : 'anonymous',
deviceId: app.globalData.systemInfo.model,
userId: app.globalData.userInfo?.nickName || 'anonymous',
deviceId: app.globalData.systemInfo?.model || '',
timestamp: Date.now()
})
})
})
socket.onMessage((res) => {
console.log('收到WebSocket消息', res.data)
socket.onMessage(msg => {
try {
const data = JSON.parse(res.data)
const data = JSON.parse(msg.data)
this.handleWebSocketMessage(data)
} catch (e) {
console.error('解析WebSocket消息失败', e)
}
} catch (e) {}
})
socket.onClose(() => {
console.log('WebSocket连接已关闭')
this.setData({
websocketConnected: false
})
// 3秒后尝试重连
setTimeout(() => {
this.initWebSocket()
}, 3000)
this.setData({ websocketConnected: false, socketTask: null })
setTimeout(() => this.initWebSocketSafe(), 3000)
})
socket.onError((err) => {
console.error('WebSocket连接错误', err)
this.setData({
websocketConnected: false
})
socket.onError(() => {
this.setData({ websocketConnected: false, socketTask: null })
})
},
// 处理WebSocket消息
handleWebSocketMessage(data) {
switch (data.type) {
case 'task_status':
// 处理任务状态更新
this.handleTaskStatusUpdate(data)
case 'wechat_login_ret':
// 收到登录响应(可能比 send 回调更早或更晚到达)
if (data.data?.openid) {
wx.setStorageSync('openId', data.data.openid)
this.setData({ openId: data.data.openid, hasUserInfo: true })
wx.showToast({ title: '登录成功', icon: 'success' })
} else {
wx.showToast({ title: '登录失败:' + (data.data?.error || '未知'), icon: 'none' })
}
this._pendingLogin = false
break
case 'message':
// 处理聊天消息
this.handleChatMessage(data)
case 'ai_message':
// AI 回复(聊天页使用)
if (this.handleAiMessage) this.handleAiMessage(data)
break
case 'wechat_decrypt_phone_ret':
// 手机号解密响应
if (data.data?.phone) {
wx.setStorageSync('phoneNumber', data.data.phone)
this.setData({ phoneNumber: data.data.phone })
wx.showToast({ title: '绑定成功', icon: 'success' })
} else {
wx.showToast({ title: '获取失败:' + (data.data?.error || '未知'), icon: 'none' })
}
this._pendingPhone = false
break
case 'pong':
break
default:
console.log('未知消息类型', data.type)
break
}
},
// 处理任务状态更新
handleTaskStatusUpdate(data) {
// 可以在这里更新任务列表或显示通知
if (data.status === 'completed') {
wx.showToast({
title: '任务完成',
icon: 'success'
})
} else if (data.status === 'failed') {
wx.showToast({
title: '任务失败',
icon: 'error'
})
}
},
// 处理聊天消息
handleChatMessage(data) {
// 可以在这里显示新消息通知
if (data.message) {
wx.showToast({
title: '新消息',
icon: 'none'
})
}
},
// 跳转到聊天页面
// ==============================================
// 跳转聊天页
// ==============================================
goToChat() {
wx.navigateTo({
url: '/pages/chat/chat'
})
wx.navigateTo({ url: '/pages/chat/chat' })
},
// 跳转到任务页面
// ==============================================
// 跳转任务页
// ==============================================
goToTask() {
wx.navigateTo({
url: '/pages/task/task'
})
},
// 显示设备信息
showDeviceInfo() {
const systemInfo = app.globalData.systemInfo
wx.showModal({
title: '设备信息',
content: `设备型号:${systemInfo.model}\n系统版本:${systemInfo.system}\n微信版本:${systemInfo.version}\n屏幕尺寸:${systemInfo.screenWidth}x${systemInfo.screenHeight}`,
showCancel: false
})
},
onShareAppMessage() {
return {
title: '智控未来 - 企业微信智能控制系统',
path: '/pages/index/index'
}
wx.navigateTo({ url: '/pages/task/task' })
}
})
})

View File

@@ -1,3 +1 @@
{
"navigationBarTitleText": "智控未来"
}
{"navigationBarTitleText": "智控未来"}

View File

@@ -1,50 +1,283 @@
<!-- 首页 - 用户登录和主界面 -->
<view class="container">
<!-- 用户信息区域 -->
<view class="user-info" wx:if="{{userInfo}}">
<image class="avatar" src="{{userInfo.avatarUrl}}" mode="aspectFill"></image>
<text class="nickname">{{userInfo.nickName}}</text>
</view>
<!-- 登录按钮 -->
<view class="login-section" wx:else>
<button class="login-btn" bindtap="getUserProfile">授权登录</button>
<text class="login-tip">请先授权登录以使用完整功能</text>
</view>
<!-- 功能菜单 -->
<view class="feature-menu" wx:if="{{userInfo}}">
<view class="menu-item" bindtap="goToChat">
<image class="menu-icon" src="/assets/icons/chat.png"></image>
<text class="menu-title">智能聊天</text>
<text class="menu-desc">与AI助手对话</text>
</view>
<!-- 首页 - 深色主题信息流布局 -->
<view class="home-page">
<!-- 内容滚动区域 -->
<scroll-view class="content-scroll" scroll-y="{{true}}">
<view class="menu-item" bindtap="goToTask">
<image class="menu-icon" src="/assets/icons/task.png"></image>
<text class="menu-title">任务管理</text>
<text class="menu-desc">创建和管理任务</text>
<!-- 时间分隔线 -->
<view class="time-divider">
<text class="time-text">{{currentTime}}</text>
</view>
<view class="menu-item" bindtap="showDeviceInfo">
<image class="menu-icon" src="/assets/icons/device.png"></image>
<text class="menu-title">设备信息</text>
<text class="menu-desc">查看设备状态</text>
<!-- 用户信息卡片 -->
<view class="user-card">
<!-- 卡片头部 -->
<view class="user-card-header">
<text class="user-card-title">账户信息</text>
<text class="user-card-subtitle" wx:if="{{!hasUserInfo}}">点击按钮获取信息</text>
<text class="user-card-subtitle status-ok" wx:if="{{hasUserInfo}}">已获取</text>
</view>
<!-- 已登录:展示所有可获取信息 -->
<block wx:if="{{hasUserInfo}}">
<!-- 头像 + 昵称区域 -->
<view class="user-profile-row">
<view class="avatar-wrap">
<open-data type="userAvatarUrl" class="open-avatar"></open-data>
</view>
<view class="user-basic-info">
<view class="info-row">
<text class="info-label">昵称</text>
<text class="info-value受限">暂时受限</text>
<text class="info-status error">❌</text>
</view>
<view class="info-row">
<text class="info-label">头像</text>
<text class="info-value受限">暂时受限</text>
<text class="info-status error">❌</text>
</view>
<view class="info-row">
<text class="info-label">OpenID</text>
<text class="info-value" selectable="true">{{openId || '加载中...'}}</text>
<text class="info-status ok">✅</text>
</view>
</view>
</view>
<!-- 信息列表 -->
<view class="info-list">
<view class="info-row">
<text class="info-label">UnionID</text>
<text class="info-value受限">{{unionId}}</text>
<text class="info-status error">❌</text>
</view>
<view class="info-row">
<text class="info-label">手机号</text>
<text class="info-value" wx:if="{{phoneNumber}}" selectable="true">{{phoneNumber}}</text>
<text class="info-value hint" wx:if="{{!phoneNumber}}">点击下方按钮获取</text>
<text class="info-status ok">✅</text>
</view>
<view class="info-row">
<text class="info-label">性别</text>
<text class="info-value受限">暂时受限</text>
<text class="info-status error">❌</text>
</view>
<view class="info-row">
<text class="info-label">地区</text>
<text class="info-value受限">暂时受限</text>
<text class="info-status error">❌</text>
</view>
<view class="info-row">
<text class="info-label">设备</text>
<text class="info-value" wx:if="{{systemInfo}}">{{systemInfo.brand}} {{systemInfo.model}}</text>
<text class="info-value hint" wx:if="{{!systemInfo}}">加载中...</text>
<text class="info-status ok">✅</text>
</view>
<view class="info-row">
<text class="info-label">系统</text>
<text class="info-value" wx:if="{{systemInfo}}">{{systemInfo.system}} {{systemInfo.version}}</text>
<text class="info-value hint" wx:if="{{!systemInfo}}">加载中...</text>
<text class="info-status ok">✅</text>
</view>
<view class="info-row">
<text class="info-label">微信版本</text>
<text class="info-value" wx:if="{{wxVersion}}">{{wxVersion}}</text>
<text class="info-value hint" wx:if="{{!wxVersion}}">加载中...</text>
<text class="info-status ok">✅</text>
</view>
<view class="info-row">
<text class="info-label">小程序版本</text>
<text class="info-value" wx:if="{{accountInfo}}">{{accountInfo.miniProgram.version}}</text>
<text class="info-value hint" wx:if="{{!accountInfo}}">加载中...</text>
<text class="info-status ok">✅</text>
</view>
<view class="info-row">
<text class="info-label">网络</text>
<text class="info-value" wx:if="{{networkType}}">{{networkType}}</text>
<text class="info-value hint" wx:if="{{!networkType}}">加载中...</text>
<text class="info-status ok">✅</text>
</view>
<view class="info-row">
<text class="info-label">位置</text>
<text class="info-value受限" wx:if="{{!locationInfo}}">授权后获取</text>
<text class="info-value" wx:if="{{locationInfo}}">{{locationInfo.latitude?.toFixed(4)}}, {{locationInfo.longitude?.toFixed(4)}}</text>
<text class="info-status error">⚠️</text>
</view>
<view class="info-row">
<text class="info-label">剪贴板</text>
<text class="info-value" wx:if="{{clipboardData}}">{{clipboardData}}</text>
<text class="info-value hint" wx:if="{{!clipboardData}}">未授权</text>
<text class="info-status ok">✅</text>
</view>
</view>
<!-- 手机号获取按钮 -->
<view class="phone-btn-wrap" wx:if="{{!phoneNumber}}">
<button
class="phone-btn"
open-type="getPhoneNumber"
bindgetphonenumber="onGetPhoneNumber"
>
📱 获取手机号
</button>
</view>
<view class="phone-btn-wrap" wx:if="{{phoneNumber}}">
<view class="phone-btn-done">✅ 手机号已绑定:{{phoneNumber}}</view>
</view>
</block>
<!-- 未登录 -->
<block wx:if="{{!hasUserInfo}}">
<view class="not-logged-in">
<view class="open-data-info">
<open-data type="userAvatarUrl" class="open-avatar-large"></open-data>
</view>
<text class="not-logged-hint">微信昵称暂时受限,请先登录</text>
<view class="info-list">
<view class="info-row">
<text class="info-label">OpenID</text>
<text class="info-value受限">登录后获取</text>
<text class="info-status error">❌</text>
</view>
<view class="info-row">
<text class="info-label">手机号</text>
<text class="info-value受限">登录后获取</text>
<text class="info-status error">❌</text>
</view>
<view class="info-row">
<text class="info-label">设备</text>
<text class="info-value受限">登录后获取</text>
<text class="info-status error">❌</text>
</view>
<view class="info-row">
<text class="info-label">系统</text>
<text class="info-value受限">登录后获取</text>
<text class="info-status error">❌</text>
</view>
<view class="info-row">
<text class="info-label">网络</text>
<text class="info-value受限">登录后获取</text>
<text class="info-status error">❌</text>
</view>
</view>
<button class="login-btn" bindtap="onLogin">微信登录,获取 OpenID</button>
</view>
</block>
</view>
</view>
<!-- 系统状态 -->
<view class="system-status">
<view class="status-item">
<text class="status-label">连接状态:</text>
<text class="status-value {{websocketConnected ? 'status-success' : 'status-error'}}">
{{websocketConnected ? '已连接' : '未连接'}}
</text>
<!-- 轮播Banner -->
<swiper
class="banner-swiper"
indicator-dots="{{false}}"
autoplay="{{true}}"
interval="{{5000}}"
duration="{{500}}"
circular="{{true}}"
>
<swiper-item wx:for="{{banners}}" wx:key="id">
<view class="banner-item" style="background-image: url('{{item.image}}');">
<view class="banner-content">
<view class="banner-tag-row">
<text class="banner-tag">{{item.tag}}</text>
</view>
<text class="banner-title">{{item.title}}</text>
<text class="banner-desc" wx:if="{{item.desc}}">{{item.desc}}</text>
</view>
</view>
</swiper-item>
</swiper>
<!-- 信息流卡片列表 -->
<view class="news-list">
<!-- 卡片项1 -->
<view class="news-card" bindtap="onNewsTap" data-id="1">
<view class="card-main">
<view class="card-category">【省医药事】</view>
<text class="card-title">硝酸甘油vs速效救心丸心脏急救药用对才救命</text>
</view>
<view class="card-tag tag-blue">
<text class="tag-text">省医药事</text>
</view>
</view>
<!-- 卡片项2 -->
<view class="news-card" bindtap="onNewsTap" data-id="2">
<view class="card-main">
<view class="card-category">【科普小站】</view>
<text class="card-title">守护"星星的孩子"笑容:孤独症患儿口腔保健全攻略</text>
</view>
<view class="card-tag tag-cyan">
<text class="tag-text">科普小站</text>
</view>
</view>
</view>
<view class="status-item">
<text class="status-label">系统版本:</text>
<text class="status-value">{{version}}</text>
<!-- 第二个时间分隔线 -->
<view class="time-divider">
<text class="time-text">{{yesterdayTime}}</text>
</view>
</view>
</view>
<!-- 第二个轮播Banner喜报类型 -->
<swiper
class="banner-swiper banner-red"
indicator-dots="{{false}}"
autoplay="{{true}}"
interval="{{6000}}"
duration="{{500}}"
circular="{{true}}"
>
<swiper-item wx:for="{{redBanners}}" wx:key="id">
<view class="banner-item banner-red-item" style="background-image: url('{{item.image}}');">
<view class="banner-content">
<view class="banner-decoration">喜报</view>
<text class="banner-title banner-white-title">{{item.title}}</text>
</view>
</view>
</swiper-item>
</swiper>
<!-- 更多信息流卡片 -->
<view class="news-list">
<!-- 卡片项3 -->
<view class="news-card" bindtap="onNewsTap" data-id="3">
<view class="card-main">
<view class="card-category">【线上义诊】</view>
<text class="card-title">连续三天!全国肿瘤防治宣传周在线义诊来啦~</text>
</view>
<view class="card-tag tag-red">
<text class="tag-text">义诊信息</text>
</view>
</view>
<!-- 卡片项4 -->
<view class="news-card" bindtap="goToChat">
<view class="card-main">
<view class="card-category">【智能服务】</view>
<text class="card-title">AI智能助手在线随时随地解答健康疑问</text>
</view>
<view class="card-tag tag-purple">
<text class="tag-text">AI助手</text>
</view>
</view>
<!-- 卡片项5 -->
<view class="news-card" bindtap="goToTask">
<view class="card-main">
<view class="card-category">【任务中心】</view>
<text class="card-title">查看您的待办事项和预约提醒</text>
</view>
<view class="card-tag tag-green">
<text class="tag-text">任务中心</text>
</view>
</view>
</view>
<!-- 底部占位 -->
<view class="bottom-placeholder"></view>
</scroll-view>
</view>

View File

@@ -1,125 +1,579 @@
/* 首页样式 */
.container {
padding: 20rpx;
background-color: #f5f5f5;
/* 首页 - 深色主题信息流样式 */
.home-page {
display: flex;
flex-direction: column;
min-height: 100vh;
background-color: #0d0d0d;
}
/* 用户信息区域 */
.user-info {
/* ====== 顶部标题栏 ====== */
/* ====== 滚动内容区 ====== */
.content-scroll {
flex: 1;
height: calc(100vh - 180rpx);
}
/* ====== 时间分隔线 ====== */
.time-divider {
display: flex;
justify-content: center;
padding: 28rpx 0 20rpx;
}
.time-text {
font-size: 24rpx;
color: #666666;
letter-spacing: 1rpx;
}
/* ====== 轮播Banner ====== */
.banner-swiper {
margin: 0 24rpx 24rpx;
height: 320rpx;
border-radius: 20rpx;
overflow: hidden;
}
.banner-item {
width: 100%;
height: 100%;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
border-radius: 20rpx;
position: relative;
/* 默认蓝色渐变背景(当图片未加载时) */
background-image: linear-gradient(135deg, #1890ff 0%, #0958d9 50%, #0050b3 100%);
display: flex;
align-items: flex-end;
padding: 40rpx 36rpx;
}
.banner-red-item {
/* 红色渐变背景 */
background-image: linear-gradient(135deg, #cf1322 0%, #a8071a 50%, #820014 100%);
}
.banner-content {
position: relative;
z-index: 2;
width: 100%;
}
.banner-tag-row {
margin-bottom: 12rpx;
}
.banner-tag {
display: inline-block;
background: rgba(255,255,255,0.25);
color: white;
font-size: 22rpx;
padding: 6rpx 18rpx;
border-radius: 8rpx;
backdrop-filter: blur(10rpx);
}
.banner-title {
display: block;
font-size: 34rpx;
font-weight: bold;
color: #ffffff;
line-height: 1.4;
letter-spacing: 1rpx;
text-shadow: 0 2rpx 8rpx rgba(0,0,0,0.3);
}
.banner-white-title {
font-size: 38rpx;
}
.banner-desc {
display: block;
font-size: 26rpx;
color: rgba(255,255,255,0.9);
margin-top: 8rpx;
line-height: 1.4;
}
.banner-decoration {
font-size: 72rpx;
font-weight: 900;
color: rgba(255,215,0,0.85);
letter-spacing: 8rpx;
margin-bottom: 8rpx;
text-shadow:
0 0 20rpx rgba(255,215,0,0.5),
2rpx 2rpx 0 rgba(139,0,0,0.5);
}
/* ====== 信息流卡片列表 ====== */
.news-list {
padding: 0 24rpx;
}
.news-card {
display: flex;
align-items: center;
padding: 40rpx;
background: linear-gradient(135deg, #07c160 0%, #06a050 100%);
border-radius: 20rpx;
margin-bottom: 30rpx;
color: white;
justify-content: space-between;
background-color: #1a1a1a;
border-radius: 16rpx;
padding: 28rpx 24rpx;
margin-bottom: 20rpx;
transition: all 0.25s ease;
}
.avatar {
width: 120rpx;
.news-card:active {
transform: scale(0.98);
background-color: #222222;
}
.card-main {
flex: 1;
margin-right: 20rpx;
overflow: hidden;
}
.card-category {
font-size: 22rpx;
color: #888888;
margin-bottom: 10rpx;
font-weight: 500;
}
.card-title {
font-size: 29rpx;
color: #e8e8e8;
line-height: 1.5;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
word-break: break-all;
}
/* ====== 标签徽章 ====== */
.card-tag {
flex-shrink: 0;
width: 96rpx;
height: 96rpx;
border-radius: 16rpx;
display: flex;
align-items: center;
justify-content: center;
writing-mode: vertical-lr;
letter-spacing: 6rpx;
}
.tag-blue {
background: linear-gradient(145deg, #1677ff, #0958d9);
}
.tag-cyan {
background: linear-gradient(145deg, #13c2c2, #08979c);
}
.tag-red {
background: linear-gradient(145deg, #f5222d, #cf1322);
}
.tag-purple {
background: linear-gradient(145deg, #722ed1, #531dab);
}
.tag-green {
background: linear-gradient(145deg, #52c41a, #389e0d);
}
.tag-text {
font-size: 24rpx;
font-weight: bold;
color: #ffffff;
line-height: 1.2;
}
/* ====== 底部占位给自定义TabBar留空间====== */
.bottom-placeholder {
height: 120rpx;
border-radius: 50%;
margin-right: 30rpx;
border: 4rpx solid white;
}
.nickname {
/* ====== 登录弹窗 ====== */
.login-modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 9999;
display: flex;
align-items: center;
justify-content: center;
}
.modal-mask {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0,0,0,0.75);
}
.modal-content {
position: relative;
width: 600rpx;
background: linear-gradient(180deg, #222222 0%, #1a1a1a 100%);
border-radius: 32rpx;
padding: 60rpx 48rpx;
z-index: 2;
text-align: center;
}
.modal-header {
margin-bottom: 48rpx;
}
.modal-title {
display: block;
font-size: 36rpx;
font-weight: bold;
color: #ffffff;
margin-bottom: 16rpx;
}
/* 登录区域 */
.login-section {
padding: 60rpx 40rpx;
background: white;
.modal-subtitle {
display: block;
font-size: 26rpx;
color: #999999;
}
.modal-login-btn {
width: 100%;
height: 96rpx;
background: linear-gradient(135deg, #07c160 0%, #06ae56 100%);
color: white;
border: none;
border-radius: 48rpx;
font-size: 32rpx;
font-weight: 600;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 8rpx 24rpx rgba(7,193,96,0.35);
transition: all 0.3s ease;
margin-bottom: 24rpx;
}
.modal-login-btn:active {
transform: scale(0.97);
opacity: 0.92;
}
.modal-cancel {
font-size: 28rpx;
color: #888888;
}
/* ====== 用户信息显示区域 ====== */
.user-info-section {
margin: 0 24rpx 24rpx;
background-color: #1a1a1a;
border-radius: 16rpx;
overflow: hidden;
}
.user-info-header {
background: linear-gradient(135deg, #1677ff 0%, #0958d9 100%);
padding: 20rpx 24rpx;
}
.user-info-title {
font-size: 28rpx;
font-weight: 600;
color: #ffffff;
}
.user-info-content {
padding: 24rpx;
}
.user-info-text {
font-size: 26rpx;
color: #e8e8e8;
line-height: 1.6;
white-space: pre-wrap;
word-break: break-all;
margin-bottom: 20rpx;
}
.get-phone-btn {
width: 100%;
height: 80rpx;
background: linear-gradient(135deg, #07c160 0%, #06ae56 100%);
color: white;
border: none;
border-radius: 8rpx;
font-size: 28rpx;
font-weight: 600;
margin-top: 20rpx;
display: flex;
align-items: center;
justify-content: center;
}
.get-phone-btn:active {
opacity: 0.9;
transform: scale(0.98);
}
.open-data-info {
display: flex;
align-items: center;
margin-bottom: 20rpx;
}
.open-data-info open-data {
margin-right: 20rpx;
}
.open-data-info open-data[type="userAvatarUrl"] {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
display: block;
}
.open-data-info open-data[type="userNickName"] {
font-size: 32rpx;
font-weight: 600;
color: #ffffff;
}
.login-btn {
width: 100%;
height: 80rpx;
background: linear-gradient(135deg, #1677FF 0%, #0C66E4 100%);
color: white;
border: none;
border-radius: 8rpx;
font-size: 28rpx;
font-weight: 600;
margin-top: 20rpx;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4rpx 12rpx rgba(22, 119, 255, 0.3);
transition: all 0.3s ease;
}
.login-btn:active {
opacity: 0.9;
transform: scale(0.98);
}
/* ====== 用户信息卡片 ====== */
.user-card {
margin: 0 24rpx 24rpx;
background-color: #1a1a1a;
border-radius: 20rpx;
margin-bottom: 30rpx;
padding: 28rpx 28rpx 24rpx;
}
.user-card-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 24rpx;
}
.user-card-title {
font-size: 30rpx;
font-weight: bold;
color: #e8e8e8;
}
.user-card-subtitle {
font-size: 22rpx;
color: #888888;
}
.user-card-subtitle.status-ok {
color: #52c41a;
}
/* 头像+昵称行 */
.user-profile-row {
display: flex;
align-items: flex-start;
margin-bottom: 24rpx;
padding-bottom: 24rpx;
border-bottom: 1rpx solid #2a2a2a;
}
.avatar-wrap {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
overflow: hidden;
background-color: #2a2a2a;
margin-right: 20rpx;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
}
.open-avatar {
width: 80rpx;
height: 80rpx;
}
.open-avatar-large {
width: 100rpx;
height: 100rpx;
}
.user-basic-info {
flex: 1;
}
/* 信息列表 */
.info-list {
margin-bottom: 20rpx;
}
.info-row {
display: flex;
align-items: center;
padding: 14rpx 0;
border-bottom: 1rpx solid #222222;
}
.info-row:last-child {
border-bottom: none;
}
.info-label {
width: 140rpx;
font-size: 26rpx;
color: #888888;
flex-shrink: 0;
}
.info-value {
flex: 1;
font-size: 26rpx;
color: #e8e8e8;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.info-value.hint {
color: #666666;
font-style: italic;
}
.info-value受限 {
flex: 1;
font-size: 26rpx;
color: #555555;
font-style: italic;
}
.info-status {
font-size: 24rpx;
margin-left: 16rpx;
flex-shrink: 0;
}
.info-status.ok {
color: #52c41a;
}
.info-status.error {
color: #666666;
}
/* 手机号按钮 */
.phone-btn-wrap {
margin-top: 16rpx;
}
.phone-btn {
width: 100%;
height: 80rpx;
background: linear-gradient(135deg, #1677ff, #0958d9);
color: #ffffff;
font-size: 28rpx;
font-weight: bold;
border-radius: 40rpx;
display: flex;
align-items: center;
justify-content: center;
border: none;
}
.phone-btn::after {
border: none;
}
.phone-btn-done {
text-align: center;
font-size: 24rpx;
color: #52c41a;
padding: 16rpx 0;
}
/* 未登录状态 */
.not-logged-in {
display: flex;
flex-direction: column;
align-items: center;
}
.open-data-info {
width: 100rpx;
height: 100rpx;
border-radius: 50%;
overflow: hidden;
background-color: #2a2a2a;
margin-bottom: 20rpx;
display: flex;
align-items: center;
justify-content: center;
}
.not-logged-hint {
font-size: 24rpx;
color: #666666;
margin-bottom: 24rpx;
text-align: center;
}
.login-btn {
background: linear-gradient(135deg, #07c160 0%, #06a050 100%);
color: white;
border: none;
border-radius: 50rpx;
padding: 30rpx 80rpx;
font-size: 32rpx;
margin-bottom: 20rpx;
}
.login-tip {
color: #999;
font-size: 28rpx;
}
/* 功能菜单 */
.feature-menu {
background: white;
border-radius: 20rpx;
padding: 20rpx;
margin-bottom: 30rpx;
}
.menu-item {
display: flex;
align-items: center;
padding: 30rpx;
border-bottom: 1rpx solid #f0f0f0;
transition: background-color 0.3s;
}
.menu-item:last-child {
border-bottom: none;
}
.menu-item:active {
background-color: #f8f8f8;
}
.menu-icon {
width: 60rpx;
height: 60rpx;
margin-right: 30rpx;
}
.menu-title {
font-size: 32rpx;
color: #333;
margin-bottom: 10rpx;
flex: 1;
}
.menu-desc {
font-size: 24rpx;
color: #999;
}
/* 系统状态 */
.system-status {
background: white;
border-radius: 20rpx;
padding: 30rpx;
}
.status-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20rpx 0;
border-bottom: 1rpx solid #f0f0f0;
}
.status-item:last-child {
border-bottom: none;
}
.status-label {
font-size: 28rpx;
color: #666;
}
.status-value {
width: 100%;
height: 80rpx;
background: linear-gradient(135deg, #1677ff, #0958d9);
color: #ffffff;
font-size: 28rpx;
font-weight: bold;
}
border-radius: 40rpx;
display: flex;
align-items: center;
justify-content: center;
border: none;
margin-top: 8rpx;
}
.login-btn::after {
border: none;
}
.login-btn:active {
opacity: 0.9;
}