- 增加团队概览组件数据绑定逻辑 - 实现统计指标组件数据获取与展示 - 更新API接口调用和数据处理逻辑 - 调整超时时间为30秒以适应网络环境 - 添加调试日志用于问题排查
1887 lines
44 KiB
Vue
1887 lines
44 KiB
Vue
<template>
|
||
<div class="sales-dashboard">
|
||
<!-- 悬浮待办组件 -->
|
||
<FloatingTodo />
|
||
<!-- 顶部导航栏 -->
|
||
<!-- 数据分析区域 - 独立占据整行 -->
|
||
<section class="analytics-section-full">
|
||
<div class="section-header">
|
||
<h1 class="app-title">销售驾驶舱</h1>
|
||
<div
|
||
class="quick-stats"
|
||
style="display: flex; align-items: center; gap: 30px"
|
||
>
|
||
<div
|
||
v-for="(stat, key) in MOCK_DATA.performance"
|
||
:key="key"
|
||
class="quick-stat-item"
|
||
>
|
||
<div class="stat-label">
|
||
{{ stat.label + ":" + stat.value.toLocaleString() }}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<UserDropdown />
|
||
</div>
|
||
<div class="section-content">
|
||
<PersonalDashboard
|
||
:kpi-data="kpiData"
|
||
:funnel-data="funnelData"
|
||
:contact-time-data="contactTimeData"
|
||
:statistics-data="statisticsData"
|
||
:urgent-problem-data="urgentProblemData"
|
||
/>
|
||
</div>
|
||
</section>
|
||
<!-- 销售时间线区域 -->
|
||
<section class="timeline-section">
|
||
<div class="section-header">
|
||
<h2>销售时间线</h2>
|
||
<p class="section-subtitle">客户转化全流程跟踪</p>
|
||
</div>
|
||
<div class="section-content">
|
||
<SalesTimelineWithTaskList
|
||
:data="timelineData"
|
||
@stage-select="handleStageSelect"
|
||
:selected-stage="selectedStage"
|
||
:contacts="filteredContacts"
|
||
:selected-contact-id="selectedContactId"
|
||
:course-customers="courseCustomers"
|
||
:kpi-data="kpiData"
|
||
@select-contact="selectContact" />
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 原始数据卡片区域 -->
|
||
<section class="raw-data-section">
|
||
<div class="section-header">
|
||
<h2>原始数据</h2>
|
||
<p class="section-subtitle">客户互动的原始记录和数据</p>
|
||
</div>
|
||
<div class="section-content">
|
||
<RawDataCards
|
||
:selected-contact="selectedContact"
|
||
@view-form-data="handleViewFormData"
|
||
@view-chat-data="handleViewChatData"
|
||
@view-call-data="handleViewCallData" />
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 主要内容区域 -->
|
||
<div class="main-layout">
|
||
<!-- 主要工作区域 -->
|
||
<main class="main-content">
|
||
<!-- 客户详情区域 -->
|
||
<section class="detail-section">
|
||
<div class="section-header">
|
||
<h2>客户详情</h2>
|
||
</div>
|
||
<div class="section-content">
|
||
<CustomerDetail :selected-contact="selectedContact" />
|
||
</div>
|
||
</section>
|
||
</main>
|
||
</div>
|
||
|
||
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, reactive, computed, onMounted, nextTick } from "vue";
|
||
import { useRouter } from "vue-router";
|
||
import { useUserStore } from "@/stores/user";
|
||
import http from "@/utils/https";
|
||
import CustomerDetail from "./components/CustomerDetail.vue";
|
||
import PersonalDashboard from "./components/PersonalDashboard.vue";
|
||
import SalesTimelineWithTaskList from "./components/SalesTimelineWithTaskList.vue";
|
||
import RawDataCards from "./components/RawDataCards.vue";
|
||
import FloatingTodo from "./components/FloatingTodo.vue";
|
||
import Header from "@/components/header.vue";
|
||
import UserDropdown from "@/components/UserDropdown.vue";
|
||
import {getCustomerAttendance,getTodayCall,getProblemDistribution,getTableFillingRate,getAverageResponseTime,getWeeklyActiveCommunicationRate,getTimeoutResponseRate,getCustomerCallInfo,getCustomerChatInfo,getCustomerFormInfo,getConversionRateAndAllocatedData} from "@/api/api.js"
|
||
|
||
// 路由实例
|
||
const router = useRouter();
|
||
|
||
// 用户store
|
||
const userStore = useUserStore();
|
||
// STATE
|
||
const selectedContactId = ref(null);
|
||
const contextPanelRef = ref(null);
|
||
const selectedStage = ref('全部'); // 选中的销售阶段
|
||
const problemDistributionData = ref(null); // 问题分布数据
|
||
const isLoadingProblemData = ref(false); // 加载状态
|
||
|
||
// KPI数据
|
||
const kpiDataState = reactive({
|
||
totalCalls: 85,
|
||
successRate: 28,
|
||
avgDuration: 125,
|
||
conversionRate: 12,
|
||
assignedData: 256,
|
||
wechatAddRate: 68
|
||
});
|
||
|
||
// 统计指标数据
|
||
const statisticsData = reactive({
|
||
customerCommunicationRate: 0,
|
||
averageResponseTime: 0,
|
||
timeoutResponseRate: 0,
|
||
severeTimeoutRate: 0,
|
||
formCompletionRate: 0
|
||
});
|
||
|
||
// 客户迫切解决的问题数据
|
||
const urgentProblemData = ref([]);
|
||
|
||
// 时间线数据
|
||
const timelineData = ref({});
|
||
|
||
// 客户列表数据
|
||
const customersList = ref({});
|
||
|
||
// 课程客户数据(课1-4)
|
||
const courseCustomers = ref({});
|
||
|
||
// MOCK DATA (Should ideally come from a store or API)
|
||
const MOCK_DATA = reactive({
|
||
contacts: [
|
||
// 今日必须联系 (high priority) - 12个任务
|
||
{
|
||
id: 1,
|
||
name: "王女士",
|
||
time: "今日 10:00",
|
||
}
|
||
],
|
||
performance: {
|
||
calls: { label: "呼叫量", value: 85, target: 100 },
|
||
talkTime: { label: "通话时长(分)", value: 125, target: 180 },
|
||
revenue: { label: "签单额(元)", value: 8500, target: 15000 },
|
||
},
|
||
personalKPIs: {
|
||
winRate: { label: "赢率", value: 28, unit: "%" },
|
||
avgDealSize: { label: "平均客单价", value: 12500, unit: "元" },
|
||
salesCycle: { label: "销售周期", value: 45, unit: "天" },
|
||
},
|
||
personalFunnel: [200, 150, 90, 40, 12],
|
||
commission: { confirmed: 4250, estimated: 7800, nextDealValue: 350 },
|
||
contactTimeAnalysis: {
|
||
labels: ["9-10点", "10-11点", "11-12点", "14-15点", "15-16点", "16-17点"],
|
||
data: [65, 85, 80, 92, 75, 60],
|
||
description: "基于历史通话数据统计的客户接听成功率",
|
||
},
|
||
});
|
||
// 核心Kpi
|
||
async function getCoreKpi() {
|
||
console.log('userStore.userInfo.user_level', userStore.userInfo)
|
||
const params = {
|
||
user_level: userStore.userInfo.user_level.toString(),
|
||
user_name: userStore.userInfo.username
|
||
}
|
||
// 今日通话
|
||
const res = await getTodayCall(params)
|
||
if (res.code === 200) {
|
||
kpiDataState.totalCalls = res.data.today_call
|
||
}
|
||
// 转化率、分配数据量、加微率
|
||
const conversionRes = await getConversionRateAndAllocatedData(params)
|
||
if (conversionRes.code === 200) {
|
||
kpiDataState.conversionRate = conversionRes.data.conversion_rate || 0
|
||
kpiDataState.assignedData = conversionRes.data.all_count || 0
|
||
kpiDataState.wechatAddRate = conversionRes.data.plus_v_conversion_rate || 0
|
||
}
|
||
}
|
||
|
||
// 获取统计数据
|
||
async function getStatisticsData() {
|
||
const params = {
|
||
user_level: userStore.userInfo.user_level.toString(),
|
||
user_name: userStore.userInfo.username
|
||
}
|
||
|
||
try {
|
||
// 获取表单填写率
|
||
const fillingRateRes = await getTableFillingRate(params)
|
||
if (fillingRateRes.code === 200) {
|
||
statisticsData.formCompletionRate = fillingRateRes.data.filling_rate
|
||
}
|
||
|
||
// 获取平均响应时间
|
||
const avgResponseRes = await getAverageResponseTime(params)
|
||
if (avgResponseRes.code === 200) {
|
||
statisticsData.averageResponseTime = avgResponseRes.data.average_minutes
|
||
}
|
||
|
||
// 获取客户沟通率
|
||
const communicationRes = await getWeeklyActiveCommunicationRate(params)
|
||
if (communicationRes.code === 200) {
|
||
statisticsData.customerCommunicationRate = communicationRes.data.communication_rate
|
||
}
|
||
|
||
// 获取超时响应率
|
||
const timeoutRes = await getTimeoutResponseRate(params)
|
||
if (timeoutRes.code === 200) {
|
||
statisticsData.timeoutResponseRate = timeoutRes.data.overtime_rate_600
|
||
statisticsData.severeTimeoutRate = timeoutRes.data.overtime_rate_800
|
||
}
|
||
} catch (error) {
|
||
console.error('获取统计数据失败:', error)
|
||
}
|
||
}
|
||
// 客户迫切解决的问题
|
||
async function getUrgentProblem() {
|
||
const params = {
|
||
user_name: userStore.userInfo.username,
|
||
user_level: userStore.userInfo.user_level.toString(),
|
||
}
|
||
const res = await getProblemDistribution(params)
|
||
if(res.code === 200) {
|
||
// 将API返回的对象格式转换为数组格式
|
||
const problemDistribution = res.data.problem_distribution
|
||
urgentProblemData.value = Object.entries(problemDistribution).map(([name, percentage]) => ({
|
||
name: name,
|
||
value: parseInt(percentage.replace('%', '')) || 0
|
||
}))
|
||
}
|
||
}
|
||
|
||
// 时间线
|
||
async function getTimeline() {
|
||
const params = {
|
||
user_name: userStore.userInfo.username,
|
||
user_level: userStore.userInfo.user_level.toString(),
|
||
}
|
||
const res = await getCustomerAttendance(params)
|
||
if(res.code === 200) {
|
||
timelineData.value = res.data.customers_count
|
||
|
||
// 处理客户列表数据
|
||
if (res.data.customers_list) {
|
||
customersList.value = res.data.customers_list
|
||
|
||
// 将客户数据转换为统一格式的数组
|
||
const processedCustomers = []
|
||
|
||
Object.keys(res.data.customers_list).forEach(stage => {
|
||
const customers = res.data.customers_list[stage]
|
||
// 检查是否是课程数据(课1-4)
|
||
if (stage === '课1-4') {
|
||
// 单独处理课程客户数据
|
||
if (Array.isArray(customers)) {
|
||
courseCustomers.value[stage] = customers.map((customer, index) => {
|
||
const stableId = `${stage}_${customer.scrm_user_main_code || customer.weChat_nickname || 'unknown'}_${index}`.replace(/[^a-zA-Z0-9_\u4e00-\u9fa5]/g, '_')
|
||
|
||
return {
|
||
id: Math.abs(stableId.split('').reduce((a,b) => (((a << 5) - a) + b.charCodeAt(0))|0, 0)),
|
||
name: customer.weChat_nickname || customer.customer_name || '未知用户',
|
||
time: customer.records && customer.records.length > 0 ? customer.records[0].first_visit_time : '未知时间',
|
||
profession: customer.customer_occupation || '学员',
|
||
education: customer.customer_child_education || '未知',
|
||
avatar: customer.weChat_avatar ? customer.weChat_avatar.trim() : null,
|
||
salesStage: stage,
|
||
health: Math.floor(Math.random() * 100) + 1,
|
||
// 原始课程相关数据
|
||
customer_name: customer.customer_name,
|
||
customer_occupation: customer.customer_occupation,
|
||
customer_child_education: customer.customer_child_education,
|
||
scrm_user_main_code: customer.scrm_user_main_code,
|
||
weChat_avatar: customer.weChat_avatar,
|
||
class_situation: customer.class_situation,
|
||
records: customer.records
|
||
}
|
||
})
|
||
// 课程客户数据独立存储,不添加到总客户列表中
|
||
}
|
||
} else {
|
||
// 处理普通销售阶段数据
|
||
if (Array.isArray(customers)) {
|
||
customers.forEach((customer, index) => {
|
||
// 生成稳定的ID
|
||
const stableId = `${stage}_${customer.customer_name || 'unknown'}_${index}`.replace(/[^a-zA-Z0-9_\u4e00-\u9fa5]/g, '_')
|
||
|
||
processedCustomers.push({
|
||
id: Math.abs(stableId.split('').reduce((a,b) => (((a << 5) - a) + b.charCodeAt(0))|0, 0)),
|
||
name: customer.customer_name || '未知',
|
||
time: customer.format_update_time || '未知时间',
|
||
profession: customer.customer_occupation || '未知职业',
|
||
education: customer.customer_child_education || '未知学历',
|
||
avatar: customer.customer_avatar_url ? customer.customer_avatar_url.trim() : null,
|
||
salesStage: stage,
|
||
health: Math.floor(Math.random() * 100) + 1
|
||
})
|
||
})
|
||
}
|
||
}
|
||
})
|
||
|
||
console.log('课程客户数据 (courseCustomers):', courseCustomers.value)
|
||
console.log('所有处理后的客户 (processedCustomers):', processedCustomers)
|
||
console.log('原始客户列表数据 (customersList):', customersList.value)
|
||
|
||
// 更新 MOCK_DATA.contacts 为实际数据
|
||
MOCK_DATA.contacts = processedCustomers
|
||
}
|
||
}
|
||
}
|
||
// 获取客户表单
|
||
async function getCustomerForm() {
|
||
if (!selectedContact.value || !selectedContact.value.name) {
|
||
console.warn('无法获取客户表单:客户信息不完整');
|
||
return;
|
||
}
|
||
|
||
const params = {
|
||
user_name: userStore.userInfo.username,
|
||
customer_name: selectedContact.value.name,
|
||
}
|
||
|
||
console.log('获取客户表单参数:', params);
|
||
console.log('选中的客户信息:', selectedContact.value);
|
||
|
||
try {
|
||
const res = await getCustomerFormInfo(params)
|
||
console.log('客户表单API响应:', res)
|
||
if(res.code === 200) {
|
||
MOCK_DATA.formFields = res.data
|
||
console.log('客户表单数据已更新:', MOCK_DATA.formFields);
|
||
} else {
|
||
console.error('获取客户表单失败:', res.message || '未知错误');
|
||
}
|
||
} catch (error) {
|
||
console.error('获取客户表单请求失败:', error);
|
||
}
|
||
}
|
||
// 为组件准备数据
|
||
const kpiData = computed(() => kpiDataState);
|
||
// COMPUTED PROPERTIES
|
||
const selectedContact = computed(() => {
|
||
return (
|
||
MOCK_DATA.contacts.find((c) => c.id === selectedContactId.value) || null
|
||
);
|
||
});
|
||
|
||
|
||
|
||
const funnelData = computed(() => ({
|
||
labels: ["线索", "沟通", "意向", "预约", "成交"],
|
||
data: MOCK_DATA.personalFunnel,
|
||
}));
|
||
|
||
const contactTimeData = computed(() => ({
|
||
labels: MOCK_DATA.contactTimeAnalysis.labels,
|
||
data: MOCK_DATA.contactTimeAnalysis.data,
|
||
}));
|
||
|
||
// 根据选中阶段筛选联系人
|
||
const filteredContacts = computed(() => {
|
||
// 默认显示"全部"阶段的客户
|
||
if (selectedStage.value === 'all' || selectedStage.value === '全部') {
|
||
return MOCK_DATA.contacts.filter(contact => contact.salesStage === '全部');
|
||
}
|
||
return MOCK_DATA.contacts.filter(contact => contact.salesStage === selectedStage.value);
|
||
});
|
||
|
||
// METHODS
|
||
const selectContact = (id) => {
|
||
selectedContactId.value = id;
|
||
|
||
// 当选中客户后,获取客户表单数据
|
||
nextTick(async () => {
|
||
if (selectedContact.value && selectedContact.value.name) {
|
||
await getCustomerForm();
|
||
}
|
||
|
||
contextPanelRef.value?.scrollIntoView({
|
||
behavior: "smooth",
|
||
block: "center",
|
||
});
|
||
});
|
||
};
|
||
|
||
// 处理时间线阶段选择
|
||
const handleStageSelect = (stage, extraData = null) => {
|
||
selectedStage.value = stage;
|
||
|
||
// 如果是课1-4阶段,处理课程数据
|
||
if (extraData && extraData.isCourseStage) {
|
||
console.log('处理课1-4阶段选择,课程数据:', extraData.courseData);
|
||
|
||
// 将课程数据转换为contacts格式并更新显示
|
||
const courseContacts = extraData.courseData.map(customer => ({
|
||
id: customer.id,
|
||
name: customer.name,
|
||
time: customer.time,
|
||
profession: customer.profession,
|
||
education: customer.education,
|
||
avatar: customer.avatar,
|
||
salesStage: '课1-4',
|
||
health: customer.health,
|
||
// 保留课程相关的原始数据
|
||
customer_name: customer.customer_name,
|
||
customer_occupation: customer.customer_occupation,
|
||
customer_child_education: customer.customer_child_education,
|
||
scrm_user_main_code: customer.scrm_user_main_code,
|
||
weChat_avatar: customer.weChat_avatar,
|
||
class_situation: customer.class_situation,
|
||
records: customer.records
|
||
}));
|
||
|
||
// 临时更新MOCK_DATA.contacts以显示课程客户
|
||
MOCK_DATA.contacts = [...MOCK_DATA.contacts.filter(c => c.salesStage !== '课1-4'), ...courseContacts];
|
||
|
||
console.log('课1-4客户数据已更新到contacts:', courseContacts);
|
||
}
|
||
};
|
||
|
||
// 处理查看表单数据
|
||
const handleViewFormData = (contact) => {
|
||
console.log('查看表单数据:', contact);
|
||
// 这里可以添加打开表单数据弹窗的逻辑
|
||
};
|
||
|
||
// 处理查看聊天记录
|
||
const handleViewChatData = (contact) => {
|
||
console.log('查看聊天记录:', contact);
|
||
// 这里可以添加打开聊天记录弹窗的逻辑
|
||
};
|
||
|
||
// 处理查看通话录音
|
||
const handleViewCallData = (contact) => {
|
||
console.log('查看通话录音:', contact);
|
||
// 这里可以添加打开通话录音弹窗的逻辑
|
||
};
|
||
|
||
// LIFECYCLE HOOKS
|
||
onMounted(async () => {
|
||
await getCoreKpi()
|
||
await getStatisticsData()
|
||
await getUrgentProblem()
|
||
await getTimeline()
|
||
// 默认选择第一个今日必须联系人
|
||
const highPriorityContacts = MOCK_DATA.contacts.filter(
|
||
(contact) => contact.priority === "high"
|
||
);
|
||
if (highPriorityContacts.length > 0) {
|
||
selectedContactId.value = highPriorityContacts[0].id;
|
||
}
|
||
});
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
body {
|
||
margin: 0;
|
||
padding: 0;
|
||
}
|
||
// Color Palette
|
||
$slate-50: #f8fafc;
|
||
$slate-100: #f1f5f9;
|
||
$slate-200: #e2e8f0;
|
||
$slate-300: #cbd5e1;
|
||
$slate-400: #94a3b8;
|
||
$slate-500: #64748b;
|
||
$slate-600: #475569;
|
||
$slate-700: #334155;
|
||
$slate-800: #1e293b;
|
||
$white: #ffffff;
|
||
|
||
$blue: #3b82f6;
|
||
$green: #22c55e;
|
||
$amber: #f59e0b;
|
||
$red: #ef4444;
|
||
$indigo: #4f46e5;
|
||
$purple: #a855f7;
|
||
|
||
// 移动端全局优化
|
||
@media (max-width: 768px) {
|
||
// 优化触摸目标大小
|
||
* {
|
||
-webkit-tap-highlight-color: transparent;
|
||
}
|
||
|
||
// 优化滚动性能
|
||
.sidebar,
|
||
.detail-section,
|
||
.analytics-section-full {
|
||
-webkit-overflow-scrolling: touch;
|
||
scroll-behavior: smooth;
|
||
}
|
||
|
||
// 防止横向滚动
|
||
body {
|
||
overflow-x: hidden;
|
||
}
|
||
}
|
||
|
||
// 超小屏幕优化
|
||
@media (max-width: 480px) {
|
||
// 减少动画以提升性能
|
||
* {
|
||
transition-duration: 0.1s !important;
|
||
}
|
||
|
||
// 优化字体渲染
|
||
body {
|
||
-webkit-font-smoothing: antialiased;
|
||
-moz-osx-font-smoothing: grayscale;
|
||
}
|
||
|
||
.sales-dashboard {
|
||
padding: 0.25rem;
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
.analytics-section-full {
|
||
.section-header {
|
||
padding: 0.5rem;
|
||
|
||
.app-title {
|
||
font-size: 1.125rem;
|
||
}
|
||
|
||
.quick-stats {
|
||
flex-direction: column;
|
||
gap: 0.25rem !important;
|
||
|
||
.quick-stat-item {
|
||
.stat-label {
|
||
font-size: 0.6875rem;
|
||
}
|
||
}
|
||
}
|
||
|
||
.header-ringht {
|
||
.avatar {
|
||
width: 25px !important;
|
||
height: 25px !important;
|
||
}
|
||
|
||
span {
|
||
font-size: 0.75rem;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.timeline-section {
|
||
.section-header {
|
||
padding: 0.5rem;
|
||
|
||
h2 {
|
||
font-size: 0.875rem;
|
||
}
|
||
|
||
.section-subtitle {
|
||
font-size: 0.6875rem;
|
||
}
|
||
}
|
||
}
|
||
|
||
.sidebar {
|
||
.sidebar-header {
|
||
padding: 0.5rem;
|
||
|
||
h2 {
|
||
font-size: 0.875rem;
|
||
}
|
||
|
||
.task-summary {
|
||
.task-count {
|
||
font-size: 1.25rem;
|
||
}
|
||
|
||
.task-label {
|
||
font-size: 0.75rem;
|
||
}
|
||
}
|
||
}
|
||
|
||
.sidebar-content {
|
||
padding: 0.5rem;
|
||
}
|
||
}
|
||
|
||
.detail-section {
|
||
.section-header {
|
||
padding: 0.5rem;
|
||
|
||
h2 {
|
||
font-size: 0.875rem;
|
||
}
|
||
|
||
.section-actions {
|
||
.action-btn {
|
||
padding: 0.25rem 0.5rem;
|
||
font-size: 0.6875rem;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 移动端优化 */
|
||
@media (max-width: 768px) {
|
||
.sales-dashboard {
|
||
padding: 0.5rem;
|
||
gap: 0.75rem;
|
||
}
|
||
|
||
.main-layout {
|
||
flex-direction: column;
|
||
gap: 1rem;
|
||
}
|
||
|
||
.sidebar {
|
||
width: 100%;
|
||
min-height: auto;
|
||
order: 2; /* 在移动端将侧边栏放到主内容下方 */
|
||
|
||
.sidebar-header {
|
||
padding: 0.75rem 1rem;
|
||
|
||
h2 {
|
||
font-size: 1rem;
|
||
}
|
||
}
|
||
|
||
.sidebar-content {
|
||
padding: 0.75rem;
|
||
}
|
||
}
|
||
|
||
.main-content {
|
||
width: 100%;
|
||
order: 1; /* 在移动端将主内容放到侧边栏上方 */
|
||
}
|
||
|
||
.detail-section {
|
||
.section-header {
|
||
padding: 0.75rem 1rem;
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
gap: 0.5rem;
|
||
|
||
h2 {
|
||
font-size: 1rem;
|
||
}
|
||
|
||
.section-actions {
|
||
width: 100%;
|
||
justify-content: flex-end;
|
||
|
||
.action-btn {
|
||
padding: 0.375rem 0.75rem;
|
||
font-size: 0.75rem;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.analytics-section-full {
|
||
.section-header {
|
||
padding: 0.75rem 1rem;
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
gap: 0.75rem;
|
||
|
||
.app-title {
|
||
font-size: 1.25rem;
|
||
}
|
||
|
||
.quick-stats {
|
||
width: 100%;
|
||
flex-wrap: wrap;
|
||
gap: 0.5rem !important;
|
||
|
||
.quick-stat-item {
|
||
.stat-label {
|
||
font-size: 0.75rem;
|
||
}
|
||
}
|
||
}
|
||
|
||
.header-ringht {
|
||
width: 100%;
|
||
justify-content: flex-end;
|
||
|
||
.avatar {
|
||
width: 30px !important;
|
||
height: 30px !important;
|
||
}
|
||
|
||
span {
|
||
font-size: 0.875rem;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Base Styles
|
||
.sales-dashboard {
|
||
background: #ffffff;
|
||
min-height: 100vh;
|
||
color: $slate-800;
|
||
font-family:
|
||
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
|
||
Arial, "Noto Sans", sans-serif;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 0;
|
||
margin: 0;
|
||
box-sizing: border-box;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
font-size: 16px;
|
||
line-height: 1.6;
|
||
padding: 0;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
font-size: 15px;
|
||
line-height: 1.55;
|
||
padding: 0;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
font-size: 14px;
|
||
line-height: 1.5;
|
||
padding: 0;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
font-size: 13px;
|
||
line-height: 1.4;
|
||
padding: 0;
|
||
}
|
||
|
||
// 确保所有子元素都使用border-box
|
||
*, *::before, *::after {
|
||
box-sizing: border-box;
|
||
}
|
||
}
|
||
|
||
// 顶部导航栏
|
||
.top-navbar {
|
||
background: rgba(255, 255, 255, 0.95);
|
||
backdrop-filter: blur(20px);
|
||
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
|
||
position: sticky;
|
||
top: 0;
|
||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
||
width: 100%;
|
||
z-index: 1000;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
width: 100%;
|
||
margin: 0;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
width: 100%;
|
||
margin: 0;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
width: 100%;
|
||
margin: 0;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
width: 100%;
|
||
margin: 0;
|
||
}
|
||
.navbar-content {
|
||
max-width: 1400px;
|
||
margin: 0 auto;
|
||
padding: 0 2rem;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
height: 70px;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
padding: 0 2.5rem;
|
||
height: 75px;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
padding: 0 2rem;
|
||
height: 70px;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
padding: 0 1rem;
|
||
height: 60px;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
padding: 0 0.5rem;
|
||
height: 55px;
|
||
}
|
||
}
|
||
|
||
.navbar-left {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 2rem;
|
||
|
||
@media (max-width: 768px) {
|
||
gap: 1rem;
|
||
}
|
||
|
||
@media (max-width: 480px) {
|
||
gap: 0.75rem;
|
||
}
|
||
|
||
.app-title {
|
||
font-size: 1.5rem;
|
||
font-weight: 700;
|
||
background: linear-gradient(135deg, #667eea, #764ba2);
|
||
-webkit-text-fill-color: transparent;
|
||
margin: 0;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
font-size: 1.75rem;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
font-size: 1.5rem;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
font-size: 1.25rem;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
font-size: 1.125rem;
|
||
}
|
||
}
|
||
|
||
.breadcrumb {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
font-size: 0.875rem;
|
||
color: $slate-500;
|
||
|
||
@media (max-width: 480px) {
|
||
font-size: 0.75rem;
|
||
gap: 0.25rem;
|
||
}
|
||
|
||
.separator {
|
||
color: $slate-400;
|
||
}
|
||
|
||
.current {
|
||
color: $slate-700;
|
||
font-weight: 500;
|
||
}
|
||
}
|
||
}
|
||
|
||
.navbar-right {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 2rem;
|
||
|
||
@media (max-width: 768px) {
|
||
gap: 1rem;
|
||
}
|
||
|
||
@media (max-width: 480px) {
|
||
gap: 0.75rem;
|
||
}
|
||
|
||
.quick-stats {
|
||
display: flex;
|
||
gap: 1.5rem;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
gap: 2rem;
|
||
flex-wrap: nowrap;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
gap: 1.5rem;
|
||
flex-wrap: nowrap;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
gap: 1rem;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
gap: 0.5rem;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.quick-stat-item {
|
||
text-align: center;
|
||
|
||
@media (max-width: 480px) {
|
||
min-width: 50px;
|
||
}
|
||
|
||
.stat-value {
|
||
font-size: 1.25rem;
|
||
font-weight: 700;
|
||
color: $slate-800;
|
||
line-height: 1;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
font-size: 1.375rem;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
font-size: 1.25rem;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
font-size: 1.125rem;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
font-size: 1rem;
|
||
}
|
||
}
|
||
|
||
.stat-label {
|
||
font-size: 0.75rem;
|
||
color: $slate-500;
|
||
margin-top: 2px;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
font-size: 0.8125rem;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
font-size: 0.75rem;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
font-size: 0.6875rem;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
font-size: 0.625rem;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.user-actions {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 1rem;
|
||
|
||
@media (max-width: 768px) {
|
||
gap: 0.75rem;
|
||
}
|
||
|
||
@media (max-width: 480px) {
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
.action-btn {
|
||
padding: 0.5rem 1rem;
|
||
border: 1px solid $slate-300;
|
||
border-radius: 0.5rem;
|
||
background: $white;
|
||
color: $slate-700;
|
||
font-size: 0.875rem;
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
touch-action: manipulation;
|
||
white-space: nowrap;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
padding: 0.625rem 1.25rem;
|
||
font-size: 0.875rem;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
padding: 0.5rem 1rem;
|
||
font-size: 0.875rem;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
padding: 0.375rem 0.75rem;
|
||
font-size: 0.8125rem;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
padding: 0.25rem 0.5rem;
|
||
font-size: 0.75rem;
|
||
}
|
||
|
||
&:hover {
|
||
background: $slate-50;
|
||
border-color: $slate-400;
|
||
}
|
||
}
|
||
|
||
.user-avatar {
|
||
width: 36px;
|
||
height: 36px;
|
||
border-radius: 50%;
|
||
background: linear-gradient(135deg, #667eea, #764ba2);
|
||
color: white;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
touch-action: manipulation;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
width: 40px;
|
||
height: 40px;
|
||
font-size: 1rem;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
width: 36px;
|
||
height: 36px;
|
||
font-size: 0.9375rem;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
width: 32px;
|
||
height: 32px;
|
||
font-size: 0.875rem;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
width: 28px;
|
||
height: 28px;
|
||
font-size: 0.75rem;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 主要布局
|
||
.main-layout {
|
||
width: 100vw;
|
||
margin: 0 auto;
|
||
padding: 1rem;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 1rem;
|
||
// min-height: calc(100vh - 70px);
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
width: 100vw;
|
||
// max-width: 1400px;
|
||
// padding: 1.5rem;
|
||
gap: 1.5rem;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
width: 90vw;
|
||
padding: 1rem;
|
||
gap: 1rem;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
width: 95vw;
|
||
padding: 0.75rem;
|
||
gap: 0.75rem;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
width: 98vw;
|
||
padding: 0.5rem;
|
||
gap: 0.5rem;
|
||
}
|
||
}
|
||
|
||
// 智能任务清单(原左侧边栏,现在在上方)
|
||
.sidebar {
|
||
background: rgba(255, 255, 255, 0.95);
|
||
backdrop-filter: blur(20px);
|
||
border-radius: 1rem;
|
||
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1);
|
||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||
overflow: hidden;
|
||
height: fit-content;
|
||
max-height: 400px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
border-radius: 1rem;
|
||
max-height: 450px;
|
||
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
border-radius: 0.875rem;
|
||
max-height: 420px;
|
||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.08);
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
border-radius: 0.75rem;
|
||
max-height: calc(100vh - 120px);
|
||
box-shadow: 0 6px 24px rgba(0, 0, 0, 0.06);
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
border-radius: 0.5rem;
|
||
max-height: calc(100vh - 100px);
|
||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.04);
|
||
}
|
||
|
||
.sidebar-header {
|
||
padding: 1.5rem;
|
||
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
||
background: linear-gradient(
|
||
135deg,
|
||
rgba(102, 126, 234, 0.1),
|
||
rgba(118, 75, 162, 0.1)
|
||
);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
padding: 1.75rem;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
padding: 1.5rem;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
padding: 1.25rem;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
padding: 1rem;
|
||
}
|
||
|
||
h2 {
|
||
margin: 0 0 0.5rem 0;
|
||
font-size: 1.125rem;
|
||
font-weight: 600;
|
||
color: $slate-800;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
font-size: 1.25rem;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
font-size: 1.125rem;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
font-size: 1rem;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
font-size: 0.9375rem;
|
||
}
|
||
}
|
||
|
||
.task-summary {
|
||
display: flex;
|
||
align-items: baseline;
|
||
gap: 0.25rem;
|
||
|
||
.task-count {
|
||
font-size: 1.5rem;
|
||
font-weight: 700;
|
||
color: #667eea;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
font-size: 1.75rem;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
font-size: 1.5rem;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
font-size: 1.375rem;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
font-size: 1.25rem;
|
||
}
|
||
}
|
||
|
||
.task-label {
|
||
font-size: 0.875rem;
|
||
color: $slate-500;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
font-size: 0.9375rem;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
font-size: 0.875rem;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
font-size: 0.8125rem;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
font-size: 0.8125rem;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.sidebar-content {
|
||
flex: 1;
|
||
overflow-y: auto;
|
||
}
|
||
}
|
||
|
||
// 主要内容区域
|
||
.main-content {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 2rem;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
gap: 2.5rem;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
gap: 2rem;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
gap: 1.5rem;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
gap: 1rem;
|
||
}
|
||
|
||
.detail-section {
|
||
background: rgba(255, 255, 255, 0.95);
|
||
backdrop-filter: blur(20px);
|
||
border-radius: 1rem;
|
||
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1);
|
||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||
overflow: hidden;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
border-radius: 1rem;
|
||
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
border-radius: 0.875rem;
|
||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.08);
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
border-radius: 0.75rem;
|
||
box-shadow: 0 6px 24px rgba(0, 0, 0, 0.06);
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
border-radius: 0.5rem;
|
||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.04);
|
||
}
|
||
|
||
.section-header {
|
||
padding: 1.5rem;
|
||
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
background: linear-gradient(
|
||
135deg,
|
||
rgba(102, 126, 234, 0.05),
|
||
rgba(118, 75, 162, 0.05)
|
||
);
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
padding: 1.75rem;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
gap: 2rem;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
padding: 1.5rem;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
gap: 1.5rem;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
padding: 1.25rem;
|
||
flex-direction: column;
|
||
gap: 1rem;
|
||
align-items: flex-start;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
padding: 1rem;
|
||
gap: 0.75rem;
|
||
}
|
||
|
||
h2 {
|
||
margin: 0;
|
||
font-size: 1.125rem;
|
||
font-weight: 600;
|
||
color: $slate-800;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
font-size: 1.25rem;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
font-size: 1.125rem;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
font-size: 1rem;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
font-size: 0.9375rem;
|
||
}
|
||
}
|
||
|
||
.section-actions {
|
||
display: flex;
|
||
gap: 0.75rem;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
gap: 1rem;
|
||
flex-wrap: nowrap;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
gap: 0.75rem;
|
||
flex-wrap: nowrap;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
gap: 0.5rem;
|
||
width: 100%;
|
||
justify-content: flex-start;
|
||
flex-wrap: nowrap;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
gap: 0.375rem;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.action-btn {
|
||
padding: 0.5rem 1rem;
|
||
border-radius: 0.5rem;
|
||
font-size: 0.875rem;
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
border: none;
|
||
touch-action: manipulation;
|
||
white-space: nowrap;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
padding: 0.625rem 1.25rem;
|
||
font-size: 0.875rem;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
padding: 0.5rem 1rem;
|
||
font-size: 0.875rem;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
padding: 0.375rem 0.75rem;
|
||
font-size: 0.8125rem;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
padding: 0.25rem 0.5rem;
|
||
font-size: 0.75rem;
|
||
min-width: 60px;
|
||
}
|
||
|
||
&.primary {
|
||
background: linear-gradient(135deg, #667eea, #764ba2);
|
||
color: white;
|
||
|
||
&:hover {
|
||
transform: translateY(-1px);
|
||
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
|
||
}
|
||
}
|
||
|
||
&.secondary {
|
||
background: $white;
|
||
color: $slate-700;
|
||
border: 1px solid $slate-300;
|
||
|
||
&:hover {
|
||
background: $slate-50;
|
||
border-color: $slate-400;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.view-toggle {
|
||
display: flex;
|
||
background: $slate-100;
|
||
border-radius: 0.5rem;
|
||
padding: 0.25rem;
|
||
|
||
.toggle-btn {
|
||
padding: 0.5rem 1rem;
|
||
border: none;
|
||
background: transparent;
|
||
color: $slate-600;
|
||
font-size: 0.875rem;
|
||
border-radius: 0.375rem;
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
|
||
&.active {
|
||
background: $white;
|
||
color: $slate-800;
|
||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
&:hover:not(.active) {
|
||
color: $slate-800;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.section-content {
|
||
padding: 0.5rem;
|
||
|
||
@media (max-width: 768px) {
|
||
padding: 1.25rem;
|
||
}
|
||
|
||
@media (max-width: 480px) {
|
||
padding: 1rem;
|
||
}
|
||
}
|
||
}
|
||
|
||
.detail-section {
|
||
flex: 0 0 auto;
|
||
}
|
||
}
|
||
|
||
// 销售漏斗和时间线区域样式
|
||
.funnel-section,
|
||
.timeline-section,
|
||
.raw-data-section {
|
||
grid-column: 1 / -1;
|
||
background: rgba(255, 255, 255, 0.95);
|
||
backdrop-filter: blur(20px);
|
||
border-radius: 1rem;
|
||
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1);
|
||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||
overflow: hidden;
|
||
margin-bottom: 1.5rem;
|
||
width: 100%;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
border-radius: 1rem;
|
||
margin-bottom: 1.5rem;
|
||
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
border-radius: 0.875rem;
|
||
margin-bottom: 1.25rem;
|
||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.08);
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
border-radius: 0.75rem;
|
||
margin-bottom: 1rem;
|
||
box-shadow: 0 6px 24px rgba(0, 0, 0, 0.06);
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
border-radius: 0.5rem;
|
||
margin-bottom: 0.75rem;
|
||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.04);
|
||
}
|
||
|
||
.section-header {
|
||
padding: 1.5rem;
|
||
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
||
background: linear-gradient(
|
||
135deg,
|
||
rgba(102, 126, 234, 0.05),
|
||
rgba(118, 75, 162, 0.05)
|
||
);
|
||
|
||
@media (max-width: 768px) {
|
||
padding: 1.25rem;
|
||
}
|
||
|
||
@media (max-width: 480px) {
|
||
padding: 1rem;
|
||
}
|
||
|
||
h2 {
|
||
margin: 0;
|
||
font-size: 1.125rem;
|
||
font-weight: 600;
|
||
color: $slate-800;
|
||
|
||
@media (max-width: 768px) {
|
||
font-size: 1rem;
|
||
}
|
||
|
||
@media (max-width: 480px) {
|
||
font-size: 0.9375rem;
|
||
}
|
||
}
|
||
|
||
.section-subtitle {
|
||
margin: 0.5rem 0 0 0;
|
||
font-size: 0.875rem;
|
||
color: $slate-600;
|
||
font-weight: 400;
|
||
|
||
@media (max-width: 768px) {
|
||
font-size: 0.8125rem;
|
||
}
|
||
|
||
@media (max-width: 480px) {
|
||
font-size: 0.75rem;
|
||
}
|
||
}
|
||
}
|
||
|
||
.section-content {
|
||
padding: 1.5rem;
|
||
|
||
@media (max-width: 768px) {
|
||
padding: 1.25rem;
|
||
}
|
||
|
||
@media (max-width: 480px) {
|
||
padding: 1rem;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 独立的数据分析区域 - 跨越整个宽度
|
||
.analytics-section-full {
|
||
grid-column: 1 / -1;
|
||
background: rgba(255, 255, 255, 0.95);
|
||
backdrop-filter: blur(20px);
|
||
border-radius: 1rem;
|
||
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1);
|
||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||
overflow: hidden;
|
||
width: 100%;
|
||
min-height: 400px;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
min-height: 450px;
|
||
border-radius: 1rem;
|
||
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
min-height: 380px;
|
||
border-radius: 0.875rem;
|
||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.08);
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
border-radius: 0.75rem;
|
||
min-height: 320px;
|
||
box-shadow: 0 6px 24px rgba(0, 0, 0, 0.06);
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
border-radius: 0.5rem;
|
||
min-height: 280px;
|
||
margin-top: 0.5rem;
|
||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.04);
|
||
}
|
||
|
||
.section-header {
|
||
padding: 1.5rem;
|
||
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
background: linear-gradient(
|
||
135deg,
|
||
rgba(102, 126, 234, 0.05),
|
||
rgba(118, 75, 162, 0.05)
|
||
);
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
padding: 1.75rem;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
gap: 2rem;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
padding: 1.5rem;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
gap: 1.5rem;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
padding: 1.25rem;
|
||
flex-direction: column;
|
||
gap: 1rem;
|
||
align-items: flex-start;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
padding: 1rem;
|
||
gap: 0.75rem;
|
||
}
|
||
|
||
h2 {
|
||
margin: 0;
|
||
font-size: 1.125rem;
|
||
font-weight: 600;
|
||
color: $slate-800;
|
||
|
||
@media (max-width: 768px) {
|
||
font-size: 1rem;
|
||
}
|
||
|
||
@media (max-width: 480px) {
|
||
font-size: 0.9375rem;
|
||
}
|
||
}
|
||
|
||
.view-toggle {
|
||
display: flex;
|
||
background: $slate-100;
|
||
border-radius: 0.5rem;
|
||
padding: 0.25rem;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
width: auto;
|
||
flex-wrap: nowrap;
|
||
justify-content: flex-start;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
width: auto;
|
||
flex-wrap: nowrap;
|
||
justify-content: flex-start;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
width: 100%;
|
||
justify-content: space-between;
|
||
flex-wrap: nowrap;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
flex-wrap: wrap;
|
||
gap: 0.25rem;
|
||
justify-content: flex-start;
|
||
}
|
||
|
||
.toggle-btn {
|
||
padding: 0.5rem 1rem;
|
||
border: none;
|
||
background: transparent;
|
||
color: $slate-600;
|
||
font-size: 0.875rem;
|
||
border-radius: 0.375rem;
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
touch-action: manipulation;
|
||
white-space: nowrap;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
padding: 0.5rem 1.25rem;
|
||
font-size: 0.875rem;
|
||
flex: none;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
padding: 0.5rem 1rem;
|
||
font-size: 0.875rem;
|
||
flex: none;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
padding: 0.375rem 0.75rem;
|
||
font-size: 0.8125rem;
|
||
flex: 1;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
padding: 0.25rem 0.5rem;
|
||
font-size: 0.75rem;
|
||
min-width: 60px;
|
||
flex: none;
|
||
}
|
||
|
||
&.active {
|
||
background: $white;
|
||
color: $slate-800;
|
||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
&:hover:not(.active) {
|
||
color: $slate-800;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.section-content {
|
||
padding: 1.5rem;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
padding: 1.75rem;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
padding: 1.5rem;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
padding: 1.25rem;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
padding: 1rem;
|
||
}
|
||
}
|
||
}
|
||
|
||
</style>
|