diff --git a/apps/case/mobile.py b/apps/case/mobile.py index 90197ee..5799e0b 100644 --- a/apps/case/mobile.py +++ b/apps/case/mobile.py @@ -1,15 +1,14 @@ """移动端病例列表(首页 / 病例页 5 个入口)。 -均读 `case_base`,只取**已发布**病例(publish_status=2 & status=1 & is_deleted=0): - -- 5.1 推荐病例(个性化) GET /api/case/mobile/recommended/ +- 5.1 推荐病例 GET /api/case/mobile/recommended/ ← **返回病例库全部已发布病例**(不做个性化) - 5.2 科室专项 GET /api/case/mobile/specialty/ - 5.3 薄弱环节 GET /api/case/mobile/weak/ - 5.4 教学互动 GET /api/case/mobile/teaching/ - 5.5 教师任务 GET /api/case/mobile/teacher-task/(CMS 暂无指派,先同教学互动) -个性化/薄弱口径读只读表 training_record(user_id=当前用户、status='completed'), -分数按 score_type 归一百分制后比较,与《个人中心》一致。 +五个入口均只取**已发布**病例(publish_status=2 & status=1 & is_deleted=0); +5.1 推荐返回全部已发布病例、按创建时间倒序(不再做个性化推荐排序)。 +薄弱口径读只读表 training_record(user_id=当前用户、status='completed'),分数按 score_type 归一百分制后比较,与《个人中心》一致。 """ from django.db.models import Q from rest_framework import serializers @@ -123,44 +122,17 @@ def _paginate(qs, request, *, case_stats=None): return paginator.get_paginated_response(data) -# ── 5.1 推荐病例(个性化)──────────────────────────────────────────────────── +# ── 5.1 推荐病例(返回病例库全部已发布病例)──────────────────────────────────── -def _recommend_score(case, *, dept_id, trained_ids, weak_dims): - """个性化推荐分:未训练 > 同科室 > 命中薄弱能力标签。""" - score = 0 - if case.id not in trained_ids: - score += 2 - if dept_id and case.department_id == dept_id: - score += 1 - if weak_dims and case.competency_tags: - tags = ' '.join(str(t) for t in case.competency_tags) - if any(w and w in tags for w in weak_dims): - score += 1 - return score - - -@extend_schema(summary='推荐病例(个性化)', tags=['病例列表']) +@extend_schema(summary='推荐病例(返回病例库全部已发布病例)', tags=['病例列表']) @api_view(['GET']) @permission_classes([IsAuthenticated]) def recommended(request): - user = request.user - qs = _apply_common_filters(_published(), request) - cases = list(qs.select_related('department')) - - trained_ids = set( - _completed_records(user).values_list('case_id', flat=True) - ) - weak_dims = [str(w) for w in (user.weak_dimensions or [])] - dept_id = user.department_id - - cases.sort( - key=lambda c: ( - _recommend_score(c, dept_id=dept_id, trained_ids=trained_ids, weak_dims=weak_dims), - c.created_at or c.id, - ), - reverse=True, - ) - return _paginate(cases, request) + """返回病例库**全部已发布病例**(publish_status=2 & status=1 & is_deleted=0), + 支持通用筛选(search / case_type / difficulty / department),按创建时间倒序。""" + qs = _apply_common_filters(_published(), request) \ + .select_related('department').order_by('-created_at', '-id') + return _paginate(qs, request) # ── 5.2 科室专项 ──────────────────────────────────────────────────────────── diff --git a/test/test_mobile_case_list.py b/test/test_mobile_case_list.py index ffcf7cc..8ae4081 100644 --- a/test/test_mobile_case_list.py +++ b/test/test_mobile_case_list.py @@ -120,18 +120,22 @@ class MobileCaseListTest(TransactionTestCase): for url in (REC_URL, SPEC_URL, WEAK_URL, TEACH_URL, TASK_URL): self.assertEqual(APIClient().get(url).status_code, 401, url) - # ── 5.1 推荐 ─────────────────────────────────────────────────────────── - def test_recommended_only_published(self): + # ── 5.1 推荐(返回病例库全部已发布病例)─────────────────────────────────── + def test_recommended_returns_all_published(self): + # 返回全部已发布病例;草稿/禁用/已下架(软删) 均不返回 resp = self.client.get(REC_URL) self.assertEqual(resp.status_code, 200, resp.content) - ids = set(self._ids(resp)) self.assertEqual(resp.json()['count'], 3) + ids = set(self._ids(resp)) self.assertEqual(ids, {self.pub_trad1.id, self.pub_teach.id, self.pub_trad2.id}) + titles = {r['title'] for r in resp.json()['results']} + self.assertNotIn('草稿病例', titles) + self.assertNotIn('禁用病例', titles) + self.assertNotIn('已下架病例', titles) - def test_recommended_untrained_first(self): - # pub_teach 未训练且命中薄弱标签+同科室 → 应排在已训练病例之前 - resp = self.client.get(REC_URL) - self.assertEqual(self._ids(resp)[0], self.pub_teach.id, resp.content) + def test_recommended_supports_search(self): + resp = self.client.get(REC_URL, {'search': '心梗'}) + self.assertEqual(self._ids(resp), [self.pub_trad1.id], resp.content) # ── 5.2 科室专项 ────────────────────────────────────────────────────────── def test_specialty_default_user_dept(self):