Browse Source

一键生成

dev01 2 months ago
parent
commit
4843365b84

+ 6 - 0
src/client/ai.client.ts

@@ -9,3 +9,9 @@ export async function generate(projectName: string, keywords: string, chapterTit
   const resp = await httpClient.post<Response<string>>(_url("ai/generate"), params);
   return resp.data.data;
 }
+
+export async function generatePlus(projectName: string, chapterTitle: string) {
+  const params = { projectName, chapterTitle }
+  const resp = await httpClient.post<Response<string>>(_url("ai/generatePlus"), params);
+  return resp.data.data;
+}

+ 4 - 0
src/services/ai.service.ts

@@ -3,3 +3,7 @@ import * as aiClient from "@/client/ai.client";
 export async function generate(projectName: string, keywords: string, chapterTitle: string) {
   return aiClient.generate(projectName, keywords, chapterTitle)
 }
+
+export async function generatePlus(projectName: string, chapterTitle: string) {
+  return aiClient.generatePlus(projectName, chapterTitle)
+}

+ 55 - 9
src/views/report/ReportEditorView.vue

@@ -112,6 +112,17 @@ function onChapterChange(index: number, data: Chapter) {
   chapterManager.setChapter(index, data);
 }
 
+function onNewChapterChange(data: Chapter) {
+  const list = chapterManager.getChapters()
+  let index:number = 0
+  for(var i = 0; i < list.length; i++){
+    if(list[i].title==data.title){
+      index = i
+    }
+  }
+  chapterManager.setChapter(index,data);
+}
+
 function onChapterMoveUp(index: number) {
   chapterManager.moveUp(index)
 }
@@ -305,16 +316,48 @@ onUnmounted(() => {
   <a-row :gutter="24" v-if="report">
     <a-col :span="12">
       <div class="metadata-wrap">
-        <RelationCompanyInput v-model:id="report.companyId" @change="onCompanyChange" ref="relationCompanyEl" />
-        <ReportField name="报告类型" v-model="report.name" :placeholder="placeholders[0]" ref="reportCategoryEl" />
-        <ReportField name="项目名称" v-model="report.reportName" :placeholder="placeholders[1]" ref="reportNameEl"/>
-        <ReportField name="项目负责人" v-model="report.supervisor" :placeholder="placeholders[2]" ref="supervisorEl" />
-        <ReportField name="关键词" v-model="report.keywords" :placeholder="placeholders[3]" ref="keywordsEl" />
+        <RelationCompanyInput
+          v-model:id="report.companyId"
+          @change="onCompanyChange"
+          ref="relationCompanyEl"
+        />
+        <ReportField
+          name="报告类型"
+          v-model="report.name"
+          :placeholder="placeholders[0]"
+          ref="reportCategoryEl"
+        />
+        <ReportField
+          name="项目名称"
+          v-model="report.reportName"
+          :placeholder="placeholders[1]"
+          ref="reportNameEl"
+        />
+        <ReportField
+          name="项目负责人"
+          v-model="report.supervisor"
+          :placeholder="placeholders[2]"
+          ref="supervisorEl"
+        />
+        <ReportField
+          name="关键词"
+          v-model="report.keywords"
+          :placeholder="placeholders[3]"
+          ref="keywordsEl"
+        />
         <DynamicMeta v-model:data="report.metadata" @change="onMetaChange" />
       </div>
     </a-col>
     <a-col :span="12">
-      <LogoComponent @change="onLogoChange" @delete="onLogoDelete" :url="logoUrl" />
+      <LogoComponent
+        :title="report.reportName"
+        :list="chapterManager.getChapters()"
+        @change="onLogoChange"
+        @delete="onLogoDelete"
+        @ok="onChapterTypeSelected"
+        @one-touch="onNewChapterChange($event)"
+        :url="logoUrl"
+      />
     </a-col>
   </a-row>
   <a-divider />
@@ -333,14 +376,14 @@ onUnmounted(() => {
     />
   </div>
   <div class="add-chapter-wrap">
-    <a-button @click="() => chapterTypeSelectVisible = true">
+    <a-button @click="() => (chapterTypeSelectVisible = true)">
       <plus-outlined />
       添加章节
     </a-button>
   </div>
   <div class="bottom-button-group">
     <a-space v-if="report">
-      <a-checkbox @change="updateStatus()"  :checked="reportStatus == 1">
+      <a-checkbox @change="updateStatus()" :checked="reportStatus == 1">
         <span v-if="reportStatus == 0">未完成</span>
         <span v-if="reportStatus == 1">已完成</span>
       </a-checkbox>
@@ -351,7 +394,10 @@ onUnmounted(() => {
       <a-button @click="duplicateCheck">查重</a-button>
     </a-space>
   </div>
-  <ChapterTypeSelect @ok="onChapterTypeSelected" v-model:visible="chapterTypeSelectVisible" />
+  <ChapterTypeSelect
+    @ok="onChapterTypeSelected"
+    v-model:visible="chapterTypeSelectVisible"
+  />
   <TemplateSaveModal ref="templateSaveModal" @ok="onSaveTemplate" />
 </template>
 

+ 5 - 5
src/views/report/components/ChapterTypeSelect.vue

@@ -7,7 +7,7 @@ defineProps({
     type: Boolean,
     required: true,
     default: false,
-  }
+  },
 });
 
 const emits = defineEmits<{
@@ -17,16 +17,16 @@ const emits = defineEmits<{
 
 const categoryOptions = ChapterTypeLabels.map((item) => ({
   label: item.label,
-  value: item.key
-}))
+  value: item.key,
+}));
 
 const checkedCategories = ref<ChapterType[]>([]);
 
 function onOk() {
   let values: ChapterType[] = [];
   for (let item of categoryOptions) {
-    if (checkedCategories.value.find(x => x == item.value)) {
-      values.push(item.value)
+    if (checkedCategories.value.find((x) => x == item.value)) {
+      values.push(item.value);
     }
   }
   emits("ok", values);

+ 158 - 21
src/views/report/components/LogoComponent.vue

@@ -1,58 +1,87 @@
 <script setup lang="ts">
-import { ref } from 'vue';
-import { PlusOutlined, LoadingOutlined, DeleteOutlined } from '@ant-design/icons-vue';
-import { message } from 'ant-design-vue';
-import type { UploadChangeParam } from 'ant-design-vue';
+import { ChapterType, ChapterTypeLabels } from "@/types/report.types";
+import { ref } from "vue";
+import type { PropType } from "vue";
+import { PlusOutlined, LoadingOutlined, DeleteOutlined } from "@ant-design/icons-vue";
+import * as aiService from "@/services/ai.service";
+import { marked } from "marked";
+import { message } from "ant-design-vue";
+import type { UploadChangeParam } from "ant-design-vue";
+import { Item } from "ant-design-vue/lib/menu";
+import { iteratee } from "lodash";
+import type { Chapter } from "@/types/report.types";
 
-defineProps({
+const props = defineProps({
   url: {
     type: String,
     required: false,
-  }
-})
+  },
+  title: {
+    type: String,
+    required: true,
+  },
+  list: {
+    type: Array as PropType<Chapter[]>,
+    default() {
+      return [];
+    },
+  },
+});
 
 const emits = defineEmits<{
   (e: "change", file: File): void;
   (e: "delete"): void;
+  (e: "ok", vaule: ChapterType[]): void;
+  (e: "one-touch", data: Chapter): void;
 }>();
 
+const categoryOptions = ChapterTypeLabels.map((item) => ({
+  label: item.label,
+  value: item.key,
+}));
+
 function getBase64(img: Blob, callback: (base64Url: string) => void) {
   const reader = new FileReader();
-  reader.addEventListener('load', () => callback(reader.result as string));
+  reader.addEventListener("load", () => callback(reader.result as string));
   reader.readAsDataURL(img);
 }
 
 const fileList = ref([]);
 const loading = ref<boolean>(false);
-const imageUrl = ref<string>('');
+const imageUrl = ref<string>("");
+const checkedCategories = ref<ChapterType[]>([
+  ChapterType.BACKGROUND,
+  ChapterType.RESEARCH_STATUS,
+  ChapterType.RESEARCH,
+]);
 
 const handleChange = (info: UploadChangeParam) => {
-  if (info.file.status === 'uploading') {
+  if (info.file.status === "uploading") {
     loading.value = true;
     return;
   }
-  if (info.file.status === 'done') {
+  if (info.file.status === "done") {
     // Get this url from response in real world.
     getBase64(info.file.originFileObj as Blob, (base64Url: string) => {
       imageUrl.value = base64Url;
       loading.value = false;
     });
   }
-  if (info.file.status === 'error') {
+  if (info.file.status === "error") {
     loading.value = false;
-    message.error('upload error');
+    message.error("upload error");
   }
 };
 
 const beforeUpload = (file: File) => {
-  const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
+  const isJpgOrPng = file.type === "image/jpeg" || file.type === "image/png";
   if (!isJpgOrPng) {
-    message.error('仅支持JPG和PNG格式的图片');
+    message.error("仅支持JPG和PNG格式的图片");
   }
 
   const isLt2M = file.size / 1024 / 1024 < 2;
   if (!isLt2M) {
-    message.error('仅支持小于2MB的图片');
+    message.error("仅支持小于2MB的图片");
   }
   if (!isJpgOrPng || !isLt2M) {
     return false;
@@ -64,7 +93,105 @@ const beforeUpload = (file: File) => {
 };
 
 function onDelete() {
-  emits("delete")
+  emits("delete");
+}
+
+function onContentChange(data: any) {
+  emits("one-touch", data);
+}
+
+function test1() {
+  let values: ChapterType[] = [];
+  let chapterTitle: string = "";
+  if(!props.title){
+    message.warning("项目名称不能为空")
+    return
+  }
+  if (props.list.length == 0) {
+    for (let item of categoryOptions) {
+      if (checkedCategories.value.find((x) => x == item.value)) {
+        values.push(item.value);
+      }
+    }
+    emits("ok", values);
+  } else {
+    let arr = [];
+    let dataList = props.list;
+    for (let item of dataList) {
+      if(item.title.includes(',')){
+        message.warning("章节类型中不能存在英文逗号!!!")
+        return
+      }
+      arr.push(item.title);
+    }
+    chapterTitle = arr.toString();
+  }
+  const loadingHandler = message.loading({
+    content: "AI正在撰写章节内容,请稍等……",
+    duration: 0,
+  });
+  aiService
+    .generatePlus(props.title, chapterTitle)
+    .then((resp) => {
+      // return;
+      const obj: any = resp;
+      if (props.list.length == 0) {
+        let list: any = [
+          {
+            title: "立项背景与意义",
+            fullTitle: "",
+            content: "",
+            chapterType: "BACKGROUND",
+            keywords: [],
+          },
+          {
+            title: "国内外研究现状与发展趋势",
+            fullTitle: "",
+            content: "",
+            chapterType: "RESEARCH_STATUS",
+            keywords: [],
+          },
+          {
+            title: "项目主要研究内容",
+            fullTitle: "",
+            content: "",
+            chapterType: "RESEARCH",
+            keywords: [],
+          },
+        ];
+        for (let item of list) {
+          const key: string = item.title;
+          onContentChange({
+            title: "",
+            fullTitle: "",
+            content: marked.parse(obj[key]),
+            chapterType: item.chapterType,
+            keywords: [],
+          });
+        }
+      } else {
+        for (let item of props.list) {
+          const key: string = item.title;
+          onContentChange({
+            title: item.title,
+            fullTitle: item.fullTitle,
+            content: marked.parse(obj[key]),
+            chapterType: item.chapterType,
+            keywords: item.keywords,
+          });
+        }
+      }
+      // onContentChange(marked.parse(resp));
+      if (loadingHandler) {
+        loadingHandler();
+      }
+    })
+    .catch((err) => {
+      console.log("err", err);
+      if (loadingHandler) {
+        loadingHandler();
+      }
+    });
 }
 </script>
 
@@ -91,9 +218,7 @@ function onDelete() {
     </a-col>
     <a-col class="description-wrap">
       <div class="description">
-        <div style="flex: 1;">
-          请按需上传企业logo<br />仅支持 jpg.  png.  格式图片
-        </div>
+        <div style="flex: 1">请按需上传企业logo<br />仅支持 jpg. png. 格式图片</div>
         <div>
           <a-popconfirm
             title="确定删除此Logoo?"
@@ -108,6 +233,13 @@ function onDelete() {
       </div>
     </a-col>
   </a-row>
+  <a-row>
+    <a-col>
+      <a-button class="generate-project" type="primary" @click="test1">
+        一键生成
+      </a-button>
+    </a-col>
+  </a-row>
 </template>
 
 <style scoped lang="scss">
@@ -129,4 +261,9 @@ function onDelete() {
     align-content: space-between;
   }
 }
-</style>
+
+.generate-project {
+  margin: 43px 0 0 20px;
+  background: green;
+}
+</style>