ReferenceDraw.vue 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. <!-- 参考文献抽屉组件 -->
  2. <script setup lang="ts">
  3. import { ref, reactive, type Ref } from "vue";
  4. import ReferenceSearchBox from "./ReferenceSearchBox.vue";
  5. import ReferenceSearchResultItem from "./ReferenceSearchResultItem.vue";
  6. import type { ChapterSearchDocResponse, ChapterSearchRequest } from "@/types/search.types"
  7. import * as chapterSearchService from "@/services/chapterSearch.service"
  8. import * as paperSectionService from "@/services/paperSection.service"
  9. import { CompLog } from "@/libs/log.lib";
  10. import SpinComponent from "@/components/SpinComponent.vue";
  11. const props = defineProps({
  12. reportName: {
  13. type: String,
  14. required: true,
  15. },
  16. reportKeywords: {
  17. type: String,
  18. required: true,
  19. },
  20. chapterKeywords: {
  21. type: Array<String>,
  22. required: true,
  23. }
  24. });
  25. const emits = defineEmits<{
  26. (e: "insert", text: string): void;
  27. (e: "close"): void;
  28. (e: "recordUse", sectionId: number): void;
  29. }>();
  30. // 组件可见状态
  31. const visible = ref<boolean>(false);
  32. // 章节搜索结果总数量
  33. const total = ref(0)
  34. // 章节搜索结果
  35. const referenceSearchResult: Ref<ChapterSearchDocResponse[]> = ref([]);
  36. // 文献章节段落内容是否使用ref
  37. const paperSectionUsage = ref<Record<number, boolean>>({})
  38. // 章节搜索状态
  39. const loading = ref(false)
  40. // 翻页
  41. const pagination = reactive({
  42. page: 1,
  43. size: 10,
  44. })
  45. // 重新检索的查询词
  46. const queryKeywords = ref<string[]>([])
  47. // 在结果中检索的查询
  48. const queryWithInKeywords = ref<string[]>([])
  49. function getFrom(page?: number) {
  50. return (Math.max(1, page || 1) - 1) * pagination.size
  51. }
  52. function getDefaultKeywords(): string[] {
  53. return props.chapterKeywords as string[]
  54. }
  55. function getSearchRequest(): ChapterSearchRequest {
  56. const request: ChapterSearchRequest = {
  57. reportName: props.reportName || '',
  58. reportKeywords: props.reportKeywords || '',
  59. chapterKeywords: getDefaultKeywords(),
  60. queryKeywords: queryKeywords.value,
  61. queryWithInKeywords: queryWithInKeywords.value,
  62. from: getFrom(pagination.page)
  63. }
  64. return request
  65. }
  66. function querySectionUsage(sectionIds: number[]) {
  67. paperSectionService.query(sectionIds).then((usages) => {
  68. paperSectionUsage.value = usages
  69. })
  70. }
  71. function search(request: ChapterSearchRequest) {
  72. loading.value = true
  73. referenceSearchResult.value = []
  74. chapterSearchService.search(request).then((resp) => {
  75. loading.value = false
  76. total.value = resp.total
  77. referenceSearchResult.value = resp.items
  78. querySectionUsage(resp.items.map(item => item.id))
  79. }).catch((err) => {
  80. CompLog.logErr("ReferenceDraw")(err)
  81. loading.value = false
  82. })
  83. }
  84. function onPageChange(page: number) {
  85. pagination.page = page
  86. search(getSearchRequest())
  87. }
  88. function onReferenceSearchBoxSearch(queryKeywordsIn: string[]) {
  89. pagination.page = 1
  90. queryKeywords.value = queryKeywordsIn
  91. queryWithInKeywords.value = []
  92. search(getSearchRequest())
  93. }
  94. function onReferenceSearchWithInSearch(queryWithInKeywordsIn: string[]) {
  95. pagination.page = 1
  96. queryWithInKeywords.value = queryWithInKeywordsIn
  97. search(getSearchRequest())
  98. }
  99. function onSectionRecordUse(sectionId: number) {
  100. paperSectionService.record(sectionId).then(() => {
  101. paperSectionUsage.value[`${sectionId}`] = true
  102. })
  103. }
  104. function onSectionRecordCancel(sectionId: number) {
  105. paperSectionService.cancel(sectionId).then(() => {
  106. paperSectionUsage.value[`${sectionId}`] = false
  107. })
  108. }
  109. function serialNumber(index: number) {
  110. index += 1;
  111. return (pagination.page - 1) * pagination.size + index;
  112. }
  113. const onClose = () => {
  114. visible.value = false;
  115. emits("close")
  116. };
  117. const show = () => {
  118. visible.value = true;
  119. const keywords = props.chapterKeywords
  120. if (keywords && keywords.length > 0) {
  121. search(getSearchRequest())
  122. }
  123. };
  124. defineExpose({
  125. show
  126. });
  127. </script>
  128. <template>
  129. <a-drawer
  130. :width="'60%'"
  131. title="检索参考文献"
  132. placement="right"
  133. :visible="visible"
  134. @close="onClose"
  135. class="reference-drawer"
  136. >
  137. <template #extra>
  138. <span>项目名称:{{ reportName }}</span>
  139. <a-divider type="vertical" />
  140. <span>关键词:{{ reportKeywords }}</span>
  141. <a-divider type="vertical" />
  142. <span>章节关键词:{{ chapterKeywords.join(", ") }}</span>
  143. </template>
  144. <ReferenceSearchBox @search="onReferenceSearchBoxSearch" @search-with-in="onReferenceSearchWithInSearch" />
  145. <a-divider orientation="left">
  146. <span class="total">章节数量:共 {{ total }} 条</span>
  147. </a-divider>
  148. <SpinComponent :spinning="loading">
  149. <div v-for="(item, index) in referenceSearchResult" :key="index">
  150. <ReferenceSearchResultItem
  151. :data="item"
  152. :used="paperSectionUsage[item.id] || false"
  153. :serialNumber="serialNumber(index)"
  154. @insert="emits('insert', $event)"
  155. @record-use="onSectionRecordUse"
  156. @record-cancel="onSectionRecordCancel"
  157. />
  158. <a-divider class="result-item-divider" v-if="index < referenceSearchResult.length - 1" />
  159. </div>
  160. <div class="pigination-wrap">
  161. <a-pagination
  162. :current="pagination.page"
  163. :pageSize="pagination.size"
  164. :total="total"
  165. :show-size-changer="false"
  166. size="small"
  167. @change="onPageChange"
  168. />
  169. </div>
  170. </SpinComponent>
  171. </a-drawer>
  172. </template>
  173. <style scoped lang="scss">
  174. .result-item-divider {
  175. margin: 1.2em 0;
  176. }
  177. .total {
  178. font-size: 0.8em;
  179. }
  180. .pigination-wrap {
  181. text-align: right;
  182. margin-top: 1em;
  183. }
  184. </style>