diff --git a/my-vue-app/src/views/person/components/SalesTimelineWithTaskList.vue b/my-vue-app/src/views/person/components/SalesTimelineWithTaskList.vue index 3493783..7cbf3c0 100644 --- a/my-vue-app/src/views/person/components/SalesTimelineWithTaskList.vue +++ b/my-vue-app/src/views/person/components/SalesTimelineWithTaskList.vue @@ -36,6 +36,167 @@ + +
+
+ +
+
+ 课1 + 转化率: {{ getCourseConversionRate(1) }}% +
+
+
+
+
+ 课1 + {{ getCourseStageCount(1, '课1') }} +
+
+
+
+
+ 付定金 + {{ getCourseStageCount(1, '付定金') }} +
+
+
+
+ + +
+
+ 课2 +
+
+
+
+
+ 课2 + {{ getCourseStageCount(2, '课2') }} +
+
+
+
+
+ 点击支付 + {{ getCourseStageCount(2, '点击未支付') }} +
+
+
+
+
+ 付定金 + {{ getCourseStageCount(2, '付定金') }} +
+
+
+
+
+ 定金转化 + {{ getCourseStageCount(2, '定金转化') }} +
+
+
+
+
+ 成交 + {{ getCourseStageCount(2, '成交') }} +
+
+
+
+ + +
+
+ 课3 +
+
+
+
+
+ 课3 + {{ getCourseStageCount(3, '课3') }} +
+
+
+
+
+ 点击未支付 + {{ getCourseStageCount(3, '点击未支付') }} +
+
+
+
+
+ 付定金 + {{ getCourseStageCount(3, '付定金') }} +
+
+
+
+
+ 定金转化 + {{ getCourseStageCount(3, '定金转化') }} +
+
+
+
+
+ 成交 + {{ getCourseStageCount(3, '成交') }} +
+
+
+
+ + +
+
+ 课4 +
+
+
+
+
+ 课4 + {{ getCourseStageCount(4, '课4') }} +
+
+
+
+
+ 点击未付 + {{ getCourseStageCount(4, '点击未支付') }} +
+
+
+
+
+ 付定金 + {{ getCourseStageCount(4, '付定金') }} +
+
+
+
+
+ 定金转化 + {{ getCourseStageCount(4, '定金转化') }} +
+
+
+
+
+ 成交 + {{ getCourseStageCount(4, '成交') }} +
+
+
+
+
+
+
@@ -44,7 +205,7 @@ :key="item.id" :id="`contact-item-${item.id}`" class="action-item" - :class="[getHealthIndicator(item.health).class, { 'active': item.id === selectedContactId }]" + :class="[getHealthClass(item.health), { 'active': item.id === selectedContactId }]" @click="selectContact(item.id)">
@@ -69,7 +230,7 @@ {{ getAttendedLessons(item.class_situation,item.class_num) }} - {{ item.type }} + {{ item.type }}
@@ -380,7 +541,7 @@ const stages = computed(() => { { id: 4, name: '待联系', displayName: '待联系', count: getStageCount('待联系'), color: '#bbdefb' }, { id: 5, name: '待到课', displayName: '待到课', count: getStageCount('待到课'), color: '#bbdefb'}, { id: 6, name: '课1-4', displayName: '课1-4', count: getStageCount('课1-4'), color: '#81c784' }, - { id: 7, name: '点击未支付', displayName: '点击未支付', count: getStageCount('点击未支付'), color: '#42a5f5' }, + { id: 7, name: '点击支付', displayName: '点击支付', count: getStageCount('点击未支付'), color: '#42a5f5' }, { id: 8, name: '付定金', displayName: '付定金', count: getStageCount('付定金'), color: '#2196f3' }, { id: 9, name: '定金转化', displayName: '定金转化', count: getStageCount('定金转化'), color: '#1e88e5' }, { id: 10, name: '成交', displayName: '成交', count: getStageCount('成交'), color: '#1976d2' } @@ -505,12 +666,6 @@ const selectContact = (id) => { emit('select-contact', id); }; -const getHealthIndicator = (score) => { - if (score > 80) return { class: 'health-good', text: '健康', textColor: 'text-green' }; - if (score > 50) return { class: 'health-ok', text: '一般', textColor: 'text-amber' }; - return { class: 'health-risk', text: '高风险', textColor: 'text-red' }; -}; - // 显示发言内容弹框 const showSpeakMessages = (speakMessages) => { modalMessages.value = speakMessages || []; @@ -522,6 +677,55 @@ const closeModal = () => { modalMessages.value = []; }; +// 获取课程阶段数量 +const getCourseStageCount = (courseNumber, stageType) => { + if (!props.customersList && !props.courseCustomers) return 0; + + // 根据课程号和阶段类型筛选客户 + let filteredCustomers = []; + + if (stageType === `课${courseNumber}`) { + // 课程阶段:筛选有对应课程到课记录的客户 + 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中筛选 + const courseKey = `课${courseNumber}`; + if (props.courseCustomers?.[courseKey]) { + filteredCustomers = props.courseCustomers[courseKey].filter(customer => customer.type === stageType); + } + } + + return filteredCustomers.length; +}; + +// 获取课程转化率 +const getCourseConversionRate = (courseNumber) => { + const courseStageCount = getCourseStageCount(courseNumber, `课${courseNumber}`); + const depositCount = getCourseStageCount(courseNumber, '付定金'); + + if (courseStageCount === 0) return 0; + return Math.round((depositCount / courseStageCount) * 100); +}; const getAttendedLessons = (classSituation, classNum) => { // 优先使用 class_num 字段 @@ -547,6 +751,23 @@ const getAttendedLessons = (classSituation, classNum) => { return '未到课'; }; + +// 获取健康度对应的CSS类 +const getHealthClass = (health) => { + if (!health && health !== 0) return ''; + + const healthValue = parseFloat(health); + + if (healthValue >= 80) { + return 'health-good'; + } else if (healthValue >= 60) { + return 'health-normal'; + } else if (healthValue >= 40) { + return 'health-warning'; + } else { + return 'health-danger'; + } +}; \ No newline at end of file diff --git a/my-vue-app/src/views/secondTop/components/Calendar.vue b/my-vue-app/src/views/secondTop/components/Calendar.vue index 80bb91d..7c962a9 100644 --- a/my-vue-app/src/views/secondTop/components/Calendar.vue +++ b/my-vue-app/src/views/secondTop/components/Calendar.vue @@ -10,21 +10,12 @@

{{ currentYear }}年{{ currentMonth + 1 }}月