Files
weicw-dshsa e192296ea7 feat(UI): 首页与个人中心按原型改版,修复纯白图标在白底上不可见
一、首页两个入口按钮改版(用户反馈「太小了」)

原为「裸图标 + 单行文字」的矮按钮(min-height 76rpx),改为
「白色圆角图标块 + 右侧主副两行文字」的大卡片(padding 22rpx 20rpx):
- 自主填报:便捷填报,快速提交
- 填报记录:历史记录,随时查看
主按钮渐变由 #f97316→#ef4444 改为 #f9863c→#f2620f 并加橙色投影。
结构对齐 create.vue 已有的 sales-entry-* 卡片。

二、个人中心三张卡片改版(用户提供原型图)

- 积分卡:改为「绿底图标块 + 大号数字 + 我的积分」,右侧新增
  「积分明细 ›」胶囊按钮;去掉原先那条突兀的 20px 绿色粗顶边。
  数字字号 30rpx → 40rpx。
- 自主填报 / 客户拜访:由单行居中文字改为「图标块 + 主标题 + 副标题」,
  副标题分别为「及时上报、真实记录」「拜访记录、有效跟进」。
- 药审核:改为整行卡片(图标 + 药审核/待审核任务 + 红色数字徽标 + 箭头),
  徽标数据来自新增接口 /yxe/yxe-audit/pending-count(见 yxe-java 侧提交),
  仅 can_auth === 1 时拉取,退出登录时清零。

三、修复纯白图标在近白底上不可见(用户反馈「图片是白色的看不清」)

根因不在 opacity 或主题色,而是图源本身就是纯白图形 + 透明背景:
  文件                       颜色构成            内容占画布
  0fd31838....png (驻店)     透明 + #FFFFFF      75% x 50%
  f5fbb2e4....png (跑店)     白色及半透明白       88% x 88%
  9c6c9884....png (新任务)   纯白                90% x 90%
  eebe6469....png (已完成)   纯白                 -
而承载它们的底色分别是 #f8fafc(选择页卡片)与平均亮度 250/255 的
近白底图(首页 tab),白图标贴白底自然完全看不见。此类图标只适合
放在深色/彩色底上,同一张 0fd31838....png 在个人中心药审核卡里
配金色底时一直正常,故长期未暴露。

改法:统一垫一层绿色圆角底块反衬白色图形
- select.vue:新增 .type-icon-wrap(未选中 #2fc6a7→#1aa88c,
  选中加深为 #16a085→#0e7a66 + 投影,顺带强化选中态)
- index.vue:新增 .tab-icon-wrap(未激活绿圆底;激活时置
  background:none,避免两层绿有色差露出一圈描边)

顺带修一个隐藏问题:两张填报图源的内容占比差很多,同尺寸渲染会让
驻店图标明显偏小,故为 store 单独放大(.type-icon-store 92rpx)。

验证:用 Pillow 按 rpx→px 实际比例合成修复前后对比图逐张核对,
确认修复前未激活图标完全不可见、修复后清晰、激活态无色差边。
模板标签、style 括号、类名定义/引用均通过脚本校验。

注:f5fbb2e4....png 渲染出来实际是「时钟」形状,用在「跑店填报」
语义是否合适待确认,本次只解决可见性,未更换图标资源。
2026-10-12 16:11:58 +08:00

1143 lines
29 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="mine-page">
<view class="mine-hero">
<!-- <AppNavbar class="mine-navbar" title="我的"/>-->
<view class="hero-content">
<view class="profile-left">
<u-avatar :src="isLoggedIn ? user.avatar : ''" size="120rpx"/>
<view class="profile-info">
<view class="name">{{ isLoggedIn ? user.nickname : '未登录' }}</view>
<view class="phone">{{ isLoggedIn ? user.phone : '点击登录同步手机号' }}</view>
</view>
<view class="primary-btn login-btn" @tap="toLogin" v-if="!isLoggedIn">去登录</view>
</view>
<view class="hero-right">
<image class="hero-mascot"
src="https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/a8cc7a2ca9d342f5a10657b735c623cb.png"
mode="aspectFit"></image>
<view class="city-chip">{{ currentCity }}</view>
</view>
</view>
<view class="flex justify-between items-center text-25" style="margin-top: 60rpx">
<text class="text-main">转发分享给新用户,可获得积分</text>
<!-- <text class="text-red font-bold">{{ getPoint }}积分</text>-->
</view>
<!-- <view class="notice-bar" v-if="lastCashLog">-->
<!-- <text class="notice-label">奖励:</text>-->
<!-- <text class="notice-text">{{ lastCashLog.user.nickname }}领取了{{ lastCashLog.money }}元</text>-->
<!-- <view class="notice-more">></view>-->
<!-- <u-icon name="https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/9fd7c6fb0046d565cbd36c316023ee87.png"/>-->
<!-- </view>-->
</view>
<view class="income-card">
<!-- <view class="income-item" @click="openBonus">-->
<!-- <view class="flex justify-start items-center">-->
<!-- <view class="income-value">{{ bonus.taskIncome }}</view>-->
<!-- <view class="income-unit">元</view>-->
<!-- </view>-->
<!-- <view class="income-label">任务收益</view>-->
<!-- </view>-->
<!-- <view class="income-item" @click="openBonus">-->
<!-- <view class="flex justify-start items-center">-->
<!-- <view class="income-value">{{ bonus.shareIncome }}</view>-->
<!-- <view class="income-unit">元</view>-->
<!-- </view>-->
<!-- <view class="income-label">晒单收益</view>-->
<!-- </view>-->
<view class="income-item" @click="openPoints">
<view class="income-icon">
<u-icon name="integral" size="28" color="#2fc6a7"/>
</view>
<view class="income-text">
<view class="income-line">
<text class="income-value income-value--points">{{ pointSummary.currentPoints }}</text>
<text class="income-unit income-unit--points">积分</text>
</view>
<view class="income-label">我的积分</view>
</view>
<view class="income-more">
<text>积分明细</text>
<u-icon name="arrow-right" size="13" color="#2fc6a7"/>
</view>
</view>
<!-- <view class="income-btn" @tap="openWithdraw">去提现</view>-->
</view>
<!-- <view class="income-card" v-if="isLoggedIn && user.canAuth === 1">-->
<!-- <view class="income-item" @click="openBonus">-->
<!-- <view class="flex justify-start items-center">-->
<!-- <view class="income-value">{{ bonus.totalTaskIncome }}</view>-->
<!-- <view class="income-unit">元</view>-->
<!-- </view>-->
<!-- <view class="income-label">总任务收益</view>-->
<!-- </view>-->
<!-- <view class="income-item" @click="openBonus">-->
<!-- <view class="flex justify-start items-center">-->
<!-- <view class="income-value">{{ bonus.totalShareIncome }}</view>-->
<!-- <view class="income-unit">元</view>-->
<!-- </view>-->
<!-- <view class="income-label">总晒单收益</view>-->
<!-- </view>-->
<!-- <view class="income-item" @click="openBonus">-->
<!-- <view class="flex justify-start items-center">-->
<!-- <view class="income-value">{{ bonus.totalTaskIncome + bonus.totalShareIncome }}</view>-->
<!-- <view class="income-unit">元</view>-->
<!-- </view>-->
<!-- <view class="income-label">合计收益</view>-->
<!-- </view>-->
<!-- </view>-->
<view class="feature-banner-group">
<view class="self-report-banner" @tap="openSelfReport">
<view class="feature-icon">
<u-icon name="edit-pen" size="24" color="#ffffff"/>
</view>
<view class="feature-text">
<text class="feature-title">自主填报</text>
<text class="feature-desc">及时上报、真实记录</text>
</view>
</view>
<view class="self-report-banner" @tap="openVisit">
<view class="feature-icon">
<u-icon name="account-fill" size="24" color="#ffffff"/>
</view>
<view class="feature-text">
<text class="feature-title">客户拜访</text>
<text class="feature-desc">拜访记录、有效跟进</text>
</view>
</view>
</view>
<view class="audit-banner" @tap="openAudit" v-if="user.canAuth === 1">
<view class="audit-icon-wrap">
<u-icon name="file-text" size="26" color="#ffffff"/>
</view>
<view class="audit-text">
<text class="audit-title">药审核</text>
<text class="audit-desc">待审核任务</text>
</view>
<view class="audit-right">
<view v-if="auditPendingCount" class="audit-badge">{{ auditPendingCount }}</view>
<u-icon name="arrow-right" size="14" color="#ffffff"/>
</view>
</view>
<view class="quick-card">
<view class="quick-item" @tap="openProfile">
<image class="quick-icon"
src="https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/f64dbb797897f7e997b9e390c9f5b3ff.png"
mode="aspectFit"></image>
<text>用户资料</text>
</view>
<view class="quick-item" @tap="openOrder">
<image class="quick-icon"
src="https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/b8462c751e121744fa20f460c1f43ed8.png"
mode="aspectFit"></image>
<text>全部订单</text>
</view>
<view class="quick-item" @tap="openCoupon">
<image class="quick-icon"
src="https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/d4a24c4f61bf29755396ed7c2eecb45a.png"
mode="aspectFit"></image>
<text>领券中心</text>
</view>
<view class="quick-item" @tap="openPoints">
<image class="quick-icon"
src="https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/7a9be3484448c3e8253140b8ff05afc6.png"
mode="aspectFit"></image>
<text>我的积分</text>
</view>
</view>
<view class="section-card">
<view class="section-title">服务内容</view>
<view class="grid">
<view class="grid-item" @tap="openMyShare">
<image class="grid-icon"
src="https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/f64dbb797897f7e997b9e390c9f5b3ff.png"
mode="aspectFit"></image>
<text>我的分享</text>
</view>
<view class="grid-item" @tap="openAddress">
<image class="grid-icon"
src="https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/b8462c751e121744fa20f460c1f43ed8.png"
mode="aspectFit"></image>
<text>收货地址</text>
</view>
<!-- <view class="grid-item" @tap="openBonus">-->
<!-- <image class="grid-icon"-->
<!-- src="https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/d4a24c4f61bf29755396ed7c2eecb45a.png"-->
<!-- mode="aspectFit"></image>-->
<!-- <text>奖金记录</text>-->
<!-- </view>-->
<!-- <view class="grid-item" @tap="openWithdraw">-->
<!-- <image class="grid-icon"-->
<!-- src="https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/7a9be3484448c3e8253140b8ff05afc6.png"-->
<!-- mode="aspectFit"></image>-->
<!-- <text>资金提现</text>-->
<!-- </view>-->
<view class="grid-item" @tap="openCertification">
<image class="grid-icon"
src="https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/6aaa42c6f235c6720735aae14cb2c16a.png"
mode="aspectFit"></image>
<text>个人信息认证</text>
</view>
<view class="grid-item" @tap="openTravel">
<image class="grid-icon"
src="https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/791479d861e69e833c3aa0073b602908.png"
mode="aspectFit"></image>
<text>差旅报销</text>
</view>
</view>
</view>
<view class="section-card">
<view class="section-title">慢病管理</view>
<view class="grid">
<view class="grid-item" @tap="openChronic">
<image class="grid-icon"
src="https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/a9249f7069c609222b031809809e4b70.png"
mode="aspectFit"></image>
<text>慢病信息收集</text>
</view>
<view class="grid-item" @tap="openChronicManage">
<image class="grid-icon"
src="https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/e3f81b35a32d0771d2fb7c5a23e393db.png"
mode="aspectFit"></image>
<text>慢病信息管理</text>
</view>
<view class="grid-item" @tap="openService">
<image class="grid-icon"
src="https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/5677d46c66b7ab57c9497e60e75daef5.png"
mode="aspectFit"></image>
<text>联系客服</text>
</view>
</view>
</view>
<view class="logout-btn" @click="logout" v-if="isLoggedIn">
<u-icon name="https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/0193f5a958ccd4797d6e76403cb14096.png"/>
<text>退出登录</text>
</view>
<!-- <view class="card block">-->
<!-- <view class="section-title">奖金记录</view>-->
<!-- <view class="bonus-grid">-->
<!-- <view class="bonus-item">-->
<!-- <view class="bonus-value">¥ {{ bonus.movement }}</view>-->
<!-- <view class="bonus-label">药动销提成</view>-->
<!-- </view>-->
<!-- <view class="bonus-item">-->
<!-- <view class="bonus-value">¥ {{ bonus.exchange }}</view>-->
<!-- <view class="bonus-label">药兑换提成</view>-->
<!-- </view>-->
<!-- </view>-->
<!-- <view class="bonus-list">-->
<!-- <view class="bonus-row" v-for="(item, idx) in bonus.history" :key="idx">-->
<!-- <view>-->
<!-- <view class="bonus-name">{{ item.name }}</view>-->
<!-- <view class="bonus-meta">{{ item.source }} · {{ item.date }}</view>-->
<!-- </view>-->
<!-- <view class="bonus-amount">+¥{{ item.amount }}</view>-->
<!-- </view>-->
<!-- </view>-->
<!-- </view>-->
<!-- <view class="card block">-->
<!-- <view class="section-title">奖金提现</view>-->
<!-- <view class="withdraw-row">-->
<!-- <view>-->
<!-- <view class="withdraw-label">可提现余额</view>-->
<!-- <view class="withdraw-value">¥ {{ withdraw.available }}</view>-->
<!-- </view>-->
<!-- <view class="primary-btn withdraw-btn" @tap="applyWithdraw">申请提现</view>-->
<!-- </view>-->
<!-- </view>-->
<Login ref="Login" @done="getUserData"/>
<u-popup :show="servicePopupVisible" mode="bottom" round="24rpx" close-on-click-overlay @close="closeServicePopup">
<view class="service-popup">
<view class="service-popup-head">
<text class="service-popup-title">联系客服</text>
<view class="service-popup-close" @tap="closeServicePopup">
<u-icon name="close" size="32rpx" color="#7a8495"/>
</view>
</view>
<view class="service-popup-body">
<view v-if="serviceList.length" class="service-list">
<view
class="service-item"
v-for="(item, index) in serviceList"
:key="index"
@tap="handleServiceItem(item)"
>
<text class="service-item-text">{{ item.type }}: {{ item.title }}{{ item.content }}</text>
</view>
</view>
<view v-else class="service-empty">暂无客服内容</view>
</view>
</view>
</u-popup>
</view>
</template>
<script>
import {auditPendingCountReq, countUserIncomeReq, userInfoReq} from "@/api/user";
import Login from '@/components/Login.vue'
import AppNavbar from "@/components/AppNavbar.vue";
import {clearUserInfo, getUserInfo} from "@/util/user";
import {getLocationAction} from "@/util";
import {dictDataInfoReq, yxeServiceReq} from "@/api/common";
import {dealerWithdrawPageReq} from "@/api/bonus";
import {userPointLogUserListReq} from "@/api/shop";
export default {
components: {Login, AppNavbar},
data() {
return {
isLoggedIn: false,
defaultAvatar: '/static/logo.png',
user: {
avatar: '',
name: '',
phone: '',
city: '',
qualification: '',
canAuth: 0,
balance: 0,
},
bonus: {
movement: 0,
exchange: 0,
taskIncome: 0,
shareIncome: 0,
totalTaskIncome: 0,
totalShareIncome: 0,
history: []
},
pointSummary: {
currentPoints: 0,
},
auditPendingCount: 0,
currentCity: '定位中',
serviceList: [],
servicePopupVisible: false,
lastCashLog: null,
getPoint: 0,
}
},
async onShow() {
await this.getPointConfig()
await this.refreshPageData()
},
async onPullDownRefresh() {
try {
await this.refreshPageData()
} finally {
uni.stopPullDownRefresh()
}
},
methods: {
async getPointConfig() {
const {data} = await dictDataInfoReq(591)
this.getPoint = data.dictDataCode
},
async refreshPageData() {
await this.getServiceList()
await this.getLastCashLog()
if (getUserInfo().token) {
this.isLoggedIn = true
await this.getUserData()
}
const res = await getLocationAction().catch(() => {
uni.showToast({
title: '请允许位置授权',
icon: 'none'
})
})
if (res) {
this.currentCity = res.city_str
}
},
async getServiceList() {
try {
const {data} = await yxeServiceReq()
this.serviceList = this.normalizeServiceList(data)
} catch (error) {
this.serviceList = []
}
},
async getUserData() {
const {data} = await userInfoReq()
this.isLoggedIn = true
this.user = data
const tasks = [
this.getUserIncomeData(),
this.getUserPointData()
]
// 药审核入口仅对审核员可见,待审数也只有此时才拉取
if (data && data.canAuth === 1) {
tasks.push(this.getAuditPendingCount())
} else {
this.auditPendingCount = 0
}
await Promise.all(tasks)
},
async getAuditPendingCount() {
try {
const {data} = await auditPendingCountReq()
this.auditPendingCount = Number(data && data.total) || 0
} catch (error) {
this.auditPendingCount = 0
}
},
async getLastCashLog() {
const {data} = await dealerWithdrawPageReq({
page: 1,
limit: 1,
})
if (data.list.length) this.lastCashLog = data.list[0]
},
async getUserIncomeData() {
const {data} = await countUserIncomeReq()
this.bonus = data
},
async getUserPointData() {
try {
const {data} = await userPointLogUserListReq({
page: 1,
limit: 20
})
this.pointSummary.currentPoints = this.extractCurrentPoints(data)
} catch (error) {
this.pointSummary.currentPoints = this.resolveUserPoints(this.user)
}
},
extractCurrentPoints(payload) {
const payloadPoints = this.resolveUserPoints(payload)
if (payloadPoints !== 0) return payloadPoints
const payloadList = Array.isArray(payload)
? payload
: (payload && Array.isArray(payload.list) ? payload.list : [])
const listPoints = payloadList.reduce((sum, item) => sum + this.resolvePointDelta(item), 0)
if (listPoints !== 0) return listPoints
return this.resolveUserPoints(this.user)
},
resolveUserPoints(source = {}) {
const candidates = [
source.currentPoints,
source.currentPoint,
source.points,
source.point,
source.totalPoints,
source.totalPoint,
source.integral,
source.score
]
for (let i = 0; i < candidates.length; i++) {
const value = Number(candidates[i])
if (Number.isFinite(value)) return value
}
return 0
},
resolvePointDelta(source = {}) {
const candidates = [
source.changePoint,
source.changePoints,
source.changeNum,
source.delta,
source.num,
source.amount,
source.value,
source.point,
source.points,
source.integral,
source.score
]
for (let i = 0; i < candidates.length; i++) {
const value = Number(candidates[i])
if (Number.isFinite(value)) return value
}
return 0
},
toLogin() {
this.$refs.Login.open()
},
normalizeServiceList(payload) {
return Array.isArray(payload)
? payload
: (payload && Array.isArray(payload.list) ? payload.list : (payload ? [payload] : []))
},
async openService() {
if (!this.serviceList.length) {
await this.getServiceList()
}
if (!this.serviceList.length) {
uni.showToast({
title: '暂无客服信息',
icon: 'none'
})
return
}
this.servicePopupVisible = true
},
closeServicePopup() {
this.servicePopupVisible = false
},
formatServiceItem(item) {
if (!item) return ''
return `${item.type}:${item.value}`
},
handleServiceItem(item) {
console.log(item)
if (item.type === '电话') {
uni.makePhoneCall({
phoneNumber: item.content
})
return
}
if (item.type === '微信') {
uni.setClipboardData({
data: item.content,
success: () => {
uni.showToast({
title: '微信号已复制',
icon: 'none'
})
}
})
}
},
openOrder() {
this.jumpWithLogin('/pages/order/list')
},
openCoupon() {
this.jumpWithLogin('/packageUser/coupon/index')
},
openPoints() {
this.jumpWithLogin('/packageUser/points/index')
},
openProfile() {
if (!this.isLoggedIn) return this.$refs.Login.open()
uni.navigateTo({
url: '/pages/mine/profile'
})
},
openMyShare() {
this.jumpWithLogin('/pages/share/mine')
},
openAddress() {
this.jumpWithLogin('/packageUser/address/index')
},
openBonus() {
this.jumpWithLogin('/pages/bonus/index')
},
openSelfReport() {
// 「自主填报」先选填报类型(驻店填报 / 跑店填报),再进对应表单页
this.jumpWithLogin('/packageUser/self-report/select')
},
openWithdraw() {
this.jumpWithLogin('/pages/bonus/withdraw')
},
openCertification() {
this.jumpWithLogin('/pages/certification/index')
},
openTravel() {
this.jumpWithLogin('/packageUser/travel/index')
},
openVisit() {
this.jumpWithLogin('/pages/visit/index')
},
openAudit() {
this.jumpWithLogin('/pages/audit/index')
},
openChronic() {
this.jumpWithLogin('/packageUser/chronic/index')
},
openChronicManage() {
this.jumpWithLogin('/packageUser/chronic/manage')
},
jumpWithLogin(url){
if (!this.isLoggedIn)
return this.$refs.Login.open()
uni.navigateTo({
url
})
},
logout(){
clearUserInfo()
this.user = {}
this.isLoggedIn = false
this.bonus = {
taskIncome: 0,
shareIncome: 0,
totalTaskIncome: 0,
totalShareIncome: 0,
}
this.pointSummary = {
currentPoints: 0,
}
this.auditPendingCount = 0
// this.$refs.Login.open()
}
}
}
</script>
<style lang="scss" scoped>
.mine-page {
min-height: 100vh;
padding: 0;
background: #f5f5f5;
}
.mine-hero {
padding: 180rpx 20rpx 20rpx 20rpx;
background: url('https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/46361d4be9d61af01e0dd97870d8765c.png') no-repeat top center / 100% auto;
}
.mine-navbar {
padding: 0 6rpx;
}
.hero-content {
margin-top: 16rpx;
display: flex;
align-items: center;
justify-content: space-between;
gap: 14rpx;
}
.profile-left {
display: flex;
align-items: center;
gap: 16rpx;
}
.profile-info {
font-size: 26rpx;
}
.name {
color: #1f2937;
font-weight: 700;
}
.phone {
color: #6b7280;
margin-top: 6rpx;
}
.login-btn {
padding: 10rpx 18rpx;
margin-left: 6rpx;
}
.hero-right {
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 8rpx;
position: relative;
}
.hero-mascot {
width: 150rpx;
height: 115rpx;
}
.city-chip {
padding: 6rpx 18rpx;
border-radius: 999rpx;
background: #ffffff;
border: 1rpx solid #2fc6a7;
color: #2fc6a7;
font-size: 24rpx;
font-weight: 700;
position: absolute;
bottom: -40rpx;
left: 50%;
transform: translateX(-50%);
width: 120rpx;
text-align: center;
}
.notice-bar {
margin: 60rpx 20rpx 0;
padding: 12rpx 16rpx;
background: #ffffff;
border-radius: 999rpx;
display: flex;
align-items: center;
gap: 10rpx;
box-shadow: 0 8rpx 16rpx rgba(0, 0, 0, 0.06);
}
.notice-label {
color: #2fc6a7;
font-weight: 700;
font-size: 24rpx;
}
.notice-text {
flex: 1;
font-size: 24rpx;
color: #111827;
}
.notice-more {
width: 40rpx;
height: 40rpx;
border-radius: 50%;
border: 1rpx solid #2fc6a7;
display: flex;
align-items: center;
justify-content: center;
color: #2fc6a7;
}
.income-card {
margin: 16rpx 20rpx 0;
background: #ffffff;
border-radius: 24rpx;
padding: 22rpx 24rpx;
display: flex;
align-items: center;
justify-content: space-between;
gap: 16rpx;
flex-wrap: wrap;
box-shadow: 0 8rpx 16rpx rgba(0, 0, 0, 0.06);
border: 1rpx solid #e6f6f2;
}
.income-item {
display: flex;
align-items: center;
gap: 18rpx;
flex: 1;
min-width: 0;
}
.income-icon {
flex-shrink: 0;
width: 80rpx;
height: 80rpx;
border-radius: 24rpx;
background: #e6f9f4;
display: flex;
align-items: center;
justify-content: center;
}
.income-text {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
gap: 4rpx;
}
.income-line {
display: flex;
align-items: baseline;
gap: 6rpx;
}
.income-more {
flex-shrink: 0;
display: flex;
align-items: center;
gap: 4rpx;
padding: 8rpx 18rpx;
border-radius: 999rpx;
background: #e6f9f4;
color: #2fc6a7;
font-size: 24rpx;
font-weight: 700;
}
.income-value {
font-size: 40rpx;
font-weight: 700;
color: #ff3b30;
}
.income-unit {
font-size: 22rpx;
color: #6b7280;
}
.income-value--points,
.income-unit--points {
color: #2fc6a7;
}
.income-label {
font-size: 22rpx;
color: #6b7280;
}
.income-btn {
padding: 10rpx 20rpx;
border-radius: 999rpx;
background: #2fc6a7;
color: #ffffff;
font-size: 24rpx;
font-weight: 700;
flex-shrink: 0;
}
.feature-banner-group {
margin: 20rpx 20rpx 0;
display: flex;
align-items: stretch;
justify-content: center;
gap: 16rpx;
}
.audit-banner {
margin: 20rpx 20rpx 0;
padding: 24rpx;
background: linear-gradient(135deg, #f2c063, #e8a63c);
color: #ffffff;
border-radius: 28rpx;
display: flex;
align-items: center;
gap: 18rpx;
box-shadow: 0 10rpx 24rpx rgba(216, 158, 58, 0.22);
}
.self-report-row {
margin: 14rpx 20rpx 0;
}
.self-report-banner {
flex: 1;
min-width: 0;
border-radius: 28rpx;
background: linear-gradient(135deg, #33d0b3, #22c3a1);
color: #ffffff;
display: flex;
align-items: center;
gap: 14rpx;
box-shadow: 0 10rpx 24rpx rgba(22, 163, 74, 0.18);
padding: 24rpx 20rpx;
}
.feature-icon {
flex-shrink: 0;
width: 68rpx;
height: 68rpx;
border-radius: 20rpx;
background: rgba(255, 255, 255, 0.22);
display: flex;
align-items: center;
justify-content: center;
}
.feature-text {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
gap: 4rpx;
}
.feature-title {
font-size: 30rpx;
font-weight: 700;
line-height: 1.2;
white-space: nowrap;
}
.feature-desc {
font-size: 20rpx;
line-height: 1.2;
opacity: 0.85;
white-space: nowrap;
}
.audit-icon-wrap {
flex-shrink: 0;
width: 68rpx;
height: 68rpx;
border-radius: 20rpx;
background: rgba(255, 255, 255, 0.22);
display: flex;
align-items: center;
justify-content: center;
}
.audit-text {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
gap: 4rpx;
}
.audit-title {
font-size: 30rpx;
font-weight: 700;
line-height: 1.2;
}
.audit-desc {
font-size: 20rpx;
line-height: 1.2;
opacity: 0.85;
}
.audit-right {
flex-shrink: 0;
display: flex;
align-items: center;
gap: 10rpx;
}
.audit-badge {
min-width: 44rpx;
height: 44rpx;
padding: 0 12rpx;
border-radius: 999rpx;
background: #ffffff;
color: #e0631a;
font-size: 24rpx;
font-weight: 700;
display: flex;
align-items: center;
justify-content: center;
}
.quick-card {
margin: 16rpx 20rpx 0;
background: #ffffff;
border-radius: 20rpx;
padding: 20rpx 10rpx;
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 10rpx;
text-align: center;
box-shadow: 0 8rpx 16rpx rgba(0, 0, 0, 0.06);
}
.quick-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 8rpx;
font-size: 24rpx;
color: #1f2937;
}
.quick-icon {
width: 44rpx;
height: 44rpx;
}
.section-card {
margin: 16rpx 20rpx 0;
background: #ffffff;
border-radius: 20rpx;
padding: 18rpx 14rpx 20rpx;
box-shadow: 0 8rpx 16rpx rgba(0, 0, 0, 0.06);
}
.section-title {
font-size: 28rpx;
font-weight: 700;
color: #1f2937;
margin-bottom: 14rpx;
}
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 18rpx 10rpx;
text-align: center;
}
.grid-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 8rpx;
font-size: 24rpx;
color: #1f2937;
}
.grid-icon {
width: 48rpx;
height: 48rpx;
}
.logout-btn {
margin: 22rpx 20rpx 0;
padding: 18rpx 0;
border-radius: 999rpx;
border: 1rpx solid #2fc6a7;
color: #2fc6a7;
text-align: center;
font-size: 26rpx;
font-weight: 700;
background-color: white;
display: flex;
align-items: center;
justify-content: center;
}
.bonus-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 12rpx;
margin-bottom: 12rpx;
}
.bonus-item {
background: linear-gradient(135deg, #f0f5ff, #ffffff);
border-radius: 14rpx;
padding: 12rpx;
border: 1rpx solid #e7eef8;
}
.bonus-value {
font-size: 32rpx;
color: var(--brand-primary);
}
.bonus-label {
color: var(--text-sub);
font-size: 24rpx;
margin-top: 4rpx;
}
.bonus-list {
border-top: 1rpx solid #edf1f7;
}
.bonus-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12rpx 0;
border-bottom: 1rpx dashed #e3eaf4;
}
.bonus-row:last-child {
border-bottom: none;
}
.bonus-name {
font-size: 28rpx;
}
.bonus-meta {
color: var(--text-sub);
font-size: 24rpx;
}
.bonus-amount {
color: #ff3b30;
}
.withdraw-row {
display: flex;
justify-content: space-between;
align-items: center;
}
.withdraw-label {
color: var(--text-sub);
font-size: 24rpx;
}
.withdraw-value {
font-size: 30rpx;
color: var(--brand-primary);
}
.withdraw-btn {
padding: 12rpx 20rpx;
}
.cert-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10rpx 0;
border-bottom: 1rpx solid #edf1f7;
}
.cert-row:last-child {
border-bottom: none;
}
.cert-title {
font-size: 28rpx;
}
.cert-meta {
color: var(--text-sub);
font-size: 24rpx;
}
.service-popup {
background: #ffffff;
padding: 24rpx 24rpx 32rpx;
border-radius: 24rpx 24rpx 0 0;
}
.service-popup-head {
display: flex;
align-items: center;
justify-content: space-between;
}
.service-popup-title {
font-size: 30rpx;
font-weight: 700;
color: #1f2937;
}
.service-popup-close {
width: 48rpx;
height: 48rpx;
display: flex;
align-items: center;
justify-content: center;
}
.service-popup-body {
margin-top: 16rpx;
}
.service-list {
display: flex;
flex-direction: column;
gap: 12rpx;
}
.service-item {
padding: 14rpx 16rpx;
border-radius: 14rpx;
background: #f8fafc;
}
.service-item-text {
font-size: 26rpx;
color: #111827;
}
.service-empty {
padding: 20rpx 0;
text-align: center;
font-size: 24rpx;
color: #9ca3af;
}
</style>