Parcourir la source

fix(@six/wisdom-legacy): 成果管理 - 读书心得接口对接

Co-authored-by: Cursor <cursoragent@cursor.com>
cmj il y a 2 jours
Parent
commit
ba291db3f0

+ 5 - 5
apps/wisdom-legacy/src/api/outcome/reading-note.api.ts

@@ -38,7 +38,7 @@ export function listReadingNoteMethod(...args: PageQueryMethodArgs) {
 
   const { params, data } = pageQueryArgsTransform(args, encodeReadingNoteQuery);
   return httpClient.Post(
-    `/wis-pc/outcome/readingNoteManage/page`,
+    `/wis-pc/outcome/perceptionManage/page`,
     { ...params, ...data },
     {
       params,
@@ -55,7 +55,7 @@ export function createReadingNoteMethod(vo: ReadingNoteSubmitVO) {
   }
 
   return httpClient.Post(
-    `/wis-pc/outcome/readingNoteManage/add`,
+    `/wis-pc/outcome/perceptionManage/add`,
     encodeReadingNote(vo),
     {
       name: 'outcome-reading-note:edit',
@@ -71,7 +71,7 @@ export function updateReadingNoteMethod(vo: ReadingNoteSubmitVO) {
   }
 
   return httpClient.Post(
-    `/wis-pc/outcome/readingNoteManage/update`,
+    `/wis-pc/outcome/perceptionManage/update`,
     encodeReadingNote(vo),
     {
       name: 'outcome-reading-note:edit',
@@ -92,7 +92,7 @@ export function getReadingNoteMethod(vo: Partial<ReadingNoteVO>) {
   }
 
   return httpClient.Post(
-    `/wis-pc/outcome/readingNoteManage/detail/${vo.id}`,
+    `/wis-pc/outcome/perceptionManage/detail/${vo.id}`,
     {},
     {
       hitSource: /^outcome-reading-note:edit/,
@@ -108,7 +108,7 @@ export function deleteReadingNoteMethod(vo: Pick<ReadingNoteVO, 'id'>) {
   }
 
   return httpClient.Post(
-    `/wis-pc/outcome/readingNoteManage/delete/${vo.id}`,
+    `/wis-pc/outcome/perceptionManage/delete/${vo.id}`,
     {},
     {
       name: 'outcome-reading-note:delete',

+ 37 - 42
apps/wisdom-legacy/src/api/outcome/reading-note.mock.ts

@@ -16,7 +16,7 @@ import {
 } from './reading-note.schema';
 
 /** 后端接口就绪后改为 false */
-export const USE_READING_NOTE_MOCK = true;
+export const USE_READING_NOTE_MOCK = false;
 
 type MethodLike<T> = PromiseLike<T> & {
   send?: (force?: boolean) => PromiseLike<T>;
@@ -27,64 +27,64 @@ const SEED_RECORDS: Omit<
   'createTime' | 'id' | 'personalStudioId' | 'updateTime'
 >[] = [
   {
-    insightTitle: '《黄帝内经》阴阳五行理论学习心得',
+    title: '《黄帝内经》阴阳五行理论学习心得',
     bookName: '《黄帝内经》',
-    authorName: '王医师',
-    noteDate: '2026-05-20',
-    noteContent:
+    author: '王医师',
+    content:
       '《黄帝内经》作为中医理论的奠基之作,其阴阳五行学说贯穿整个中医理论体系。通过深入学习,我对阴阳互根、五行生克有了更深刻的理解,这对临床辨证论治具有重要指导意义。',
-    agreeCount: 23,
+    praiseCount: 23,
     createBy: '王医师',
+    fileUrl: '',
   },
   {
-    insightTitle: '《伤寒论》六经辨证临床应用体会',
+    title: '《伤寒论》六经辨证临床应用体会',
     bookName: '《伤寒论》',
-    authorName: '李主任',
-    noteDate: '2026-05-18',
-    noteContent:
+    author: '李主任',
+    content:
       '六经辨证是《伤寒论》的核心内容。在临床实践中,太阳病与少阳病的鉴别尤为关键。结合具体病例,我总结了若干辨证要点,供同仁参考。',
-    agreeCount: 18,
+    praiseCount: 18,
     createBy: '李主任',
+    fileUrl: '',
   },
   {
-    insightTitle: '《金匮要略》杂病诊治思路梳理',
+    title: '《金匮要略》杂病诊治思路梳理',
     bookName: '《金匮要略》',
-    authorName: '张教授',
-    noteDate: '2026-05-15',
-    noteContent:
+    author: '张教授',
+    content:
       '《金匮要略》对杂病的论述系统而深入。本书心得重点梳理了虚劳、痰饮、水气等常见杂病的辨治思路,并结合现代临床进行了延伸思考。',
-    agreeCount: 31,
+    praiseCount: 31,
     createBy: '张教授',
+    fileUrl: '',
   },
   {
-    insightTitle: '《温病条辨》卫气营血辨证学习笔记',
+    title: '《温病条辨》卫气营血辨证学习笔记',
     bookName: '《温病条辨》',
-    authorName: '赵医师',
-    noteDate: '2026-05-12',
-    noteContent:
+    author: '赵医师',
+    content:
       '温病学说是中医外感热病学的重要组成部分。吴鞠通的卫气营血辨证体系层次分明,对急性热病的诊治具有重要价值。',
-    agreeCount: 15,
+    praiseCount: 15,
     createBy: '赵医师',
+    fileUrl: '',
   },
   {
-    insightTitle: '《神农本草经》药物性味归经研读',
+    title: '《神农本草经》药物性味归经研读',
     bookName: '《神农本草经》',
-    authorName: '陈教授',
-    noteDate: '2026-05-10',
-    noteContent:
+    author: '陈教授',
+    content:
       '《神农本草经》是我国现存最早的本草学专著。通过系统研读,我对药物四气五味、升降浮沉及归经理论有了更系统的认识。',
-    agreeCount: 27,
+    praiseCount: 27,
     createBy: '陈教授',
+    fileUrl: '',
   },
   {
-    insightTitle: '《针灸大成》腧穴配伍心得',
+    title: '《针灸大成》腧穴配伍心得',
     bookName: '《针灸大成》',
-    authorName: '刘医师',
-    noteDate: '2026-05-08',
-    noteContent:
+    author: '刘医师',
+    content:
       '《针灸大成》汇集历代针灸精华。本书心得重点记录了常用腧穴配伍规律及临床运用体会,对提高针灸疗效颇有帮助。',
-    agreeCount: 12,
+    praiseCount: 12,
     createBy: '刘医师',
+    fileUrl: '',
   },
 ];
 
@@ -99,7 +99,7 @@ function createInitialStore(): ReadingNoteDTO[] {
       ...seed,
       id: String(index + 1),
       personalStudioId: '327477138296832',
-      agreeCount: (seed.agreeCount ?? 0) + (index % 5),
+      praiseCount: (seed.praiseCount ?? 0) + (index % 5),
       createTime: `2026-${month}-${day}T10:00:00`,
       updateTime: `2026-05-${day}T10:00:00`,
     });
@@ -121,12 +121,7 @@ function delay<T>(runner: () => Promise<T> | T, ms = 120): MethodLike<T> {
 
 function matchKeyword(record: ReadingNoteDTO, keyword?: string) {
   if (!keyword) return true;
-  const text = [
-    record.insightTitle,
-    record.bookName,
-    record.authorName,
-    record.createBy,
-  ]
+  const text = [record.title, record.bookName, record.author, record.createBy]
     .filter(Boolean)
     .join(' ');
   return text.includes(keyword);
@@ -139,8 +134,8 @@ function matchWorkroom(record: ReadingNoteDTO, workroomId?: string) {
 
 function sortRecords(records: ReadingNoteDTO[]) {
   return records.toSorted((a, b) => {
-    const timeA = a.noteDate ? Date.parse(a.noteDate) : 0;
-    const timeB = b.noteDate ? Date.parse(b.noteDate) : 0;
+    const timeA = a.createTime ? Date.parse(a.createTime) : 0;
+    const timeB = b.createTime ? Date.parse(b.createTime) : 0;
     return timeB - timeA;
   });
 }
@@ -208,8 +203,8 @@ export function mockEditReadingNoteMethod(vo: ReadingNoteSubmitVO) {
     store.unshift({
       ...dto,
       id,
-      agreeCount: 0,
-      createBy: dto.authorName ?? '当前用户',
+      praiseCount: 0,
+      createBy: dto.author ?? '当前用户',
       createTime: now,
       updateTime: now,
     });

+ 30 - 21
apps/wisdom-legacy/src/api/outcome/reading-note.schema.ts

@@ -11,20 +11,28 @@ import { decodeAuditRecord } from '#/request/schema/audit-record';
 // DTO
 // ---------------------------------------------------------------------------
 
+/** 读书心得 DTO,对应 `OutcomePerceptionDetail` */
 export interface ReadingNoteDTO extends AuditRecordDTO {
   id?: number | string;
+  status?: string;
+  remark?: string;
   personalStudioId?: number | string;
-  insightTitle?: string;
+  fileUrl?: string;
+  downloadCount?: number;
+  browseCount?: number;
+  commentCount?: number;
+  praiseCount?: number;
+  title?: string;
   bookName?: string;
-  authorName?: string;
-  noteDate?: string;
-  noteContent?: string;
-  agreeCount?: number;
+  author?: string;
+  content?: string;
 }
 
 export interface ReadingNoteQueryDTO {
   mixture?: string;
   personalStudioId?: number | string;
+  type?: string;
+  status?: string;
   pageNum?: number;
   pageSize?: number;
 }
@@ -37,11 +45,12 @@ export interface ReadingNoteVO extends AuditRecordVO {
   id?: string;
   workroomId: string;
   title: string;
-  bookName: string;
-  author: string;
-  noteDate: string;
+  bookName?: string;
+  author?: string;
   content: string;
+  fileUrl?: string;
   likeCount?: number;
+  browseCount?: number;
 }
 
 export type ReadingNoteSubmitVO = ReadingNoteVO;
@@ -59,9 +68,8 @@ export const ReadingNoteVOSchema = z.object({
   id: z.string().optional(),
   workroomId: z.string().min(1, '工作室不能为空'),
   title: z.string().min(1, '请输入心得标题'),
-  bookName: z.string().min(1, '请输入书名'),
-  author: z.string().min(1, '请输入心得作者'),
-  noteDate: z.string().min(1, '请选择日期'),
+  bookName: z.string().optional(),
+  author: z.string().optional(),
   content: z.string().min(1, '请输入心得'),
 });
 
@@ -74,12 +82,13 @@ export function decodeReadingNote(dto: ReadingNoteDTO): ReadingNoteVO {
     ...decodeAuditRecord(dto),
     id: dto.id?.toString(),
     workroomId: dto.personalStudioId?.toString() ?? '',
-    title: dto.insightTitle ?? '',
-    bookName: dto.bookName ?? '',
-    author: dto.authorName ?? '',
-    noteDate: dto.noteDate ?? '',
-    content: dto.noteContent ?? '',
-    likeCount: dto.agreeCount ?? 0,
+    title: dto.title ?? '',
+    bookName: dto.bookName,
+    author: dto.author,
+    content: dto.content ?? '',
+    fileUrl: dto.fileUrl,
+    likeCount: dto.praiseCount ?? 0,
+    browseCount: dto.browseCount ?? 0,
   };
 }
 
@@ -96,11 +105,11 @@ export function encodeReadingNote(vo: ReadingNoteSubmitVO): ReadingNoteDTO {
   return {
     id: vo.id,
     personalStudioId: vo.workroomId,
-    insightTitle: vo.title,
+    fileUrl: vo.fileUrl ?? '',
+    title: vo.title,
     bookName: vo.bookName,
-    authorName: vo.author,
-    noteDate: vo.noteDate,
-    noteContent: vo.content,
+    author: vo.author,
+    content: vo.content,
   };
 }
 

+ 25 - 7
apps/wisdom-legacy/src/views/outcome/ReadingNoteList.vue

@@ -6,6 +6,7 @@ import { computed, h, 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,
@@ -102,17 +103,26 @@ async function openEdit(row: ReadingNoteVO) {
   }
 }
 
+function formatDate(value?: string) {
+  if (!value) return '';
+  return String(value).slice(0, 10);
+}
+
 function openView(row: ReadingNoteVO) {
+  const meta = [
+    row.bookName ? `书名:${row.bookName}` : '',
+    row.author ? `作者:${row.author}` : '',
+    row.createdAt ? formatDate(row.createdAt) : '',
+  ]
+    .filter(Boolean)
+    .join(' · ');
+
   Modal.info({
     title: row.title,
     width: 640,
     okText: '关闭',
     content: h('div', { class: 'pt-2' }, [
-      h(
-        'p',
-        { class: 'mb-4 text-sm text-foreground/70' },
-        `书名:${row.bookName} · 作者:${row.author} · ${row.noteDate}`,
-      ),
+      meta ? h('p', { class: 'mb-4 text-sm text-foreground/70' }, meta) : null,
       h(
         'div',
         { class: 'whitespace-pre-wrap text-sm leading-7 text-foreground/85' },
@@ -137,11 +147,19 @@ async function handleDelete(row: ReadingNoteVO) {
   }
 }
 
-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;

+ 16 - 5
apps/wisdom-legacy/src/views/outcome/components/ReadingNoteCard.vue

@@ -20,6 +20,11 @@ const emit = defineEmits<{
   edit: [ReadingNoteVO];
   view: [ReadingNoteVO];
 }>();
+
+function formatDate(value?: string) {
+  if (!value) return '';
+  return String(value).slice(0, 10);
+}
 </script>
 
 <template>
@@ -40,11 +45,17 @@ const emit = defineEmits<{
         </h3>
 
         <p class="mb-2 text-sm text-foreground/70">
-          书名:{{ data.bookName }}
-          <span class="mx-1 text-foreground/40">·</span>
-          作者:{{ data.author }}
-          <span class="mx-1 text-foreground/40">·</span>
-          {{ data.noteDate }}
+          <template v-if="data.bookName">书名:{{ data.bookName }}</template>
+          <template v-if="data.bookName && data.author">
+            <span class="mx-1 text-foreground/40">·</span>
+          </template>
+          <template v-if="data.author">作者:{{ data.author }}</template>
+          <template v-if="(data.bookName || data.author) && data.createdAt">
+            <span class="mx-1 text-foreground/40">·</span>
+          </template>
+          <template v-if="data.createdAt">
+            {{ formatDate(data.createdAt) }}
+          </template>
         </p>
 
         <p

+ 0 - 15
apps/wisdom-legacy/src/views/outcome/reading-note.data.ts

@@ -1,7 +1,5 @@
 import type { ReadingNoteVO } from '#/api/outcome';
 
-import { getPopupContainer } from '@vben/utils';
-
 import { defineEditShell } from '#/adapter/shell/edit';
 import {
   editReadingNoteMethod,
@@ -51,19 +49,6 @@ export const readingNoteForm = defineEditShell<ReadingNoteVO>({
       },
       rules: ReadingNoteVOSchema.shape.author,
     },
-    {
-      component: 'DatePicker',
-      fieldName: 'noteDate',
-      label: '日期',
-      componentProps: {
-        class: 'w-full',
-        format: 'YYYY-MM-DD',
-        placeholder: '年/月/日',
-        valueFormat: 'YYYY-MM-DD',
-        getPopupContainer,
-      },
-      rules: ReadingNoteVOSchema.shape.noteDate,
-    },
     {
       component: 'Textarea',
       fieldName: 'content',