123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541 |
- <template>
- <ContentWrap>
- <!-- 搜索工作栏 -->
- <el-form
- class="-mb-15px"
- :model="queryParams"
- ref="queryFormRef"
- :inline="true"
- label-width="68px"
- >
- <el-form-item label="名称" prop="name">
- <el-input v-model="queryParams.name" placeholder="请输入名称" clearable @keyup.enter="handleQuery" class="!w-180px" />
- </el-form-item>
- <el-form-item>
- <el-button @click="handleQuery('search')"><Icon icon="ep:search" /> 搜索</el-button>
- <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
- <el-button type="primary" plain @click="handleAdd">
- <Icon icon="ep:plus" class="mr-5px" /> 新增解析
- </el-button>
- </el-form-item>
- </el-form>
- </ContentWrap>
- <!-- 列表 -->
- <ContentWrap>
- <el-table v-loading="loading" :data="list" :stripe="true">
- <el-table-column label="姓名(中)" align="center" prop="name_zh" fixed="left" />
- <el-table-column label="姓名(英)" align="center" prop="name_en" />
- <el-table-column label="职位" align="center" prop="title_zh" />
- <el-table-column label="酒店/公司" align="center" prop="hotel_zh" />
- <el-table-column label="手机号码" align="center" prop="phone" />
- <el-table-column label="固定电话" align="center" prop="mobile" />
- <el-table-column label="创建日期" align="center" prop="created_at" :formatter="dateFormatter" />
- <el-table-column label="状态" align="center" prop="status" width="80">
- <template #default="scope">
- <el-tag type="success" v-if="scope.row.status === 'active'">已启用</el-tag>
- <el-tag type="danger" v-else>已禁用</el-tag>
- </template>
- </el-table-column>
- <el-table-column label="操作" align="center" fixed="right" min-width="110">
- <template #default="scope">
- <el-button link type="primary" @click="handleEdit(scope.row)">编辑</el-button>
- <el-button link type="danger" @click="handleDelete(scope.row.id)">删除</el-button>
- <el-button link :type="scope.row.status === 'active' ? 'danger': 'success'" @click="handleDisable(scope.row)">
- {{ scope.row.status === 'active' ? '禁用' : '启用'}}
- </el-button>
- </template>
- </el-table-column>
- </el-table>
- <!-- 上传 -->
- <Dialog title="名片解析" v-model="openUploadImg" width="500" @close="handleCancel">
- <UploadImg
- v-model="filePath"
- :limit="1"
- :uploadSuccessTip="false"
- @handle-change="uploadChange"
- height="150px" width="150px" style="margin: 20px auto; width: 150px;"
- >
- <template #tip>{{ filePath ? '' : '请上传名片' }}</template>
- </UploadImg>
- <template #footer>
- <el-button @click="handleAnalysis" type="success" :disabled="analysisLoading" :loading="analysisLoading">解 析</el-button>
- <el-button @click="handleCancel">取 消</el-button>
- </template>
- </Dialog>
- <!-- 解析回显 -->
- <Dialog title="名片解析" v-model="showAnalysisTable" width="80%">
- <div class="analysisInfoBox">
- <div class="image">
- <el-image v-if="filePath" class="!w-100%" :src="filePath" />
- <div v-else>
- <UploadImg
- v-model="filePath"
- :limit="1"
- :uploadSuccessTip="false"
- drag
- buttonUpload
- @handle-change="uploadChange"
- height="32px" width="104px"
- style="margin: 0 auto; width: 104px;margin-top: 40%;"
- >
- <template #tip>{{ filePath ? '' : '请上传名片' }}</template>
- </UploadImg>
- </div>
- </div>
- <div class="formBox">
- <el-form
- ref="formRef"
- :model="formQuery"
- label-width="128px"
- v-loading="formLoading"
- >
- <el-row>
- <div class="m-title">基础信息</div>
- </el-row>
- <el-row :gutter="10">
- <el-col :span="12">
- <el-form-item label="姓名(中)" prop="name_zh">
- <el-input v-model="formQuery.name_zh" placeholder="请输入中文姓名" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="姓名(英)" prop="name_en">
- <el-input v-model="formQuery.name_en" placeholder="请输入英文姓名" />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="10">
- <el-col :span="12">
- <el-form-item label="职位/头衔(中)" prop="title_zh">
- <el-input v-model="formQuery.title_zh" placeholder="请输入中文职位/头衔" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="职位/头衔(英)" prop="title_en">
- <el-input v-model="formQuery.title_en" placeholder="请输入英文职位/头衔" />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="10">
- <el-col :span="24">
- <el-form-item label="生日" prop="birthday">
- <el-input v-model="formQuery.birthday" placeholder="请输入出生日期" />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="10">
- <el-col :span="24">
- <el-form-item label="居住地" prop="residence">
- <el-input v-model="formQuery.residence" placeholder="请输入当前居住地址" />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row>
- <div class="m-title">联系方式</div>
- </el-row>
- <el-row :gutter="10">
- <el-col :span="12">
- <el-form-item label="手机号码" prop="mobile">
- <el-input v-model="formQuery.mobile" placeholder="请输入手机号码" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="固定电话" prop="phone">
- <el-input v-model="formQuery.phone" placeholder="请输入固定电话" />
- </el-form-item>
- </el-col>
- </el-row>
- <el-form-item label="电子邮箱" prop="email">
- <el-input v-model="formQuery.email" placeholder="请输入电子邮箱" />
- </el-form-item>
- <el-row>
- <div class="m-title">酒店/公司信息</div>
- </el-row>
- <el-form-item label="酒店/公司名称(中)" prop="hotel_zh">
- <el-input v-model="formQuery.hotel_zh" placeholder="请输入中文酒店/公司名称" />
- </el-form-item>
- <el-form-item label="酒店/公司名称(英)" prop="hotel_en">
- <el-input v-model="formQuery.hotel_en" placeholder="请输入英文酒店/公司名称" />
- </el-form-item>
- <el-form-item label="品牌名称(中)" prop="brand_zh">
- <el-input v-model="formQuery.brand_zh" placeholder="请输入中文品牌名称" />
- </el-form-item>
- <el-form-item label="品牌名称(英)" prop="brand_en">
- <el-input v-model="formQuery.brand_en" placeholder="请输入英文品牌名称" />
- </el-form-item>
- <el-form-item label="隶属关系(中)" prop="affiliation_zh">
- <el-input v-model="formQuery.affiliation_zh" placeholder="请输入中文隶属关系" />
- </el-form-item>
- <el-form-item label="隶属关系(英)" prop="affiliation_en">
- <el-input v-model="formQuery.affiliation_en" placeholder="请输入英文隶属关系" />
- </el-form-item>
- <el-form-item label="品牌组合" prop="brand_group">
- <el-input v-model="formQuery.brand_group" placeholder="请输入品牌组合" />
- </el-form-item>
- <el-row>
- <div class="m-title">职业轨迹</div>
- </el-row>
- <el-row :gutter="10" class="trajectoryBox" v-for="(item, index) of careerTrajectory" :key="'trajectory' + index">
- <el-col :span="20">
- <el-form-item label="酒店名称" prop="hotel_zh" label-width="128px">
- <el-input v-model="item.hotel_zh" placeholder="请输入酒店名称" />
- </el-form-item>
- <el-form-item label="职位名称" prop="title_zh" label-width="128px">
- <el-input v-model="item.title_zh" placeholder="请输入职位名称" />
- </el-form-item>
- <el-form-item label="任职时间" prop="date">
- <el-date-picker
- v-model="item.date"
- value-format="YYYY-MM-DD"
- type="date"
- start-placeholder="开始日期"
- end-placeholder="结束日期"
- />
- </el-form-item>
- </el-col>
- <el-col :span="4">
- <div class="flex justify-center items-center !h-100%" style="flex-direction: column;">
- <el-button @click="addCareer(index)" type="primary" class="cursor-pointer" :icon="Plus" circle />
- <el-button
- v-if="careerTrajectory.length > 1"
- class="mt-15px ml-0 cursor-pointer"
- @click="removeCareer(index)"
- type="danger"
- :icon="Delete"
- circle
- />
- </div>
- </el-col>
- </el-row>
- <el-row>
- <div class="m-title">地址信息</div>
- </el-row>
- <el-form-item label="中文地址" prop="address_zh">
- <el-input v-model="formQuery.address_zh" placeholder="请输入中文地址" />
- </el-form-item>
- <el-form-item label="英文地址" prop="address_en">
- <el-input v-model="formQuery.address_en" placeholder="请输入英文地址" />
- </el-form-item>
- <el-row :gutter="10">
- <el-col :span="12">
- <el-form-item label="邮政编码(中)" prop="postal_code_zh">
- <el-input v-model="formQuery.postal_code_zh" placeholder="请输入中文邮政编码" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="邮政编码(英)" prop="postal_code_en">
- <el-input v-model="formQuery.postal_code_en" placeholder="请输入英文邮政编码" />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row v-if="formType === 'edit'">
- <div class="m-title">系统信息</div>
- </el-row>
- <el-form-item v-if="formType === 'edit'" label="状态">
- <el-tag v-if="itemData.status" :type="itemData.status === 'active' ? 'success' : 'danger'">
- {{ itemData.status === 'active' ? '已启用' : '已禁用' }}
- </el-tag>
- </el-form-item>
- <el-form-item label="创建时间" v-if="formType === 'edit'">
- <el-tag v-if="itemData.created_at" type="primary" effect="light">{{ itemData.created_at }}</el-tag>
- </el-form-item>
- <el-form-item label="更新时间" v-if="formType === 'edit'">
- <el-tag v-if="itemData.updated_at" type="primary" effect="light">{{ itemData.updated_at }}</el-tag>
- </el-form-item>
- </el-form>
- </div>
- </div>
- <template #footer>
- <el-button @click="handleSave" type="success" :disabled="analysisLoading">保 存</el-button>
- <el-button @click="showAnalysisTable = false">取 消</el-button>
- </template>
- </Dialog>
- </ContentWrap>
- <MergeForm ref="mergeFormRef" @refresh="getList" />
- </template>
- <script setup>
- import { dateFormatter } from '@/utils/formatTime'
- import { talentLabelingApi } from '@/api/menduner/system/talentMap/labeling'
- import { Delete, Plus } from '@element-plus/icons-vue'
- import MergeForm from '../../components/merge.vue'
- /** 人才地图 列表 */
- defineOptions({ name: 'TalentMapCard' })
- const message = useMessage() // 消息弹窗
- const { t } = useI18n() // 国际化
- const loading = ref(false) // 列表的加载中
- const list = ref([]) // 列表的数据
- const total = ref(0) // 列表的总页数
- const queryParams = reactive({
- name: undefined,
- })
- const queryFormRef = ref() // 搜索的表单
- /** 查询列表 */
- const getList = async () => {
- loading.value = true
- try {
- list.value = []
- const data = await talentLabelingApi.getCardList()
- list.value = data ? data.reverse() : []
- } finally {
- loading.value = false
- }
- }
- /** 搜索按钮操作 */
- const handleQuery = (type) => {
- // if (type === 'search') {
- // message.warning('搜索正在建设中...')
- // return
- // }
- getList()
- }
- /** 重置按钮操作 */
- const resetQuery = () => {
- queryFormRef.value.resetFields()
- handleQuery()
- }
- const dealData = (item) => {
- itemData.value = { ...item }
- careerTrajectory.value = item?.career_path ? JSON.parse(JSON.stringify(item.career_path)) : []
- if (!careerTrajectory.value?.length) careerTrajectory.value = [{ company_name: null, position: null, current_date: null }]
- Object.keys(formQuery.value).forEach(key => {
- formQuery.value[key] = item[key] || null
- })
- }
- /** 删除按钮操作 */
- const handleDelete = async (id) => {
- try {
- // 删除的二次确认
- await message.delConfirm()
- // 发起删除
- await talentLabelingApi.deleteBusinessCard(id)
- message.success(t('common.delSuccess'))
- // 刷新列表
- setTimeout(async () => {
- await getList()
- }, 0)
- } catch {}
- }
- /** 编辑 */
- const { push } = useRouter()
- const handleEdit = async (item) => {
- formType.value = 'edit'
- dealData(item)
- file.value = null
- filePath.value = null
- try {
- if (!item?.image_path) {
- showAnalysisTable.value = true
- return
- }
- const data = await talentLabelingApi.getBusinessCardImage(item.image_path)
- if (!data?.type) return
- file.value = new File([data], item.image_path, { type: data.type })
- filePath.value = URL.createObjectURL(data)
- } catch (error) {
- console.log('打印->getBusinessCardImage', error)
- } finally {
- showAnalysisTable.value = true
- }
- }
- /** 禁用按钮操作 */
- const handleDisable = async (item) => {
- if (!item?.id) return message.warning('操作失败,请稍后再试')
- try {
- // 禁用的二次确认
- const status = item.status === 'active' ? 'inactive' : 'active'
- const text = status === 'inactive' ? '禁用' : '启用'
-
- await message.delConfirm(`是否${text}该名片?`)
- // 发起禁用
- await talentLabelingApi.updateBusinessCardStatus({
- status,
- }, item.id)
- message.success(`${text}成功`)
- // 刷新列表
- await getList()
- } catch {}
- }
- const formQuery = ref({
- name_zh: undefined,
- name_en: undefined,
- title_zh: undefined,
- title_en: undefined,
- mobile: undefined,
- phone: undefined,
- email: undefined,
- hotel_zh: undefined,
- hotel_en: undefined,
- brand_zh: undefined,
- brand_en: undefined,
- affiliation_zh: undefined,
- affiliation_en: undefined,
- brand_group: undefined,
- address_zh: undefined,
- address_en: undefined,
- postal_code_zh: undefined,
- postal_code_en: undefined,
- birthday: undefined,
- residence: undefined,
- })
- const careerTrajectory = ref([{ company_name: null, position: null, current_date: null }])
- const file = ref(null)
- const uploadFile = ref(null)
- const uploadChange = (raw) => {
- file.value = raw
- }
- const addCareer = () => {
- careerTrajectory.value = careerTrajectory.value || []
- careerTrajectory.value.push({ company_name: null, position: null, current_date: null })
- }
- const removeCareer = (index) => {
- if (careerTrajectory.value.length <= 1) return
- careerTrajectory.value.splice(index, 1)
- }
- // 更新
- const showAnalysisTable = ref(false)
- const formLoading = ref(false)
- const formType = ref('')
- const formRef = ref() // 表单 Ref
- const mergeFormRef = ref() // 合并表单 Ref
- const handleSave = async () => {
- try {
- formLoading.value = true
- formQuery.value.career_path = careerTrajectory
- Object.assign(itemData.value, formQuery.value)
- let result = {}
- if (formType.value === 'create') {
- uploadFile.value.append('card_data', JSON.stringify(itemData.value))
- result = await talentLabelingApi.createBusinessCard(uploadFile.value)
- message.success('新增成功')
- if (result.code === 202 || result.message.includes('疑似重复')) {
- if (!result.data?.main_card?.id) return
- message.notifyWarning('发现与当前名片的疑似数据,请处理')
- mergeFormRef.value.open(result.data?.main_card?.id)
- }
- } else {
- await talentLabelingApi.updateBusinessCard(itemData.value, itemData.value.id)
- message.success('更新成功')
- }
- showAnalysisTable.value = false
- // 刷新列表
- getList()
- } catch (error) {
- console.log('更新失败', error)
- } finally {
- uploadFile.value = null
- formLoading.value = false
- }
- }
- // 关闭解析弹窗
- const handleCancel = () => {
- // console.log('关闭解析弹窗')
- openUploadImg.value = false
- analysisLoading.value = false
- }
- // 解析中
- const analysisLoading = ref(false)
- const filePath = ref(null)
- const itemData = ref({})
- const handleAnalysis = async () => {
- if (!filePath.value) {
- message.warning('请先上传名片!')
- return
- }
- try {
- analysisLoading.value = true
- // 开始解析
- uploadFile.value = new FormData()
- uploadFile.value.append('image', file.value)
- message.warning('正在解析...')
- const index = createAnalysisNum.value
- const res = await talentLabelingApi.businessCardParse(uploadFile.value)
- if (index !== createAnalysisNum.value || !openUploadImg.value) return // 不是最新的名片解析数据(用户在解析完成前已重新上传)或用户已取消解析
- dealData(res?.data || res)
- openUploadImg.value = false
- showAnalysisTable.value = true
- message.success('名片解析成功')
- } catch (error) {
- console.log('解析失败', error)
- uploadFile.value = null
- } finally {
- analysisLoading.value = false
- }
- }
- // 新增
- const openUploadImg = ref(false)
- const createAnalysisNum = ref(0)
- const handleAdd = () => {
- formType.value = 'create'
- file.value = null
- filePath.value = null
- analysisLoading.value = false
- createAnalysisNum.value++
- careerTrajectory.value = [{ company_name: null, position: null, current_date: null }]
- openUploadImg.value = true
- }
- /** 初始化 **/
- onMounted(() => {
- getList()
- })
- </script>
- <style lang="scss" scoped>
- .analysisInfoBox {
- display: flex;
- .image {
- width: 52%;
- max-height: 70vh;
- padding-right: 12px;
- overflow: auto;
- }
- .formBox {
- flex: 1;
- max-height: 70vh;
- padding: 12px;
- overflow: auto;
- background-color: #f5f7f9;
- .m-title {
- margin: 12px 8px;
- font-size: 13px;
- // font-weight: bold;
- color: #999;
- }
- .trajectoryBox {
- margin: 10px 20px;
- padding-top: 20px;
- padding-bottom: 5px;
- border-radius: 5px;
- background-color: #fff;
- }
- }
- }
- </style>
|