feat(secondTop): 添加营期阶段调控功能并优化KPI显示
- 在secondTop页面添加营期阶段调控UI,支持修改"接数据"天数 - 计算并显示当前营期阶段及日期范围 - 优化PersonalDashboard中的KPI指标名称显示 - 隐藏topOne页面中不需要的CampManagement组件
This commit is contained in:
@@ -58,7 +58,6 @@ export const getCustomerChatInfo = (params) => {
|
||||
// 客户表单详情 /api/v1/sales/get_customer_form_info
|
||||
export const getCustomerFormInfo = (params) => {
|
||||
return https.post('/api/v1/sales_timeline/get_customer_form_info', params)
|
||||
|
||||
}
|
||||
|
||||
// 客户通话录音 /api/v1/sales/get_customer_call_info
|
||||
|
||||
@@ -17,15 +17,15 @@
|
||||
</div>
|
||||
<div class="kpi-item">
|
||||
<div class="kpi-value">{{ props.kpiData.successRate }}%</div>
|
||||
<p>成功率</p>
|
||||
<p>电话接通率</p>
|
||||
</div>
|
||||
<div class="kpi-item">
|
||||
<div class="kpi-value">{{ props.kpiData.avgDuration }}<span class="kpi-unit">min</span></div>
|
||||
<p>平均时长</p>
|
||||
<p>平均通话时长</p>
|
||||
</div>
|
||||
<div class="kpi-item">
|
||||
<div class="kpi-value">{{ props.kpiData.conversionRate }}</div>
|
||||
<p>转化率</p>
|
||||
<p>成交转化率</p>
|
||||
</div>
|
||||
<div class="kpi-item">
|
||||
<div class="kpi-value">{{ props.kpiData.assignedData }}</div>
|
||||
|
||||
@@ -24,10 +24,20 @@
|
||||
<p>统筹多组运营,优化资源配置,驱动业绩增长,实现团队协同发展。</p>
|
||||
</div>
|
||||
|
||||
<!-- 营期阶段信息 -->
|
||||
<!-- 营期阶段信息与调控 -->
|
||||
<div class="stage-info" style="margin-left: 100px;">
|
||||
<span class="stage-label">营期所属阶段:</span>
|
||||
<span class="stage-value">接数据</span>
|
||||
<span class="stage-value">{{ currentStage }}</span>
|
||||
|
||||
<!-- 仅在“接数据”阶段显示调控UI -->
|
||||
<div v-if="isDataReceivingStage" class="stage-control">
|
||||
<span class="control-label">调整“接数据”天数:</span>
|
||||
<input type="number" v-model.number="dataReceivingStage.days" min="1" class="days-input" />
|
||||
<button @click="saveCampSettings" class="save-button">保存</button>
|
||||
</div>
|
||||
<div v-for="stage in centerData.stages" :key="stage.name" class="stage-dates">
|
||||
<span>{{ stage.name }}: {{ stage.startDate }} to {{ stage.endDate }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -174,6 +184,76 @@
|
||||
} from '@/api/secondTop.js'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useUserStore } from '@/stores/user.js'
|
||||
|
||||
// 营期调控逻辑
|
||||
// This would ideally come from a prop or API call based on the logged-in user
|
||||
const centerData = ref({
|
||||
id: 1,
|
||||
name: '一中心',
|
||||
startDate: '2025-08-18',
|
||||
stages: [
|
||||
{ name: '接数据', days: 3, color: '#ffc107', startDate: '', endDate: '' },
|
||||
{ name: '课一', days: 1, color: '#0dcaf0', startDate: '', endDate: '' },
|
||||
{ name: '课二', days: 1, color: '#0d6efd', startDate: '', endDate: '' },
|
||||
{ name: '课三', days: 1, color: '#6f42c1', startDate: '', endDate: '' },
|
||||
{ name: '课四', days: 1, color: '#d63384', startDate: '', endDate: '' }
|
||||
]
|
||||
});
|
||||
const getCurrentStage = (center) => {
|
||||
const today = new Date();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
const startDate = new Date(center.startDate);
|
||||
startDate.setHours(0, 0, 0, 0);
|
||||
|
||||
if (today < startDate) {
|
||||
return '未开始';
|
||||
}
|
||||
|
||||
const diffTime = Math.abs(today - startDate);
|
||||
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)) + 1; // 当天算第一天
|
||||
|
||||
let cumulativeDays = 0;
|
||||
for (let i = 0; i < center.stages.length; i++) {
|
||||
const stage = center.stages[i];
|
||||
cumulativeDays += stage.days;
|
||||
if (diffDays <= cumulativeDays) {
|
||||
return stage.name;
|
||||
}
|
||||
}
|
||||
|
||||
return '已结束';
|
||||
};
|
||||
|
||||
const currentStage = computed(() => getCurrentStage(centerData.value));
|
||||
|
||||
const isDataReceivingStage = computed(() => currentStage.value === '接数据');
|
||||
|
||||
// The '接数据' stage object
|
||||
const dataReceivingStage = computed(() => centerData.value.stages.find(s => s.name === '接数据'));
|
||||
|
||||
const recalculateStageDates = () => {
|
||||
const startDate = new Date(centerData.value.startDate);
|
||||
let cumulativeDays = 0;
|
||||
centerData.value.stages.forEach(stage => {
|
||||
const stageStartDate = new Date(startDate);
|
||||
stageStartDate.setDate(startDate.getDate() + cumulativeDays);
|
||||
stage.startDate = stageStartDate.toISOString().split('T')[0];
|
||||
|
||||
cumulativeDays += stage.days;
|
||||
|
||||
const stageEndDate = new Date(startDate);
|
||||
stageEndDate.setDate(startDate.getDate() + cumulativeDays - 1);
|
||||
stage.endDate = stageEndDate.toISOString().split('T')[0];
|
||||
});
|
||||
};
|
||||
|
||||
const saveCampSettings = () => {
|
||||
recalculateStageDates();
|
||||
console.log('Saving camp settings for', centerData.value.name);
|
||||
console.log('Updated data:', JSON.parse(JSON.stringify(centerData.value)));
|
||||
alert('营期设置已保存!');
|
||||
};
|
||||
|
||||
// 组别数据
|
||||
const groups = ref([])
|
||||
// loading 状态
|
||||
@@ -511,6 +591,7 @@ const conversionRateVsAverage = ref({})
|
||||
return statusMap[status] || '未知'
|
||||
}
|
||||
onMounted(async () => {
|
||||
recalculateStageDates();
|
||||
try {
|
||||
isLoading.value = true
|
||||
await CenterOverallCenterPerformance()
|
||||
@@ -1134,4 +1215,26 @@ const conversionRateVsAverage = ref({})
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
}
|
||||
.stage-control {
|
||||
margin-left: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.control-label {
|
||||
margin-right: 10px;
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.days-input {
|
||||
width: 60px;
|
||||
text-align: center;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.save-button {
|
||||
padding: 5px 10px;
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
@@ -57,7 +57,7 @@
|
||||
<problem-ranking :ranking-data="problemRankingData" />
|
||||
</div>
|
||||
<!-- 第四行:详细数据表格和数据详情 -->
|
||||
<div class="dashboard-row">
|
||||
<div class="dashboard-row" v-show="false">
|
||||
<CampManagement />
|
||||
</div>
|
||||
<!-- 第五行 -->
|
||||
|
||||
Reference in New Issue
Block a user