|
|
@@ -27,13 +27,6 @@
|
|
|
>
|
|
|
<el-table-column label="课程名称" align="center" prop="courseName" width="200" />
|
|
|
<el-table-column label="小节" align="center" prop="videoName" width="210" />
|
|
|
-<!-- <el-table-column label="小节状态" align="center" prop="videoStatus" width="120">-->
|
|
|
-<!-- <template slot-scope="scope">-->
|
|
|
-<!-- <el-tag :type="scope.row.videoStatus === '已开课' ? 'success' : scope.row.videoStatus === '已结束' ? 'info' : 'warning'">-->
|
|
|
-<!-- {{ scope.row.videoStatus }}-->
|
|
|
-<!-- </el-tag>-->
|
|
|
-<!-- </template>-->
|
|
|
-<!-- </el-table-column>-->
|
|
|
<el-table-column label="开课状态" align="center" prop="openStatus" width="120">
|
|
|
<template slot-scope="scope">
|
|
|
<el-tag :type="scope.row.openStatus === '已开课' ? 'success' : scope.row.openStatus === '已结束' ? 'info' : 'warning'">
|
|
|
@@ -112,78 +105,84 @@
|
|
|
</el-card>
|
|
|
|
|
|
<!-- 第二块:首次点播数据 -->
|
|
|
+<!-- <el-card class="detail-card" shadow="never">-->
|
|
|
+<!-- <div slot="header" class="card-header">-->
|
|
|
+<!-- <span>首次点播数据</span>-->
|
|
|
+<!-- </div>-->
|
|
|
+<!-- <el-row :gutter="20">-->
|
|
|
+<!-- <el-col :span="6">-->
|
|
|
+<!-- <div class="stat-item">-->
|
|
|
+<!-- <div class="stat-label">观看人数</div>-->
|
|
|
+<!-- <div class="stat-value">{{ detailDialog.data.firstWatchCount || 0 }}</div>-->
|
|
|
+<!-- </div>-->
|
|
|
+<!-- </el-col>-->
|
|
|
+<!-- <el-col :span="6">-->
|
|
|
+<!-- <div class="stat-item">-->
|
|
|
+<!-- <div class="stat-label">>=20分钟人数(首次)</div>-->
|
|
|
+<!-- <div class="stat-value">{{ detailDialog.data.firstWatch20MinCount || 0 }}</div>-->
|
|
|
+<!-- </div>-->
|
|
|
+<!-- </el-col>-->
|
|
|
+<!-- <el-col :span="6">-->
|
|
|
+<!-- <div class="stat-item">-->
|
|
|
+<!-- <div class="stat-label">>=30分钟人数(首次)</div>-->
|
|
|
+<!-- <div class="stat-value">{{ detailDialog.data.firstWatch30MinCount || 0 }}</div>-->
|
|
|
+<!-- </div>-->
|
|
|
+<!-- </el-col>-->
|
|
|
+<!-- <el-col :span="6">-->
|
|
|
+<!-- <div class="stat-item">-->
|
|
|
+<!-- <div class="stat-label">到课完课率首次(>=20分钟)</div>-->
|
|
|
+<!-- <div class="stat-value">{{ detailDialog.data.firstCompleteRate20Min || '0%' }}</div>-->
|
|
|
+<!-- </div>-->
|
|
|
+<!-- </el-col>-->
|
|
|
+<!-- <el-col :span="6">-->
|
|
|
+<!-- <div class="stat-item">-->
|
|
|
+<!-- <div class="stat-label">到课完课率首次(>=30分钟)</div>-->
|
|
|
+<!-- <div class="stat-value">{{ detailDialog.data.firstCompleteRate30Min || '0%' }}</div>-->
|
|
|
+<!-- </div>-->
|
|
|
+<!-- </el-col>-->
|
|
|
+<!-- </el-row>-->
|
|
|
+<!-- </el-card>-->
|
|
|
+
|
|
|
+ <!-- 第三块:实际看课数据(修复后) -->
|
|
|
<el-card class="detail-card" shadow="never">
|
|
|
<div slot="header" class="card-header">
|
|
|
- <span>首次点播数据</span>
|
|
|
+ <span>实际看课数据</span>
|
|
|
</div>
|
|
|
<el-row :gutter="20">
|
|
|
<el-col :span="6">
|
|
|
<div class="stat-item">
|
|
|
- <div class="stat-label">观看人数</div>
|
|
|
- <div class="stat-value">{{ detailDialog.data.firstWatchCount || 0 }}</div>
|
|
|
- </div>
|
|
|
- </el-col>
|
|
|
- <el-col :span="6">
|
|
|
- <div class="stat-item">
|
|
|
- <div class="stat-label">>=20分钟人数(首次)</div>
|
|
|
- <div class="stat-value">{{ detailDialog.data.firstWatch20MinCount || 0 }}</div>
|
|
|
- </div>
|
|
|
- </el-col>
|
|
|
- <el-col :span="6">
|
|
|
- <div class="stat-item">
|
|
|
- <div class="stat-label">>=30分钟人数(首次)</div>
|
|
|
- <div class="stat-value">{{ detailDialog.data.firstWatch30MinCount || 0 }}</div>
|
|
|
- </div>
|
|
|
- </el-col>
|
|
|
- <el-col :span="6">
|
|
|
- <div class="stat-item">
|
|
|
- <div class="stat-label">到课完课率首次(>=20分钟)</div>
|
|
|
- <div class="stat-value">{{ detailDialog.data.firstCompleteRate20Min || '0%' }}</div>
|
|
|
- </div>
|
|
|
- </el-col>
|
|
|
- <el-col :span="6">
|
|
|
- <div class="stat-item">
|
|
|
- <div class="stat-label">到课完课率首次(>=30分钟)</div>
|
|
|
- <div class="stat-value">{{ detailDialog.data.firstCompleteRate30Min || '0%' }}</div>
|
|
|
+ <div class="stat-label">实际到课人数</div>
|
|
|
+ <div class="stat-value">{{ detailDialog.data.totalStudents || 0 }}</div>
|
|
|
</div>
|
|
|
</el-col>
|
|
|
- </el-row>
|
|
|
- </el-card>
|
|
|
-
|
|
|
- <!-- 第三块:第2-n次观看数据 -->
|
|
|
- <el-card class="detail-card" shadow="never">
|
|
|
- <div slot="header" class="card-header">
|
|
|
- <span>第2-n次观看数据</span>
|
|
|
- </div>
|
|
|
- <el-row :gutter="20">
|
|
|
<el-col :span="6">
|
|
|
<div class="stat-item">
|
|
|
- <div class="stat-label">观看人数</div>
|
|
|
- <div class="stat-value">{{ detailDialog.data.repeatWatchCount || 0 }}</div>
|
|
|
+ <div class="stat-label">实际完课人数</div>
|
|
|
+ <div class="stat-value">{{ detailDialog.data.completedCount || 0 }}</div>
|
|
|
</div>
|
|
|
</el-col>
|
|
|
<el-col :span="6">
|
|
|
<div class="stat-item">
|
|
|
- <div class="stat-label">>=20分钟人数</div>
|
|
|
- <div class="stat-value">{{ detailDialog.data.repeatWatch20MinCount || 0 }}</div>
|
|
|
+ <div class="stat-label">实际完课率</div>
|
|
|
+ <div class="stat-value">{{ detailDialog.data.actualCompletionRate ? detailDialog.data.actualCompletionRate + '%' : '0%' }}</div>
|
|
|
</div>
|
|
|
</el-col>
|
|
|
<el-col :span="6">
|
|
|
<div class="stat-item">
|
|
|
- <div class="stat-label">>=30分钟人数</div>
|
|
|
- <div class="stat-value">{{ detailDialog.data.repeatWatch30MinCount || 0 }}</div>
|
|
|
+ <div class="stat-label">人均看课时长</div>
|
|
|
+ <div class="stat-value">{{ (detailDialog.data.avgWatchDurationMinutes || 0) + '分' }}</div>
|
|
|
</div>
|
|
|
</el-col>
|
|
|
<el-col :span="6">
|
|
|
<div class="stat-item">
|
|
|
- <div class="stat-label">到课完课率2-n次(>=20分钟)</div>
|
|
|
- <div class="stat-value">{{ detailDialog.data.repeatCompleteRate20Min || '0%' }}</div>
|
|
|
+ <div class="stat-label">人均完课时长</div>
|
|
|
+ <div class="stat-value">{{ (detailDialog.data.avgCompletedDuration || 0) + '分' }}</div>
|
|
|
</div>
|
|
|
</el-col>
|
|
|
<el-col :span="6">
|
|
|
<div class="stat-item">
|
|
|
- <div class="stat-label">到课完课率2-n次(>=30分钟)</div>
|
|
|
- <div class="stat-value">{{ detailDialog.data.repeatCompleteRate30Min || '0%' }}</div>
|
|
|
+ <div class="stat-label">人均完课完播率</div>
|
|
|
+ <div class="stat-value">{{ detailDialog.data.avgCompletionPlaybackRate ? detailDialog.data.avgCompletionPlaybackRate + '%' : '0%' }}</div>
|
|
|
</div>
|
|
|
</el-col>
|
|
|
</el-row>
|
|
|
@@ -249,7 +248,7 @@
|
|
|
<!-- 第五块:单品销量统计 -->
|
|
|
<el-card class="detail-card" shadow="never">
|
|
|
<div slot="header" class="card-header">
|
|
|
- <span>单品销量统计</span>
|
|
|
+ <span>商品销量统计</span>
|
|
|
</div>
|
|
|
<el-table
|
|
|
:data="detailDialog.data.productList || []"
|
|
|
@@ -287,12 +286,12 @@
|
|
|
style="width: 100%"
|
|
|
>
|
|
|
<el-table-column label="用户名称" align="center" prop="userName" width="150" />
|
|
|
- <el-table-column label="观看时长" align="center" prop="watchDuration" width="120">
|
|
|
- <template slot-scope="scope">
|
|
|
- {{ formatDuration(scope.row.watchDuration) }}
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- <el-table-column label="第2-n次观看时长" align="center" prop="repeatWatchDuration" width="150">
|
|
|
+<!-- <el-table-column label="观看时长" align="center" prop="watchDuration" width="120">-->
|
|
|
+<!-- <template slot-scope="scope">-->
|
|
|
+<!-- {{ formatDuration(scope.row.watchDuration) }}-->
|
|
|
+<!-- </template>-->
|
|
|
+<!-- </el-table-column>-->
|
|
|
+ <el-table-column label="观看时长" align="center" prop="repeatWatchDuration" width="150">
|
|
|
<template slot-scope="scope">
|
|
|
{{ formatDuration(scope.row.repeatWatchDuration) }}
|
|
|
</template>
|
|
|
@@ -452,7 +451,6 @@ export default {
|
|
|
this.detailDialog.visible = true;
|
|
|
this.detailDialog.loading = true;
|
|
|
|
|
|
- // 调用API获取总体数据
|
|
|
const videoId = row.videoId || row.id;
|
|
|
const periodId = this.queryParams.periodId;
|
|
|
|
|
|
@@ -465,25 +463,30 @@ export default {
|
|
|
getCourseStatisticsDetail(videoId, periodId).then(response => {
|
|
|
if (response.code === 200 && response.data) {
|
|
|
const data = response.data;
|
|
|
+ // 安全获取实际看课数据对象
|
|
|
+ const actualVO = data.fsActualCompletionVO || {};
|
|
|
+
|
|
|
// 设置总体数据
|
|
|
this.detailDialog.data = {
|
|
|
- videoDuration: data.videoDuration || 0,
|
|
|
- totalWatchCount: data.totalWatchCount || 0,
|
|
|
- totalCompleteCount: data.totalCompleteCount || 0,
|
|
|
+ // 总体数据
|
|
|
+ videoDuration: data.videoDuration ?? 0,
|
|
|
+ totalWatchCount: data.totalWatchCount ?? 0,
|
|
|
+ totalCompleteCount: data.totalCompleteCount ?? 0,
|
|
|
completeRate: data.completeRate != null ? Number(data.completeRate).toFixed(2) + '%' : '0%',
|
|
|
- // 首次点播数据(接口返回)
|
|
|
+ // 首次点播数据
|
|
|
firstWatchCount: data.firstWatchCount ?? 0,
|
|
|
firstWatch20MinCount: data.firstWatch20MinCount ?? 0,
|
|
|
firstWatch30MinCount: data.firstWatch30MinCount ?? 0,
|
|
|
firstCompleteRate20Min: data.firstCompleteRate20Min != null ? Number(data.firstCompleteRate20Min).toFixed(2) + '%' : '0%',
|
|
|
firstCompleteRate30Min: data.firstCompleteRate30Min != null ? Number(data.firstCompleteRate30Min).toFixed(2) + '%' : '0%',
|
|
|
- // 第2-n次观看数据(接口返回)
|
|
|
- repeatWatchCount: data.repeatWatchCount ?? 0,
|
|
|
- repeatWatch20MinCount: data.repeatWatch20MinCount ?? 0,
|
|
|
- repeatWatch30MinCount: data.repeatWatch30MinCount ?? 0,
|
|
|
- repeatCompleteRate20Min: data.repeatCompleteRate20Min != null ? Number(data.repeatCompleteRate20Min).toFixed(2) + '%' : '0%',
|
|
|
- repeatCompleteRate30Min: data.repeatCompleteRate30Min != null ? Number(data.repeatCompleteRate30Min).toFixed(2) + '%' : '0%',
|
|
|
- // 订单数据(接口返回)
|
|
|
+ // 实际看课数据(修复后,所有字段都有默认值)
|
|
|
+ totalStudents: actualVO.totalStudents ?? 0,
|
|
|
+ completedCount: actualVO.completedCount ?? 0,
|
|
|
+ actualCompletionRate: actualVO.actualCompletionRate != null ? Number(actualVO.actualCompletionRate).toFixed(2) : '0',
|
|
|
+ avgWatchDurationMinutes: actualVO.avgWatchDurationMinutes ?? 0,
|
|
|
+ avgCompletedDuration: actualVO.avgCompletedDuration ?? 0,
|
|
|
+ avgCompletionPlaybackRate: actualVO.avgCompletionPlaybackRate != null ? Number(actualVO.avgCompletionPlaybackRate).toFixed(2) : '0',
|
|
|
+ // 订单数据
|
|
|
gmv: data.gmv != null ? Number(data.gmv).toFixed(2) : '0.00',
|
|
|
paidUserCount: data.paidUserCount ?? 0,
|
|
|
paidOrderCount: data.paidOrderCount ?? 0,
|