|  | @@ -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>
 |