总学习人数
-
{{ taskInfo.totalTaskNum || 0 }}
+
{{ totalPerson }}
已完成人数
-
{{ taskInfo.completedTaskNum || 0 }}
+
{{ completedPerson }}
@@ -138,6 +138,7 @@ import * as echarts from 'echarts';
import type { ECharts } from 'echarts';
import { learningTaskApi } from '@/apis/study/learning-task';
import { ElMessage } from 'element-plus';
+import { TaskVO } from '@/types';
// Props
const props = defineProps<{
@@ -146,7 +147,7 @@ const props = defineProps<{
// 响应式数据
const loading = ref(false);
-const taskInfo = ref
({});
+const taskInfo = ref();
const durationDistribution = ref([]);
const progressDistribution = ref([]);
const completionRanking = ref([]);
@@ -158,12 +159,12 @@ const progressChartRef = ref();
let durationChart: ECharts | null = null;
let progressChart: ECharts | null = null;
+const totalPerson = computed(() => taskInfo.value?.taskUsers?.length || 0);
+const completedPerson = computed(() => taskInfo.value?.taskUsers?.filter((user: any) => user.status === 2).length || 0);
// 计算完成率
const completionRate = computed(() => {
- const total = taskInfo.value.totalTaskNum || 0;
- const completed = taskInfo.value.completedTaskNum || 0;
- if (total === 0) return 0;
- return ((completed / total) * 100).toFixed(1);
+ if (totalPerson.value === 0) return 0;
+ return ((completedPerson.value / totalPerson.value) * 100).toFixed(1);
});
// 获取排名样式类
diff --git a/schoolNewsWeb/src/views/public/article/ArticleShowView.vue b/schoolNewsWeb/src/views/public/article/ArticleShowView.vue
index 851e2c0..8d34f50 100644
--- a/schoolNewsWeb/src/views/public/article/ArticleShowView.vue
+++ b/schoolNewsWeb/src/views/public/article/ArticleShowView.vue
@@ -1,6 +1,7 @@
route.query.articleId as string || '');
+const taskId = computed(() => route.query.taskId as string || '');
// 返回上一页
function handleBack() {
diff --git a/schoolNewsWeb/src/views/public/article/components/ArticleShow.vue b/schoolNewsWeb/src/views/public/article/components/ArticleShow.vue
index 8a3c1bb..8bc7dad 100644
--- a/schoolNewsWeb/src/views/public/article/components/ArticleShow.vue
+++ b/schoolNewsWeb/src/views/public/article/components/ArticleShow.vue
@@ -113,6 +113,7 @@ interface Props {
width?: string; // Dialog 宽度
articleData?: Resource; // 文章数据(Dialog 模式使用)
resourceID?: string; // 资源ID(路由模式使用)
+ taskId?: string; // 任务ID(路由模式使用)
showEditButton?: boolean; // 是否显示编辑按钮
showBackButton?: boolean; // 是否显示返回按钮(路由模式)
backButtonText?: string; // 返回按钮文本
@@ -181,7 +182,7 @@ onMounted(() => {
// 路由模式下,从路由参数加载文章
if (!props.asDialog) {
const articleId = route.query.articleId as string;
- const taskId = route.query.taskId as string;
+ const taskId = props.taskId || (route.query.taskId as string);
// 如果传入了 articleData,则不需要从路由加载
if (props.articleData && Object.keys(props.articleData).length > 0) {
@@ -325,15 +326,6 @@ async function loadLearningRecord(resourceID: string) {
}
}
-// 生成学习记录的taskId(当没有真实taskId时)
-function generateTaskId(resourceID: string, userID: string): string {
- // 使用简短格式,确保不超过50字符:SA_{resourceID的hash}_{userID的hash}
- // SA = Self-study Article
- const resourceHash = hashString(resourceID).substring(0, 16);
- const userHash = hashString(userID).substring(0, 16);
- return `SA_${resourceHash}_${userHash}`; // 长度:3 + 16 + 1 + 16 = 36字符
-}
-
// 简单的字符串哈希函数
function hashString(str: string): string {
let hash = 0;
@@ -351,9 +343,9 @@ async function createLearningRecord(resourceID: string) {
if (!userInfo.value?.id) return;
try {
- const taskId = route.query.taskId as string;
+ const taskId = props.taskId || (route.query.taskId as string);
// 如果没有taskId,生成一个自学任务ID
- const effectiveTaskId = taskId || generateTaskId(resourceID, userInfo.value.id!);
+ const effectiveTaskId = taskId
const res = await learningRecordApi.createRecord({
userID: userInfo.value.id,
@@ -445,7 +437,7 @@ async function markArticleComplete() {
try {
// 使用learningRecord中保存的taskID(可能是真实任务ID或生成的自学ID)
- const taskId = learningRecord.value.taskID || (route.query.taskId as string);
+ const taskId = learningRecord.value.taskID || props.taskId || (route.query.taskId as string);
await learningRecordApi.markComplete({
id: learningRecord.value.id,
@@ -547,11 +539,19 @@ async function createHistoryRecord(resourceID: string) {
if (!userInfo.value?.id) return;
try {
- const res = await learningHistoryApi.recordResourceView(
- userInfo.value.id,
- resourceID,
- 0 // 初始时长为0
- );
+ const taskId = props.taskId || (route.query.taskId as string);
+
+ // 直接创建学习历史对象,包含 taskID
+ const historyData: TbLearningHistory = {
+ userID: userInfo.value.id,
+ resourceType: 1, // 1资源/新闻
+ resourceID: resourceID,
+ duration: 0,
+ deviceType: 'web',
+ taskID: taskId || undefined // 如果没有 taskId,传 undefined
+ };
+
+ const res = await learningHistoryApi.recordLearningHistory(historyData);
if (res.success && res.data) {
learningHistory.value = res.data;
@@ -597,7 +597,8 @@ async function saveHistoryRecord() {
const updatedHistory: TbLearningHistory = {
...learningHistory.value,
duration: (learningHistory.value.duration || 0) + duration,
- endTime: new Date().toISOString()
+ endTime: new Date().toISOString(),
+ taskID: learningHistory.value.taskID // 保持原有的 taskID
};
// 调用API更新学习历史
@@ -654,7 +655,7 @@ function handleBack() {
}
stopLearningTimer();
- const taskId = route.query.taskId as string;
+ const taskId = props.taskId || (route.query.taskId as string);
// 如果有 taskId,返回任务详情
if (taskId) {
router.push({
diff --git a/schoolNewsWeb/src/views/public/task/LearningProgress.vue b/schoolNewsWeb/src/views/public/task/LearningProgress.vue
index 967f5a4..8d09544 100644
--- a/schoolNewsWeb/src/views/public/task/LearningProgress.vue
+++ b/schoolNewsWeb/src/views/public/task/LearningProgress.vue
@@ -3,7 +3,7 @@