feat(销售时间轴): 添加子时间轴阶段选择功能

实现子时间轴各阶段的点击选择功能,将筛选后的客户数据转换为统一格式并传递给父组件
This commit is contained in:
2025-08-30 17:19:53 +08:00
parent d204c7befe
commit c10b514779
2 changed files with 107 additions and 19 deletions

View File

@@ -36,7 +36,7 @@
</div>
</div>
<!-- 课1-4子时间轴 -->
<!-- 课1-4子时间轴 -->
<div v-if="selectedStage === '课1-4'" class="course-sub-timeline">
<div class="sub-timeline-container">
<!-- 课1子时间轴 -->
@@ -46,14 +46,14 @@
<span class="course-conversion">转化率: {{ getCourseConversionRate(1) }}%</span>
</div>
<div class="mini-timeline">
<div class="mini-stage" :class="{ active: getCourseStageCount(1, '课1') > 0 }">
<div class="mini-stage" :class="{ active: getCourseStageCount(1, '课1') > 0 }" @click="selectCourseStage(1, '课1')">
<div class="mini-marker"></div>
<div class="mini-content">
<span class="mini-title">课1</span>
<span class="mini-count">{{ getCourseStageCount(1, '课1') }}</span>
</div>
</div>
<div class="mini-stage" :class="{ active: getCourseStageCount(1, '付定金') > 0 }">
<div class="mini-stage" :class="{ active: getCourseStageCount(1, '付定金') > 0 }" @click="selectCourseStage(1, '付定金')">
<div class="mini-marker"></div>
<div class="mini-content">
<span class="mini-title">付定金</span>
@@ -69,35 +69,35 @@
<span class="course-title">课2</span>
</div>
<div class="mini-timeline">
<div class="mini-stage" :class="{ active: getCourseStageCount(2, '课2') > 0 }">
<div class="mini-stage" :class="{ active: getCourseStageCount(2, '课2') > 0 }" @click="selectCourseStage(2, '课2')">
<div class="mini-marker"></div>
<div class="mini-content">
<span class="mini-title">课2</span>
<span class="mini-count">{{ getCourseStageCount(2, '课2') }}</span>
</div>
</div>
<div class="mini-stage" :class="{ active: getCourseStageCount(2, '点击未支付') > 0 }">
<div class="mini-stage" :class="{ active: getCourseStageCount(2, '点击未支付') > 0 }" @click="selectCourseStage(2, '点击未支付')">
<div class="mini-marker"></div>
<div class="mini-content">
<span class="mini-title">点击支付</span>
<span class="mini-count">{{ getCourseStageCount(2, '点击未支付') }}</span>
</div>
</div>
<div class="mini-stage" :class="{ active: getCourseStageCount(2, '付定金') > 0 }">
<div class="mini-stage" :class="{ active: getCourseStageCount(2, '付定金') > 0 }" @click="selectCourseStage(2, '付定金')">
<div class="mini-marker"></div>
<div class="mini-content">
<span class="mini-title">付定金</span>
<span class="mini-count">{{ getCourseStageCount(2, '付定金') }}</span>
</div>
</div>
<div class="mini-stage" :class="{ active: getCourseStageCount(2, '定金转化') > 0 }">
<div class="mini-stage" :class="{ active: getCourseStageCount(2, '定金转化') > 0 }" @click="selectCourseStage(2, '定金转化')">
<div class="mini-marker"></div>
<div class="mini-content">
<span class="mini-title">定金转化</span>
<span class="mini-count">{{ getCourseStageCount(2, '定金转化') }}</span>
</div>
</div>
<div class="mini-stage" :class="{ active: getCourseStageCount(2, '成交') > 0 }">
<div class="mini-stage" :class="{ active: getCourseStageCount(2, '成交') > 0 }" @click="selectCourseStage(2, '成交')">
<div class="mini-marker"></div>
<div class="mini-content">
<span class="mini-title">成交</span>
@@ -113,35 +113,35 @@
<span class="course-title">课3</span>
</div>
<div class="mini-timeline">
<div class="mini-stage" :class="{ active: getCourseStageCount(3, '课3') > 0 }">
<div class="mini-stage" :class="{ active: getCourseStageCount(3, '课3') > 0 }" @click="selectCourseStage(3, '课3')">
<div class="mini-marker"></div>
<div class="mini-content">
<span class="mini-title">课3</span>
<span class="mini-count">{{ getCourseStageCount(3, '课3') }}</span>
</div>
</div>
<div class="mini-stage" :class="{ active: getCourseStageCount(3, '点击未支付') > 0 }">
<div class="mini-stage" :class="{ active: getCourseStageCount(3, '点击未支付') > 0 }" @click="selectCourseStage(3, '点击未支付')">
<div class="mini-marker"></div>
<div class="mini-content">
<span class="mini-title">点击未支付</span>
<span class="mini-count">{{ getCourseStageCount(3, '点击未支付') }}</span>
</div>
</div>
<div class="mini-stage" :class="{ active: getCourseStageCount(3, '付定金') > 0 }">
<div class="mini-stage" :class="{ active: getCourseStageCount(3, '付定金') > 0 }" @click="selectCourseStage(3, '付定金')">
<div class="mini-marker"></div>
<div class="mini-content">
<span class="mini-title">付定金</span>
<span class="mini-count">{{ getCourseStageCount(3, '付定金') }}</span>
</div>
</div>
<div class="mini-stage" :class="{ active: getCourseStageCount(3, '定金转化') > 0 }">
<div class="mini-stage" :class="{ active: getCourseStageCount(3, '定金转化') > 0 }" @click="selectCourseStage(3, '定金转化')">
<div class="mini-marker"></div>
<div class="mini-content">
<span class="mini-title">定金转化</span>
<span class="mini-count">{{ getCourseStageCount(3, '定金转化') }}</span>
</div>
</div>
<div class="mini-stage" :class="{ active: getCourseStageCount(3, '成交') > 0 }">
<div class="mini-stage" :class="{ active: getCourseStageCount(3, '成交') > 0 }" @click="selectCourseStage(3, '成交')">
<div class="mini-marker"></div>
<div class="mini-content">
<span class="mini-title">成交</span>
@@ -157,35 +157,35 @@
<span class="course-title">课4</span>
</div>
<div class="mini-timeline">
<div class="mini-stage" :class="{ active: getCourseStageCount(4, '课4') > 0 }">
<div class="mini-stage" :class="{ active: getCourseStageCount(4, '课4') > 0 }" @click="selectCourseStage(4, '课4')">
<div class="mini-marker"></div>
<div class="mini-content">
<span class="mini-title">课4</span>
<span class="mini-count">{{ getCourseStageCount(4, '课4') }}</span>
</div>
</div>
<div class="mini-stage" :class="{ active: getCourseStageCount(4, '点击未支付') > 0 }">
<div class="mini-stage" :class="{ active: getCourseStageCount(4, '点击未支付') > 0 }" @click="selectCourseStage(4, '点击未支付')">
<div class="mini-marker"></div>
<div class="mini-content">
<span class="mini-title">点击未付</span>
<span class="mini-count">{{ getCourseStageCount(4, '点击未支付') }}</span>
</div>
</div>
<div class="mini-stage" :class="{ active: getCourseStageCount(4, '付定金') > 0 }">
<div class="mini-stage" :class="{ active: getCourseStageCount(4, '付定金') > 0 }" @click="selectCourseStage(4, '付定金')">
<div class="mini-marker"></div>
<div class="mini-content">
<span class="mini-title">付定金</span>
<span class="mini-count">{{ getCourseStageCount(4, '付定金') }}</span>
</div>
</div>
<div class="mini-stage" :class="{ active: getCourseStageCount(4, '定金转化') > 0 }">
<div class="mini-stage" :class="{ active: getCourseStageCount(4, '定金转化') > 0 }" @click="selectCourseStage(4, '定金转化')">
<div class="mini-marker"></div>
<div class="mini-content">
<span class="mini-title">定金转化</span>
<span class="mini-count">{{ getCourseStageCount(4, '定金转化') }}</span>
</div>
</div>
<div class="mini-stage" :class="{ active: getCourseStageCount(4, '成交') > 0 }">
<div class="mini-stage" :class="{ active: getCourseStageCount(4, '成交') > 0 }" @click="selectCourseStage(4, '成交')">
<div class="mini-marker"></div>
<div class="mini-content">
<span class="mini-title">成交</span>
@@ -195,7 +195,7 @@
</div>
</div>
</div>
</div>
</div>
<div class="task-body">
<div class="actionable-list">
@@ -768,6 +768,55 @@ const getHealthClass = (health) => {
return 'health-danger';
}
};
// 选择课程阶段
const selectCourseStage = (courseNumber, stageType) => {
let filteredCustomers = [];
if (stageType === `${courseNumber}`) {
// 课程阶段从customersList中筛选
filteredCustomers = props.customersList.filter(customer => {
const classNum = customer.class_num;
const classSituation = customer.class_situation;
// 检查class_num字段
if (classNum && Array.isArray(classNum)) {
return classNum.includes(courseNumber);
}
// 检查class_situation字段
if (classSituation) {
if (Array.isArray(classSituation)) {
return classSituation.includes(courseNumber);
}
if (typeof classSituation === 'object') {
return classSituation.hasOwnProperty(courseNumber.toString());
}
}
return false;
});
} else {
// 其他阶段从courseCustomers中筛选
if (props.courseCustomers?.['课1-4']) {
filteredCustomers = props.courseCustomers['课1-4'].filter(customer => {
// 检查客户是否参加了指定课程并且类型匹配
const hasAttendedCourse = customer.class_num && customer.class_num.includes(courseNumber);
return hasAttendedCourse && customer.type === stageType;
});
}
}
// 发送子时间轴选择事件给父组件,使用不同的事件名称避免与主轴冲突
emit('sub-stage-select', {
filteredCustomers,
stageType: `${courseNumber}-${stageType}`,
customerCount: filteredCustomers.length,
courseNumber,
originalStageType: stageType,
keepSubTimeline: true // 标识保持子时间轴显示
});
};
</script>
<style lang="scss" scoped>

View File

@@ -42,6 +42,7 @@
v-else
:data="timelineData"
@stage-select="handleStageSelect"
@sub-stage-select="handleSubStageSelect"
:selected-stage="selectedStage"
:contacts="filteredContacts"
:selected-contact-id="selectedContactId"
@@ -772,6 +773,44 @@ const handleStageSelect = (stage, extraData = null) => {
currentFilteredCustomers.value = [];
}
};
// 处理子时间轴阶段选择
const handleSubStageSelect = (eventData) => {
console.log('子时间轴选择事件:', eventData);
// 将筛选后的客户数据转换为contacts格式
const filteredContacts = eventData.filteredCustomers.map(customer => ({
id: customer.customer_name || customer.id,
name: customer.customer_name || customer.name,
phone: customer.phone,
profession: customer.customer_occupation || customer.profession,
education: customer.customer_child_education || customer.education,
lastMessageTime: customer.latest_message_time || customer.time,
avatarUrl: customer.customer_avatar_url || customer.avatar,
avatar: customer.customer_avatar_url || customer.avatar || '/default-avatar.svg',
type: customer.type || eventData.originalStageType,
classNum: customer.class_num,
class_num: customer.class_num,
salesStage: eventData.stageType,
priority: customer.type === '待联系' ? 'high' : 'normal',
time: customer.latest_message_time || customer.time || '未知',
health: customer.health || 75,
// 保留原始数据
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
}));
// 更新当前筛选的客户数据但保持selectedStage不变保持子时间轴显示
currentFilteredCustomers.value = filteredContacts;
console.log(`已筛选出${eventData.originalStageType}阶段的${filteredContacts.length}位客户`);
};
const handleViewFormData = async (contact) => {
// 获取客户表单数据
await getCustomerForm();