1129 lines
26 KiB
Vue
1129 lines
26 KiB
Vue
<template>
|
||
<div class="customer-detail-container">
|
||
<div v-if="selectedContact" class="customer-detail-content">
|
||
<!-- 头部信息 -->
|
||
<div class="customer-header">
|
||
<h3>{{ selectedContact.name }}</h3>
|
||
<div class="action-buttons">
|
||
<button
|
||
@click="startBasicAnalysis"
|
||
class="analysis-button"
|
||
:disabled="isBasicAnalysisLoading"
|
||
>
|
||
{{ isBasicAnalysisLoading ? '基础分析中...' : '基础信息分析' }}
|
||
</button>
|
||
<button
|
||
@click="startSopAnalysis"
|
||
class="analysis-button sop-button"
|
||
:disabled="isSopAnalysisLoading || !hasCallData"
|
||
>
|
||
{{ isSopAnalysisLoading ? 'SOP分析中...' : (hasCallData ? 'SOP通话分析' : '暂无通话数据') }}
|
||
</button>
|
||
<!-- <button
|
||
@click="startDemandAnalysis"
|
||
class="analysis-button demand-button"
|
||
:disabled="isDemandAnalysisLoading"
|
||
>
|
||
{{ isDemandAnalysisLoading ? '诉求分析中...' : '客户诉求分析' }}
|
||
</button> -->
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 分析区域 -->
|
||
<div class="analysis-areas">
|
||
<!-- 上方两个区域 -->
|
||
<div class="top-row">
|
||
<!-- 基础信息分析 -->
|
||
<div class="analysis-section basic-analysis">
|
||
<div class="section-header">
|
||
<h4>基础信息分析</h4>
|
||
</div>
|
||
<div class="section-content">
|
||
<div class="text-content" v-if="basicAnalysisResult">
|
||
<div class="analysis-text" v-html="formattedBasicAnalysis"></div>
|
||
</div>
|
||
<div class="placeholder-text" v-else>
|
||
<p>点击"基础信息分析"按钮开始分析客户基础信息</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- SOP通话分析 -->
|
||
<div class="analysis-section sop-analysis">
|
||
<div class="section-header">
|
||
<h4>SOP通话分析</h4>
|
||
</div>
|
||
<div class="section-content">
|
||
<div class="text-content" v-if="sopAnalysisResult">
|
||
<div class="analysis-text" v-html="formattedSopAnalysis"></div>
|
||
</div>
|
||
<div class="placeholder-text" v-else>
|
||
<p>点击"SOP通话分析"按钮开始分析通话记录</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 下方整行区域 -->
|
||
<!-- <div class="bottom-row">
|
||
<div class="analysis-section demand-analysis">
|
||
<div class="section-header">
|
||
<h4>客户诉求分析</h4>
|
||
</div>
|
||
<div class="section-content">
|
||
<div class="text-content" v-if="demandAnalysisResult">
|
||
<div class="analysis-text" v-html="formattedDemandAnalysis"></div>
|
||
</div>
|
||
<div class="placeholder-text" v-else>
|
||
<p>点击"客户诉求分析"按钮开始深度分析客户需求和诉求</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div> -->
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 未选择客户时的提示 -->
|
||
<div v-else class="no-selection">
|
||
<p>请选择一个客户查看详情</p>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, watch, computed } from 'vue';
|
||
import { SimpleChatService } from '@/utils/ChatService.js';
|
||
import MarkdownIt from 'markdown-it';
|
||
import https from '@/utils/https'
|
||
import axios from 'axios'
|
||
|
||
// 定义props
|
||
const props = defineProps({
|
||
selectedContact: {
|
||
type: Object,
|
||
default: null
|
||
},
|
||
formInfo: {
|
||
type: Object,
|
||
default: () => ({})
|
||
},
|
||
chatRecords: {
|
||
type: Array,
|
||
default: () => []
|
||
},
|
||
callRecords: {
|
||
type: Array,
|
||
default: () => []
|
||
}
|
||
});
|
||
|
||
console.log(999999999,props.selectedContact);
|
||
// 分析结果状态
|
||
const basicAnalysisResult = ref(''); // 基础信息分析结果
|
||
const sopAnalysisResult = ref(''); // SOP通话分析结果
|
||
const demandAnalysisResult = ref(''); // 客户诉求分析结果
|
||
|
||
// 加载状态
|
||
const isBasicAnalysisLoading = ref(false); // 基础分析加载状态
|
||
const isSopAnalysisLoading = ref(false); // SOP分析加载状态
|
||
const isDemandAnalysisLoading = ref(false); // 诉求分析加载状态
|
||
|
||
// Dify API配置
|
||
const DIFY_API_KEY_01 = 'app-h4uBo5kOGoiYhjuBF1AHZi8b'; //基础信息分析
|
||
const DIFY_API_KEY = 'app-ZIJSFWbcdZLufkwCp9RrvpUR';
|
||
// 初始化ChatService
|
||
const chatService_01 = new SimpleChatService(DIFY_API_KEY_01);
|
||
const chatService = new SimpleChatService(DIFY_API_KEY);
|
||
|
||
// 初始化markdown-it
|
||
const md = new MarkdownIt({
|
||
html: true,
|
||
linkify: true,
|
||
typographer: true
|
||
});
|
||
|
||
// 计算属性:格式化基础分析结果
|
||
const formattedBasicAnalysis = computed(() => {
|
||
if (!basicAnalysisResult.value) return '';
|
||
return md.render(basicAnalysisResult.value);
|
||
});
|
||
|
||
// 计算属性:格式化SOP分析结果
|
||
const formattedSopAnalysis = computed(() => {
|
||
if (!sopAnalysisResult.value) return '';
|
||
return md.render(sopAnalysisResult.value);
|
||
});
|
||
|
||
// 计算属性:格式化诉求分析结果
|
||
const formattedDemandAnalysis = computed(() => {
|
||
if (!demandAnalysisResult.value) return '';
|
||
return md.render(demandAnalysisResult.value);
|
||
});
|
||
|
||
// 计算属性:检查是否有通话数据
|
||
const hasCallData = computed(() => {
|
||
return props.callRecords && props.callRecords.length > 0;
|
||
});
|
||
|
||
// 监听selectedContact变化,重置所有分析结果
|
||
watch(() => props.selectedContact, (newContact) => {
|
||
if (newContact) {
|
||
// 重置所有分析状态
|
||
basicAnalysisResult.value = '';
|
||
sopAnalysisResult.value = '';
|
||
demandAnalysisResult.value = '';
|
||
isBasicAnalysisLoading.value = false;
|
||
isSopAnalysisLoading.value = false;
|
||
isDemandAnalysisLoading.value = false;
|
||
} else {
|
||
// 清空所有结果
|
||
basicAnalysisResult.value = '';
|
||
sopAnalysisResult.value = '';
|
||
demandAnalysisResult.value = '';
|
||
isBasicAnalysisLoading.value = false;
|
||
isSopAnalysisLoading.value = false;
|
||
isDemandAnalysisLoading.value = false;
|
||
}
|
||
}, { immediate: true });
|
||
|
||
// 基础信息分析
|
||
const startBasicAnalysis = async () => {
|
||
if (!props.selectedContact) return;
|
||
|
||
isBasicAnalysisLoading.value = true;
|
||
basicAnalysisResult.value = '';
|
||
|
||
// 构建表单信息
|
||
const formData = props.formInfo || {};
|
||
let formInfoText = '暂无表单信息';
|
||
|
||
if (Object.keys(formData).length > 0) {
|
||
console.log(888888,formData);
|
||
const allInfo = [];
|
||
|
||
// 处理第一种格式:基础信息和additional_info
|
||
if (formData.name || formData.mobile || formData.additional_info) {
|
||
const basicInfo = [];
|
||
const additionalInfo = [];
|
||
|
||
// 处理基础信息字段
|
||
const basicFields = {
|
||
name: '姓名',
|
||
mobile: '手机号',
|
||
occupation: '职业',
|
||
territory: '地区',
|
||
child_name: '孩子姓名',
|
||
child_gender: '孩子性别',
|
||
child_education: '孩子教育阶段',
|
||
child_relation: '与孩子关系'
|
||
};
|
||
|
||
Object.entries(basicFields).forEach(([key, label]) => {
|
||
if (formData[key] && formData[key] !== '暂无' && formData[key] !== '') {
|
||
basicInfo.push(`${label}: ${formData[key]}`);
|
||
}
|
||
});
|
||
|
||
// 处理 additional_info 数组
|
||
if (formData.additional_info && Array.isArray(formData.additional_info)) {
|
||
formData.additional_info.forEach(item => {
|
||
if (item.topic && item.answer) {
|
||
additionalInfo.push(`${item.topic}\n答案: ${item.answer}`);
|
||
}
|
||
});
|
||
}
|
||
|
||
// 添加基础信息
|
||
if (basicInfo.length > 0) {
|
||
allInfo.push('=== 基础信息 ===');
|
||
allInfo.push(...basicInfo);
|
||
}
|
||
|
||
// 添加问卷信息
|
||
if (additionalInfo.length > 0) {
|
||
allInfo.push('\n=== 问卷信息 ===');
|
||
allInfo.push(...additionalInfo);
|
||
}
|
||
}
|
||
|
||
// 处理第二种格式:customerExpandFieldMap
|
||
if (formData.customerExpandFieldMap) {
|
||
const expandInfo = [];
|
||
const map = formData.customerExpandFieldMap;
|
||
|
||
// 处理所有expand字段
|
||
Object.entries(map).forEach(([key, value]) => {
|
||
// 跳过原型链上的属性
|
||
if (!map.hasOwnProperty(key)) return;
|
||
|
||
// 如果是对象类型(包含key和typeCode的字段)
|
||
if (value && typeof value === 'object' && value.key) {
|
||
const question = value.key;
|
||
let answer = '';
|
||
|
||
// 根据不同的类型处理答案
|
||
if (value.typeCode === 'SINGLE_SELECT' || value.typeCode === 'MULTIPLE_SELECT') {
|
||
if (value.expandValueList && value.expandValueList.length > 0) {
|
||
answer = value.expandValueList.map(item => item.itemName).join('、');
|
||
}
|
||
} else if (value.typeCode === 'TEXT' || value.typeCode === 'TEXTAREA' || value.typeCode === 'NUMBER') {
|
||
// 直接从formData中获取对应的expand值
|
||
answer = formData[key] || '';
|
||
}
|
||
|
||
// 只添加有答案的问题
|
||
if (answer && answer !== '暂无' && answer !== '') {
|
||
expandInfo.push(`${question}\n答案: ${answer}`);
|
||
}
|
||
}
|
||
});
|
||
|
||
// 添加扩展信息
|
||
if (expandInfo.length > 0) {
|
||
if (allInfo.length > 0) allInfo.push('\n'); // 如果已有其他信息,添加分隔行
|
||
allInfo.push('=== 问卷详细信息 ===');
|
||
allInfo.push(...expandInfo);
|
||
}
|
||
}
|
||
|
||
formInfoText = allInfo.length > 0 ? allInfo.join('\n') : '暂无表单信息';
|
||
}
|
||
|
||
// 构建聊天记录信息
|
||
const chatData = props.chatRecords || [];
|
||
const chatInfoText = chatData.messages.length > 0 ?
|
||
`聊天记录数量: ${chatData.messages.length}条\n最近聊天内容: ${JSON.stringify(chatData.messages.slice(-3), null, 2)}` :
|
||
'暂无聊天记录';
|
||
|
||
// 构建通话记录信息
|
||
const callData = props.callRecords || [];
|
||
const callInfoText = callData.length > 0 ?
|
||
`通话记录数量: ${callData.length}次\n通话记录详情: ${JSON.stringify(callData, null, 2)}` :
|
||
'暂无通话记录';
|
||
|
||
const query = `请对客户进行基础信息分析:
|
||
客户姓名:${props.selectedContact.name}
|
||
联系电话:${props.selectedContact.phone || '未提供'}
|
||
销售阶段:${props.selectedContact.salesStage || '未知'}
|
||
|
||
=== 表单信息 ===
|
||
${formInfoText}
|
||
|
||
=== 聊天记录 ===
|
||
${chatInfoText}
|
||
|
||
=== 通话记录 ===
|
||
${callData.length > 0 && callData[0].record_context ? callData[0].record_context : callInfoText}
|
||
|
||
请基于以上客户的表单信息、聊天记录和通话记录,分析客户的基本情况、背景信息和初步画像。`;
|
||
|
||
console.log(888888,formInfoText);
|
||
try {
|
||
await chatService_01.sendMessage(
|
||
query,
|
||
(update) => {
|
||
basicAnalysisResult.value = update.content;
|
||
},
|
||
() => {
|
||
isBasicAnalysisLoading.value = false;
|
||
console.log('基础信息分析完成');
|
||
}
|
||
);
|
||
} catch (error) {
|
||
console.error('基础信息分析失败:', error);
|
||
basicAnalysisResult.value = `分析失败: ${error.message}`;
|
||
isBasicAnalysisLoading.value = false;
|
||
}
|
||
};
|
||
|
||
// SOP通话分析
|
||
const startSopAnalysis = async () => {
|
||
console.log(888888888777777,props.selectedContact.wechat_id)
|
||
if (!props.selectedContact) return;
|
||
|
||
isSopAnalysisLoading.value = true;
|
||
sopAnalysisResult.value = '';
|
||
// 构建通话记录信息
|
||
const callData = props.callRecords || [];
|
||
const callInfoText = callData.length > 0 ?
|
||
`通话记录数量: ${callData.length}次\n通话记录详情: ${JSON.stringify(callData, null, 2)}` :
|
||
'暂无通话记录';
|
||
const query = `=== 通话记录 ===
|
||
${callData.length > 0 && callData[0].record_context ? callData[0].record_context : callInfoText}`;
|
||
|
||
|
||
try {
|
||
// await chatService.sendMessage(
|
||
// query,
|
||
// (update) => {
|
||
// sopAnalysisResult.value = update.content;
|
||
// },
|
||
// () => {
|
||
// isSopAnalysisLoading.value = false;
|
||
// console.log('SOP通话分析完成');
|
||
// }
|
||
// );
|
||
const res= await axios.get('http://192.168.3.112:6002/api/v1/call',
|
||
{
|
||
params:{
|
||
wechat_id:props.selectedContact.wechat_id
|
||
}
|
||
})
|
||
sopAnalysisResult.value = res.data.report_content;
|
||
} catch (error) {
|
||
console.error('SOP通话分析失败:', error);
|
||
sopAnalysisResult.value = `分析失败: ${error.message}`;
|
||
isSopAnalysisLoading.value = false;
|
||
}
|
||
};
|
||
|
||
// 客户诉求分析
|
||
const startDemandAnalysis = async () => {
|
||
if (!props.selectedContact) return;
|
||
|
||
isDemandAnalysisLoading.value = true;
|
||
demandAnalysisResult.value = '';
|
||
|
||
const query = `请对客户 ${props.selectedContact.name} 进行深度诉求分析:
|
||
|
||
请从以下维度分析客户的真实需求和诉求:
|
||
1. 显性需求分析(客户明确表达的需求)
|
||
2. 隐性需求挖掘(潜在的、未明确表达的需求)
|
||
3. 痛点识别(客户面临的主要问题和挑战)
|
||
4. 决策因素分析(影响客户决策的关键因素)
|
||
5. 价值期望(客户期望获得的价值和收益)
|
||
6. 风险顾虑(客户可能的担忧和顾虑)
|
||
7. 个性化建议(针对性的解决方案建议)
|
||
|
||
客户信息:
|
||
姓名:${props.selectedContact.name}
|
||
公司:${props.selectedContact.company || '未提供'}
|
||
职位:${props.selectedContact.position || '未提供'}
|
||
销售阶段:${props.selectedContact.salesStage || '未知'}
|
||
健康度:${props.selectedContact.health || '未知'}%`;
|
||
|
||
try {
|
||
await chatService.sendMessage(
|
||
query,
|
||
(update) => {
|
||
demandAnalysisResult.value = update.content;
|
||
},
|
||
() => {
|
||
isDemandAnalysisLoading.value = false;
|
||
console.log('客户诉求分析完成');
|
||
}
|
||
);
|
||
} catch (error) {
|
||
console.error('客户诉求分析失败:', error);
|
||
demandAnalysisResult.value = `分析失败: ${error.message}`;
|
||
isDemandAnalysisLoading.value = false;
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
// 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;
|
||
|
||
// 容器样式
|
||
.customer-detail-container {
|
||
width: 100%;
|
||
height: 100%;
|
||
box-sizing: border-box;
|
||
padding: 16px;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
// padding: 24px;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
padding: 20px;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
padding: 12px;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
padding: 8px;
|
||
}
|
||
}
|
||
|
||
// 客户详情内容
|
||
.customer-detail-content {
|
||
height: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 16px;
|
||
}
|
||
|
||
// 客户头部信息
|
||
.customer-header {
|
||
background: $white;
|
||
border-radius: 8px;
|
||
padding: 16px;
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||
border: 1px solid $slate-200;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
padding: 20px;
|
||
border-radius: 12px;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
padding: 18px;
|
||
border-radius: 10px;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
gap: 16px;
|
||
padding: 16px;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
padding: 12px;
|
||
gap: 12px;
|
||
}
|
||
|
||
h3 {
|
||
margin: 0;
|
||
color: $slate-800;
|
||
font-size: 20px;
|
||
font-weight: 600;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
font-size: 24px;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
font-size: 22px;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
font-size: 18px;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
font-size: 16px;
|
||
}
|
||
}
|
||
|
||
.action-buttons {
|
||
display: flex;
|
||
gap: 12px;
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
width: 100%;
|
||
flex-direction: column;
|
||
gap: 8px;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
gap: 6px;
|
||
}
|
||
|
||
.analysis-button {
|
||
padding: 10px 16px;
|
||
background: $blue;
|
||
color: white;
|
||
border: none;
|
||
border-radius: 6px;
|
||
cursor: pointer;
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
transition: all 0.2s ease;
|
||
white-space: nowrap;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
padding: 12px 20px;
|
||
font-size: 15px;
|
||
border-radius: 8px;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
padding: 11px 18px;
|
||
font-size: 14px;
|
||
border-radius: 7px;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
width: 100%;
|
||
padding: 12px 16px;
|
||
font-size: 14px;
|
||
text-align: center;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
padding: 10px 12px;
|
||
font-size: 13px;
|
||
}
|
||
|
||
&:hover:not(:disabled) {
|
||
background: #2563eb;
|
||
transform: translateY(-1px);
|
||
}
|
||
|
||
&:disabled {
|
||
background: $slate-400;
|
||
cursor: not-allowed;
|
||
transform: none;
|
||
}
|
||
|
||
&.sop-button {
|
||
background: $green;
|
||
|
||
&:hover:not(:disabled) {
|
||
background: #16a34a;
|
||
}
|
||
}
|
||
|
||
&.demand-button {
|
||
background: $purple;
|
||
|
||
&:hover:not(:disabled) {
|
||
background: #9333ea;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 分析区域
|
||
.analysis-areas {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 16px;
|
||
min-height: 0;
|
||
}
|
||
|
||
// 上方行
|
||
.top-row {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 16px;
|
||
height: 45%;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
gap: 20px;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
gap: 18px;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
grid-template-columns: 1fr;
|
||
height: auto;
|
||
gap: 16px;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
gap: 12px;
|
||
}
|
||
}
|
||
|
||
// 下方行
|
||
.bottom-row {
|
||
height: 55%;
|
||
}
|
||
|
||
// 分析区域样式
|
||
.analysis-section {
|
||
background: $white;
|
||
border-radius: 8px;
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||
border: 1px solid $slate-200;
|
||
display: flex;
|
||
flex-direction: column;
|
||
overflow: hidden;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
border-radius: 12px;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
border-radius: 10px;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
min-height: 300px;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
min-height: 250px;
|
||
}
|
||
|
||
.section-header {
|
||
padding: 12px 16px;
|
||
background: $slate-50;
|
||
border-bottom: 1px solid $slate-200;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
padding: 16px 20px;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
padding: 14px 18px;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
padding: 12px 16px;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
padding: 10px 12px;
|
||
}
|
||
|
||
h4 {
|
||
margin: 0;
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
color: $slate-700;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
font-size: 18px;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
font-size: 17px;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
font-size: 15px;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
font-size: 14px;
|
||
}
|
||
}
|
||
}
|
||
|
||
.section-content {
|
||
flex: 1;
|
||
padding: 16px;
|
||
overflow-y: auto;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
padding: 20px;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
padding: 18px;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
padding: 16px;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
padding: 12px;
|
||
}
|
||
|
||
.text-content {
|
||
height: 100%;
|
||
|
||
.analysis-text {
|
||
color: $slate-700;
|
||
font-size: 14px;
|
||
line-height: 1.6;
|
||
word-wrap: break-word;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
font-size: 15px;
|
||
line-height: 1.7;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
font-size: 14px;
|
||
line-height: 1.65;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
font-size: 13px;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
font-size: 12px;
|
||
line-height: 1.5;
|
||
}
|
||
}
|
||
}
|
||
|
||
.placeholder-text {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
height: 100%;
|
||
background: $slate-50;
|
||
border-radius: 6px;
|
||
border: 2px dashed $slate-200;
|
||
|
||
p {
|
||
margin: 0;
|
||
color: $slate-500;
|
||
font-size: 14px;
|
||
text-align: center;
|
||
padding: 16px;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
font-size: 15px;
|
||
padding: 20px;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
font-size: 14px;
|
||
padding: 18px;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
font-size: 13px;
|
||
padding: 16px;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
font-size: 12px;
|
||
padding: 12px;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 不同分析区域的主题色
|
||
&.basic-analysis {
|
||
.section-header {
|
||
background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%);
|
||
|
||
h4 {
|
||
color: $blue;
|
||
}
|
||
}
|
||
}
|
||
|
||
&.sop-analysis {
|
||
.section-header {
|
||
background: linear-gradient(135deg, #f0fdf4 0%, #dcfce7 100%);
|
||
|
||
h4 {
|
||
color: $green;
|
||
}
|
||
}
|
||
}
|
||
|
||
&.demand-analysis {
|
||
.section-header {
|
||
background: linear-gradient(135deg, #faf5ff 0%, #f3e8ff 100%);
|
||
|
||
h4 {
|
||
color: $purple;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Markdown样式
|
||
.analysis-text {
|
||
// Markdown样式
|
||
h1, h2, h3, h4, h5, h6 {
|
||
margin: 1rem 0 0.5rem 0;
|
||
font-weight: 600;
|
||
color: $slate-800;
|
||
|
||
&:first-child {
|
||
margin-top: 0;
|
||
}
|
||
}
|
||
|
||
h1 { font-size: 1.25rem; }
|
||
h2 { font-size: 1.125rem; }
|
||
h3 { font-size: 1rem; }
|
||
h4 { font-size: 0.875rem; }
|
||
h5 { font-size: 0.75rem; }
|
||
h6 { font-size: 0.75rem; }
|
||
|
||
p {
|
||
margin: 0.5rem 0;
|
||
|
||
&:first-child {
|
||
margin-top: 0;
|
||
}
|
||
|
||
&:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
}
|
||
|
||
ul, ol {
|
||
margin: 0.5rem 0;
|
||
padding-left: 1.5rem;
|
||
|
||
li {
|
||
margin: 0.25rem 0;
|
||
}
|
||
}
|
||
|
||
blockquote {
|
||
margin: 1rem 0;
|
||
padding: 0.5rem 1rem;
|
||
border-left: 4px solid $blue;
|
||
background: rgba(59, 130, 246, 0.05);
|
||
font-style: italic;
|
||
}
|
||
|
||
code {
|
||
background: $slate-100;
|
||
padding: 0.125rem 0.25rem;
|
||
border-radius: 0.25rem;
|
||
font-family: 'Courier New', monospace;
|
||
font-size: 0.8rem;
|
||
}
|
||
|
||
pre {
|
||
background: $slate-100;
|
||
padding: 1rem;
|
||
border-radius: 0.5rem;
|
||
overflow-x: auto;
|
||
margin: 1rem 0;
|
||
|
||
code {
|
||
background: none;
|
||
padding: 0;
|
||
}
|
||
}
|
||
|
||
strong {
|
||
font-weight: 600;
|
||
color: $slate-800;
|
||
}
|
||
|
||
em {
|
||
font-style: italic;
|
||
}
|
||
|
||
a {
|
||
color: $blue;
|
||
text-decoration: none;
|
||
|
||
&:hover {
|
||
text-decoration: underline;
|
||
}
|
||
}
|
||
|
||
hr {
|
||
margin: 1.5rem 0;
|
||
border: none;
|
||
border-top: 1px solid $slate-200;
|
||
}
|
||
|
||
table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
margin: 1rem 0;
|
||
|
||
th, td {
|
||
padding: 0.5rem;
|
||
border: 1px solid $slate-200;
|
||
text-align: left;
|
||
}
|
||
|
||
th {
|
||
background: $slate-50;
|
||
font-weight: 600;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 未选择状态
|
||
.no-selection {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
height: 100%;
|
||
background: $slate-50;
|
||
border-radius: 8px;
|
||
border: 2px dashed $slate-200;
|
||
color: $slate-500;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
border-radius: 12px;
|
||
min-height: 500px;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
border-radius: 10px;
|
||
min-height: 450px;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
height: 400px;
|
||
border-radius: 8px;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
height: 300px;
|
||
border-radius: 6px;
|
||
}
|
||
|
||
p {
|
||
margin: 0;
|
||
font-size: 1rem;
|
||
text-align: center;
|
||
padding: 1rem;
|
||
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
font-size: 1.125rem;
|
||
padding: 1.5rem;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
font-size: 1.0625rem;
|
||
padding: 1.25rem;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
font-size: 0.875rem;
|
||
padding: 1rem;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
font-size: 0.75rem;
|
||
padding: 0.75rem;
|
||
}
|
||
}
|
||
}
|
||
|
||
h2.section-title {
|
||
font-size: 1.25rem;
|
||
font-weight: bold;
|
||
color: $slate-700;
|
||
}
|
||
|
||
h4 {
|
||
font-weight: 600;
|
||
color: $slate-700;
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
// Context Panel
|
||
.section-card {
|
||
background-color: $white;
|
||
border-radius: 0.5rem;
|
||
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
|
||
// padding: 1rem;
|
||
// margin-top: 12px;
|
||
}
|
||
|
||
// 分析区域布局优化
|
||
.analysis-areas {
|
||
// PC端保持一致布局
|
||
@media (min-width: 1024px) {
|
||
gap: 20px;
|
||
}
|
||
|
||
// 平板端适配
|
||
@media (max-width: 1023px) and (min-width: 769px) {
|
||
gap: 18px;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
gap: 16px;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
gap: 12px;
|
||
}
|
||
}
|
||
|
||
// 下方行适配
|
||
.bottom-row {
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
height: auto;
|
||
min-height: 300px;
|
||
}
|
||
|
||
// 小屏移动端适配
|
||
@media (max-width: 480px) {
|
||
min-height: 250px;
|
||
}
|
||
}
|
||
|
||
</style> |