From e1a5ca2afadf03eb6d690f605a8d38727cd26fe0 Mon Sep 17 00:00:00 2001 From: shihan11 Date: Thu, 18 Jun 2026 15:21:09 +0800 Subject: [PATCH] feat: add profile and defalt hospital --- apps/cms/stats.py | 3 +++ apps/organization/serializers.py | 11 ++++++++++- apps/organization/views.py | 6 +++--- test/test_cms_institution.py | 16 +++++++++------- test/test_cms_stats.py | 3 +++ 5 files changed, 28 insertions(+), 11 deletions(-) diff --git a/apps/cms/stats.py b/apps/cms/stats.py index cb4450f..de939fc 100644 --- a/apps/cms/stats.py +++ b/apps/cms/stats.py @@ -282,9 +282,12 @@ def hospital_overview(request): profile = { 'institution_id': inst_id, + 'code': inst.code if inst else '', 'name': inst.name if inst else '', 'logo': _build_banner_url(request, inst.banner_url) if inst else '', # 完整 URL(含 STATIC_PUBLIC_PREFIX) 'level': inst.level if inst else '', + 'province': inst.province if inst else '', + 'city': inst.city if inst else '', 'cooperation_days': (now - inst.created_at).days if inst and inst.created_at else None, } diff --git a/apps/organization/serializers.py b/apps/organization/serializers.py index d7345cf..16f12b1 100644 --- a/apps/organization/serializers.py +++ b/apps/organization/serializers.py @@ -25,7 +25,16 @@ class CmsInstitutionSerializer(serializers.ModelSerializer): 'id', 'code', 'name', 'type', 'level', 'province', 'city', 'banner_url', 'created_at', 'updated_at', ] - read_only_fields = ['id', 'created_at', 'updated_at'] + # type 不可编辑:新增/编辑均不接收,存库恒为 hospital(见 create/update) + read_only_fields = ['id', 'type', 'created_at', 'updated_at'] + + def create(self, validated_data): + validated_data['type'] = 'hospital' + return super().create(validated_data) + + def update(self, instance, validated_data): + validated_data['type'] = 'hospital' # 每次保存都归一为 hospital + return super().update(instance, validated_data) def to_representation(self, instance): data = super().to_representation(instance) diff --git a/apps/organization/views.py b/apps/organization/views.py index f082f0f..0fbdb03 100644 --- a/apps/organization/views.py +++ b/apps/organization/views.py @@ -18,7 +18,7 @@ from .serializers import CmsInstitutionSerializer, CmsDepartmentSerializer ALLOWED_BANNER_EXT = ('.png', '.jpg', '.jpeg', '.webp') MAX_BANNER_BYTES = 5 * 1024 * 1024 # 5MB -INST_IMPORT_HEADERS = ['机构编码', '名称', '类型', '等级', '省', '市'] +INST_IMPORT_HEADERS = ['机构编码', '名称', '等级', '省', '市'] INST_EXPORT_HEADERS = ['ID', '机构编码', '名称', '类型', '等级', '省', '市'] DEPT_IMPORT_HEADERS = ['科室名称', '分类'] DEPT_EXPORT_HEADERS = ['ID', '科室名称', '分类'] @@ -135,7 +135,7 @@ class CmsInstitutionViewSet(viewsets.ModelViewSet): @action(detail=False, methods=['post'], url_path='import', parser_classes=[MultiPartParser, FormParser]) def import_institutions(self, request): - """Excel 批量导入机构。列:机构编码 | 名称 | 类型 | 等级 | 省 | 市。""" + """Excel 批量导入机构。列:机构编码 | 名称 | 等级 | 省 | 市(类型固定 hospital,不在表内)。""" file = request.FILES.get('file') if not file: raise AppError('CMS_IMPORT_FILE_REQUIRED', '请上传 .xlsx 文件(字段名 file)', status_code=400) @@ -157,7 +157,7 @@ class CmsInstitutionViewSet(viewsets.ModelViewSet): errors.append({'row': idx, 'reason': f'机构编码已存在:{code}'}); continue Institution.objects.create( code=code, name=name, - type=(row.get('类型') or 'hospital').strip() or 'hospital', + type='hospital', # 类型固定 hospital,不从 Excel 读取 level=(row.get('等级') or '').strip(), province=(row.get('省') or '').strip(), city=(row.get('市') or '').strip(), diff --git a/test/test_cms_institution.py b/test/test_cms_institution.py index 1d89385..97d49dc 100644 --- a/test/test_cms_institution.py +++ b/test/test_cms_institution.py @@ -96,9 +96,10 @@ class CmsInstitutionCrudTest(CacheTestCase): self.assertTrue(any(i['code'] == 'CMS-H010' for i in results)) def test_create_success(self): + # type 不可编辑:即便传 type 也忽略,存库恒为 hospital payload = { 'code': 'CMS-NEW-1', 'name': '新建示例医院', - 'type': 'hospital', 'level': '三甲', + 'type': 'school', 'level': '三甲', 'province': '北京', 'city': '北京', } resp = self.client.post(CMS_INST_URL, payload) @@ -107,7 +108,7 @@ class CmsInstitutionCrudTest(CacheTestCase): self.assertEqual(body['code'], 'CMS-NEW-1') self.assertEqual(body['name'], '新建示例医院') self.assertEqual(body['banner_url'], '') # 未配图为空串 - self.assertTrue(Institution.objects.filter(code='CMS-NEW-1').exists()) + self.assertEqual(Institution.objects.get(code='CMS-NEW-1').type, 'hospital') # 忽略传入 school def test_create_duplicate_code(self): ensure_institution(name='已存在', code='CMS-DUP') @@ -244,12 +245,13 @@ class CmsInstitutionImportExportTest(CacheTestCase): def test_import(self): ensure_institution(name='已存在', code='CMS-IMP-DUP') + # 导入模板已去掉「类型」列:机构编码 | 名称 | 等级 | 省 | 市(类型固定 hospital) f = _xlsx( - ['机构编码', '名称', '类型', '等级', '省', '市'], + ['机构编码', '名称', '等级', '省', '市'], [ - ['CMS-IMP-1', '新医院A', 'hospital', '三甲', '北京', '北京'], - ['', '无编码', 'hospital', '', '', ''], # 编码空 → 失败 - ['CMS-IMP-DUP', '重复编码', 'hospital', '', '', ''], # 重复 → 失败 + ['CMS-IMP-1', '新医院A', '三甲', '北京', '北京'], + ['', '无编码', '', '', ''], # 编码空 → 失败 + ['CMS-IMP-DUP', '重复编码', '', '', ''], # 重复 → 失败 ], ) resp = self.client.post('/api/cms/institutions/import/', {'file': f}, format='multipart') @@ -257,4 +259,4 @@ class CmsInstitutionImportExportTest(CacheTestCase): body = resp.json() self.assertEqual(body['success'], 1) self.assertEqual(body['failed'], 2) - self.assertTrue(Institution.objects.filter(code='CMS-IMP-1').exists()) + self.assertEqual(Institution.objects.get(code='CMS-IMP-1').type, 'hospital') diff --git a/test/test_cms_stats.py b/test/test_cms_stats.py index e1c4a1b..e6b8083 100644 --- a/test/test_cms_stats.py +++ b/test/test_cms_stats.py @@ -151,6 +151,9 @@ class StatsOverviewTest(TransactionTestCase): def test_hospital_overview(self): d = get_auth_client(self.hosp).get(HOSPITAL).json() self.assertEqual(d['profile']['name'], 'A院') + self.assertEqual(d['profile']['code'], 'STAT-A') # 机构编码 + self.assertEqual(d['profile']['province'], '北京') # 省 + self.assertEqual(d['profile']['city'], '北京') # 市 self.assertEqual(d['summary']['student_count'], 2) self.assertEqual(d['summary']['doctor_count'], 1) self.assertEqual(d['summary']['train_total'], 2) # s1+s2 记录