Procházet zdrojové kódy

人才采集:查看详情,任务解析失败时可重新提交解析

Xiao_123 před 2 měsíci
rodič
revize
377dc8dac8

+ 39 - 39
src/views/menduner/system/talentMap/maintenance/examine/store.vue

@@ -11,7 +11,7 @@
         <div v-if="hasSourceUrl">
           <!-- 门墩儿人才库 -->
           <template v-if="type === '招聘'">
-            <!-- <el-tabs v-model="activeName" type="border-card">
+            <el-tabs v-model="activeName" type="border-card">
               <el-tab-pane label="基本信息" name="info">
                 <Info :id="personId" :user-id="userId" @echo="infoEcho" />
                 <expExtend :user-id="userId" defaultShowAll class="m-t-20px" @echo="expEcho" />
@@ -19,8 +19,7 @@
               <el-tab-pane label="附件简历" name="Attachment">
                 <Attachment showPreview :user-id="userId" />
               </el-tab-pane>
-            </el-tabs> -->
-            人才ID:{{ originUrl }}
+            </el-tabs>
           </template>
           <!-- 简历解析 -->
           <template v-if="type === '简历'">
@@ -60,9 +59,9 @@
 defineOptions({ name: 'Store' })
 import { ElLoading } from 'element-plus'
 import FormPage from '@/views/menduner/system/talentMap/components/FormPage.vue'
-// import Info from '@/views/menduner/system/person/details/components/info.vue'
-// import expExtend from '@/views/menduner/system/person/details/components/expExtend.vue'
-// import Attachment from '@/views/menduner/system/person/details/components/attachment.vue'
+import Info from '@/views/menduner/system/person/details/components/info.vue'
+import expExtend from '@/views/menduner/system/person/details/components/expExtend.vue'
+import Attachment from '@/views/menduner/system/person/details/components/attachment.vue'
 import { cloneDeep } from 'lodash-es'
 import { marked } from 'marked'
 import { timesTampChange, timestampToAge } from '@/utils/transform/date'
@@ -78,9 +77,9 @@ const type = ref('')
 const originData = ref([])
 
 const originUrl = ref(null)
-// const personId = ref('')
-// const userId = ref('')
-// const activeName = ref('info')
+const personId = ref('')
+const userId = ref('')
+const activeName = ref('info')
 const hasSourceUrl = ref(false)
 
 // markdown回显
@@ -130,11 +129,12 @@ const dealData = async (type, data) => {
     originUrl.value = data.image_path
   }
   
-  // if (type === '招聘') { // 门墩儿招聘-人员信息在组件中通过id和userId获取
-  //   personId.value = data?.id || ''
-  //   userId.value = data?.userId || ''
-  //   activeName.value = 'info'
-  // }
+  if (type === '招聘') { // 门墩儿招聘-人员信息在组件中通过id和userId获取
+    const obj = JSON.parse(data.image_path)
+    personId.value = obj?.id || ''
+    userId.value = obj?.userId || ''
+    activeName.value = 'info'
+  }
   if (type === '新任命') {
     await nextTick()
     const response = await fetch(data.image_path)
@@ -154,33 +154,33 @@ const dealData = async (type, data) => {
 }
 
 // 门墩儿招聘人才详情回显赋值
-// const infoEcho = (data) => {
-//   data = data ? JSON.parse(data) : null
-//   itemData.value = {
-//     ...itemData.value,
-//     name_zh: data?.name || '',
-//     email: data?.email || '',
-//     mobile: data?.phone || '',
-//     birthday: data?.birthday ? timesTampChange(data.birthday, 'Y-M-D') : '',
-//     age: data?.birthday ? timestampToAge(data.birthday) : null,
-//     created_at: data?.createTime ? timesTampChange(data.createTime, 'Y-M-D') : null,
-//     updated_at: data?.updateTime ? timesTampChange(data.updateTime, 'Y-M-D') : null,
-//   }
-// }
+const infoEcho = (data) => {
+  data = data ? JSON.parse(data) : null
+  itemData.value = {
+    ...itemData.value,
+    name_zh: data?.name || '',
+    email: data?.email || '',
+    mobile: data?.phone || '',
+    birthday: data?.birthday ? timesTampChange(data.birthday, 'Y-M-D') : '',
+    age: data?.birthday ? timestampToAge(data.birthday) : null,
+    created_at: data?.createTime ? timesTampChange(data.createTime, 'Y-M-D') : null,
+    updated_at: data?.updateTime ? timesTampChange(data.updateTime, 'Y-M-D') : null,
+  }
+}
 
 // 门墩儿招聘人才工作经历回显赋值
-// const expEcho = (workList) => {
-//   itemData.value = {
-//     ...itemData.value,
-//     career_path: workList ? workList.map(e => {
-//       return {
-//         hotel_zh: e?.enterpriseName || null,
-//         title_zh: e?.positionName || null,
-//         date: e?.startTime ? timesTampChange(e.startTime, 'Y-M-D') : null
-//       }
-//     }) : null
-//   }
-// }
+const expEcho = (workList) => {
+  itemData.value = {
+    ...itemData.value,
+    career_path: workList ? workList.map(e => {
+      return {
+        hotel_zh: e?.enterpriseName || null,
+        title_zh: e?.positionName || null,
+        date: e?.startTime ? timesTampChange(e.startTime, 'Y-M-D') : null
+      }
+    }) : null
+  }
+}
 
 // 重置
 const resetData = () => {

+ 81 - 2
src/views/menduner/system/talentMap/maintenance/gather/components/detail.vue

@@ -50,7 +50,35 @@
       <div class="flex-1">
 				<el-tabs type="border-card">
           <el-tab-pane label="原始数据">
-						<el-table v-loading="false" :data="list" :stripe="true" border>
+            <el-table
+              v-loading="false"
+              class="mb-50px"
+              v-if="otherList?.length > 0"
+              :data="otherList"
+              border
+            >
+							<el-table-column label="文件名" align="center" prop="original_filename" />
+							<el-table-column label="发布时间" align="center" prop="publish_time" />
+							<el-table-column label="状态" align="center" prop="status">
+								上传成功
+							</el-table-column>
+							<el-table-column label="操作" align="center" fixed="right" min-width="110">
+								<template #default="scope">
+									<el-button link type="primary" @click="handleDetail(scope.row)">详情</el-button>
+								</template>
+							</el-table-column>
+						</el-table>
+
+						<el-table 
+              v-loading="false"
+              :data="list"
+              border
+              row-key="minio_path"
+              height="60vh"
+              @select="handleSelect"
+              @select-all="handleSelectAll"
+            >
+              <el-table-column v-if="showAnalysisBtn" type="selection" width="55" :selectable="selectable" />
 							<el-table-column v-if="source !== '招聘'" label="文件名" align="center" prop="original_filename" />
 							<el-table-column v-if="source === '新任命'" label="发布时间" align="center" prop="publish_time" />
 							<template v-if="source === '招聘'">
@@ -71,6 +99,7 @@
       </div>
     </div>
     <template #footer>
+      <el-button type="primary" v-if="showAnalysisBtn" @click="handleAnlysis">执行解析</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
@@ -84,11 +113,14 @@ import Info from '@/views/menduner/system/person/details/components/info.vue'
 import expExtend from '@/views/menduner/system/person/details/components/expExtend.vue'
 import Attachment from '@/views/menduner/system/person/details/components/attachment.vue'
 
+const emit = defineEmits(['analysis'])
 const message = useMessage() // 消息弹窗
 
 const dialogTitle = ref(null)
 const dialogVisible = ref(false)
+const otherList = ref([])
 const list = ref([])
+const selectable = (row) => !row.disabled
 const originUrl = ref(null)
 const source = ref(null)
 const typeObj = {
@@ -100,10 +132,13 @@ const typeObj = {
 }
 
 const resetData = () => {
+  originData.value = {}
 	list.value = []
+  otherList.value = []
 	originUrl.value = null
 	source.value = null
 	isDrilling.value = false
+  showAnalysisBtn.value = false
 	dialogTitle.value = null
 }
 
@@ -181,12 +216,35 @@ const dealData = async (data) => {
   }
 }
 
+const handleSelect = (arr, row) => {
+  const index = list.value.indexOf(row)
+  list.value[index].parse_flag = arr.length ? 1 : 0
+}
+const handleSelectAll = (arr) => {
+  list.value.forEach(e => {
+    if (!e.disabled) e.parse_flag = arr.length ? 1 : 0 
+  })
+}
+
 // 打开弹窗
+const originData = ref({})
+const showAnalysisBtn = ref(false)
 const open = async (row) => {
   resetData()
+  originData.value = row
 	dialogTitle.value = `${typeObj[row.task_type]}【${row.task_name}】详情`
 	source.value = row.task_type
-	list.value = row.task_source || []
+
+  let restList = row.task_source || []
+  if (row.task_type === '新任命' && row.task_source?.length > 1) {
+    otherList.value = [row.task_source[0]]
+    restList = row.task_source.slice(1)
+  }
+  list.value = restList.map(k => {
+    // parse_flag:0表示已经解析完成, 1表示需要提交执行解析
+    if (k.parse_flag === 0) k.disabled = true
+    return k
+  })
 
   // 只有一条数据时默认展示原始数据
   if (list.value.length === 1) {
@@ -194,6 +252,11 @@ const open = async (row) => {
 	  dealData(list.value[0])
   }
 
+  // 待解析 解析成功 部分解析成功 解析失败
+  if (['部分解析成功', '解析失败'].includes(row.task_status)) {
+    showAnalysisBtn.value = row.task_source.some(e => e.parse_flag.toString() === '1')
+  }
+
   dialogVisible.value = true
 }
 defineExpose({ open }) // 提供 open 方法,用于打开弹窗
@@ -204,6 +267,22 @@ const handleDetail = (row) => {
 	isDrilling.value = true
 	dealData(row)
 }
+
+// 执行解析
+const handleAnlysis = () => {
+  const isNoAnalysis = list.value.every(e => e.parse_flag === 0)
+  if (isNoAnalysis) return message.warning('请勾选要进行解析的项')
+
+  list.value.forEach(e => delete e.disabled)
+  let taskList = list.value || []
+  if (originData.value.task_type === '新任命' && otherList.value.length) {
+    taskList = [originData.value.task_source[0], ...list.value]
+  }
+  originData.value.task_source = taskList
+
+  emit('analysis', originData.value)
+  dialogVisible.value = false
+}
 </script>
 
 <style lang="scss" scpoed>

+ 2 - 2
src/views/menduner/system/talentMap/maintenance/gather/components/search.vue

@@ -88,8 +88,8 @@
     <el-tag v-for="(i, index) in addList" :key="i.id" closable type="success" style="margin: 5px 10px 5px 0;" @close="delAddTag(index)">
       {{ i.name_zh }}
     </el-tag>
-    <div class="mt-10px">
-      <el-button type="primary" @click="emit('submit')">提交</el-button>
+    <div class="mt-10px text-end">
+      <el-button type="primary" @click="emit('submit')">提交解析</el-button>
     </div>
   </ContentWrap>
 

+ 3 - 3
src/views/menduner/system/talentMap/maintenance/gather/index.vue

@@ -169,7 +169,7 @@
     </template>
   </Dialog>
 
-  <TaskDetail ref="TaskDetailRef" />
+  <TaskDetail ref="TaskDetailRef" @analysis="val => handleAnalysis(val, true)" />
 </template>
 
 <script setup>
@@ -258,8 +258,8 @@ const handleDetail = (row) => {
 }
 
 // 任务解析
-const handleAnalysis = async (row) => {
-  await message.confirm('是否确认解析当前任务?')
+const handleAnalysis = async (row, noTip = false) => {
+  if (!noTip) await message.confirm('是否确认解析当前任务?')
 
   const loading = ElLoading.service({
     lock: true,

+ 1 - 1
src/views/menduner/system/talentMap/maintenance/labeling/index.vue

@@ -48,7 +48,7 @@
       <el-table-column label="姓名" align="center" prop="name_zh" />
       <el-table-column label="职位" align="center" prop="title_zh" :show-overflow-tooltip="true" />
       <el-table-column label="酒店" align="center" prop="hotel_zh" :show-overflow-tooltip="true" />
-      <el-table-column label="标签数" align="center" prop="" />
+      <el-table-column label="标签数" align="center" prop="tag_count" />
       <el-table-column label="人才状态" align="center" prop="status">
         <template #default="scope">
           <el-tag :type="scope.row.status === 'active' ? 'success' : 'danger'">

+ 33 - 30
src/views/menduner/system/talentMap/search/index.vue

@@ -126,9 +126,9 @@
 </template>
 
 <script setup>
-import { ref, computed } from 'vue'
 import { Search } from '@element-plus/icons-vue'
 import { generateUUID } from '@/utils'
+import { marked } from 'marked'
 import { talentSearchApi } from '@/api/menduner/system/talentMap/search'
 import { talentLabelingApi } from '@/api/menduner/system/talentMap/labeling'
 
@@ -185,35 +185,33 @@ const showPage = (id, html) => {
     .replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/g, '')
     .replace(/https/g, 'http')
 
-  nextTick(() => {
-    const iframe = document.getElementById(id)
-    if (!iframe) return
-    const doc = iframe.contentDocument || iframe.document
-    // 设置 iframe 中请求不发送 referrer,以绕过图片防盗链
-    const htmlArr = html.split('</head>')
-    const html_src_add = htmlArr[0] + '<meta name="referrer" content="never"></head>' + htmlArr[1]
-    doc.open()
-    doc.write(html_src_add)
-    doc.close()
+  const iframe = document.getElementById(id)
+  
+  const doc = iframe.contentDocument || iframe.document
+  // 设置 iframe 中请求不发送 referrer,以绕过图片防盗链
+  const htmlArr = html.split('</head>')
+  const html_src_add = htmlArr[0] + '<meta name="referrer" content="never"></head>' + htmlArr[1]
+  doc.open()
+  doc.write(html_src_add)
+  doc.close()
 
-    // 设置图片宽高
-    let iwindow = iframe.contentWindow;
-    iframe.addEventListener('load',function () {
-      let idoc = iwindow.document;
-      let imgs = idoc.getElementsByTagName('img')
-      for (let i = 0; i < imgs.length; i++) {
-        const img = imgs[i]
-        if (img) {
-          if (img.width >= img.height) {
-            img.width = iframe.clientWidth / 2
-          } else {
-            img.height = iframe.clientHeight / 2
-            let left = (iframe.clientWidth - img.width) / 2
-            img.style.marginLeft = left + "px"
-          }
+  // 设置图片宽高
+  let iwindow = iframe.contentWindow;
+  iframe.addEventListener('load',function () {
+    let idoc = iwindow.document;
+    let imgs = idoc.getElementsByTagName('img')
+    for (let i = 0; i < imgs.length; i++) {
+      const img = imgs[i]
+      if (img) {
+        if (img.width >= img.height) {
+          img.width = iframe.clientWidth / 2
+        } else {
+          img.height = iframe.clientHeight / 2
+          let left = (iframe.clientWidth - img.width) / 2
+          img.style.marginLeft = left + "px"
         }
       }
-    })
+    }
   })
 }
 
@@ -256,11 +254,11 @@ const handleDetails = async (id) => {
 			const sortedList = list.sort((a, b) => new Date(b.source_date) - new Date(a.source_date))
 			sourceList.value = sortedList.map(e => {
 				const item = { ...e, id: generateUUID() }
-
 				if (e.task_type === '新任命') {
-					handleShowPage(item.id, item.minio_path)
+					setTimeout(() => {
+						handleShowPage(item.id, item.minio_path)
+					}, 200)
 				}
-				
 				return item
 			})
 		}
@@ -323,5 +321,10 @@ const handleSearch = (type='search') => {
 			background-color: #f5f7fa;
 		}
 	}
+	.markdownContent {
+		width: 100%;
+		max-width: 100%;
+		height: 600px;
+	}
 }
 </style>