Browse Source

feature 1001561

报告撰写界面报告导出功能实现
Kevin Jiang 2 years ago
parent
commit
3593f4f0cb

+ 9 - 0
src/client/reportExport.client.ts

@@ -0,0 +1,9 @@
+import httpClient from "@/services/httpClient";
+import * as urlHelper from "@/libs/url.lib"
+
+const _url = urlHelper.withPrefix('/gw/user/reportExport');
+
+export async function download(id: number) {
+  const resp = await httpClient.get<any>(_url(id))
+  return resp.data
+}

+ 51 - 0
src/libs/reportExport.lib.ts

@@ -0,0 +1,51 @@
+import { useAuthStore } from "@/stores/auth.store"
+
+export function useReportExport() {
+  const authStore = useAuthStore()
+
+  // async function download(name: string, id: number) {
+  //   return reportExportService.download(id).then((resp) => {
+  //     if (!resp) {
+  //       return
+  //     }
+  //     const url = window.URL.createObjectURL(new Blob([resp]))
+  //     const a = document.createElement('a')
+  //     a.style.display = 'none'
+  //     a.setAttribute('download', name + '.docx')
+  //     a.href = url
+  //     document.body.appendChild(a)
+  //     a.click()
+  //     window.URL.revokeObjectURL(a.href)
+  //     document.body.removeChild(a)
+  //   })
+  // }
+
+  function download(name: string, id: number) {
+    const href = link(id, authStore.token)
+    if (!href) {
+      return
+    }
+    const a = document.createElement("a")
+    a.setAttribute("download", name + '.docx')
+    a.setAttribute("href", href)
+    a.style.display = 'none'
+    document.body.appendChild(a)
+    a.click()
+    document.body.removeChild(a)
+  }
+
+  /**
+   * 生成报告下载链接
+   * @param id 报告ID
+   * @param token 用户token
+   * @returns 报告下载的链接字符串或者null
+   */
+  function link(id: number, token: string | null) {
+    if (!token || !id) {
+      return null
+    }
+    return `/gw/user/reportExport/${id}?token=${token}`
+  }
+
+  return { download, link }
+}

+ 5 - 0
src/router/index.ts

@@ -32,6 +32,11 @@ export const router = createRouter({
           component: () => import("../views/report/ReportEditorView.vue"),
         },
         {
+          path: "preview/:id",
+          name: "ReportPreview",
+          component: () => import("../views/reportPreview/ReportPreviewView.vue"),
+        },
+        {
           path: "template",
           name: "ReportTemplate",
           component: () => import("../views/reportTemplate/ReportTemplateListView.vue"),

+ 5 - 0
src/services/reportExport.service.ts

@@ -0,0 +1,5 @@
+import * as reportExportClient from "@/client/reportExport.client"
+
+export async function download(id: number) {
+  return reportExportClient.download(id)
+}

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

@@ -17,11 +17,15 @@ import { CompLog } from "@/libs/log.lib";
 import { message } from "ant-design-vue";
 import TemplateSaveModal from "./components/TemplateSaveModal.vue";
 import type { ReportTemplateModal } from "./reportComponent.types";
+import { useReportExport } from "@/libs/reportExport.lib";
 
 const _componentName = 'ReportEditorView'
 const logError = CompLog.logErr(_componentName)
 
+// 当前路由
 const route = useRoute();
+// 报告下载函数库
+const reportExport = useReportExport()
 
 const report: Ref<ReportSaveRequest | null> = ref(null);
 const reportCategoryEl = ref<HTMLInputElement | null>(null);
@@ -87,6 +91,14 @@ function onSave() {
   }
 }
 
+function onExport() {
+  if (report.value) {
+    reportExport.download(report.value.name, report.value.id)
+  } else {
+    message.warning("暂无数据可以导出")
+  }
+}
+
 const templateSaveModal = ref<InstanceType<typeof TemplateSaveModal> | null>(null);
 
 function showTemplateSaveModal() {
@@ -163,7 +175,8 @@ onMounted(() => {
     <a-space>
       <a-button type="primary" @click="onSave" :loading="saveLoading">保存</a-button>
       <a-button>预览</a-button>
-      <a-button>导出</a-button>
+      <a-button @click="onExport">导出</a-button>
+      <!-- <a-button v-if="report" type="link" :href="reportExport.link(report.id, authStore.token)" target="_blank">导出</a-button> -->
       <a-button @click="showTemplateSaveModal">另保存为模板</a-button>
     </a-space>
   </div>

+ 0 - 8
src/views/report/ReportListView.vue

@@ -107,14 +107,6 @@ onMounted(() => {
     <PageHeader title="我的报告">
       <a-button type="primary" @click="onCreateReport"><plus-outlined />新建报告</a-button>
     </PageHeader>
-    <!-- <a-row type="flex" justify="space-between">
-      <a-col>
-        <PageHeader title="我的报告" />
-      </a-col>
-      <a-col>
-        <a-button type="primary" @click="onCreateReport"><plus-outlined />新建报告</a-button>
-      </a-col>
-    </a-row> -->
 
     <div class="query-box-wrap">
       <QueryBox v-model:field="field" v-model:keyword="keyword" @search="onQuery" />

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

@@ -1,8 +1,15 @@
 <!-- 报告列表的一项 -->
 <script setup lang="ts">
+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';
 
+// 用户权限store
+const authStore = useAuthStore()
+// 报告下载函数库
+const reportExport = useReportExport()
+
 const props = defineProps({
   data: {
     type: Object as PropType<ReportBasic>,
@@ -17,7 +24,7 @@ const title = computed(() => props.data.companyName + ' - ' + props.data.name)
   <a-card size="small" :title="title">
     <template #extra>
       <RouterLink :to="{ name: 'ReportEditor', params: { id: data.id } }">编辑</RouterLink>
-      <a-button type="link">下载</a-button>
+      <a-button type="link" :href="reportExport.link(data.id, authStore.token)" target="_blank">下载</a-button>
     </template>
     <div class="report-metadata-wrap">
       <p><span>企业名称:</span><span>{{ data.companyName }}</span></p>
@@ -25,10 +32,6 @@ const title = computed(() => props.data.companyName + ' - ' + props.data.name)
         <span>{{ item.name }}:</span>
         <span>{{ item.value }}</span>
       </p>
-      <!-- <p><span>项目负责人:</span><span></span></p>
-      <p><span>起止时间:</span><span></span></p>
-      <p><span>创建时间:</span><span></span></p>
-      <p><span>最后编辑时间:</span><span></span></p> -->
     </div>
   </a-card>
 </template>

+ 50 - 0
src/views/reportPreview/ReportPreviewView.vue

@@ -0,0 +1,50 @@
+<!--报告预览视图-->
+<script setup lang="ts">
+import { onMounted, ref } from 'vue';
+import { useRoute } from "vue-router";
+import * as reportService from "@/services/report.service"
+import type { ReportSaveRequest } from '@/types/report.types';
+import { CompLog } from '@/libs/log.lib';
+
+const logError = CompLog.logErr("ReportPreviewView")
+
+const route = useRoute()
+
+const data = ref<ReportSaveRequest | null>(null)
+
+onMounted(() => {
+  const id = parseInt(route.params.id as string);
+  if (id && id > 0) {
+    reportService.get(id).then((resp) => {
+      data.value = resp;
+    }).catch(logError)
+  }
+})
+</script>
+
+<template>
+  <div v-if="data">
+    {{ data.id }}
+    <h1>{{ data.name }}</h1>
+    <a-row v-for="(item, index) in data.metadata" :key="index" class="metadata-wrap">
+      <a-col class="metadata-name">{{ item.name }}:</a-col>
+      <a-col class="metadata-value">{{ item.value }}</a-col>
+    </a-row>
+    <h2>{{ data.companyName }}</h2>
+    <h3>{{ (new Date()) }}</h3>
+    <a-divider />
+    <p v-for="(chapter, index) in data.chapters" :key="index">
+      {{ chapter }}
+    </p>
+  </div>
+</template>
+
+<style scoped lang="scss">
+.metadata-wrap {
+  .metadata-value {
+    margin: 10px 10px;
+    padding: 20px 10px;
+    border-bottom: 1px soild #000;
+  }
+}
+</style>