ReportListView.vue 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. <script setup lang="ts">
  2. import { onMounted, ref } from "vue";
  3. import { PlusOutlined } from "@ant-design/icons-vue";
  4. import PageHeader from "@/components/PageHeader.vue";
  5. import QueryBox from "./components/report-list/QueryBox.vue";
  6. import type { FieldType } from "./components/report-list/QueryBox.vue";
  7. import CompanySelect from "./components/report-list/CompanySelect.vue";
  8. import ReportItem from "./components/report-list/ReportItem.vue";
  9. import * as reportService from "@/services/report.service";
  10. import * as reportsService from "@/services/reports.service";
  11. import { CompLog } from "@/libs/log.lib";
  12. import type { ReportBasic } from "@/types/report.types";
  13. import { routeToReportEditor } from "@/router";
  14. import SpinComponent from "@/components/SpinComponent.vue";
  15. import TemplateSelect from "./components/TemplateSelect.vue";
  16. import { message } from "ant-design-vue";
  17. const _componentName = "ReportListView";
  18. const logError = CompLog.logErr(_componentName);
  19. const currentPage = ref(1);
  20. const reportStatus = ref([
  21. {
  22. label: "全部",
  23. value: undefined,
  24. },
  25. {
  26. label: "编写中",
  27. value: 0,
  28. },
  29. {
  30. label: "已完成",
  31. value: 1,
  32. },
  33. ]);
  34. const status = ref(undefined);
  35. interface CompanyAggProp {
  36. id?: number;
  37. label: string;
  38. tail: number;
  39. checked: boolean;
  40. }
  41. // 我服务的企业名录列表
  42. const companies = ref<CompanyAggProp[]>([]);
  43. // 报告总数
  44. const total = ref(0);
  45. // 当前面报告列表
  46. const reports = ref<ReportBasic[]>([]);
  47. // 加载状态
  48. const spinning = ref(true);
  49. // 查询字段
  50. const field = ref<FieldType>("title");
  51. // 查询关键词
  52. const keyword = ref("");
  53. // 过滤栏选择的企业id
  54. const companyIdSelected = ref<Array<number>>([]);
  55. // 模板选择器ref
  56. const templateSelect = ref<InstanceType<typeof TemplateSelect> | null>(null);
  57. function fetchReports(
  58. companyIds?: Array<number>,
  59. page?: number,
  60. field?: string,
  61. keyword?: string
  62. ) {
  63. spinning.value = true;
  64. reportsService
  65. .query(page, companyIds, field, keyword, status.value)
  66. .then((resp) => {
  67. total.value = resp.total;
  68. reports.value = resp.reports;
  69. spinning.value = false;
  70. })
  71. .catch((err) => {
  72. // logError(err);
  73. spinning.value = false;
  74. });
  75. }
  76. // function onCompanySelectChange(event: {index: number, checked: boolean}) {
  77. // console.log('company select change', event);
  78. // const company = companies.value[event.index];
  79. // company.checked = event.checked;
  80. // if (company.id || company.id == 0) {
  81. // if (!event.checked) {
  82. // companyIdSelected.value.splice(companyIdSelected.value.indexOf(company.id), 1);
  83. // } else {
  84. // companyIdSelected.value.push(company.id);
  85. // }
  86. // }
  87. // if (companyIdSelected.value) {
  88. // if (companyIdSelected.value.length > 0) {
  89. // fetchReports(companyIdSelected.value)
  90. // } else {
  91. // fetchReports()
  92. // }
  93. // }
  94. // }
  95. function onQuery(queryData: { field: string; keyword: string }) {
  96. currentPage.value = 1;
  97. fetchReports(
  98. companyIdSelected.value,
  99. currentPage.value,
  100. queryData.field,
  101. queryData.keyword
  102. );
  103. }
  104. function onPaginationChange(page: number) {
  105. fetchReports(companyIdSelected.value, page, field.value, keyword.value)
  106. }
  107. function onCreateReport() {
  108. templateSelect.value?.show();
  109. }
  110. // function onTemplateSelected(templateId: number | null) {
  111. // reportService.create({templateId}).then((id) => {
  112. // // routeToReportEditor(id);
  113. // }).catch(logError);
  114. // }
  115. function onFilterChange() {
  116. currentPage.value = 1;
  117. fetchReports(companyIdSelected.value, currentPage.value);
  118. }
  119. function onReportDelete(id: number) {
  120. reportService
  121. .remove(id)
  122. .then((ok) => {
  123. if (ok) {
  124. message.success("删除报告成功");
  125. currentPage.value =
  126. reports.value.length === 1 ? currentPage.value - 1 : currentPage.value;
  127. fetchReports(
  128. companyIdSelected.value,
  129. currentPage.value,
  130. field.value,
  131. keyword.value
  132. );
  133. } else {
  134. message.success("删除报告失败");
  135. }
  136. })
  137. .catch(() => {
  138. message.success("删除报告失败");
  139. });
  140. }
  141. function serialNumber(index: number) {
  142. index += 1;
  143. return (currentPage.value - 1) * 10 + index;
  144. }
  145. onMounted(() => {
  146. fetchReports();
  147. // 左侧企业名录统计;
  148. // reportsService
  149. // .agg()
  150. // .then((aggs) => {
  151. // companies.value = aggs
  152. // .filter((agg) => agg.count > 0)
  153. // .map((agg) => {
  154. // return {
  155. // id: agg.companyId,
  156. // label: agg.name,
  157. // tail: agg.count,
  158. // checked: false,
  159. // };
  160. // });
  161. // })
  162. // .catch(logError);
  163. });
  164. </script>
  165. <template>
  166. <div class="reports-wrap">
  167. <PageHeader title="全部报告">
  168. <a-button type="primary" @click="onCreateReport"
  169. ><plus-outlined />新建报告</a-button
  170. >
  171. </PageHeader>
  172. <div class="query-box-wrap">
  173. <QueryBox v-model:field="field" v-model:keyword="keyword" @search="onQuery" />
  174. </div>
  175. <div class="filter-box-wrap">
  176. <a-radio-group
  177. :options="reportStatus"
  178. v-model:value="status"
  179. @change="onFilterChange()"
  180. />
  181. </div>
  182. <a-row class="main-content" :gutter="24">
  183. <!-- <a-col :xxl="5" :xl="6" :lg="7" :span="8" class="company-filter-wrap">
  184. <h3>我所服务的企业 <span>【{{ companies.length }}】</span></h3>
  185. <CompanySelect :data="companies" @change="onCompanySelectChange" />
  186. </a-col> -->
  187. <a-col :xxl="24" :xl="24" :lg="24" :span="24">
  188. <SpinComponent :spinning="spinning">
  189. <ReportItem
  190. v-for="(report, index) in reports"
  191. :data="report"
  192. :key="index"
  193. :serialNumber="serialNumber(index)"
  194. class="report-item"
  195. @delete="onReportDelete"
  196. />
  197. </SpinComponent>
  198. </a-col>
  199. </a-row>
  200. <div class="pagination-wrap">
  201. <a-pagination
  202. v-model:current="currentPage"
  203. :total="total"
  204. @change="onPaginationChange"
  205. />
  206. </div>
  207. </div>
  208. <!-- <TemplateSelect ref="templateSelect" @ok="onTemplateSelected" /> -->
  209. </template>
  210. <style scoped lang="scss">
  211. @import "@/assets/base.scss";
  212. .reports-wrap {
  213. .query-box-wrap {
  214. width: 80%;
  215. margin: 0 auto;
  216. }
  217. .filter-box-wrap {
  218. display: flex;
  219. margin: 1.5em 21.1%;
  220. }
  221. .main-content {
  222. margin-top: 1.5em;
  223. .company-filter-wrap {
  224. border: 1px solid $border-color-primary;
  225. padding: 20px 16px;
  226. > h3 > span {
  227. color: red;
  228. }
  229. }
  230. .report-item {
  231. margin-top: 16px;
  232. &:first-child {
  233. margin-top: 0;
  234. }
  235. }
  236. :deep(.ant-card) {
  237. background-color: #f5f5f5;
  238. .ant-card-head-title {
  239. font-size: 1.2em;
  240. }
  241. .ant-card-body p {
  242. margin-bottom: 0.5em;
  243. }
  244. &.ant-card-bordered {
  245. border: 1px solid #d0d0d0;
  246. }
  247. }
  248. }
  249. .pagination-wrap {
  250. margin-top: 1em;
  251. text-align: right;
  252. }
  253. }
  254. </style>