1048 lines
22 KiB
Vue
1048 lines
22 KiB
Vue
<template>
|
||
<view class="page today-page employee-page-shell">
|
||
<view class="brand-bar">
|
||
<view class="brand-left">
|
||
<image class="brand-logo" src="/static/brand-logo.png" mode="aspectFit" />
|
||
<text class="brand-name">银城员工端</text>
|
||
</view>
|
||
<view class="brand-bell" @click="openBuilding('消息通知')">
|
||
<uni-icons class="bell-icon" type="notification" size="28" color="#16191f" />
|
||
<view class="bell-dot" />
|
||
</view>
|
||
</view>
|
||
|
||
<view v-if="message" class="status-message">{{ message }}</view>
|
||
|
||
<view class="mentor-hero">
|
||
<view class="hero-copy">
|
||
<text class="hero-role">{{ positionProfile.value }}</text>
|
||
<text class="hero-title">{{ positionProfile.heroTitle }}</text>
|
||
<text class="hero-sub">有问题,随时问老师傅</text>
|
||
</view>
|
||
<view class="mentor-stage">
|
||
<view class="mentor-bubble">
|
||
<text>{{ mentorBubbleText }}</text>
|
||
</view>
|
||
<image class="mentor-image" src="/static/mentor-hifi.png" mode="aspectFit" />
|
||
</view>
|
||
</view>
|
||
|
||
<view class="ask-card employee-card">
|
||
<view class="voice-panel">
|
||
<button class="voice-primary" @click="goSop">
|
||
<view class="voice-emblem">
|
||
<text class="voice-mark">问</text>
|
||
</view>
|
||
<view class="voice-copy">
|
||
<text class="voice-title">问老师傅</text>
|
||
<text class="voice-desc">语音提问,快速解答</text>
|
||
</view>
|
||
</button>
|
||
<view class="voice-divider" />
|
||
<button class="voice-secondary" @click="goSop">
|
||
<view class="keyboard-mark">
|
||
<uni-icons class="keyboard-icon" type="chatboxes" size="24" color="#5d6571" />
|
||
</view>
|
||
<view class="voice-copy secondary-copy">
|
||
<text class="voice-title secondary-title">打字问</text>
|
||
<text class="voice-desc">输入问题获得解答</text>
|
||
</view>
|
||
</button>
|
||
</view>
|
||
|
||
<view class="mentor-chips">
|
||
<view class="chip-row">
|
||
<button
|
||
v-for="(item, index) in quickQuestions"
|
||
:key="item"
|
||
class="chip"
|
||
:class="`chip-${index}`"
|
||
@click="ask(item)"
|
||
>
|
||
<uni-icons
|
||
class="chip-icon"
|
||
:type="chipIcon(index)"
|
||
size="22"
|
||
color="#e70014"
|
||
/>
|
||
<text class="chip-text">{{ item }}</text>
|
||
<text class="chip-arrow">›</text>
|
||
</button>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="section-card employee-card login-section" v-if="!loggedIn">
|
||
<view class="login-copy">
|
||
<text class="login-title">登录后查看今日安排</text>
|
||
<text class="login-desc">训练任务、复习提醒和成长数据会按你的手机号展示。</text>
|
||
</view>
|
||
<button class="primary-button login-button" @click="goLogin">去登录</button>
|
||
</view>
|
||
|
||
<view class="section-card employee-card schedule-card" v-else-if="hasSchedule">
|
||
<view class="section-head">
|
||
<view class="section-title">
|
||
<view class="section-bar" />
|
||
<text>今日安排</text>
|
||
</view>
|
||
<button class="section-link" @click="openTool('刻意练习')">
|
||
<text>{{ scheduleCountLabel }}</text>
|
||
<text class="section-link-arrow">›</text>
|
||
</button>
|
||
</view>
|
||
|
||
<view class="schedule-list">
|
||
<view class="schedule-row" v-if="primaryScheduleTitle">
|
||
<view class="schedule-icon-wrap">
|
||
<uni-icons class="schedule-icon" type="compose" size="26" color="#e70014" />
|
||
</view>
|
||
<view class="schedule-copy">
|
||
<text class="schedule-title">{{ primaryScheduleTitle }}</text>
|
||
<view class="schedule-meta">
|
||
<text class="meta-item"><uni-icons type="calendar" size="15" color="#8a8d93" /> {{ primaryScheduleTime }}</text>
|
||
<text class="meta-dot">·</text>
|
||
<text class="meta-item"><uni-icons type="location" size="15" color="#8a8d93" /> {{ primarySchedulePlace }}</text>
|
||
</view>
|
||
<text class="schedule-desc">{{ primaryScheduleDesc }}</text>
|
||
</view>
|
||
<button class="schedule-action" @click="openPrimarySchedule">开始</button>
|
||
</view>
|
||
|
||
<view class="schedule-row" v-if="home?.review">
|
||
<view class="schedule-icon-wrap review-icon">
|
||
<uni-icons class="schedule-icon" type="calendar-filled" size="26" color="#d98200" />
|
||
</view>
|
||
<view class="schedule-copy">
|
||
<text class="schedule-title">{{ home?.review?.title }}</text>
|
||
<view class="schedule-meta">
|
||
<text class="meta-item"><uni-icons type="calendar" size="15" color="#8a8d93" /> 今日</text>
|
||
<text class="meta-dot">·</text>
|
||
<text class="meta-item"><uni-icons type="location" size="15" color="#8a8d93" /> 线上复习</text>
|
||
</view>
|
||
<text class="schedule-desc">{{ home?.review?.desc }}</text>
|
||
</view>
|
||
<button class="schedule-action review-action" @click="ask(home?.review?.title || '岗前SOP复习')">去复习</button>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="section-card employee-card map-card">
|
||
<view class="section-head">
|
||
<view class="section-title">
|
||
<view class="section-bar" />
|
||
<text>我的地图</text>
|
||
</view>
|
||
</view>
|
||
<view class="map-grid">
|
||
<button
|
||
v-for="tile in mapTiles"
|
||
:key="tile.title"
|
||
class="map-tile"
|
||
:class="tile.tone"
|
||
@click="openTool(tile.title)"
|
||
>
|
||
<view class="map-symbol" :class="tile.tone">
|
||
<text>{{ tile.shortTitle }}</text>
|
||
</view>
|
||
<view class="map-copy">
|
||
<text class="map-title">{{ tile.title }}</text>
|
||
<text class="map-desc">{{ tile.desc }}</text>
|
||
</view>
|
||
<text class="map-arrow">›</text>
|
||
</button>
|
||
</view>
|
||
<button class="tip-card" @click="ask(primaryTipQuestion)">
|
||
<uni-icons class="tip-mark" type="help" size="22" color="#d98200" />
|
||
<text class="tip-label">小贴士</text>
|
||
<text class="tip-divider">|</text>
|
||
<text class="tip-text">{{ tipBody }}</text>
|
||
<text class="tip-arrow">›</text>
|
||
</button>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { computed, ref } from 'vue';
|
||
import { onShow } from '@dcloudio/uni-app';
|
||
import type { PracticeAssignment, RoleHome } from '@/types/api';
|
||
import { getMobileHome } from '@/services/home';
|
||
import { getPracticeAssignments } from '@/services/practice';
|
||
import { getSelectedPositionProfile, isLoggedIn, rememberLoginRedirect } from '@/services/auth';
|
||
import { resetPageScroll } from '@/services/navigation';
|
||
import { ensureEmployeePosition } from '@/services/position';
|
||
|
||
const home = ref<RoleHome | null>(null);
|
||
const assignments = ref<PracticeAssignment[]>([]);
|
||
const message = ref('');
|
||
const loggedIn = ref(false);
|
||
const positionProfile = ref(getSelectedPositionProfile());
|
||
const quickQuestions = computed(() => positionProfile.value.quickQuestions);
|
||
const primaryTipQuestion = computed(() => quickQuestions.value[0] || '岗位SOP');
|
||
const pendingSopQueryKey = 'aihr_sop_pending_query';
|
||
const pendingAssignmentKey = 'aihr_pending_assignment_id';
|
||
|
||
const chipIcons = ['chatbubble', 'help', 'wallet'];
|
||
const chipIcon = (index: number) => chipIcons[index] || 'chatbubble';
|
||
|
||
const mapTiles = computed(() => [
|
||
{
|
||
title: '问老师傅',
|
||
shortTitle: '问',
|
||
desc: '随时提问\n快速解决问题',
|
||
tone: 'ask'
|
||
},
|
||
{
|
||
title: '刻意练习',
|
||
shortTitle: '练',
|
||
desc: '情景演练\n提升服务能力',
|
||
tone: 'practice'
|
||
},
|
||
{
|
||
title: '学习中心',
|
||
shortTitle: '学',
|
||
desc: '课程学习\n掌握专业知识',
|
||
tone: 'learn'
|
||
},
|
||
{
|
||
title: '工作上报',
|
||
shortTitle: '报',
|
||
desc: '日报/任务/问题\n及时上报反馈',
|
||
tone: 'report'
|
||
}
|
||
]);
|
||
|
||
const primaryAssignment = computed(() =>
|
||
assignments.value.find((item) => item.status === '待训练' && item.source !== 'daily')
|
||
|| assignments.value.find((item) => item.status === '待训练')
|
||
|| null
|
||
);
|
||
|
||
const hasSchedule = computed(() => Boolean(primaryAssignment.value || home.value?.primary || home.value?.review));
|
||
|
||
const scheduleCount = computed(() => {
|
||
let count = 0;
|
||
if (primaryAssignment.value || home.value?.primary) count += 1;
|
||
if (home.value?.review) count += 1;
|
||
return count;
|
||
});
|
||
|
||
const scheduleCountLabel = computed(() => `${scheduleCount.value || 1} 项任务`);
|
||
|
||
const primaryScheduleTitle = computed(() => {
|
||
const item = primaryAssignment.value;
|
||
if (item) {
|
||
return item.source === 'daily'
|
||
? (item.question || item.scenarioName || '每日三题')
|
||
: (item.scenarioName || item.question || '专项训练');
|
||
}
|
||
if (home.value?.primary?.title) {
|
||
return home.value.primary.title.replace('三角色对练', '').replace('重点训练', '专项练习').trim() || '场景练习';
|
||
}
|
||
return '';
|
||
});
|
||
|
||
const primaryScheduleDesc = computed(() => {
|
||
const item = primaryAssignment.value;
|
||
if (item) {
|
||
if (item.source === 'daily') return '提交后显示反馈与参考答案';
|
||
return item.reason || '学习投诉处理全流程与沟通话术';
|
||
}
|
||
return home.value?.primary?.desc || '进入练习页查看今日任务';
|
||
});
|
||
|
||
const primaryScheduleTime = computed(() => {
|
||
const item = primaryAssignment.value;
|
||
if (item?.source === 'daily') return '今日';
|
||
return '09:30-11:30';
|
||
});
|
||
|
||
const primarySchedulePlace = computed(() => {
|
||
const item = primaryAssignment.value;
|
||
if (item?.source === 'daily') return '线上答题';
|
||
return '线上学习';
|
||
});
|
||
|
||
const tipBody = computed(() => {
|
||
const tip = positionProfile.value.tip || '';
|
||
return tip.replace(/^今日小贴士[::]\s*/, '').replace(/^小贴士[::]\s*/, '') || tip;
|
||
});
|
||
|
||
const mentorBubbleText = computed(() => {
|
||
if (!loggedIn.value) return '登录后看今天任务';
|
||
if (primaryScheduleTitle.value) {
|
||
const topic = primaryScheduleTitle.value.replace(/专项|训练|练习/g, '').trim();
|
||
if (topic) return `今天先把${topic}练熟`;
|
||
}
|
||
return '今天先把投诉处理练熟';
|
||
});
|
||
|
||
const loadHome = async () => {
|
||
loggedIn.value = isLoggedIn();
|
||
positionProfile.value = getSelectedPositionProfile();
|
||
message.value = '';
|
||
assignments.value = [];
|
||
if (!loggedIn.value) {
|
||
home.value = null;
|
||
return;
|
||
}
|
||
if (!(await ensureEmployeePosition('/pages/user/today/index'))) {
|
||
return;
|
||
}
|
||
positionProfile.value = getSelectedPositionProfile();
|
||
const [homeResult, assignmentResult] = await Promise.allSettled([
|
||
getMobileHome('user'),
|
||
getPracticeAssignments(true)
|
||
]);
|
||
if (homeResult.status === 'fulfilled') {
|
||
home.value = homeResult.value;
|
||
} else {
|
||
home.value = null;
|
||
message.value = homeResult.reason instanceof Error ? homeResult.reason.message : '首页数据加载失败';
|
||
}
|
||
if (assignmentResult.status === 'fulfilled') {
|
||
assignments.value = assignmentResult.value;
|
||
} else {
|
||
loggedIn.value = isLoggedIn();
|
||
if (!loggedIn.value) {
|
||
home.value = null;
|
||
message.value = '登录已过期,请重新登录';
|
||
return;
|
||
}
|
||
message.value = assignmentResult.reason instanceof Error ? assignmentResult.reason.message : '今日任务加载失败';
|
||
}
|
||
};
|
||
|
||
const goSop = () => {
|
||
uni.switchTab({ url: '/pages/user/sop/index' });
|
||
};
|
||
|
||
const ask = (query: string) => {
|
||
uni.setStorageSync(pendingSopQueryKey, query);
|
||
uni.switchTab({ url: '/pages/user/sop/index' });
|
||
};
|
||
|
||
const goLogin = () => {
|
||
rememberLoginRedirect('/pages/user/today/index');
|
||
uni.navigateTo({ url: '/pages/auth/login/index' });
|
||
};
|
||
|
||
const openPrimarySchedule = () => {
|
||
if (primaryAssignment.value) {
|
||
uni.setStorageSync(pendingAssignmentKey, String(primaryAssignment.value.id));
|
||
}
|
||
uni.switchTab({ url: '/pages/user/practice/index' });
|
||
};
|
||
|
||
const openBuilding = (title: string) => {
|
||
uni.navigateTo({ url: `/pages/common/building/index?title=${encodeURIComponent(title)}` });
|
||
};
|
||
|
||
const openTool = (title: string) => {
|
||
if (title.includes('问') || title.includes('SOP') || title.includes('sop')) {
|
||
goSop();
|
||
return;
|
||
}
|
||
if (title.includes('练') || title.includes('训练') || title.includes('开始')) {
|
||
uni.switchTab({ url: '/pages/user/practice/index' });
|
||
return;
|
||
}
|
||
if (title.includes('学') || title.includes('案例学习')) {
|
||
uni.navigateTo({ url: '/pages/user/learning/index' });
|
||
return;
|
||
}
|
||
if (title.includes('案例') || title.includes('素材') || title.includes('提交')) {
|
||
uni.navigateTo({ url: '/pages/user/cases/index' });
|
||
return;
|
||
}
|
||
openBuilding(title);
|
||
};
|
||
|
||
onShow(() => {
|
||
resetPageScroll();
|
||
void loadHome();
|
||
});
|
||
</script>
|
||
|
||
<style scoped>
|
||
.today-page {
|
||
min-height: 100vh;
|
||
padding: 0 24px 112px;
|
||
background: linear-gradient(180deg, #ffffff 0%, #fbfbfb 62%, #f6f6f6 100%);
|
||
}
|
||
|
||
.brand-bar {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: calc(env(safe-area-inset-top) + 20px) 2px 10px;
|
||
}
|
||
|
||
.brand-left {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
}
|
||
|
||
.brand-logo {
|
||
width: 34px;
|
||
height: 34px;
|
||
}
|
||
|
||
.brand-name {
|
||
color: #1a1a1a;
|
||
font-size: 20px;
|
||
font-weight: 800;
|
||
letter-spacing: 0.02em;
|
||
}
|
||
|
||
.brand-bell {
|
||
position: relative;
|
||
display: flex;
|
||
width: 42px;
|
||
height: 42px;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.bell-icon {
|
||
line-height: 1;
|
||
}
|
||
|
||
.bell-dot {
|
||
position: absolute;
|
||
top: 6px;
|
||
right: 7px;
|
||
width: 8px;
|
||
height: 8px;
|
||
border: 1.5px solid #f5f5f6;
|
||
border-radius: 50%;
|
||
background: #e70014;
|
||
}
|
||
|
||
.status-message {
|
||
margin: 4px 0 8px;
|
||
padding: 10px 12px;
|
||
border-radius: 12px;
|
||
background: #fff4f4;
|
||
color: #c01222;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.mentor-hero {
|
||
position: relative;
|
||
display: flex;
|
||
min-height: 232px;
|
||
align-items: flex-start;
|
||
justify-content: space-between;
|
||
margin-top: 2px;
|
||
padding: 6px 0 0;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.hero-copy {
|
||
position: relative;
|
||
z-index: 2;
|
||
display: flex;
|
||
max-width: 45%;
|
||
flex-direction: column;
|
||
padding-top: 11px;
|
||
}
|
||
|
||
.hero-role,
|
||
.hero-title {
|
||
color: #111111;
|
||
font-size: 42px;
|
||
font-weight: 900;
|
||
line-height: 1.12;
|
||
letter-spacing: 0;
|
||
}
|
||
|
||
.hero-sub {
|
||
margin-top: 18px;
|
||
color: #8a8d93;
|
||
font-size: 17px;
|
||
white-space: nowrap;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
.mentor-stage {
|
||
position: relative;
|
||
z-index: 1;
|
||
width: 240px;
|
||
height: 227px;
|
||
flex: none;
|
||
}
|
||
|
||
.mentor-image {
|
||
position: absolute;
|
||
right: -20px;
|
||
bottom: 0;
|
||
width: 240px;
|
||
height: 240px;
|
||
transform: translateY(50px);
|
||
filter: drop-shadow(0 10px 16px rgba(20, 24, 32, 0.12));
|
||
}
|
||
|
||
.mentor-bubble {
|
||
position: absolute;
|
||
top: 38px;
|
||
right: 130px;
|
||
z-index: 3;
|
||
width: 112px;
|
||
padding: 10px 12px;
|
||
border-radius: 18px;
|
||
background: #ffffff;
|
||
box-shadow: 0 8px 20px rgba(20, 24, 32, 0.1);
|
||
}
|
||
|
||
.mentor-bubble::after {
|
||
position: absolute;
|
||
right: -6px;
|
||
bottom: 18px;
|
||
width: 12px;
|
||
height: 12px;
|
||
border-radius: 2px;
|
||
background: #ffffff;
|
||
content: '';
|
||
transform: rotate(45deg);
|
||
}
|
||
|
||
.mentor-bubble text {
|
||
color: #33363c;
|
||
font-size: 15px;
|
||
font-weight: 600;
|
||
line-height: 1.45;
|
||
}
|
||
|
||
.ask-card {
|
||
position: relative;
|
||
z-index: 4;
|
||
margin-top: 0;
|
||
padding: 16px 14px 25px;
|
||
border: 0;
|
||
border-radius: 20px;
|
||
background: #ffffff;
|
||
box-shadow: 0 10px 28px rgba(24, 28, 36, 0.06);
|
||
}
|
||
|
||
.voice-panel {
|
||
display: flex;
|
||
align-items: center;
|
||
min-height: 82px;
|
||
gap: 2px;
|
||
transform: translateY(7px);
|
||
}
|
||
|
||
.voice-primary,
|
||
.voice-secondary {
|
||
display: flex;
|
||
min-width: 0;
|
||
align-items: center;
|
||
margin: 0;
|
||
border: 0;
|
||
border-radius: 0;
|
||
background: transparent;
|
||
box-shadow: none;
|
||
text-align: left;
|
||
}
|
||
|
||
.voice-primary::after,
|
||
.voice-secondary::after {
|
||
border: 0;
|
||
}
|
||
|
||
.voice-primary {
|
||
flex: 1.7;
|
||
gap: 20px;
|
||
padding: 0 8px 0 14px;
|
||
}
|
||
|
||
.voice-secondary {
|
||
flex: 1;
|
||
gap: 10px;
|
||
padding: 0 2px 0 16px;
|
||
}
|
||
|
||
.voice-divider {
|
||
width: 1px;
|
||
height: 42px;
|
||
flex: none;
|
||
background: #ececee;
|
||
}
|
||
|
||
.voice-emblem {
|
||
display: flex;
|
||
width: 80px;
|
||
height: 80px;
|
||
flex: none;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border-radius: 50%;
|
||
background: #e70014;
|
||
box-shadow: 0 0 0 8px #fff1f2, 0 8px 16px rgba(231, 0, 20, 0.22);
|
||
}
|
||
|
||
.voice-mark {
|
||
color: #ffffff;
|
||
font-size: 24px;
|
||
font-weight: 900;
|
||
line-height: 1;
|
||
}
|
||
|
||
.voice-copy {
|
||
display: flex;
|
||
min-width: 0;
|
||
flex-direction: column;
|
||
gap: 4px;
|
||
}
|
||
|
||
.voice-title {
|
||
color: #1a1a1a;
|
||
font-size: 18px;
|
||
font-weight: 800;
|
||
line-height: 1.2;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.secondary-title {
|
||
font-size: 18px;
|
||
}
|
||
|
||
.voice-desc {
|
||
color: #9a9da3;
|
||
font-size: 12px;
|
||
font-weight: 500;
|
||
line-height: 1.3;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.secondary-copy {
|
||
max-width: 108px;
|
||
}
|
||
|
||
.secondary-copy .voice-desc {
|
||
width: 96px;
|
||
white-space: normal;
|
||
line-height: 1.45;
|
||
}
|
||
|
||
.keyboard-mark {
|
||
display: flex;
|
||
width: 40px;
|
||
height: 40px;
|
||
flex: none;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border-radius: 50%;
|
||
background: #f3f4f6;
|
||
}
|
||
|
||
.keyboard-icon {
|
||
color: #6b7280;
|
||
line-height: 1;
|
||
}
|
||
|
||
.mentor-chips {
|
||
margin-top: 14px;
|
||
padding-top: 12px;
|
||
border-top: 1px solid #f0f1f3;
|
||
}
|
||
|
||
.chip-row {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||
gap: 8px;
|
||
padding: 0 10px;
|
||
}
|
||
|
||
.chip {
|
||
display: flex;
|
||
width: 100%;
|
||
min-height: 40px;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 4px;
|
||
padding: 0 6px;
|
||
border: 1px solid #ececee;
|
||
border-radius: 12px;
|
||
background: #ffffff;
|
||
color: #e70014;
|
||
font-size: 13px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.chip-icon {
|
||
font-size: 13px;
|
||
line-height: 1;
|
||
}
|
||
|
||
.chip-text {
|
||
max-width: 4.5em;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.chip-arrow {
|
||
color: #f0717c;
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.section-card {
|
||
margin-top: 12px;
|
||
padding: 22px 18px;
|
||
border: 0;
|
||
border-radius: 22px;
|
||
background: #ffffff;
|
||
box-shadow: 0 8px 24px rgba(24, 28, 36, 0.05);
|
||
}
|
||
|
||
.login-section {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 12px;
|
||
}
|
||
|
||
.login-copy {
|
||
min-width: 0;
|
||
flex: 1;
|
||
}
|
||
|
||
.login-title,
|
||
.login-desc {
|
||
display: block;
|
||
}
|
||
|
||
.login-title {
|
||
color: #1a1a1a;
|
||
font-size: 16px;
|
||
font-weight: 800;
|
||
}
|
||
|
||
.login-desc {
|
||
margin-top: 6px;
|
||
color: #8a8d93;
|
||
font-size: 13px;
|
||
line-height: 1.45;
|
||
}
|
||
|
||
.login-button {
|
||
width: 88px;
|
||
min-width: 88px;
|
||
min-height: 42px;
|
||
flex: 0 0 88px;
|
||
border-radius: 12px;
|
||
background: #e70014;
|
||
color: #ffffff;
|
||
font-size: 15px;
|
||
font-weight: 800;
|
||
box-shadow: 0 8px 16px rgba(231, 0, 20, 0.18);
|
||
}
|
||
|
||
.section-head {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.section-title {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
color: #1a1a1a;
|
||
font-size: 22px;
|
||
font-weight: 800;
|
||
}
|
||
|
||
.section-bar {
|
||
width: 4px;
|
||
height: 22px;
|
||
border-radius: 2px;
|
||
background: #e70014;
|
||
}
|
||
|
||
.section-link {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 2px;
|
||
color: #9a9da3;
|
||
font-size: 13px;
|
||
font-weight: 600;
|
||
background: transparent;
|
||
}
|
||
|
||
.section-link-arrow {
|
||
font-size: 15px;
|
||
color: #b0b3b8;
|
||
}
|
||
|
||
.schedule-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 10px;
|
||
}
|
||
|
||
.schedule-row {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 16px;
|
||
padding: 4px 0;
|
||
}
|
||
|
||
.schedule-icon-wrap {
|
||
display: flex;
|
||
width: 60px;
|
||
height: 60px;
|
||
flex: none;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border-radius: 50%;
|
||
background: #fff1f1;
|
||
}
|
||
|
||
.review-icon {
|
||
background: #fff7eb;
|
||
}
|
||
|
||
.schedule-icon {
|
||
line-height: 1;
|
||
}
|
||
|
||
.schedule-copy {
|
||
display: flex;
|
||
min-width: 0;
|
||
flex: 1;
|
||
flex-direction: column;
|
||
gap: 4px;
|
||
}
|
||
|
||
.schedule-title {
|
||
color: #1a1a1a;
|
||
font-size: 19px;
|
||
font-weight: 800;
|
||
line-height: 1.25;
|
||
}
|
||
|
||
.schedule-meta {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
align-items: center;
|
||
gap: 4px;
|
||
color: #9a9da3;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.meta-dot {
|
||
color: #c5c7cb;
|
||
}
|
||
|
||
.schedule-desc {
|
||
color: #8a8d93;
|
||
font-size: 14px;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
.schedule-action {
|
||
display: flex;
|
||
width: 86px;
|
||
min-height: 52px;
|
||
flex: none;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border-radius: 12px;
|
||
background: #e70014;
|
||
box-shadow: 0 8px 16px rgba(231, 0, 20, 0.18);
|
||
color: #ffffff;
|
||
font-size: 18px;
|
||
font-weight: 800;
|
||
}
|
||
|
||
.review-action {
|
||
background: #d98200;
|
||
box-shadow: 0 8px 16px rgba(217, 130, 0, 0.16);
|
||
}
|
||
|
||
.map-grid {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 10px;
|
||
}
|
||
|
||
.map-tile {
|
||
display: flex;
|
||
min-height: 108px;
|
||
align-items: center;
|
||
gap: 10px;
|
||
padding: 16px 14px;
|
||
border: 1px solid #f0f1f3;
|
||
border-radius: 16px;
|
||
background: #ffffff;
|
||
text-align: left;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.map-symbol {
|
||
display: flex;
|
||
width: 56px;
|
||
height: 56px;
|
||
flex: none;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border-radius: 50%;
|
||
color: #ffffff;
|
||
font-size: 24px;
|
||
font-weight: 900;
|
||
}
|
||
|
||
.map-symbol.ask {
|
||
background: #e70014;
|
||
box-shadow: 0 6px 12px rgba(231, 0, 20, 0.2);
|
||
}
|
||
|
||
.map-symbol.practice {
|
||
background: #1f9a4a;
|
||
box-shadow: 0 6px 12px rgba(31, 154, 74, 0.2);
|
||
}
|
||
|
||
.map-symbol.learn {
|
||
background: #e8900c;
|
||
box-shadow: 0 6px 12px rgba(232, 144, 12, 0.2);
|
||
}
|
||
|
||
.map-symbol.report {
|
||
background: #4b5563;
|
||
box-shadow: 0 6px 12px rgba(75, 85, 99, 0.18);
|
||
}
|
||
|
||
.map-copy {
|
||
display: flex;
|
||
min-width: 0;
|
||
flex: 1;
|
||
flex-direction: column;
|
||
gap: 2px;
|
||
}
|
||
|
||
.map-title {
|
||
color: #1a1a1a;
|
||
font-size: 18px;
|
||
font-weight: 800;
|
||
line-height: 1.2;
|
||
}
|
||
|
||
.map-desc {
|
||
color: #9a9da3;
|
||
font-size: 13px;
|
||
line-height: 1.35;
|
||
white-space: pre-line;
|
||
}
|
||
|
||
.map-arrow {
|
||
color: #c5c7cb;
|
||
font-size: 18px;
|
||
flex: none;
|
||
}
|
||
|
||
.tip-card {
|
||
display: flex;
|
||
margin-top: 18px;
|
||
min-height: 58px;
|
||
align-items: center;
|
||
gap: 6px;
|
||
padding: 14px 16px;
|
||
border: 0;
|
||
border-radius: 14px;
|
||
background: #fff6e8;
|
||
box-shadow: none;
|
||
text-align: left;
|
||
}
|
||
|
||
.tip-mark {
|
||
flex: none;
|
||
line-height: 1;
|
||
}
|
||
|
||
.tip-label {
|
||
flex: none;
|
||
color: #b07000;
|
||
font-size: 15px;
|
||
font-weight: 800;
|
||
}
|
||
|
||
.tip-divider {
|
||
flex: none;
|
||
margin: 0 2px;
|
||
color: #e0c08a;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.tip-text {
|
||
min-width: 0;
|
||
flex: 1;
|
||
overflow: hidden;
|
||
color: #8a5a12;
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
line-height: 1.4;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.tip-arrow {
|
||
flex: none;
|
||
color: #c9a46a;
|
||
font-size: 16px;
|
||
}
|
||
|
||
@media (max-width: 360px) {
|
||
.hero-role,
|
||
.hero-title {
|
||
font-size: 28px;
|
||
}
|
||
|
||
.mentor-stage {
|
||
width: 140px;
|
||
height: 150px;
|
||
}
|
||
|
||
.mentor-image {
|
||
width: 128px;
|
||
height: 150px;
|
||
}
|
||
|
||
.mentor-bubble {
|
||
right: 92px;
|
||
width: 96px;
|
||
padding: 8px 10px;
|
||
}
|
||
|
||
.voice-title {
|
||
font-size: 16px;
|
||
}
|
||
|
||
.secondary-title {
|
||
font-size: 14px;
|
||
}
|
||
|
||
.voice-desc {
|
||
font-size: 11px;
|
||
}
|
||
|
||
.chip-text {
|
||
max-width: 3.8em;
|
||
font-size: 12px;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 400px) {
|
||
.chip-row {
|
||
padding-right: 0;
|
||
padding-left: 0;
|
||
}
|
||
}
|
||
</style>
|