diff --git a/my-vue-app/src/utils/https.js b/my-vue-app/src/utils/https.js
index fed8748..68cbdab 100644
--- a/my-vue-app/src/utils/https.js
+++ b/my-vue-app/src/utils/https.js
@@ -5,7 +5,7 @@ import { useUserStore } from '@/stores/user'
// 创建axios实例
const service = axios.create({
- baseURL: 'http://192.168.15.53:8890' || '', // API基础路径,支持完整URL
+ baseURL: 'http://192.168.15.121:8890' || '', // API基础路径,支持完整URL
timeout: 100000, // 请求超时时间
headers: {
'Content-Type': 'application/json;charset=UTF-8'
diff --git a/my-vue-app/src/views/maneger/components/MemberDetails.vue b/my-vue-app/src/views/maneger/components/MemberDetails.vue
index 976dae3..22f64e2 100644
--- a/my-vue-app/src/views/maneger/components/MemberDetails.vue
+++ b/my-vue-app/src/views/maneger/components/MemberDetails.vue
@@ -165,23 +165,23 @@ const tooltip = reactive({
const metricDescriptions = {
totalCalls: {
title: '总通话次数计算方式',
- description: '统计该成员在选定时间范围内的所有外呼和接听通话的总次数,包括有效通话和无效通话。'
+ description: '统计在选定时间范围内的所有外呼和接听通话的总次数,包括有效通话和无效通话。'
},
callTime: {
title: '通话时长计算方式',
- description: '累计该成员所有有效通话的时长,以小时为单位显示,精确到小数点后一位。'
+ description: '累计所有有效通话的时长,以小时为单位显示,精确到小数点后一位。'
},
newClients: {
title: '新增客户计算方式',
- description: '统计该成员在选定时间范围内新建档的客户数量,不包括重复录入的客户。'
+ description: '在选定时间范围内新建档的客户数量,不包括重复录入的客户。'
},
deals: {
title: '成交单数计算方式',
- description: '统计该成员在选定时间范围内成功签约的订单数量,包括全款和定金订单。'
+ description: '在选定时间范围内成功签约的订单数量,包括全款和定金订单。'
},
conversionRate: {
title: '转化率计算方式',
- description: '成交单数 ÷ 新增客户数 × 100%,反映该成员将潜在客户转化为成交客户的能力。'
+ description: '成交单数 ÷ 新增客户数 × 100%'
}
}
diff --git a/my-vue-app/src/views/person/components/SalesTimelineWithTaskList.vue b/my-vue-app/src/views/person/components/SalesTimelineWithTaskList.vue
index 7e67c50..9cc5a64 100644
--- a/my-vue-app/src/views/person/components/SalesTimelineWithTaskList.vue
+++ b/my-vue-app/src/views/person/components/SalesTimelineWithTaskList.vue
@@ -25,9 +25,12 @@
{{ stage.displayName || stage.name }}
{{ stage.name === '全部' ? customersCount : stage.count }}
- 位客户
+ 位
- {{ getPercentage(stage.count) }}%
+
+ {{ stage.unName }}
+
+ {{ getPercentage(stage.count, stage.id, stage.name) }}%
@@ -217,6 +220,50 @@ const getStageCount = (stageType) => {
return props.payMoneyCustomersCount || (props.payMoneyCustomersList?.length || 0);
}
+ // 待填表单阶段:统计customer_occupation或customer_child_education字段为'未知'的客户数量
+ if (stageType === '待填表单') {
+ if (props.customersList?.length) {
+ return props.customersList.filter(customer => {
+ return (customer.customer_occupation === '未知' || !customer.customer_occupation) ||
+ (customer.customer_child_education === '未知' || !customer.customer_child_education);
+ }).length;
+ }
+ return props.data[stageType] || 0;
+ }
+
+ // 待到课阶段:统计没有到课数据的客户数量
+ if (stageType === '待到课') {
+ if (props.customersList?.length) {
+ return props.customersList.filter(customer => {
+ // 根据getAttendedLessons函数的逻辑判断是否为'未到课'
+ const classNum = customer.class_num;
+ const classSituation = customer.class_situation;
+
+ // 优先检查class_num字段
+ if (classNum && Array.isArray(classNum) && classNum.length > 0) {
+ return false; // 有class_num数据,不是待到课
+ }
+
+ // 检查class_situation字段
+ if (!classSituation) return true; // 没有class_situation,是待到课
+
+ if (Array.isArray(classSituation)) {
+ return classSituation.length === 0; // 空数组,是待到课
+ }
+
+ if (typeof classSituation === 'object') {
+ const lessonNumbers = Object.keys(classSituation)
+ .map(key => parseInt(key))
+ .filter(num => !isNaN(num));
+ return lessonNumbers.length === 0; // 没有有效的课程数据,是待到课
+ }
+
+ return true; // 其他情况默认为待到课
+ }).length;
+ }
+ return props.data[stageType] || 0;
+ }
+
// 课1-4阶段从courseCustomers获取数量
if (stageType === '课1-4' && props.courseCustomers?.['课1-4']) {
return props.courseCustomers['课1-4'].length;
@@ -258,11 +305,11 @@ const stages = computed(() => {
const stageList = [
{ id: 0, name: '全部', displayName: '全部', count: totalCount, color: '#f3f4f6' },
- { id: 1, name: '待加微', displayName: '待加微', count: getStageCount('待加微'), color: '#e3f2fd' },
- { id: 2, name: '待填表单', displayName: '待填表单', count: getStageCount('待填表单'), color: '#90caf9' },
- { id: 3, name: '待入群', displayName: '待入群', count: getStageCount('待入群'), color: '#bbdefb' },
- { id: 4, name: '待联系', displayName: '待联系', count: getStageCount('待联系'), color: '#bbdefb' },
- { id: 5, name: '待到课', displayName: '待到课', count: getStageCount('待到课'), color: '#bbdefb' },
+ { id: 1, name: '待加微', displayName: '待加微', count: getStageCount('待加微'), color: '#e3f2fd' ,unName:'已加微'},
+ { id: 2, name: '待填表单', displayName: '待填表单', count: getStageCount('待填表单'), color: '#90caf9' ,unName:'已填表单'},
+ { id: 3, name: '待入群', displayName: '待入群', count: getStageCount('待入群'), color: '#bbdefb' ,unName:'已入群'},
+ { id: 4, name: '待联系', displayName: '待联系', count: getStageCount('待联系'), color: '#bbdefb' ,unName:'已联系'},
+ { id: 5, name: '待到课', displayName: '待到课', count: getStageCount('待到课'), color: '#bbdefb' ,unName:'已到课'},
{ id: 6, name: '课1', displayName: '课1', count: getStageCount('课1'), color: '#81c784' },
{ id: 7, name: '课2', displayName: '课2', count: getStageCount('课2'), color: '#64b5f6' },
{ id: 8, name: '课3', displayName: '课3', count: getStageCount('课3'), color: '#ffb74d' },
@@ -277,9 +324,31 @@ const stages = computed(() => {
});
-const getPercentage = (count) => {
+const getPercentage = (count, stageId, stageName) => {
if (totalCustomers.value === 0) return 0;
- return Math.round((count / totalCustomers.value) * 100);
+
+ // 待填表单阶段特殊计算:(总数-有数据人数)/总数
+ if (stageName === '待填表单') {
+ return Math.round((totalCustomers.value - count) / totalCustomers.value * 100);
+ }
+
+ // 待到课阶段特殊计算:(总数-有到课数据人数)/总数
+ if (stageName === '待到课') {
+ return Math.round((totalCustomers.value - count) / totalCustomers.value * 100);
+ }
+
+ // 阶段1-5使用现在的算法(转化率)
+ if (stageId >= 1 && stageId <= 5) {
+ return Math.round((totalCustomers.value - count) / totalCustomers.value * 100);
+ }
+
+ // 阶段5-13使用直接数量除以总数
+ if (stageId >5 && stageId <= 13) {
+ return Math.round((count / totalCustomers.value) * 100);
+ }
+
+ // 其他阶段保持原有逻辑
+ return Math.round((totalCustomers.value - count) / totalCustomers.value * 100);
};
@@ -328,6 +397,40 @@ const selectStage = (stageName) => {
if (props.courseCustomers?.['课1-4']) {
filteredCustomers = props.courseCustomers['课1-4'].filter(customer => customer.type === stageName);
}
+ } else if (stageName === '待填表单') {
+ // 待填表单阶段:筛选customer_occupation或customer_child_education字段为'未知'的客户
+ filteredCustomers = props.customersList.filter(customer => {
+ return (customer.customer_occupation === '未知' || !customer.customer_occupation) ||
+ (customer.customer_child_education === '未知' || !customer.customer_child_education);
+ });
+ } else if (stageName === '待到课') {
+ // 待到课阶段:筛选没有到课数据的客户
+ filteredCustomers = props.customersList.filter(customer => {
+ // 根据getAttendedLessons函数的逻辑判断是否为'未到课'
+ const classNum = customer.class_num;
+ const classSituation = customer.class_situation;
+
+ // 优先检查class_num字段
+ if (classNum && Array.isArray(classNum) && classNum.length > 0) {
+ return false; // 有class_num数据,不是待到课
+ }
+
+ // 检查class_situation字段
+ if (!classSituation) return true; // 没有class_situation,是待到课
+
+ if (Array.isArray(classSituation)) {
+ return classSituation.length === 0; // 空数组,是待到课
+ }
+
+ if (typeof classSituation === 'object') {
+ const lessonNumbers = Object.keys(classSituation)
+ .map(key => parseInt(key))
+ .filter(num => !isNaN(num));
+ return lessonNumbers.length === 0; // 没有有效的课程数据,是待到课
+ }
+
+ return true; // 其他情况默认为待到课
+ });
} else {
// 前6个阶段从customersList中筛选
filteredCustomers = props.customersList.filter(customer => customer.type === stageName);
@@ -650,8 +753,9 @@ $indigo: #4f46e5;
.stage-content {
.stage-title {
+ font-size: 1rem;
color: $slate-800;
- font-weight: 600;
+ font-weight: 500;
}
.stage-count {
diff --git a/my-vue-app/src/views/secondTop/components/CenterOverview.vue b/my-vue-app/src/views/secondTop/components/CenterOverview.vue
index 30eb5fb..99ea236 100644
--- a/my-vue-app/src/views/secondTop/components/CenterOverview.vue
+++ b/my-vue-app/src/views/secondTop/components/CenterOverview.vue
@@ -1,14 +1,28 @@