Files
yxe-mp/packageUser/self-report/select.vue
T
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

313 lines
7.6 KiB
Vue
Raw 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="select-page">
<!-- 本页 hero 即页头(设计如此),不套 AppNavbar;
navigationStyle 是 custom,状态栏高度要自己让出来,否则内容冲顶。 -->
<view class="hero" :style="{paddingTop: `${heroPaddingTop}px`}">
<view class="hero-back" @tap="back">
<u-icon name="arrow-left" size="20" color="#0f2f52"/>
</view>
<view class="hero-text">
<view class="hero-title">自主填报</view>
<view class="hero-sub">真实记录 · 及时上报 · 共创佳绩</view>
</view>
<image class="hero-avatar" :src="heroAvatar" mode="aspectFit"/>
</view>
<view class="card block">
<view class="section-title-row">
<view class="section-title">请选择填报类型</view>
</view>
<view class="section-desc">请选择您本次要填写的工作类型</view>
<view
v-for="item in typeOptions"
:key="item.value"
:class="['type-card', form.type === item.value ? 'type-card-active' : '']"
@tap="form.type = item.value"
>
<view :class="['type-icon-wrap', form.type === item.value ? 'type-icon-wrap-active' : '']">
<image :class="['type-icon', item.value === 'store' ? 'type-icon-store' : '']"
:src="item.icon" mode="aspectFit"/>
</view>
<view class="type-body">
<view class="type-title">{{ item.title }}</view>
<view class="type-desc">{{ item.desc }}</view>
</view>
<view :class="['type-radio', form.type === item.value ? 'type-radio-active' : '']">
<view v-if="form.type === item.value" class="type-radio-dot"/>
</view>
</view>
</view>
<view class="select-actions">
<view class="primary-btn confirm" @tap="confirm">确认选择</view>
</view>
<view class="select-tip">① 请选择合适的填报类型,以便更准确地记录您的工作</view>
</view>
</template>
<script>
// 顶部插画:暂无独立设计稿资源,沿用首页自主填报入口所用的同色系插图
const HERO_AVATAR = 'https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/9c6c98843c2e30247355d86ea47552aa.png'
const ICON_STORE = 'https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/0fd31838127cd57b1c1db44f2c749353.png'
const ICON_VISIT = 'https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260127/f5fbb2e4be31bcc830156f174e7931b8.png'
export default {
data() {
return {
heroAvatar: HERO_AVATAR,
// 状态栏高度:本页自绘页头,得自己避让,否则内容会顶到状态栏
statusBarHeight: 0,
form: {
type: 'store'
},
typeOptions: [
{
value: 'store',
title: '驻店填报',
desc: '适用于在门店驻店,进行商品陈列、销售等工作的场景',
icon: ICON_STORE
},
{
value: 'visit',
title: '跑店填报',
desc: '适用于外出拜访门店、客户或其他工作场景',
icon: ICON_VISIT
}
]
}
},
computed: {
// 内联 padding-top 会覆盖 .hero 里 padding 简写的上边距,
// 所以这里把原有 24rpx(≈12px)一并算进去,视觉与设计稿一致。
heroPaddingTop() {
return this.statusBarHeight + 12
}
},
onLoad() {
this.statusBarHeight = this.readStatusBarHeight()
},
methods: {
// 优先用新接口,取不到时回退旧接口,避免 getSystemInfoSync 的废弃告警
readStatusBarHeight() {
try {
if (uni.getWindowInfo) {
const info = uni.getWindowInfo()
if (info && info.statusBarHeight !== undefined) return info.statusBarHeight || 0
}
} catch (error) {
// ignore:新接口不可用时走下面的回退
}
try {
const systemInfo = uni.getSystemInfoSync()
return (systemInfo && systemInfo.statusBarHeight) || 0
} catch (error) {
return 0
}
},
back() {
if (getCurrentPages().length === 1) {
uni.switchTab({url: '/pages/index/index'})
return
}
uni.navigateBack()
},
confirm() {
const type = this.form.type
const url = type === 'visit'
? '/packageUser/self-report/visit'
: '/packageUser/self-report/create'
uni.navigateTo({
url,
fail: () => {
uni.showToast({title: '页面打开失败', icon: 'none'})
}
})
}
}
}
</script>
<style lang="scss" scoped>
.select-page {
min-height: 100vh;
background: #eef8f5;
padding-bottom: 60rpx;
}
.hero {
position: relative;
display: flex;
align-items: center;
justify-content: space-between;
padding: 24rpx 40rpx 36rpx;
background: linear-gradient(180deg, #d9f5ec 0%, #eef8f5 100%);
}
/* 本页没有 AppNavbar,返回入口自绘;随流排布,避免与标题重叠 */
.hero-back {
flex-shrink: 0;
margin-right: 20rpx;
width: 64rpx;
height: 64rpx;
border-radius: 999rpx;
background: rgba(255, 255, 255, 0.7);
display: flex;
align-items: center;
justify-content: center;
z-index: 2;
}
.hero-text {
flex: 1;
}
.hero-title {
display: flex;
align-items: center;
font-size: 56rpx;
font-weight: 800;
color: #0f2f52;
letter-spacing: 4rpx;
}
.hero-sub {
margin-top: 14rpx;
font-size: 24rpx;
color: #5c6c84;
letter-spacing: 2rpx;
}
.hero-avatar {
width: 180rpx;
height: 150rpx;
flex-shrink: 0;
}
.block {
margin: 0 24rpx;
}
.section-title-row {
display: flex;
align-items: center;
justify-content: space-between;
}
.section-desc {
margin: -6rpx 0 24rpx;
font-size: 24rpx;
color: #9aa3b2;
}
.type-card {
display: flex;
align-items: center;
gap: 20rpx;
padding: 26rpx 22rpx;
margin-bottom: 22rpx;
border-radius: 20rpx;
border: 3rpx solid #e6eaf0;
background: #f8fafc;
}
.type-card:last-child {
margin-bottom: 0;
}
.type-card-active {
border-color: #2fc6a7;
background: #f1fbf8;
}
/* 图标本身是纯白图形 + 透明底,直接放浅色卡片上会看不见,
所以垫一层彩色圆角底块反衬;选中后加深,兼作选中态提示。
底色取偏深的绿,保证白色图形有足够对比度。 */
.type-icon-wrap {
flex-shrink: 0;
width: 112rpx;
height: 100rpx;
border-radius: 24rpx;
background: linear-gradient(135deg, #2fc6a7, #1aa88c);
display: flex;
align-items: center;
justify-content: center;
}
.type-icon-wrap-active {
background: linear-gradient(135deg, #16a085, #0e7a66);
box-shadow: 0 8rpx 20rpx rgba(47, 198, 167, 0.32);
}
.type-icon {
width: 62rpx;
height: 62rpx;
}
/* 两张图源的内容占比差得多(visit 约占画布 88%×88%,store 只占 75%×50%),
同尺寸渲染会让驻店图标明显偏小,这里按可见图形补正。 */
.type-icon-store {
width: 92rpx;
height: 92rpx;
}
.type-body {
flex: 1;
}
.type-title {
font-size: 34rpx;
font-weight: 700;
color: #1f2937;
}
.type-desc {
margin-top: 12rpx;
font-size: 24rpx;
color: #7b8794;
line-height: 1.5;
}
.type-radio {
width: 44rpx;
height: 44rpx;
border-radius: 50%;
border: 3rpx solid #d3d9e2;
background: #ffffff;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
}
.type-radio-active {
border-color: #2fc6a7;
}
.type-radio-dot {
width: 22rpx;
height: 22rpx;
border-radius: 50%;
background: #2fc6a7;
}
.select-actions {
margin: 48rpx 24rpx 0;
}
.confirm {
height: 92rpx;
font-size: 32rpx;
font-weight: 600;
box-shadow: 0 12rpx 26rpx rgba(47, 198, 167, 0.28);
}
.select-tip {
margin-top: 26rpx;
text-align: center;
font-size: 22rpx;
color: #9aa3b2;
}
</style>