style(portal): 将主CTA重构为靠右侧纯正正圆图标FAB,释放全屏通透空间
这个提交包含在:
@@ -213,11 +213,11 @@
|
|||||||
<text class="ai-entry-text">{{ textOf('card.ai_chat') }}</text>
|
<text class="ai-entry-text">{{ textOf('card.ai_chat') }}</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 5. 单屏唯一定位主 CTA (悬浮动态胶囊:主人态分享名片 / 访客态保存到通讯录) -->
|
<!-- 5. 靠右侧核心主 CTA (图标形式:主人态分享出示 / 访客态保存到通讯录) -->
|
||||||
<view v-if="state.card != null" class="portal-cta-bar">
|
<view v-if="state.card != null" class="portal-cta-bar">
|
||||||
<button class="primary-cta-btn" @click="handlePrimaryCta">
|
<button class="primary-cta-btn" :title="primaryCtaLabel" @click="handlePrimaryCta">
|
||||||
<text class="primary-cta-btn-text">{{ primaryCtaLabel }}</text>
|
<text v-if="isOwner" class="primary-cta-btn-icon">↗</text>
|
||||||
<text class="primary-cta-btn-arrow">↗</text>
|
<text v-else class="primary-cta-btn-icon">↓</text>
|
||||||
</button>
|
</button>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@@ -1277,52 +1277,41 @@ onUnload(() => {
|
|||||||
color: var(--oc-ai, #7C5CFF);
|
color: var(--oc-ai, #7C5CFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 5. 单屏唯一定位主 CTA (现代极简悬浮胶囊,透气留白,告别死板通栏横条) */
|
/* 5. 靠右侧核心主 CTA (图标形式,正圆微光晕 FAB,彻底释放屏幕中下部空间) */
|
||||||
.portal-cta-bar {
|
.portal-cta-bar {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 0;
|
inset-inline-end: 16px;
|
||||||
right: 0;
|
|
||||||
bottom: calc(16px + var(--window-bottom, 0px) + env(safe-area-inset-bottom, 0px));
|
bottom: calc(16px + var(--window-bottom, 0px) + env(safe-area-inset-bottom, 0px));
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
pointer-events: none;
|
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
}
|
}
|
||||||
.primary-cta-btn {
|
.primary-cta-btn {
|
||||||
pointer-events: auto;
|
width: 48px;
|
||||||
height: 44px;
|
height: 48px;
|
||||||
min-height: 44px;
|
min-width: 48px;
|
||||||
width: auto;
|
min-height: 48px;
|
||||||
min-width: 150px;
|
padding: 0;
|
||||||
max-width: 220px;
|
|
||||||
padding: 0 24px;
|
|
||||||
background: var(--oc-primary-gradient, linear-gradient(135deg, #00A3FF 0%, #0B63E5 100%));
|
background: var(--oc-primary-gradient, linear-gradient(135deg, #00A3FF 0%, #0B63E5 100%));
|
||||||
border-radius: var(--oc-radius-pill, 9999px);
|
border-radius: var(--oc-radius-pill, 9999px);
|
||||||
box-shadow: 0 8px 24px rgba(0, 136, 255, 0.26), 0 2px 6px rgba(11, 99, 229, 0.12);
|
box-shadow: 0 8px 24px rgba(0, 136, 255, 0.35), 0 2px 6px rgba(11, 99, 229, 0.16);
|
||||||
border: 1px solid rgba(255, 255, 255, 0.25);
|
border: 1px solid rgba(255, 255, 255, 0.25);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: opacity 150ms cubic-bezier(0.2, 0.8, 0.2, 1);
|
transition: opacity 150ms cubic-bezier(0.2, 0.8, 0.2, 1), transform 150ms cubic-bezier(0.2, 0.8, 0.2, 1);
|
||||||
}
|
}
|
||||||
.primary-cta-btn:active {
|
.primary-cta-btn:active {
|
||||||
opacity: 0.85;
|
opacity: 0.85;
|
||||||
|
transform: scale(0.95);
|
||||||
}
|
}
|
||||||
.primary-cta-btn-text {
|
.primary-cta-btn-icon {
|
||||||
color: #FFFFFF;
|
color: #FFFFFF;
|
||||||
font-size: 14px;
|
font-size: 20px;
|
||||||
font-weight: 600;
|
font-weight: 700;
|
||||||
letter-spacing: 0.4px;
|
line-height: 1;
|
||||||
}
|
|
||||||
.primary-cta-btn-arrow {
|
|
||||||
color: rgba(255, 255, 255, 0.85);
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 600;
|
|
||||||
margin-inline-start: 4px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 6. 商务预约排期卡片与抽屉样式 (Bento Grid Appointment & Bottom Sheet) */
|
/* 6. 商务预约排期卡片与抽屉样式 (Bento Grid Appointment & Bottom Sheet) */
|
||||||
|
|||||||
@@ -168,24 +168,25 @@ test('5. 多语言文案解析与主客态映射审查', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('6. 主 CTA 悬浮胶囊形态与呼吸感视觉规范审查', () => {
|
test('6. 主 CTA 靠右侧图标形式与悬浮触控规范审查', () => {
|
||||||
const content = fs.readFileSync(portalUvuePath, 'utf-8');
|
const content = fs.readFileSync(portalUvuePath, 'utf-8');
|
||||||
assert.ok(
|
assert.ok(
|
||||||
|
content.includes('inset-inline-end: 16px') || content.includes('right: 16px'),
|
||||||
|
'主 CTA 必须靠右侧布局 (inset-inline-end: 16px)'
|
||||||
|
);
|
||||||
|
assert.ok(
|
||||||
|
content.includes('border-radius: 50%') ||
|
||||||
content.includes('border-radius: var(--oc-radius-pill, 9999px);') ||
|
content.includes('border-radius: var(--oc-radius-pill, 9999px);') ||
|
||||||
content.includes('border-radius: 9999px;'),
|
content.includes('border-radius: 9999px;'),
|
||||||
'primary-cta-btn 必须使用胶囊 Pill 圆角 (9999px) 替代沉重矩形'
|
'主 CTA 必须使用圆形或大圆角图标形态'
|
||||||
);
|
);
|
||||||
assert.ok(
|
assert.ok(
|
||||||
content.includes('max-width: 220px') || content.includes('min-width: 150px'),
|
content.includes('height: 48px') || content.includes('min-height: 44px'),
|
||||||
'primary-cta-btn 严禁撑满全屏,必须使用精致收窄胶囊尺寸'
|
'主 CTA 触控尺寸必须满足规范 (>= 44px)'
|
||||||
);
|
);
|
||||||
assert.ok(
|
assert.ok(
|
||||||
content.includes('.portal-cta-bar') && content.includes('pointer-events: none;'),
|
content.includes('env(safe-area-inset-bottom') && content.includes('var(--window-bottom'),
|
||||||
'portal-cta-bar 容器必须开启 pointer-events: none 以实现居中悬浮呼吸感'
|
'主 CTA 必须适配视口安全区与 TabBar 避让'
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
content.includes('.primary-cta-btn') && content.includes('pointer-events: auto;'),
|
|
||||||
'primary-cta-btn 自身必须显式开启 pointer-events: auto'
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
在新工单中引用
屏蔽一个用户