瀏覽代碼

报告模板,报告列表支持翻页与字段查询

Kevin Jiang 2 年之前
父節點
當前提交
1c8ebbee72

+ 3 - 2
src/client/reportTemplate.client.ts

@@ -15,8 +15,9 @@ export async function tags(): Promise<string[]> {
   return resp.data.data
 }
 
-export async function list(): Promise<ReportTemplatesResponse> {
-  const resp = await httpClient.get<Response<ReportTemplatesResponse>>(_url());
+export async function list(field?: string, keyword?: string, page?: number): Promise<ReportTemplatesResponse> {
+  const params = { field, keyword, page }
+  const resp = await httpClient.get<Response<ReportTemplatesResponse>>(_url(), { params });
   return resp.data.data
 }
 

+ 5 - 5
src/client/reports.client.ts

@@ -8,11 +8,11 @@ import type { Response } from "@/types/response.types";
 
 const _url = withPrefix("/gw/user")
 
-export async function query(page: number, companyId?: number): Promise<ReportsResponse> {
-  const params: any = { page }
-  if (companyId) {
-    params['companyId'] = companyId;
-  }
+export async function query(page: number, companyId?: number, field?: string, keyword?: string): Promise<ReportsResponse> {
+  const params: any = { page, companyId, field, keyword }
+  // if (companyId) {
+  //   params['companyId'] = companyId;
+  // }
   const resp = await httpClient.get<Response<ReportsResponse>>(_url("/reports"), { params })
   return resp.data.data
 }

+ 2 - 2
src/services/reportTemplate.service.ts

@@ -9,8 +9,8 @@ export async function tags() {
   return reportTemplateClient.tags()
 }
 
-export async function list() {
-  return reportTemplateClient.list();
+export async function list(field?: string, keyword?: string, page?: number) {
+  return reportTemplateClient.list(field, keyword, page);
 }
 
 export async function remove(id: number) {

+ 2 - 2
src/services/reports.service.ts

@@ -1,7 +1,7 @@
 import * as reportsClient from "@/client/reports.client"
 
-export async function query(page?: number, companyId?: number) {
-  return reportsClient.query(page || 1, companyId);
+export async function query(page?: number, companyId?: number, field?: string, keyword?: string) {
+  return reportsClient.query(page || 1, companyId, field, keyword);
 }
 
 export async function agg() {

+ 22 - 10
src/views/report/ReportListView.vue

@@ -3,6 +3,7 @@ import { onMounted, ref } from "vue";
 import { PlusOutlined } from '@ant-design/icons-vue';
 import PageHeader from '@/components/PageHeader.vue';
 import QueryBox from './components/report-list/QueryBox.vue';
+import type { FieldType } from './components/report-list/QueryBox.vue';
 import CompanySelect from "./components/report-list/CompanySelect.vue";
 import ReportItem from './components/report-list/ReportItem.vue';
 import * as reportService from "@/services/report.service"
@@ -20,19 +21,24 @@ interface CompanyAggProp {
   tail: number;
   checked: boolean;
 }
-
+// 我服务的企业名录列表
 const companies = ref<CompanyAggProp[]>([]);
-
+// 报告总数
 const total = ref(0);
-
+// 当前面报告列表
 const reports = ref<ReportBasic[]>([]);
-
 // 加载状态
 const spinning = ref(true);
-
-function fetchReports(companyId?: number) {
+// 查询字段
+const field = ref<FieldType>('title')
+// 查询关键词
+const keyword = ref('')
+// 过滤栏选择的企业id
+const companyIdSelected = ref<number | undefined>(undefined)
+
+function fetchReports(companyId?: number, page?: number, field?: string, keyword?: string) {
   spinning.value = true;
-  reportsService.query(1, companyId).then((resp) => {
+  reportsService.query(page, companyId, field, keyword).then((resp) => {
     total.value = resp.total;
     reports.value = resp.reports;
     spinning.value = false;
@@ -48,14 +54,20 @@ function onCompanySelectChange(event: {index: number, checked: boolean}) {
   company.checked = event.checked;
 
   if (event.checked) {
+    companyIdSelected.value = company.id;
     fetchReports(company.id)
   } else {
+    companyIdSelected.value = undefined;
     fetchReports()
   }
 }
 
-function onPaginationChange(page: number, pageSize: number) {
-  console.log('page', page, 'pageSize', pageSize);
+function onQuery(queryData: { field: string, keyword: string }) {
+  fetchReports(companyIdSelected.value, currentPage.value, queryData.field, queryData.keyword)
+}
+
+function onPaginationChange(page: number) {
+  fetchReports(companyIdSelected.value, page)
 }
 
 function onCreateReport() {
@@ -92,7 +104,7 @@ onMounted(() => {
     </a-row>
 
     <div class="query-box-wrap">
-      <QueryBox />
+      <QueryBox v-model:field="field" v-model:keyword="keyword" @search="onQuery" />
     </div>
     <a-row class="main-content" :gutter="24">
       <a-col :xxl="5" :xl="6" :lg="7" :span="8" class="company-filter-wrap">

+ 28 - 10
src/views/report/components/report-list/QueryBox.vue

@@ -1,25 +1,42 @@
 <script setup lang="ts">
 import type { SelectProps } from "ant-design-vue";
-import { ref } from "vue";
+import { ref, type PropType } from "vue";
 
-const field = ref('title');
-const keyword = ref('');
+export type FieldType = 'title' | 'companyName';
+
+const props = defineProps({
+  field: {
+    type: String as PropType<FieldType>,
+    required: true,
+  },
+  keyword: {
+    type: String,
+    required: true,
+  }
+});
 
 const fieldOptions = ref<SelectProps['options']>([
   { value: 'title', label: '按标题' },
-  { value: 'company_name', label: '按企业名称' },
+  { value: 'companyName', label: '按企业名称' },
 ]);
 
-function onFieldChange(value: string) {
-  console.log('field value', value);
-}
-
 const emits = defineEmits<{
+  (e: "update:field", field: string): void;
+  (e: "update:keyword", keyword: string): void;
   (e: "search", data: { field: string, keyword: string }): void;
 }>();
 
+function onFieldChange(value: string) {
+  emits("update:field", value);
+}
+
+function onKeywordChange(e: InputEvent) {
+  const value = (e.target as HTMLInputElement).value
+  emits("update:keyword", value);
+}
+
 function onSearch() {
-  emits("search", { field: field.value, keyword: keyword.value})
+  emits("search", { field: props.field, keyword: props.keyword })
 }
 </script>
 
@@ -37,10 +54,11 @@ function onSearch() {
     </a-col>
     <a-col flex="1">
       <a-input-search
-        v-model:value="keyword"
+        :value="keyword"
         placeholder="请输入关键词进行查询"
         enter-button="查&nbsp;&nbsp;询"
         size="large"
+        @change="onKeywordChange"
         @search="onSearch"
       />
     </a-col>

+ 46 - 15
src/views/reportTemplate/ReportTemplateListView.vue

@@ -3,52 +3,75 @@ import { onMounted, ref } from "vue";
 import PageHeader from '@/components/PageHeader.vue';
 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 { CompLog } from "@/helpers/log.helper";
 import SpinComponent from "@/components/SpinComponent.vue";
 import { message } from "ant-design-vue";
 
+// 报告模板总数
 const total = ref(0);
+// 报告模板列表
 const templates = ref<ReportTemplateSave[]>([])
+// 加载列表的状态
 const loading = ref(false)
+// 当前所在页数
+const currentPage = ref(1)
+// 查询字段
+const field = ref<FieldType>('title')
+// 查询关键词
+const keyword = ref('')
+
+function fetchTemplates(field?: string, keyword?: string, page?: number) {
+  loading.value = true
+  reportTemplateService.list(field, keyword, page).then((resp) => {
+    total.value = resp.total;
+    templates.value = resp.items;
+    loading.value = false
+  }).catch((err) => {
+    loading.value = false
+    CompLog.logErr(err)
+  })
+}
 
 function onQuery(queryData: { field: string, keyword: string }) {
-  console.log(queryData);
+  fetchTemplates(queryData.field, queryData.keyword)
+}
+
+function onPaginationChange(page: number) {
+  fetchTemplates(field.value, keyword.value, page)
 }
 
 function onDelete(index: number) {
   const template = templates.value[index];
-  console.log('delete template', template);
   if (template.id) {
-    reportTemplateService.remove(template.id)
+    reportTemplateService.remove(template.id).then((deleted) => {
+      if (deleted) {
+        fetchTemplates()
+      } else {
+        CompLog.logErr('删除报告失败:' + template.id)
+      }
+    })
   } else {
     message.warning("模板ID为空,无法为您删除模板 " + template.name)
   }
 }
 
 onMounted(() => {
-  loading.value = true
-  reportTemplateService.list().then((resp) => {
-    total.value = resp.total;
-    templates.value = resp.items;
-    loading.value = false
-  }).catch((err) => {
-    loading.value = false
-    CompLog.logErr(err)
-  })
+  fetchTemplates();
 });
 </script>
 
 <template>
   <PageHeader title="报告模板管理" />
   <div class="query-box-wrap">
-    <ReportTemplateQueryBox @search="onQuery" />
+    <ReportTemplateQueryBox v-model:field="field" v-model:keyword="keyword" @search="onQuery" />
   </div>
   <div class="templates-wrap">
     <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">使用模板创建报告</a-button>
           <a-popconfirm
             :title="'确定删模板 ' + item.name"
             ok-text="确定"
@@ -68,6 +91,9 @@ onMounted(() => {
       </a-card>
     </SpinComponent>
   </div>
+  <div class="pagination-wrap">
+    <a-pagination v-model:current="currentPage" :total="total" @change="onPaginationChange" />
+  </div>
 </template>
 
 <style scoped lang="scss">
@@ -80,11 +106,16 @@ onMounted(() => {
   margin-top: 2em;
 
   .template-item {
-    margin-top: 2em;
+    margin-top: 1em;
 
     &:first-child {
       margin-top: 0;
     }
   }
 }
+
+.pagination-wrap {
+  margin-top: 1em;
+  text-align: right;
+}
 </style>

+ 28 - 5
src/views/reportTemplate/components/ReportTemplateQueryBox.vue

@@ -1,9 +1,19 @@
 <script setup lang="ts">
 import type { SelectProps } from "ant-design-vue";
-import { ref } from "vue";
+import { ref, type PropType } from "vue";
 
-const field = ref('title');
-const keyword = ref('');
+export type FieldType = 'title' | 'tags';
+
+const props = defineProps({
+  field: {
+    type: String as PropType<FieldType>,
+    required: true,
+  },
+  keyword: {
+    type: String,
+    required: true,
+  }
+});
 
 const fieldOptions = ref<SelectProps['options']>([
   { value: 'title', label: '按模板名称' },
@@ -11,11 +21,22 @@ const fieldOptions = ref<SelectProps['options']>([
 ]);
 
 const emits = defineEmits<{
+  (e: "update:field", field: string): void;
+  (e: "update:keyword", keyword: string): void;
   (e: "search", data: { field: string, keyword: string }): void;
 }>();
 
+function onFeidlChange(value: string) {
+  emits("update:field", value);
+}
+
+function onKeywordChange(e: InputEvent) {
+  const value = (e.target as HTMLInputElement).value
+  emits("update:keyword", value);
+}
+
 function onSearch() {
-  emits("search", { field: field.value, keyword: keyword.value})
+  emits("search", { field: props.field, keyword: props.keyword})
 }
 </script>
 
@@ -28,14 +49,16 @@ function onSearch() {
         style="width: 140px"
         :options="fieldOptions"
         size="large"
+        @change="onFeidlChange"
       ></a-select>
     </a-col>
     <a-col flex="1">
       <a-input-search
-        v-model:value="keyword"
+        :value="keyword"
         placeholder="请输入关键词进行查询"
         enter-button="查&nbsp;&nbsp;询"
         size="large"
+        @change="onKeywordChange"
         @search="onSearch"
       />
     </a-col>