Procházet zdrojové kódy

fix(@six/wisdom-legacy): 成果管理 - 研究报告页面接口对接

cmj před 2 dny
rodič
revize
686eb350df

+ 18 - 6
apps/wisdom-legacy/src/api/outcome/research-report.api.ts

@@ -1,9 +1,11 @@
 import type {
+  ResearchReportDTO,
   ResearchReportSubmitVO,
   ResearchReportVO,
 } from './research-report.schema';
 
 import type { PageQueryMethodArgs } from '#/request/schema';
+import type { PageDTO } from '#/request/schema/record';
 
 import { getEnvelopeData, httpClient } from '#/request';
 import {
@@ -21,8 +23,10 @@ import {
 } from './research-report.mock';
 import {
   decodeResearchReport,
+  decodeResearchReportType,
   encodeResearchReport,
   encodeResearchReportQuery,
+  filterResearchReportPageByCategory,
 } from './research-report.schema';
 
 export { USE_RESEARCH_REPORT_MOCK } from './research-report.mock';
@@ -53,13 +57,21 @@ export function listResearchReportMethod(...args: PageQueryMethodArgs) {
     args,
     encodeResearchReportQuery,
   );
+  const filterCategory = data.type
+    ? decodeResearchReportType(data.type)
+    : undefined;
+
   return httpClient.Post(
-    `/wis-pc/outcome/researchReportManage/page`,
+    `/wis-pc/outcome/syrtManage/page`,
     { ...params, ...data },
     {
       params,
       hitSource: /^outcome-research-report:(edit|delete)/,
-      transform: paginateTransform(decodeResearchReport),
+      transform: (page: PageDTO<ResearchReportDTO>) =>
+        filterResearchReportPageByCategory(
+          paginateTransform(decodeResearchReport)(page),
+          filterCategory,
+        ),
     },
   );
 }
@@ -71,7 +83,7 @@ export function createResearchReportMethod(vo: ResearchReportSubmitVO) {
   }
 
   return httpClient.Post(
-    `/wis-pc/outcome/researchReportManage/add`,
+    `/wis-pc/outcome/syrtManage/add`,
     encodeResearchReport(vo),
     {
       name: 'outcome-research-report:edit',
@@ -87,7 +99,7 @@ export function updateResearchReportMethod(vo: ResearchReportSubmitVO) {
   }
 
   return httpClient.Post(
-    `/wis-pc/outcome/researchReportManage/update`,
+    `/wis-pc/outcome/syrtManage/update`,
     encodeResearchReport(vo),
     {
       name: 'outcome-research-report:edit',
@@ -110,7 +122,7 @@ export function getResearchReportMethod(vo: Partial<ResearchReportVO>) {
   }
 
   return httpClient.Post(
-    `/wis-pc/outcome/researchReportManage/detail/${vo.id}`,
+    `/wis-pc/outcome/syrtManage/detail/${vo.id}`,
     {},
     {
       hitSource: /^outcome-research-report:edit/,
@@ -126,7 +138,7 @@ export function deleteResearchReportMethod(vo: Pick<ResearchReportVO, 'id'>) {
   }
 
   return httpClient.Post(
-    `/wis-pc/outcome/researchReportManage/delete/${vo.id}`,
+    `/wis-pc/outcome/syrtManage/delete/${vo.id}`,
     {},
     {
       name: 'outcome-research-report:delete',

+ 65 - 61
apps/wisdom-legacy/src/api/outcome/research-report.mock.ts

@@ -13,12 +13,14 @@ import { pageQueryArgsTransform } from '#/request/schema';
 
 import {
   decodeResearchReport,
+  decodeResearchReportProgress,
+  decodeResearchReportType,
   encodeResearchReport,
   encodeResearchReportQuery,
 } from './research-report.schema';
 
 /** 后端接口就绪后改为 false */
-export const USE_RESEARCH_REPORT_MOCK = true;
+export const USE_RESEARCH_REPORT_MOCK = false;
 
 type MethodLike<T> = PromiseLike<T> & {
   send?: (force?: boolean) => PromiseLike<T>;
@@ -32,91 +34,91 @@ const SEED_RECORDS: Omit<
   'createTime' | 'id' | 'personalStudioId' | 'updateTime'
 >[] = [
   {
-    status: 'completed',
-    category: 'clinical',
+    progress: '2',
+    type: '0',
     title: '中医药治疗慢性心力衰竭的临床研究',
-    leader: '王教授课题组',
-    startDate: '2023-03',
-    endDate: '2025-12',
+    curatorName: '王教授课题组',
+    beginTime: '2023-03-01T00:00:00',
+    endTime: '2025-12-01T00:00:00',
     fundingSource: '国家自然科学基金',
-    projectNumber: '82370001',
-    keywords: '中医药;慢性心力衰竭;临床研究',
-    abstract:
+    projectCode: '82370001',
+    keyword: '中医药;慢性心力衰竭;临床研究',
+    resume:
       '本研究旨在评价益气活血类中药复方对慢性心力衰竭患者心功能及生活质量的改善作用,采用随机双盲安慰剂对照试验设计。',
-    objectives:
+    target:
       '主要目标:评价中药复方对心衰患者6分钟步行距离的影响;次要目标:评估心功能指标及生活质量评分变化。',
-    methods:
+    method:
       '多中心、随机、双盲、安慰剂对照临床试验,纳入符合标准的慢性心力衰竭患者120例,随访12个月。',
-    expectedResults:
+    result:
       '预期证实中药复方可显著改善患者心功能,为中医药治疗心衰提供循证依据。',
-    viewCount: 320,
+    browseCount: 320,
     createBy: '王刚',
     fileUrl: MOCK_PDF_URL,
   },
   {
-    status: 'in_progress',
-    category: 'basic',
+    progress: '0',
+    type: '1',
     title: '中药活性成分的抗炎机制研究',
-    leader: '李研究员团队',
-    startDate: '2024-01',
-    endDate: '2026-06',
+    curatorName: '李研究员团队',
+    beginTime: '2024-01-01T00:00:00',
+    endTime: '2026-06-01T00:00:00',
     fundingSource: '省自然科学基金',
-    projectNumber: '2024JZ0012',
-    keywords: '中药;抗炎;机制研究',
-    abstract:
+    projectCode: '2024JZ0012',
+    keyword: '中药;抗炎;机制研究',
+    resume:
       '通过体外细胞实验与动物模型,探讨经典方剂中关键活性成分的抗炎信号通路及分子机制。',
-    objectives: '阐明活性成分调控炎症反应的关键靶点与通路。',
-    methods: '细胞培养、Western blot、动物炎症模型及分子生物学检测。',
-    expectedResults: '揭示抗炎机制,为新药研发提供理论基础。',
-    viewCount: 156,
+    target: '阐明活性成分调控炎症反应的关键靶点与通路。',
+    method: '细胞培养、Western blot、动物炎症模型及分子生物学检测。',
+    result: '揭示抗炎机制,为新药研发提供理论基础。',
+    browseCount: 156,
     createBy: '张许',
     fileUrl: MOCK_PDF_URL,
   },
   {
-    status: 'paused',
-    category: 'epidemiological',
+    progress: '1',
+    type: '2',
     title: '某地区中医药服务利用现状流行病学调查',
-    leader: '陈教授课题组',
-    startDate: '2022-09',
-    endDate: '2024-08',
+    curatorName: '陈教授课题组',
+    beginTime: '2022-09-01T00:00:00',
+    endTime: '2024-08-01T00:00:00',
     fundingSource: '卫健委专项',
-    projectNumber: 'WJ2022-045',
-    keywords: '流行病学;中医药服务;调查',
-    abstract:
+    projectCode: 'WJ2022-045',
+    keyword: '流行病学;中医药服务;调查',
+    resume:
       '对目标地区居民中医药服务利用情况进行横断面调查,分析影响因素与服务可及性。',
-    viewCount: 89,
+    browseCount: 89,
     createBy: '李虎',
     fileUrl: MOCK_PDF_URL,
   },
   {
-    status: 'in_progress',
-    category: 'clinical',
+    progress: '0',
+    type: '0',
     title: '针灸联合康复训练治疗脑卒中后运动功能障碍研究',
-    leader: '赵主任团队',
-    startDate: '2024-06',
-    endDate: '2027-05',
+    curatorName: '赵主任团队',
+    beginTime: '2024-06-01T00:00:00',
+    endTime: '2027-05-01T00:00:00',
     fundingSource: '国家重点研发计划',
-    projectNumber: '2024YFC3600100',
-    keywords: '针灸;脑卒中;康复',
-    abstract:
+    projectCode: '2024YFC3600100',
+    keyword: '针灸;脑卒中;康复',
+    resume:
       '评价针灸联合现代康复训练对脑卒中后运动功能障碍患者的疗效及安全性。',
-    viewCount: 210,
+    browseCount: 210,
     createBy: '王刚',
     fileUrl: MOCK_PDF_URL,
   },
   {
-    status: 'completed',
-    category: 'translational',
+    progress: '2',
+    type: '4',
     title: '经典名方现代化制剂转化研究',
-    leader: '孙教授课题组',
-    startDate: '2021-01',
-    endDate: '2023-12',
+    curatorName: '孙教授课题组',
+    beginTime: '2021-01-01T00:00:00',
+    endTime: '2023-12-01T00:00:00',
     fundingSource: '企业合作课题',
-    projectNumber: 'HZ2021-088',
-    keywords: '经典名方;制剂;转化',
-    abstract:
+    projectCode: 'HZ2021-088',
+    keyword: '经典名方;制剂;转化',
+    resume:
       '围绕经典名方开展质量标准建立、工艺优化及临床前研究,推进成果转化。',
-    viewCount: 445,
+    browseCount: 445,
     createBy: '张许',
     fileUrl: MOCK_PDF_URL,
   },
@@ -156,10 +158,10 @@ function matchKeyword(record: ResearchReportDTO, keyword?: string) {
   if (!keyword) return true;
   const text = [
     record.title,
-    record.leader,
-    record.keywords,
-    record.abstract,
-    record.projectNumber,
+    record.curatorName,
+    record.keyword,
+    record.resume,
+    record.projectCode,
     record.createBy,
   ]
     .filter(Boolean)
@@ -177,12 +179,12 @@ function matchCategory(
   category?: ResearchReportCategory,
 ) {
   if (!category) return true;
-  return record.category === category;
+  return decodeResearchReportType(record.type) === category;
 }
 
 function matchStatus(record: ResearchReportDTO, status?: ResearchReportStatus) {
   if (!status) return true;
-  return record.status === status;
+  return decodeResearchReportProgress(record.progress) === status;
 }
 
 function toVo(dto: ResearchReportDTO): ResearchReportVO {
@@ -198,8 +200,10 @@ export function mockListResearchReportMethod(...args: PageQueryMethodArgs) {
   const pageSize = Number(params.pageSize ?? 10);
   const keyword = data.mixture;
   const workroomId = data.personalStudioId?.toString();
-  const category = data.category;
-  const status = data.status;
+  const category = data.type ? decodeResearchReportType(data.type) : undefined;
+  const status = data.progress
+    ? decodeResearchReportProgress(data.progress)
+    : undefined;
 
   const filtered = store.filter(
     (record) =>
@@ -254,7 +258,7 @@ export function mockEditResearchReportMethod(vo: ResearchReportSubmitVO) {
     store.unshift({
       ...dto,
       id,
-      viewCount: 0,
+      browseCount: 0,
       createBy: dto.createBy ?? '当前用户',
       createTime: now,
       updateTime: now,

+ 159 - 41
apps/wisdom-legacy/src/api/outcome/research-report.schema.ts

@@ -18,8 +18,54 @@ export type ResearchReportCategory =
   | 'observational'
   | 'translational';
 
+/** 后端 `progress` 字段:0-进行中 1-已暂停 2-已完成 */
+export type ResearchReportProgressDTO = '0' | '1' | '2';
+
+/** 后端 `type` 字段,对应字典:智慧传承系统-研究类型 */
+export type ResearchReportTypeDTO = '0' | '1' | '2' | '3' | '4';
+
 export type ResearchReportStatus = 'completed' | 'in_progress' | 'paused';
 
+const RESEARCH_PROGRESS_TO_DTO: Record<
+  ResearchReportStatus,
+  ResearchReportProgressDTO
+> = {
+  in_progress: '0',
+  paused: '1',
+  completed: '2',
+};
+
+const RESEARCH_PROGRESS_FROM_DTO: Record<
+  ResearchReportProgressDTO,
+  ResearchReportStatus
+> = {
+  '0': 'in_progress',
+  '1': 'paused',
+  '2': 'completed',
+};
+
+const RESEARCH_TYPE_TO_DTO: Record<
+  ResearchReportCategory,
+  ResearchReportTypeDTO
+> = {
+  clinical: '0',
+  basic: '1',
+  epidemiological: '2',
+  observational: '3',
+  translational: '4',
+};
+
+const RESEARCH_TYPE_FROM_DTO: Record<
+  ResearchReportTypeDTO,
+  ResearchReportCategory
+> = {
+  '0': 'clinical',
+  '1': 'basic',
+  '2': 'epidemiological',
+  '3': 'observational',
+  '4': 'translational',
+};
+
 export const RESEARCH_REPORT_CATEGORY_OPTIONS = [
   { label: '临床研究', value: 'clinical' },
   { label: '基础研究', value: 'basic' },
@@ -82,35 +128,105 @@ export function formatResearchPeriod(
   return startDate ?? endDate ?? '';
 }
 
+export function decodeResearchReportType(
+  type?: number | string,
+): ResearchReportCategory {
+  const normalized = type?.toString();
+  if (
+    normalized === '0' ||
+    normalized === '1' ||
+    normalized === '2' ||
+    normalized === '3' ||
+    normalized === '4'
+  ) {
+    return RESEARCH_TYPE_FROM_DTO[normalized];
+  }
+  return 'clinical';
+}
+
+export function decodeResearchReportProgress(
+  progress?: number | string,
+): ResearchReportStatus {
+  const normalized = progress?.toString();
+  if (normalized === '0' || normalized === '1' || normalized === '2') {
+    return RESEARCH_PROGRESS_FROM_DTO[normalized];
+  }
+  return 'in_progress';
+}
+
+/** 按研究类型过滤分页结果(后端未按 type 过滤时的兜底) */
+export function filterResearchReportPageByCategory<
+  T extends { items: ResearchReportVO[]; total: number },
+>(page: T, category?: ResearchReportCategory): T {
+  if (!category) return page;
+  const items = page.items.filter((item) => item.category === category);
+  return { ...page, items };
+}
+
+function encodeResearchReportType(
+  category: ResearchReportCategory,
+): ResearchReportTypeDTO {
+  return RESEARCH_TYPE_TO_DTO[category];
+}
+
+function encodeResearchReportProgress(
+  status: ResearchReportStatus,
+): ResearchReportProgressDTO {
+  return RESEARCH_PROGRESS_TO_DTO[status];
+}
+
+function formatDateTime(date: string) {
+  if (!date) return date;
+  if (/^\d{4}-\d{2}$/.test(date)) {
+    return `${date}-01T00:00:00`;
+  }
+  return date;
+}
+
+function formatMonthDate(dateTime?: string) {
+  if (!dateTime) return '';
+  return dateTime.slice(0, 7);
+}
+
 // ---------------------------------------------------------------------------
 // DTO
 // ---------------------------------------------------------------------------
 
+/** 研究报告 DTO,对应 `OutcomeStudyReportDetail` */
 export interface ResearchReportDTO extends AuditRecordDTO {
   id?: number | string;
+  status?: string;
+  remark?: string;
   personalStudioId?: number | string;
-  status?: ResearchReportStatus;
-  category?: ResearchReportCategory;
+  fileUrl?: string;
+  downloadCount?: number;
+  browseCount?: number;
+  commentCount?: number;
+  praiseCount?: number;
   title?: string;
-  leader?: string;
-  startDate?: string;
-  endDate?: string;
+  /** 负责人姓名 */
+  curatorName?: string;
+  /** 研究类型,详见字典:智慧传承系统-研究类型 */
+  type?: ResearchReportTypeDTO | string;
+  /** 进度 0-进行中 1-已暂停 2-已完成 */
+  progress?: ResearchReportProgressDTO | string;
+  beginTime?: string;
+  endTime?: string;
   fundingSource?: string;
-  projectNumber?: string;
-  keywords?: string;
-  abstract?: string;
-  objectives?: string;
-  methods?: string;
-  expectedResults?: string;
-  fileUrl?: string;
-  viewCount?: number;
+  projectCode?: string;
+  keyword?: string;
+  resume?: string;
+  target?: string;
+  method?: string;
+  result?: string;
 }
 
 export interface ResearchReportQueryDTO {
   mixture?: string;
   personalStudioId?: number | string;
-  category?: ResearchReportCategory;
-  status?: ResearchReportStatus;
+  type?: ResearchReportTypeDTO | string;
+  status?: string;
+  progress?: ResearchReportProgressDTO | string;
   pageNum?: number;
   pageSize?: number;
 }
@@ -184,21 +300,21 @@ export function decodeResearchReport(dto: ResearchReportDTO): ResearchReportVO {
     ...decodeAuditRecord(dto),
     id: dto.id?.toString(),
     workroomId: dto.personalStudioId?.toString() ?? '',
-    status: dto.status ?? 'in_progress',
-    category: dto.category ?? 'clinical',
+    status: decodeResearchReportProgress(dto.progress),
+    category: decodeResearchReportType(dto.type),
     title: dto.title ?? '',
-    leader: dto.leader ?? '',
-    startDate: dto.startDate ?? '',
-    endDate: dto.endDate,
+    leader: dto.curatorName ?? '',
+    startDate: formatMonthDate(dto.beginTime),
+    endDate: dto.endTime ? formatMonthDate(dto.endTime) : undefined,
     fundingSource: dto.fundingSource,
-    projectNumber: dto.projectNumber,
-    keywords: dto.keywords,
-    abstract: dto.abstract ?? '',
-    objectives: dto.objectives,
-    methods: dto.methods,
-    expectedResults: dto.expectedResults,
+    projectNumber: dto.projectCode,
+    keywords: dto.keyword,
+    abstract: dto.resume ?? '',
+    objectives: dto.target,
+    methods: dto.method,
+    expectedResults: dto.result,
     pdfUrl: dto.fileUrl,
-    viewCount: dto.viewCount ?? 0,
+    viewCount: dto.browseCount ?? 0,
   };
 }
 
@@ -208,8 +324,10 @@ export function encodeResearchReportQuery(
   return {
     mixture: query.keyword,
     personalStudioId: query.workroomId,
-    category: query.category,
-    status: query.status,
+    type: query.category ? encodeResearchReportType(query.category) : undefined,
+    progress: query.status
+      ? encodeResearchReportProgress(query.status)
+      : undefined,
   };
 }
 
@@ -219,20 +337,20 @@ export function encodeResearchReport(
   return {
     id: vo.id,
     personalStudioId: vo.workroomId,
-    status: vo.status,
-    category: vo.category,
+    fileUrl: vo.pdfUrl ?? '',
     title: vo.title,
-    leader: vo.leader,
-    startDate: vo.startDate,
-    endDate: vo.endDate,
+    curatorName: vo.leader,
+    type: encodeResearchReportType(vo.category),
+    progress: encodeResearchReportProgress(vo.status),
+    beginTime: formatDateTime(vo.startDate),
+    endTime: vo.endDate ? formatDateTime(vo.endDate) : undefined,
     fundingSource: vo.fundingSource,
-    projectNumber: vo.projectNumber,
-    keywords: vo.keywords,
-    abstract: vo.abstract,
-    objectives: vo.objectives,
-    methods: vo.methods,
-    expectedResults: vo.expectedResults,
-    fileUrl: vo.pdfUrl,
+    projectCode: vo.projectNumber,
+    keyword: vo.keywords,
+    resume: vo.abstract,
+    target: vo.objectives,
+    method: vo.methods,
+    result: vo.expectedResults,
   };
 }
 

+ 11 - 2
apps/wisdom-legacy/src/views/outcome/ResearchReportList.vue

@@ -10,6 +10,7 @@ import { computed, ref, shallowRef, triggerRef, watch } from 'vue';
 import { Page } from '@vben/common-ui';
 import { Plus } from '@vben/icons';
 
+import { watchDebounced } from '@vueuse/core';
 import {
   Button,
   Empty,
@@ -152,11 +153,19 @@ async function handleDelete(row: ResearchReportVO) {
   }
 }
 
-function onSearch() {
-  searchKeyword.value = keyword.value.trim();
+function applySearch(value: string) {
+  const next = value.trim();
+  if (next === searchKeyword.value) return;
+  searchKeyword.value = next;
   pageNum.value = 1;
 }
 
+watchDebounced(keyword, applySearch, { debounce: 300 });
+
+function onSearch() {
+  applySearch(keyword.value);
+}
+
 function onPageChange(page: number, size: number) {
   pageNum.value = page;
   pageSize.value = size;

+ 4 - 0
apps/wisdom-legacy/src/views/outcome/modules/ResearchReportEdit.vue

@@ -113,6 +113,10 @@ const { Form, Shell, api } = useEditShell<ResearchReportSubmitVO>(
         message.warning('文件上传中,请稍候');
         throw new Error('uploading');
       }
+      if (!pdfUrl.value) {
+        message.error('请上传研究文档');
+        throw new Error('pdf required');
+      }
 
       return {
         ...values,

+ 1 - 0
apps/wisdom-legacy/src/views/outcome/research-report.data.ts

@@ -65,6 +65,7 @@ export const researchReportForm = defineEditShell<ResearchReportVO>({
       fieldName: 'category',
       label: '研究类型',
       componentProps: {
+        class: 'w-full',
         options: [...RESEARCH_REPORT_CATEGORY_OPTIONS],
         placeholder: '请选择研究类型',
         getPopupContainer,