Xiao_123 3 dni temu
rodzic
commit
23de2749f7

+ 45 - 0
src/api/menduner/system/talentMap/labeling.ts

@@ -0,0 +1,45 @@
+import request from '@/config/axios'
+
+export const talentLabelingApi = {
+	// 获取所有名片列表
+	getCardList: async () => {
+		return await request.get({ 
+			url: `/api/parse/get-business-cards`, 
+			baseURL: import.meta.env.VITE_BASE_URL 
+		})
+	},
+
+	// 根据人才id获取关联的标签列表
+	getTalentTagById: async (talent_id: number) => {
+		return await request.get({ 
+			url: `/api/parse/talent-get-tags/${talent_id}`, 
+			baseURL: import.meta.env.VITE_BASE_URL
+		})
+	},
+
+	// 更新人才关联标签
+	updateTalentTags: async (data: any) => {
+		return await request.post({ 
+			url: `/api/parse/talent-update-tags`, 
+			data, 
+			baseURL: import.meta.env.VITE_BASE_URL 
+		})
+	},
+
+	// 人才启用/禁用
+	updateTalentStatus: async (talent_id: number, data: any) => {
+		return await request.put({ 
+			url: `/api/parse/update-business-cards/${talent_id}/status`,
+			data,
+			baseURL: import.meta.env.VITE_BASE_URL 
+		})
+	},
+
+	// 获取人才名片
+	getTalentCardByImagePath: async (image_path: string) => {
+		return await request.download({ 
+			url: `/api/parse/business-cards/image/${image_path}`,
+			baseURL: import.meta.env.VITE_BASE_URL 
+		})
+	}
+}

+ 2 - 2
src/api/menduner/system/talentMap/tag.ts

@@ -10,7 +10,7 @@ export const talentTagApi = {
 	},
 
 	// 创建人才标签
-	createTalentTag: async (data: TagVO) => {
+	createTalentTag: async (data: any) => {
 		return await request.post({ 
 			url: `/api/parse/create-talent-tag`, 
 			data, 
@@ -19,7 +19,7 @@ export const talentTagApi = {
 	},
 
 	// 更新人才标签
-	updateTalentTag: async (tag_id: number, data: TagVO) => {
+	updateTalentTag: async (tag_id: number, data: any) => {
 		return await request.put({ 
 			url: `/api/parse/update-talent-tag/${tag_id}`, 
 			data, 

+ 180 - 0
src/views/menduner/system/talentMap/labeling/LabelingForm.vue

@@ -0,0 +1,180 @@
+<template>
+  <Dialog title="人才标注" v-model="dialogVisible" class="!w-90%">
+		<el-row>
+			<el-col :span="8">
+				<div>
+					<p :class="{'cursor-pointer': previewUrl}" :style="{'color': previewUrl ? '#2d8cf0' : ''}">
+						名片
+						<Icon v-if="previewUrl" :size="20" icon="ep:zoom-out" />
+					</p>
+					<img v-if="previewUrl" width="100%" class="cursor-pointer" :src="previewUrl" />
+					<p class="mb-3" :class="{'mt-3': !previewUrl}">门墩儿新任命</p>
+					<p>门墩儿用户简历</p>
+				</div>
+			</el-col>
+			<el-col :span="16">
+				<div>
+					<div class="base-info">
+						<div class="mb-15px">
+							{{ talentItem.name_zh }}
+							<span v-if="talentItem.name_en">({{ talentItem.name_en }})</span>
+						</div>
+						<div class="flex align-center">
+							<div v-for="(val, index) in talentInfoKeys" :key="index" class="common-width info-item">
+								<p>{{ talentItem[val.key] }}</p>
+								<p>{{ talentItem[val.value] }}</p>
+							</div>
+						</div>
+						<div class="flex align-center my-24px">
+							<div class="common-width pr-12px">{{ talentItem.mobile }}</div>
+							<div class="flex-1">{{ talentItem.email }}</div>
+						</div>
+						<div>{{ talentItem.address_zh }}</div>
+					</div>
+
+					<div class="my-5">
+						<p>人才标签</p>
+						<div v-if="talentSelectedTags?.length" class="mt-4 px-3 pb-3" style="border: 1px dashed #67c23a; border-radius: 4px;">
+							<el-tag 
+								v-for="(item, index) in talentSelectedTags" 
+								:key="index"
+								closable
+								size="large"
+								type="success"
+								class="mr-14px mt-14px"
+								@close="closeClick(item)"
+							>
+								{{ item.name }}
+							</el-tag>
+						</div>
+						<div :class="{'mt-5': talentSelectedTags?.length > 0}">
+							<el-tag 
+								v-for="(item, index) in tagList" :key="index"
+								size="large"
+								type="primary"
+								class="mr-14px mt-14px"
+								:class="{'cursor-pointer': !talentSelectedTags.find(k => k.name === item.name)}"
+								:effect="talentSelectedTags.find(k => k.name === item.name) ? 'info' : 'default'"
+								@click="handleAdd(item)"
+							>
+								+ {{ item.name }}
+							</el-tag>
+						</div>
+					</div>
+				</div>
+			</el-col>
+		</el-row>
+    <template #footer>
+      <el-button @click="submitForm" type="primary" :disabled="loading">确 定</el-button>
+      <el-button @click="dialogVisible = false">取 消</el-button>
+    </template>
+  </Dialog>
+</template>
+
+<script setup lang="ts">
+import { talentLabelingApi } from '@/api/menduner/system/talentMap/labeling'
+import { talentTagApi } from '@/api/menduner/system/talentMap/tag'
+
+const message = useMessage() // 消息弹窗
+const loading = ref(false)
+const dialogVisible = ref(false) // 弹窗的是否展示
+const talentItem = ref({})
+const previewUrl = ref<string>()
+const talentSelectedTags = ref([])
+const tagList = ref([])
+const talentInfoKeys = [
+	{ key: 'title_zh', value: 'title_en' },
+	{ key: 'hotel_zh', value: 'hotel_en' },
+	{ key: 'brand_zh', value: 'brand_en' },
+]
+
+// 获取人才标签
+const getTagList = async () => {
+	loading.value = true
+	try {
+		const data = await talentTagApi.getTalentTagList()
+		tagList.value = data || []
+	} finally {
+		loading.value = false
+	}
+}
+
+/** 打开弹窗 */
+const open = async (data: any) => {
+  dialogVisible.value = true
+	talentItem.value = data
+
+	// 获取所有人才标签
+	await getTagList()
+
+	// 获取名片预览
+	if (data.image_path) {
+		const result = await talentLabelingApi.getTalentCardByImagePath(data.image_path)
+		previewUrl.value = URL.createObjectURL(result)
+	}
+
+	// 获取人才标签
+	const tagData = await talentLabelingApi.getTalentTagById(data.id)
+	talentSelectedTags.value = tagData ? tagData.map((i) => {
+		return { id: i.talent, name: i.tag }
+	}) : []
+}
+defineExpose({ open }) // 提供 open 方法,用于打开弹窗
+
+// 标签删除
+const closeClick = (item) => {
+	const index = talentSelectedTags.value.findIndex((i) => i === item)
+	if (index !== -1) talentSelectedTags.value.splice(index, 1)
+}
+
+// 标签添加
+const handleAdd = (item: any) => {
+	talentSelectedTags.value.push(item)
+}
+
+/** 提交表单 */
+const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
+const submitForm = async () => {
+	if (!talentSelectedTags.value || !talentSelectedTags.value.length) return message.warning('请选择要更新的人才标签')
+
+	loading.value = true
+	const tags = talentSelectedTags.value.map(e => {
+		return { talent: talentItem.value.id, tag: e.name }
+	})
+
+  // 提交请求
+  try {
+    await talentLabelingApi.updateTalentTags(tags)
+    dialogVisible.value = false
+    // 发送操作成功的事件
+    emit('success')
+  } finally {
+    loading.value = false
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.base-info {
+	background-color: #f7f8fa;
+	border-radius: 6px;
+	padding: 15px;
+}
+.common-width {
+	width: 33.3%;
+	max-width: 33.3%;
+}
+.info-item {
+	padding-right: 12px;
+	&:nth-child(3n) {
+		padding-right: 0;
+	}
+	p {
+		height: 24px;
+	}
+}
+.active {
+	color: var(--v-primary-base);
+	cursor: pointer;
+}
+</style>

+ 155 - 0
src/views/menduner/system/talentMap/labeling/index.vue

@@ -0,0 +1,155 @@
+<template>
+  <!-- 搜索工作栏 -->
+  <ContentWrap>
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="40px"
+    >
+      <el-form-item label="职位" prop="title_zh">
+        <el-input
+          v-model="queryParams.title_zh"
+          placeholder="请输入职位名称"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="酒店" prop="hotel_zh">
+        <el-input
+          v-model="queryParams.hotel_zh"
+          placeholder="请输入酒店名称"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="姓名" prop="name_zh">
+        <el-input
+          v-model="queryParams.name_zh"
+          placeholder="请输入姓名"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
+        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+      </el-form-item>
+    </el-form>
+  </ContentWrap>
+
+  <!-- 列表 -->
+  <ContentWrap>
+    <el-table v-loading="loading" :data="list" :stripe="true" row-key="id">
+      <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="status">
+        <template #default="scope">
+          <el-tag :type="scope.row.status === 'active' ? 'success' : 'danger'">
+            {{ scope.row.status === 'active' ? '已启用' : '已禁用' }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="创建时间" align="center" prop="created_at" width="180" />
+      <el-table-column label="操作" align="center">
+        <template #default="scope">
+          <el-button
+            link
+            type="primary"
+            @click="openForm(scope.row)"
+          >
+            标注
+          </el-button>
+          <el-button
+            v-if="scope.row.status === 'active'"
+            link
+            type="danger"
+            @click="handleAction(scope.row.id, 'inactive')"
+          >
+            禁用
+          </el-button>
+          <el-button
+            v-if="scope.row.status === 'inactive'"
+            link
+            type="success"
+            @click="handleAction(scope.row.id, 'active')"
+          >
+            启用
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+  </ContentWrap>
+
+  <!-- 表单弹窗:添加/修改 -->
+  <LabelingForm ref="formRef" @success="getList" />
+</template>
+
+<script setup lang="ts" name="Tag">
+import { talentLabelingApi } from '@/api/menduner/system/talentMap/labeling'
+import LabelingForm from './LabelingForm.vue'
+
+const loading = ref(false)
+const list = ref([])
+const queryParams = reactive({
+  hotel_zh: undefined,
+  name_zh: undefined,
+  title_zh: undefined
+})
+const queryFormRef = ref() // 搜索的表单
+
+const message = useMessage() // 消息弹窗
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await talentLabelingApi.getCardList()
+    list.value = data
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 添加/修改操作 */
+const formRef = ref()
+const openForm = (data: any) => {
+  formRef.value.open(data)
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value.resetFields()
+  handleQuery()
+}
+
+/** 禁用、启用按钮操作 */
+const handleAction = async (id: number, status: string) => {
+  try {
+    // 二次确认
+    await message.confirm(`是否确定${status === 'active' ? '启用' : '禁用'}?`)
+    // 发起删除
+    await talentLabelingApi.updateTalentStatus(id, { status })
+    message.success('操作成功')
+    // 刷新列表
+    setTimeout(async () => {
+      await getList()
+    }, 0)
+  } catch {}
+}
+
+/** 初始化 **/
+onMounted(() => {
+  getList()
+})
+</script>