refactor(mpuniapp): 删掉繁冗堆叠,按现代极简分组风格彻底重构名片主个人中心
这个提交包含在:
@@ -1,160 +1,80 @@
|
||||
<template>
|
||||
<view class="profile-page">
|
||||
<scroll-view class="profile-scroll" :scroll-y="true">
|
||||
<view class="profile-container">
|
||||
<!-- 1. Header Hero Bento: Profile identity & Quick site preview -->
|
||||
<view class="hero-card">
|
||||
<view class="hero-main">
|
||||
<view class="avatar-box">
|
||||
<image
|
||||
v-if="state.account.avatar !== ''"
|
||||
class="account-avatar"
|
||||
:src="state.account.avatar"
|
||||
mode="aspectFill"
|
||||
@click="onAvatarClick"
|
||||
/>
|
||||
<view
|
||||
v-else
|
||||
class="account-avatar-placeholder"
|
||||
@click="onAvatarChoose"
|
||||
>
|
||||
<text class="avatar-placeholder-plus">+</text>
|
||||
</view>
|
||||
<view
|
||||
v-if="state.account.avatar !== ''"
|
||||
class="avatar-del-badge"
|
||||
@click="onAvatarDelete"
|
||||
>
|
||||
<text class="avatar-del-icon">×</text>
|
||||
</view>
|
||||
<view class="profile-content">
|
||||
<!-- 1. Minimal Profile Identity Header -->
|
||||
<view class="profile-header">
|
||||
<view class="avatar-wrap">
|
||||
<image
|
||||
v-if="state.account.avatar !== ''"
|
||||
class="avatar-img"
|
||||
:src="state.account.avatar"
|
||||
mode="aspectFill"
|
||||
@click="onAvatarClick"
|
||||
/>
|
||||
<view
|
||||
v-else
|
||||
class="avatar-empty"
|
||||
@click="onAvatarChoose"
|
||||
>
|
||||
<text class="avatar-add-icon">+</text>
|
||||
</view>
|
||||
|
||||
<view class="hero-info">
|
||||
<view class="name-row">
|
||||
<text class="account-name">{{ state.account.name }}</text>
|
||||
<view class="tier-pill">
|
||||
<text class="tier-pill-text">{{ t('tierBadge') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<text class="account-company">{{ state.account.company }}</text>
|
||||
<text class="account-dept">{{ state.account.department }}</text>
|
||||
<view
|
||||
v-if="state.account.avatar !== ''"
|
||||
class="avatar-remove-badge"
|
||||
@click="onAvatarDelete"
|
||||
>
|
||||
<text class="avatar-remove-icon">×</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="hero-actions">
|
||||
<view class="preview-btn" @click="openPage('/pages/portal/index')">
|
||||
<text class="preview-btn-text">{{ t('previewPortal') }}</text>
|
||||
</view>
|
||||
<view class="identity-info">
|
||||
<text class="identity-name">{{ state.account.name }}</text>
|
||||
<text class="identity-company">{{ state.account.company }}</text>
|
||||
<text class="identity-dept">{{ state.account.department }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 2. Bento Metrics Grid: Core Business Assets -->
|
||||
<view class="metrics-grid">
|
||||
<view class="metric-cell" @click="openPage('/pages/owner/card/index')">
|
||||
<text class="metric-val">{{ cardCount }}</text>
|
||||
<text class="metric-lbl">{{ t('metricsCards') }}</text>
|
||||
<!-- 2. Operational Hardware & Team Group -->
|
||||
<view class="menu-group">
|
||||
<view class="menu-row" @click="openPage('/pages/owner/nfc/scan')">
|
||||
<text class="menu-title">{{ t('nfcScan') }}</text>
|
||||
<text class="menu-arrow">›</text>
|
||||
</view>
|
||||
<view class="metric-cell" @click="openPage('/pages/owner/radar')">
|
||||
<text class="metric-val">{{ visitorCount }}</text>
|
||||
<text class="metric-lbl">{{ t('metricsVisitors') }}</text>
|
||||
<view class="menu-divider"></view>
|
||||
<view class="menu-row" @click="openPage('/pages/owner/nfc/mode')">
|
||||
<text class="menu-title">{{ t('nfcMode') }}</text>
|
||||
<text class="menu-arrow">›</text>
|
||||
</view>
|
||||
<view class="metric-cell" @click="openPage('/pages/owner/leads')">
|
||||
<text class="metric-val">{{ leadCount }}</text>
|
||||
<text class="metric-lbl">{{ t('metricsLeads') }}</text>
|
||||
<view class="menu-divider"></view>
|
||||
<view class="menu-row" @click="openPage('/pages/owner/nfc/security')">
|
||||
<text class="menu-title">{{ t('nfcSecurity') }}</text>
|
||||
<text class="menu-arrow">›</text>
|
||||
</view>
|
||||
<view class="menu-divider"></view>
|
||||
<view class="menu-row" @click="openPage('/pages/owner/team/overview')">
|
||||
<text class="menu-title">{{ t('teamBriefing') }}</text>
|
||||
<text class="menu-arrow">›</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 3. Plan & Quota Bento Card -->
|
||||
<view class="section-card quota-card">
|
||||
<view class="card-header-row">
|
||||
<text class="section-title">{{ t('quotaSection') }}</text>
|
||||
<view class="plan-status-badge">
|
||||
<view class="status-dot"></view>
|
||||
<text class="plan-status-text">{{ t('planActive') }}</text>
|
||||
</view>
|
||||
<!-- 3. Plan & Quota Group -->
|
||||
<view class="menu-group">
|
||||
<view class="menu-row">
|
||||
<text class="menu-title">{{ t('quotaCards') }}</text>
|
||||
<text class="menu-value">{{ quotaLine }}</text>
|
||||
</view>
|
||||
|
||||
<view class="quota-body">
|
||||
<view class="quota-meta-row">
|
||||
<text class="quota-tier-name">{{ t('tierPro') }}</text>
|
||||
<text class="quota-usage-num">{{ quotaLine }}</text>
|
||||
</view>
|
||||
|
||||
<!-- Visual Progress Bar -->
|
||||
<view class="progress-track">
|
||||
<view
|
||||
class="progress-fill"
|
||||
:class="{ 'progress-fill-warning': quotaExceeded }"
|
||||
:style="{ width: quotaPercent + '%' }"
|
||||
></view>
|
||||
</view>
|
||||
|
||||
<view class="quota-footer-row">
|
||||
<text v-if="quotaExceeded" class="quota-warn-text">{{ t('quotaUpgrade') }}</text>
|
||||
<text v-else class="quota-sub-desc">{{ t('quotaCards') }}</text>
|
||||
<view class="quota-action-link" @click="openBillingPage">
|
||||
<text class="quota-action-text">{{ t('upgradeQuota') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="quotaExceeded" class="quota-tip-row">
|
||||
<text class="quota-tip-text">{{ t('quotaUpgrade') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 4. Operational Workspace: Hardware & Team Briefing -->
|
||||
<view class="section-card">
|
||||
<text class="section-title">{{ t('workspaceSection') }}</text>
|
||||
|
||||
<view class="setting-cell" @click="openPage('/pages/owner/nfc/scan')">
|
||||
<view class="cell-left">
|
||||
<text class="cell-label">{{ t('nfcScan') }}</text>
|
||||
</view>
|
||||
<view class="cell-right">
|
||||
<text class="cell-arrow">›</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="row-divider"></view>
|
||||
|
||||
<view class="setting-cell" @click="openPage('/pages/owner/nfc/mode')">
|
||||
<view class="cell-left">
|
||||
<text class="cell-label">{{ t('nfcMode') }}</text>
|
||||
</view>
|
||||
<view class="cell-right">
|
||||
<text class="cell-arrow">›</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="row-divider"></view>
|
||||
|
||||
<view class="setting-cell" @click="openPage('/pages/owner/nfc/security')">
|
||||
<view class="cell-left">
|
||||
<text class="cell-label">{{ t('nfcSecurity') }}</text>
|
||||
</view>
|
||||
<view class="cell-right">
|
||||
<text class="cell-arrow">›</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="row-divider"></view>
|
||||
|
||||
<view class="setting-cell" @click="openPage('/pages/owner/team/overview')">
|
||||
<view class="cell-left">
|
||||
<text class="cell-label">{{ t('teamBriefing') }}</text>
|
||||
</view>
|
||||
<view class="cell-right">
|
||||
<text class="cell-arrow">›</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 5. Notifications Settings -->
|
||||
<view class="section-card">
|
||||
<text class="section-title">{{ t('notificationsSection') }}</text>
|
||||
|
||||
<!-- Radar push notification -->
|
||||
<view class="setting-cell setting-cell-switch">
|
||||
<view class="cell-text-wrap">
|
||||
<text class="cell-label">{{ t('radarPushTitle') }}</text>
|
||||
<text class="cell-desc">{{ t('radarPushDesc') }}</text>
|
||||
<!-- 4. Notifications & Switches Group -->
|
||||
<view class="menu-group">
|
||||
<view class="menu-row menu-row-switch">
|
||||
<view class="switch-label-wrap">
|
||||
<text class="menu-title">{{ t('radarPushTitle') }}</text>
|
||||
<text class="menu-subtitle">{{ t('radarPushDesc') }}</text>
|
||||
</view>
|
||||
<view class="switch-touch-area">
|
||||
<switch
|
||||
@@ -164,14 +84,11 @@
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="row-divider"></view>
|
||||
|
||||
<!-- Lead notice notification -->
|
||||
<view class="setting-cell setting-cell-switch">
|
||||
<view class="cell-text-wrap">
|
||||
<text class="cell-label">{{ t('leadNoticeTitle') }}</text>
|
||||
<text class="cell-desc">{{ t('leadNoticeDesc') }}</text>
|
||||
<view class="menu-divider"></view>
|
||||
<view class="menu-row menu-row-switch">
|
||||
<view class="switch-label-wrap">
|
||||
<text class="menu-title">{{ t('leadNoticeTitle') }}</text>
|
||||
<text class="menu-subtitle">{{ t('leadNoticeDesc') }}</text>
|
||||
</view>
|
||||
<view class="switch-touch-area">
|
||||
<switch
|
||||
@@ -183,22 +100,22 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 6. Preferred Display Language -->
|
||||
<view class="section-card">
|
||||
<text class="section-title">{{ t('languageSection') }}</text>
|
||||
<text class="section-desc">{{ t('languageLabel') }}</text>
|
||||
|
||||
<view class="language-options">
|
||||
<!-- 5. Display Language Preferences Group -->
|
||||
<view class="menu-group">
|
||||
<view class="language-header">
|
||||
<text class="menu-title">{{ t('languageSection') }}</text>
|
||||
</view>
|
||||
<view class="language-chip-list">
|
||||
<view
|
||||
v-for="item in languageList"
|
||||
:key="item.code"
|
||||
class="language-chip"
|
||||
:class="{ 'language-chip-active': item.code === state.locale }"
|
||||
class="lang-pill"
|
||||
:class="{ 'lang-pill-active': item.code === state.locale }"
|
||||
@click="onSelectLocale(item.code)"
|
||||
>
|
||||
<text
|
||||
class="language-chip-text"
|
||||
:class="{ 'language-chip-text-active': item.code === state.locale }"
|
||||
class="lang-pill-text"
|
||||
:class="{ 'lang-pill-text-active': item.code === state.locale }"
|
||||
>
|
||||
{{ item.label }}
|
||||
</text>
|
||||
@@ -206,19 +123,19 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 7. Logout Action (Minimal, safe text button) -->
|
||||
<view class="logout-wrap">
|
||||
<view class="logout-btn" @click="onLogout">
|
||||
<text class="logout-text">{{ t('logout') }}</text>
|
||||
<!-- 6. Minimal Sign Out -->
|
||||
<view class="signout-section">
|
||||
<view class="signout-btn" @click="onLogout">
|
||||
<text class="signout-text">{{ t('logout') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Error feedback banner -->
|
||||
<view v-if="state.errorMessage !== ''" class="error-banner">
|
||||
<text class="error-banner-text">{{ state.errorMessage }}</text>
|
||||
<!-- System error notification if any -->
|
||||
<view v-if="state.errorMessage !== ''" class="error-notice">
|
||||
<text class="error-notice-text">{{ state.errorMessage }}</text>
|
||||
</view>
|
||||
|
||||
<view class="bottom-spacer"></view>
|
||||
<view class="bottom-safe-space"></view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
@@ -235,7 +152,6 @@ import {
|
||||
resolveProfileText,
|
||||
previewAccountAvatar,
|
||||
removeAccountAvatar,
|
||||
calculateQuotaPercent,
|
||||
} from './useProfile.uts';
|
||||
import { OmniLocale } from '../../../common/locale.uts';
|
||||
import { fetchCardQuota } from '../../../common/api.uts';
|
||||
@@ -249,10 +165,6 @@ type LangOption = {
|
||||
const state = reactive<ProfileState>(loadProfileSettings());
|
||||
const quotaLine = ref('--');
|
||||
const quotaExceeded = ref(false);
|
||||
const quotaPercent = ref(20);
|
||||
const cardCount = ref('1');
|
||||
const visitorCount = ref('12');
|
||||
const leadCount = ref('5');
|
||||
|
||||
function onAvatarClick(): void {
|
||||
if (state.account.avatar !== '') {
|
||||
@@ -313,25 +225,15 @@ function openPage(url: string): void {
|
||||
});
|
||||
}
|
||||
|
||||
function openBillingPage(): void {
|
||||
uni.showToast({
|
||||
title: resolveProfileText('tierPro'),
|
||||
icon: 'none',
|
||||
});
|
||||
}
|
||||
|
||||
async function loadQuota(): Promise<void> {
|
||||
try {
|
||||
const tenantId = getTenantId();
|
||||
const quota = await fetchCardQuota(tenantId !== '' ? tenantId : 1);
|
||||
quotaLine.value = `${quota.used} / ${quota.limit}`;
|
||||
quotaExceeded.value = quota.exceeded === true;
|
||||
quotaPercent.value = calculateQuotaPercent(quota.used, quota.limit);
|
||||
cardCount.value = `${quota.used}`;
|
||||
} catch (_e) {
|
||||
quotaLine.value = '1 / 5';
|
||||
quotaExceeded.value = false;
|
||||
quotaPercent.value = 20;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,373 +283,159 @@ onShow(() => {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.profile-container {
|
||||
padding: 16px 16px 32px 16px;
|
||||
.profile-content {
|
||||
padding: 24px 16px 32px 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* 1. Hero Identity Bento */
|
||||
.hero-card {
|
||||
background-color: #FFFFFF;
|
||||
border: 1px solid #E3E7ED;
|
||||
border-radius: 16px;
|
||||
padding: 16px;
|
||||
margin-bottom: 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.hero-main {
|
||||
/* 1. Minimal Identity Header */
|
||||
.profile-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
padding: 4px 4px;
|
||||
}
|
||||
|
||||
.avatar-box {
|
||||
.avatar-wrap {
|
||||
position: relative;
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
margin-right: 14px;
|
||||
width: 54px;
|
||||
height: 54px;
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
.account-avatar {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
border-radius: 28px;
|
||||
.avatar-img {
|
||||
width: 54px;
|
||||
height: 54px;
|
||||
border-radius: 27px;
|
||||
background-color: #E3E7ED;
|
||||
}
|
||||
|
||||
.account-avatar-placeholder {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
border-radius: 28px;
|
||||
.avatar-empty {
|
||||
width: 54px;
|
||||
height: 54px;
|
||||
border-radius: 27px;
|
||||
border: 1px dashed #C9CDD4;
|
||||
background-color: #F7F8FA;
|
||||
background-color: #FFFFFF;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.avatar-placeholder-plus {
|
||||
font-size: 24px;
|
||||
.avatar-add-icon {
|
||||
font-size: 22px;
|
||||
color: #667085;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.avatar-del-badge {
|
||||
.avatar-remove-badge {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 9px;
|
||||
top: -2px;
|
||||
right: -2px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 8px;
|
||||
background-color: rgba(240, 68, 56, 0.9);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.avatar-del-icon {
|
||||
.avatar-remove-icon {
|
||||
color: #FFFFFF;
|
||||
font-size: 13px;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.hero-info {
|
||||
.identity-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.name-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.account-name {
|
||||
font-size: 17px;
|
||||
.identity-name {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #101828;
|
||||
line-height: 1.4;
|
||||
margin-right: 8px;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.tier-pill {
|
||||
padding: 1px 6px;
|
||||
border-radius: 6px;
|
||||
background-color: #EAF1FF;
|
||||
border: 1px solid #0B5CFF;
|
||||
}
|
||||
|
||||
.tier-pill-text {
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
color: #0B5CFF;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.account-company {
|
||||
.identity-company {
|
||||
font-size: 13px;
|
||||
color: #667085;
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.account-dept {
|
||||
.identity-dept {
|
||||
font-size: 12px;
|
||||
color: #667085;
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
.hero-actions {
|
||||
margin-top: 12px;
|
||||
padding-top: 12px;
|
||||
border-top: 1px solid #E3E7ED;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.preview-btn {
|
||||
height: 32px;
|
||||
padding: 0 12px;
|
||||
border-radius: 8px;
|
||||
background-color: #F7F8FA;
|
||||
border: 1px solid #E3E7ED;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.preview-btn-text {
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
color: #101828;
|
||||
}
|
||||
|
||||
/* 2. Metrics Bento Grid */
|
||||
.metrics-grid {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 8px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.metric-cell {
|
||||
flex: 1;
|
||||
background-color: #FFFFFF;
|
||||
border: 1px solid #E3E7ED;
|
||||
border-radius: 12px;
|
||||
padding: 12px 8px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.metric-val {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: #101828;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.metric-lbl {
|
||||
font-size: 11px;
|
||||
color: #667085;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
/* 3. Common Section Cards */
|
||||
.section-card {
|
||||
/* 2. Modern Inset Grouped Card */
|
||||
.menu-group {
|
||||
background-color: #FFFFFF;
|
||||
border: 1px solid #E3E7ED;
|
||||
border-radius: 16px;
|
||||
padding: 16px;
|
||||
margin-bottom: 12px;
|
||||
padding: 0 16px;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.card-header-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: #101828;
|
||||
}
|
||||
|
||||
.section-desc {
|
||||
font-size: 13px;
|
||||
color: #667085;
|
||||
margin-top: 2px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.plan-status-badge {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: 2px 8px;
|
||||
border-radius: 10px;
|
||||
background-color: #F7F8FA;
|
||||
border: 1px solid #E3E7ED;
|
||||
}
|
||||
|
||||
.status-dot {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 3px;
|
||||
background-color: #12B76A;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.plan-status-text {
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
color: #667085;
|
||||
}
|
||||
|
||||
/* Quota Details */
|
||||
.quota-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.quota-meta-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.quota-tier-name {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #101828;
|
||||
}
|
||||
|
||||
.quota-usage-num {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: #0B5CFF;
|
||||
}
|
||||
|
||||
.progress-track {
|
||||
height: 6px;
|
||||
border-radius: 3px;
|
||||
background-color: #F7F8FA;
|
||||
border: 1px solid #E3E7ED;
|
||||
overflow: hidden;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.progress-fill {
|
||||
height: 100%;
|
||||
border-radius: 3px;
|
||||
background-color: #0B5CFF;
|
||||
}
|
||||
|
||||
.progress-fill-warning {
|
||||
background-color: #F04438;
|
||||
}
|
||||
|
||||
.quota-footer-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.quota-sub-desc {
|
||||
font-size: 12px;
|
||||
color: #667085;
|
||||
}
|
||||
|
||||
.quota-warn-text {
|
||||
font-size: 12px;
|
||||
color: #F04438;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.quota-action-link {
|
||||
min-height: 28px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.quota-action-text {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: #0B5CFF;
|
||||
}
|
||||
|
||||
/* Operational Cells */
|
||||
.setting-cell {
|
||||
.menu-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
min-height: 48px;
|
||||
padding-top: 6px;
|
||||
padding-bottom: 6px;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.setting-cell:active {
|
||||
opacity: 0.75;
|
||||
.menu-row:active {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.cell-left {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
.menu-row-switch {
|
||||
min-height: 52px;
|
||||
}
|
||||
|
||||
.cell-text-wrap {
|
||||
.menu-title {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #101828;
|
||||
}
|
||||
|
||||
.menu-value {
|
||||
font-size: 13px;
|
||||
color: #667085;
|
||||
}
|
||||
|
||||
.menu-arrow {
|
||||
font-size: 16px;
|
||||
color: #667085;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.menu-divider {
|
||||
height: 1px;
|
||||
background-color: #E3E7ED;
|
||||
}
|
||||
|
||||
.switch-label-wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
padding-right: 12px;
|
||||
}
|
||||
|
||||
.cell-label {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #101828;
|
||||
}
|
||||
|
||||
.cell-desc {
|
||||
.menu-subtitle {
|
||||
font-size: 12px;
|
||||
color: #667085;
|
||||
line-height: 1.4;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.cell-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 24px;
|
||||
}
|
||||
|
||||
.cell-arrow {
|
||||
font-size: 18px;
|
||||
color: #667085;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.setting-cell-switch {
|
||||
min-height: 52px;
|
||||
}
|
||||
|
||||
.switch-touch-area {
|
||||
min-width: 44px;
|
||||
min-height: 44px;
|
||||
@@ -756,26 +444,33 @@ onShow(() => {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.row-divider {
|
||||
height: 1px;
|
||||
background-color: #E3E7ED;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 4px;
|
||||
.quota-tip-row {
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
|
||||
/* Language Chips */
|
||||
.language-options {
|
||||
.quota-tip-text {
|
||||
font-size: 12px;
|
||||
color: #F04438;
|
||||
}
|
||||
|
||||
/* Language selector */
|
||||
.language-header {
|
||||
padding-top: 14px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.language-chip-list {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-top: 4px;
|
||||
padding-bottom: 14px;
|
||||
}
|
||||
|
||||
.language-chip {
|
||||
min-height: 44px;
|
||||
padding: 0 16px;
|
||||
border-radius: 12px;
|
||||
.lang-pill {
|
||||
min-height: 36px;
|
||||
padding: 0 14px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid #E3E7ED;
|
||||
background-color: #F7F8FA;
|
||||
display: flex;
|
||||
@@ -783,58 +478,62 @@ onShow(() => {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.language-chip-active {
|
||||
.lang-pill-active {
|
||||
border-color: #0B5CFF;
|
||||
background-color: #0B5CFF;
|
||||
}
|
||||
|
||||
.language-chip-text {
|
||||
font-size: 13px;
|
||||
.lang-pill-text {
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
color: #101828;
|
||||
}
|
||||
|
||||
.language-chip-text-active {
|
||||
.lang-pill-text-active {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
/* Logout wrap */
|
||||
.logout-wrap {
|
||||
/* Sign out button */
|
||||
.signout-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: 8px;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.logout-btn {
|
||||
.signout-btn {
|
||||
min-height: 44px;
|
||||
padding: 0 24px;
|
||||
padding: 0 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.logout-text {
|
||||
font-size: 14px;
|
||||
.signout-text {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: #667085;
|
||||
}
|
||||
|
||||
.error-banner {
|
||||
padding: 12px 16px;
|
||||
background-color: #F7F8FA;
|
||||
border: 1px solid #E3E7ED;
|
||||
border-radius: 12px;
|
||||
margin-bottom: 16px;
|
||||
.signout-btn:active {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.error-banner-text {
|
||||
font-size: 13px;
|
||||
.error-notice {
|
||||
padding: 10px 14px;
|
||||
background-color: #F7F8FA;
|
||||
border: 1px solid #E3E7ED;
|
||||
border-radius: 10px;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.error-notice-text {
|
||||
font-size: 12px;
|
||||
color: #667085;
|
||||
}
|
||||
|
||||
.bottom-spacer {
|
||||
height: calc(32px + var(--window-bottom, 0px) + env(safe-area-inset-bottom, 0px));
|
||||
.bottom-safe-space {
|
||||
height: calc(24px + var(--window-bottom, 0px) + env(safe-area-inset-bottom, 0px));
|
||||
}
|
||||
</style>
|
||||
|
||||
在新工单中引用
屏蔽一个用户