Browse Source

feature 1001630, 1001631, 1001567

1. 章节搜索报告关键词搜索实现
2. 在报告撰写界面保存报告模板时,章节关键词保存实现
3. 参考文献段落标记为使用功能实现
Kevin Jiang 2 years ago
parent
commit
404ad98cf8

+ 4 - 0
src/assets/base.scss

@@ -80,4 +80,8 @@ $desc-color: #4f4f4f;
 
 h1.title {
   font-size: 1.75em;
+}
+
+.text-red {
+  color: red;
 }

+ 1 - 0
src/types/report.types.ts

@@ -143,6 +143,7 @@ export interface ReportBasic {
   companyName?: string;
   name: string;
   logoPath: string;
+  keywords: string;
   metadata: ReportMetadataItem[];
   userId: number;
   createAt?: string;

+ 2 - 1
src/types/search.types.ts

@@ -37,7 +37,8 @@ export type ResultMode = 'brief' | 'detail';
 export interface ChapterSearchRequest {
   from?: number;
   size?: number;
-  keywords: string[];
+  reportKeywords: string;
+  chapterKeywords: string[];
   queryKeywords?: string[];
   queryWithInKeywords?: string[];
 }

+ 6 - 1
src/views/report/ReportEditorView.vue

@@ -5,6 +5,7 @@ import { PlusOutlined } from "@ant-design/icons-vue";
 import PageHeader from '@/components/PageHeader.vue';
 import RelationCompanyInput from './components/report-create/RelationCompanyInput.vue';
 import ReportCategory from './components/report-create/ReportCategory.vue';
+import ReportKeywords from './components/report-create/ReportKeywords.vue';
 import DynamicMeta from './components/dynamic-meta/DynamicMeta.vue';
 import ChapterTypeSelect from "./components/ChapterTypeSelect.vue";
 import LogoComponent from "./components/LogoComponent.vue";
@@ -166,7 +167,8 @@ function showTemplateSaveModal() {
 function onSaveTemplate(modalData: ReportTemplateModal) {
   let chapters = report.value?.chapters.map((chapter) => {
     return {
-      title: chapter.title
+      title: chapter.title,
+      keywords: chapter.keywords,
     } as Chapter
   })
   const reportTemplateSave: ReportTemplateSave = {
@@ -179,6 +181,7 @@ function onSaveTemplate(modalData: ReportTemplateModal) {
 
   reportTemplateService.save(reportTemplateSave).then(() => {
     templateSaveModal.value?.complete()
+    message.success("模板保存成功")
   }).catch((err) => {
     logError(err)
     templateSaveModal.value?.complete()
@@ -218,6 +221,7 @@ onUnmounted(() => {
       <div class="metadata-wrap">
         <RelationCompanyInput v-model:id="report.companyId" @change="onCompanyChange" />
         <ReportCategory v-model="report.name" ref="reportCategoryEl" />
+        <ReportKeywords v-model="report.keywords" />
         <DynamicMeta v-model:data="report.metadata" @change="onMetaChange" />
       </div>
     </a-col>
@@ -231,6 +235,7 @@ onUnmounted(() => {
       v-for="(item, index) in chapterManager.getChapters()"
       :key="index"
       :data="item"
+      :reportKeywords="report.keywords"
       @change="onChapterChange(index, $event)"
       @move-up="onChapterMoveUp(index)"
       @move-down="onChapterMoveDown(index)"

+ 8 - 3
src/views/report/components/ChapterEditor.vue

@@ -8,6 +8,10 @@ import ContentEditor from "../components/ContentEditor.vue";
 import ReferenceDraw from "../components/reference/ReferenceDraw.vue";
 
 const props = defineProps({
+  reportKeywords: {
+    type: String,
+    required: false,
+  },
   data: {
     type: Object as PropType<Chapter>,
     required: true
@@ -140,7 +144,7 @@ function onSectionRecordUse(sectionId: number) {
         <!-- 关键词编辑 -->
         <a-space class="keywords-wrap">
           <h1>
-            <span>关键词:</span><span v-if="!keywordsEditing">{{ data.keywords.join(', ') }}</span>
+            <span>章节关键词:</span><span v-if="!keywordsEditing">{{ data.keywords.join(', ') }}</span>
           </h1>
           <a-input
             v-if="keywordsEditing"
@@ -175,7 +179,7 @@ function onSectionRecordUse(sectionId: number) {
       </a-col>
     </a-row>
     <p v-if="contentEditorVisible">
-      <ContentEditor :data="data.content" @change="onContentChange" ref="contentEditor" />
+      <ContentEditor :data="data.content || ''" @change="onContentChange" ref="contentEditor" />
     </p>
     <div class="chapter-button-group" v-if="contentEditorVisible">
       <a-space>
@@ -185,7 +189,8 @@ function onSectionRecordUse(sectionId: number) {
     </div>
   </div>
   <ReferenceDraw
-    :keywords="data.keywords || []"
+    :reportKeywords="reportKeywords || ''"
+    :chapter-keywords="data.keywords || []"
     ref="referenceDraw"
     @insert="onInsert"
     @close="onReferenceDrawClose"

+ 12 - 5
src/views/report/components/reference/ReferenceDraw.vue

@@ -11,7 +11,11 @@ import { CompLog } from "@/libs/log.lib";
 import SpinComponent from "@/components/SpinComponent.vue";
 
 const props = defineProps({
-  keywords: {
+  reportKeywords: {
+    type: String,
+    required: true,
+  },
+  chapterKeywords: {
     type: Array<String>,
     required: true,
   }
@@ -48,12 +52,13 @@ function getFrom(page?: number) {
 }
 
 function getDefaultKeywords(): string[] {
-  return props.keywords as string[]
+  return props.chapterKeywords as string[]
 }
 
 function getSearchRequest(): ChapterSearchRequest {
   const request: ChapterSearchRequest = {
-    keywords: getDefaultKeywords(),
+    reportKeywords: props.reportKeywords || '',
+    chapterKeywords: getDefaultKeywords(),
     queryKeywords: queryKeywords.value,
     queryWithInKeywords: queryWithInKeywords.value,
     from: getFrom(pagination.page)
@@ -119,7 +124,7 @@ const onClose = () => {
 
 const show = () => {
   visible.value = true;
-  const keywords = props.keywords
+  const keywords = props.chapterKeywords
   if (keywords && keywords.length > 0) {
     search(getSearchRequest())
   }
@@ -140,7 +145,9 @@ defineExpose({
     class="reference-drawer"
   >
     <template #extra>
-      <span>关键词:{{ keywords.join(", ") }}</span>
+      <span>关键词:{{ reportKeywords }}</span>
+      <a-divider type="vertical" />
+      <span>章节关键词:{{ chapterKeywords.join(", ") }}</span>
     </template>
     <ReferenceSearchBox @search="onReferenceSearchBoxSearch" @search-with-in="onReferenceSearchWithInSearch" />
     <a-divider orientation="left">

+ 37 - 0
src/views/report/components/report-create/ReportKeywords.vue

@@ -0,0 +1,37 @@
+<script setup lang="ts">
+import { ref } from "vue";
+
+defineProps({
+  modelValue: String,
+});
+
+const emits = defineEmits<{
+  (e: "update:modelValue", value: string): void;
+}>();
+
+const input = ref<HTMLInputElement | null>(null);
+
+function focus() {
+  input.value?.focus();
+}
+
+defineExpose({
+  focus
+});
+</script>
+
+<template>
+  <a-row type="flex" style="align-items: center">
+    <a-col style="width: 120px; text-align: right;">
+      关键词:
+    </a-col>
+    <a-col flex="1">
+      <a-input
+        :value="modelValue"
+        @input="emits('update:modelValue', $event.target.value)"
+        placeholder="请输入报告关键词,多个关键词使用空格分割"
+        ref="input"
+      />
+    </a-col>
+  </a-row>
+</template>

+ 10 - 5
src/views/report/components/report-list/ReportItem.vue

@@ -3,25 +3,30 @@
 import { useReportExport } from '@/libs/reportExport.lib';
 import { useAuthStore } from '@/stores/auth.store';
 import type { ReportBasic } from '@/types/report.types';
-import { computed, type PropType } from 'vue';
+import type { PropType } from 'vue';
 
 // 用户权限store
 const authStore = useAuthStore()
 // 报告下载函数库
 const reportExport = useReportExport()
 
-const props = defineProps({
+defineProps({
   data: {
     type: Object as PropType<ReportBasic>,
     required: true,
   }
 });
-
-const title = computed(() => props.data.companyName + ' - ' + props.data.name)
 </script>
 
 <template>
-  <a-card size="small" :title="title">
+  <a-card size="small">
+    <template #title>
+      <span v-if="data.companyName"> {{  data.companyName }}</span>
+      <span v-else class="text-red">无关联企业</span>
+      <span> - </span>
+      <span v-if="data.name">{{ data.name }}</span>
+      <span v-else class="text-red">无报告类型</span>
+    </template>
     <template #extra>
       <RouterLink :to="{ name: 'ReportEditor', params: { id: data.id } }">编辑</RouterLink>
       <a-button type="link" :href="reportExport.link(data.id, authStore.token)" target="_blank">下载</a-button>

+ 18 - 1
src/views/reportTemplate/ReportTemplateListView.vue

@@ -5,9 +5,11 @@ import type { ReportTemplateSave } from '@/types/report.types';
 import ReportTemplateQueryBox from "./components/ReportTemplateQueryBox.vue"
 import type { FieldType } from "./components/ReportTemplateQueryBox.vue"
 import * as reportTemplateService from "@/services/reportTemplate.service"
+import * as reportService from "@/services/report.service"
 import { CompLog } from "@/libs/log.lib";
 import SpinComponent from "@/components/SpinComponent.vue";
 import { message } from "ant-design-vue";
+import { routeToReportEditor } from "@/router";
 
 const logError = CompLog.logErr("ReportTemplateListView")
 
@@ -59,6 +61,21 @@ function onDelete(index: number) {
   }
 }
 
+function onCreateReport(templateId: number | undefined) {
+  const msgHandler = message.loading("正在使用模板创造报告...", 120)
+  if (!templateId) {
+    return;
+  }
+  reportService.create({templateId}).then((id) => {
+    routeToReportEditor(id);
+    msgHandler()
+    message.success("创建报告成功,正在中转到编辑页面")
+  }).catch((err) => {
+    msgHandler()
+    logError(err);
+  });
+}
+
 onMounted(() => {
   fetchTemplates();
 });
@@ -73,7 +90,7 @@ onMounted(() => {
     <SpinComponent :spinning="loading">
       <a-card v-for="(item, index) in templates" :key="index" :title="item.name" class="template-item">
         <template #extra>
-          <a-button type="link">使用模板创建报告</a-button>
+          <a-button type="link" @click="onCreateReport(item.id)">使用模板创建报告</a-button>
           <RouterLink :to="{ name: 'ReportTemplateEditor', params: { id: item.id }}">编辑</RouterLink>
           <a-popconfirm
             :title="'确定删模板 ' + item.name"