index.vue 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. <template>
  2. <div>
  3. <v-card elevation="5" class="px-10 py-10 d-flex flex-column justify-center" :height="items.length ? 'auto' : '300px'">
  4. <div class="d-flex align-center">
  5. <TextInput
  6. v-model="content"
  7. :item="textItem"
  8. @enter="handleSearch"
  9. @appendInnerClick="handleSearch"
  10. ></TextInput>
  11. <v-btn color="primary" width="100" class="ml-5" :loading="loading" @click="handleSearch">搜 索</v-btn>
  12. </div>
  13. <div v-if="!isSearch" class="color-999 mt-1 font-size-14">例如:有酒店筹开经验,且担任总经理的人</div>
  14. </v-card>
  15. <v-card v-if="isSearch" elevation="5" class="mt-3">
  16. <CtTable
  17. :items="items"
  18. class="pa-3"
  19. :headers="headers"
  20. :loading="loading"
  21. :disable-sort="true"
  22. :elevation="0"
  23. :isTools="false"
  24. :items-per-page="-1"
  25. height="calc(100vh - 400px)"
  26. :showFixedLastItem="true"
  27. itemKey="id"
  28. >
  29. <template #actions="{ item }">
  30. <v-btn variant="text" color="primary" @click.stop="handleDetail(item)">详 情</v-btn>
  31. </template>
  32. </CtTable>
  33. </v-card>
  34. <v-navigation-drawer v-model="showDetail" absolute location="right" rounded temporary width="700" class="pa-5">
  35. <!-- 名片 -->
  36. <div v-if="previewUrl">
  37. <div class="color-primary font-size-18 font-weight-bold">名片</div>
  38. <div class="text-center cursor-pointer" @click="showPreview = true">
  39. <img width="300" height="400" :src="previewUrl" />
  40. </div>
  41. </div>
  42. <!-- 基本信息 -->
  43. <baseInfo :data="detail" :tagList="talentTags"></baseInfo>
  44. <!-- 职业轨迹 -->
  45. <careerPath :data="detail"></careerPath>
  46. </v-navigation-drawer>
  47. </div>
  48. <Loading :visible="detailLoading"></Loading>
  49. <PreviewImage v-if="showPreview" :initialIndex="0" :urlList="[previewUrl]" @close="showPreview = !showPreview" />
  50. </template>
  51. <script setup>
  52. defineOptions({ name: 'NewTalentMapSearch' })
  53. import { ref } from 'vue'
  54. import { getTalentList, getBusinessCardDetails, getTalentCardByImagePath, getTalentTagById } from '@/api/recruit/enterprise/talentSearch'
  55. import Snackbar from '@/plugins/snackbar'
  56. import baseInfo from './components/baseInfo.vue'
  57. import careerPath from './components/careerPath.vue'
  58. const loading = ref(false)
  59. const showPreview = ref(false)
  60. const detailLoading = ref(false)
  61. const content = ref('')
  62. const items = ref([])
  63. const headers = [
  64. { title: '中文名', key: 'name_zh', sortable: false },
  65. { title: '英文名', key: 'name_en', sortable: false },
  66. { title: '联系电话', key: 'mobile', sortable: false },
  67. { title: '电子邮箱', key: 'email', sortable: false },
  68. { title: '更新时间', key: 'updated_at', sortable: false },
  69. { title: '操作', key: 'actions', sortable: false, align: 'center' }
  70. ]
  71. const textItem = ref({
  72. type: 'text',
  73. value: '',
  74. label: '请输入您的描述信息定位人才',
  75. placeholder: '请输入您的描述信息,例如:查找所有在上海的五星级酒店担任总经理职位的人才',
  76. clearable: true,
  77. hideDetails: true,
  78. appendInnerIcon: 'mdi-magnify'
  79. })
  80. const isSearch = ref(false)
  81. const abortController = ref(null)
  82. // 人才列表
  83. const getList = async () => {
  84. loading.value = true
  85. try {
  86. abortController.value = new AbortController()
  87. const signal = abortController.value.signal
  88. const data = await getTalentList({ query_requirement: content.value }, signal)
  89. if (!data || !data.length) {
  90. Snackbar.warning('暂无数据,请更换查询条件后再试')
  91. items.value = []
  92. isSearch.value = false
  93. return
  94. }
  95. items.value = data || []
  96. } finally {
  97. loading.value = false
  98. }
  99. }
  100. // 查看详情
  101. const showDetail = ref(false)
  102. const detail = ref({})
  103. const talentTags = ref([])
  104. const previewUrl = ref(null)
  105. const handleDetail = async ({ pg_id }) => {
  106. if (!pg_id) {
  107. return
  108. }
  109. detailLoading.value = true
  110. try {
  111. const result = await getBusinessCardDetails(pg_id)
  112. if (!result || !Object.keys(result).length) return Snackbar.warning('暂无详细信息,去查看其他人的信息吧~')
  113. detail.value = result
  114. // 获取名片预览
  115. if (result?.image_path) {
  116. const data = await getTalentCardByImagePath(result.image_path)
  117. previewUrl.value = URL.createObjectURL(data)
  118. }
  119. // 获取人才标签
  120. const tagData = await getTalentTagById(pg_id)
  121. talentTags.value = tagData ?? []
  122. showDetail.value = true
  123. } finally {
  124. detailLoading.value = false
  125. }
  126. }
  127. // 搜索
  128. const handleSearch = async (value, type) => {
  129. if (type === 'clear') {
  130. items.value = []
  131. isSearch.value = false
  132. if (abortController.value) {
  133. abortController.value.abort()
  134. abortController.value = null
  135. }
  136. return
  137. }
  138. isSearch.value = true
  139. if (!type && !content.value) return Snackbar.warning('请输入您的描述信息定位人才')
  140. getList()
  141. }
  142. </script>
  143. <style scoped lang="scss">
  144. </style>