|
@@ -0,0 +1,357 @@
|
|
|
|
+<template>
|
|
|
|
+ <view>
|
|
|
|
+ <uni-card v-for="(val, index) in items" :key="index" :is-shadow="true" @tap.stop="handleDetail(val)" :border='false' shadow="0px 0px 3px 1px rgba(0,0,0,0.1)">
|
|
|
|
+ <!-- 基本信息 -->
|
|
|
|
+ <view class="d-flex align-center">
|
|
|
|
+ <view class="user-avatar">
|
|
|
|
+ <image class="user-avatar-img" :src="getUserAvatar(val.person?.avatar, val.person?.sex)" mode="scaleToFill"></image>
|
|
|
|
+ <image class="user-avatar-sex" :src="val?.person?.sex ? val?.person?.sex === '1' ? '/static/img/man.png' : '/static/img/female.png' : ''" alt="" mode="scaleToFill" />
|
|
|
|
+ </view>
|
|
|
|
+ <view style="flex: 1; margin-left: 10px;">
|
|
|
|
+ <view class="d-flex justify-space-between align-center">
|
|
|
|
+ <view class="font-size-18">{{ val.person?.name }}</view>
|
|
|
|
+ <view v-if="current !== 4">
|
|
|
|
+ <span v-if="current === 0" :style="{'color': val.status && val.status === '0' ? '#fb8c00' : '#00B760'}">
|
|
|
|
+ {{ val.status && val.status === '0' ? '未查看' : '已查看' }}
|
|
|
|
+ </span>
|
|
|
|
+ <span v-else class="color-999">{{ val.status ? statusList.find(i => i.value === val.status)?.label : '' }}</span>
|
|
|
|
+ </view>
|
|
|
|
+ </view>
|
|
|
|
+ <view class="ss-m-t-10">
|
|
|
|
+ <span
|
|
|
|
+ class="color-999"
|
|
|
|
+ v-for="(key, index) in desc"
|
|
|
|
+ :key="index"
|
|
|
|
+ >
|
|
|
|
+ {{ val.person?.[key] }}
|
|
|
|
+ <span v-if="index !== desc.length - 1 && val.person?.[key]" class="ss-m-x-10">|</span>
|
|
|
|
+ </span>
|
|
|
|
+ </view>
|
|
|
|
+ </view>
|
|
|
|
+ </view>
|
|
|
|
+
|
|
|
|
+ <view class="ss-m-t-15 color-999">
|
|
|
|
+ <view>投递职位:{{ formatName(val.job?.name) }}</view>
|
|
|
|
+ <view>操作时间:{{ timesTampChange(val.createTime) }}</view>
|
|
|
|
+ </view>
|
|
|
|
+
|
|
|
|
+ <view class="sub-li-bottom ss-m-t-20">
|
|
|
|
+ <view class="sub-li-bottom-item color-primary" @tap.stop="handlePreview(val)">查看/下载附件</view>
|
|
|
|
+ <view
|
|
|
|
+ class="sub-li-bottom-item d-flex align-center justify-center"
|
|
|
|
+ @tap.stop="handleLoadMore(val)"
|
|
|
|
+ :style="{'color': !actionItems(val)?.length ? '#ccc' : '#00B760'}"
|
|
|
|
+ >
|
|
|
|
+ <view>更多操作</view>
|
|
|
|
+ <uni-icons type="list" class="ss-m-l-10" size="20" :color="!actionItems(val)?.length ? '#ccc' : '#00B760'"></uni-icons>
|
|
|
|
+ </view>
|
|
|
|
+ </view>
|
|
|
|
+ </uni-card>
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ <!-- 更多操作 -->
|
|
|
|
+ <uni-popup ref="popup" type="bottom" :mask-click="true">
|
|
|
|
+ <view class="actions" v-if="itemData && Object.keys(itemData).length">
|
|
|
|
+ <view
|
|
|
|
+ class="action-item"
|
|
|
|
+ v-for="(val, index) in actionItems(itemData)"
|
|
|
|
+ :key="index"
|
|
|
|
+ @tap.stop="val.click(itemData)"
|
|
|
|
+ >{{ val.title }}</view>
|
|
|
|
+ </view>
|
|
|
|
+ <button class="big-cancel-button" @tap.stop="handleClosePopup">取消</button>
|
|
|
|
+ </uni-popup>
|
|
|
|
+ </view>
|
|
|
|
+</template>
|
|
|
|
+
|
|
|
|
+<script setup>
|
|
|
|
+import { ref } from 'vue'
|
|
|
|
+import { timesTampChange } from '@/utils/date'
|
|
|
|
+import { getUserAvatar } from '@/utils/avatar'
|
|
|
|
+import { formatName } from '@/utils/getText'
|
|
|
|
+import { preview } from '@/utils/preview'
|
|
|
|
+import { getDict } from '@/hooks/useDictionaries'
|
|
|
|
+import { userStore } from '@/store/user'
|
|
|
|
+import { defaultText, talkToUser } from '@/hooks/useIM'
|
|
|
|
+import { joinToTalentPool, joinEliminate, personCvUnfitCancel, personEntryByEnterprise, hireJobCvRelSettlement, personJobCvLook } from '@/api/resume'
|
|
|
|
+
|
|
|
|
+const emit = defineEmits(['refresh'])
|
|
|
|
+const props = defineProps({ items: Array, current: [Number, String] })
|
|
|
|
+
|
|
|
|
+const user = userStore()
|
|
|
|
+const statusList = ref([])
|
|
|
|
+getDict('menduner_interview_invite_status').then(({ data }) => {
|
|
|
|
+ statusList.value = data.data || []
|
|
|
|
+})
|
|
|
|
+
|
|
|
|
+const desc = ['jobStatusName', 'eduName', 'expName']
|
|
|
|
+const popup = ref()
|
|
|
|
+const itemData = ref({})
|
|
|
|
+
|
|
|
|
+// 查看在线简历
|
|
|
|
+const handleDetail = async (val) => {
|
|
|
|
+ if (!val.userId || !val.id) {
|
|
|
|
+ uni.showToast({ title: '用户ID不存在', icon: 'none' })
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ try {
|
|
|
|
+ const {data } = await personJobCvLook(val.id)
|
|
|
|
+ if (data) emit('refresh')
|
|
|
|
+ } catch {}
|
|
|
|
+ uni.navigateTo({
|
|
|
|
+ url: `/pagesB/personnelDetails/index?id=${val.userId}&type=1`
|
|
|
|
+ })
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 查看附件
|
|
|
|
+const handlePreview = async (val) => {
|
|
|
|
+ if (!val.userId || !val.id) {
|
|
|
|
+ uni.showToast({ title: '用户ID不存在', icon: 'none' })
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ try {
|
|
|
|
+ const {data } = await personJobCvLook(val.id)
|
|
|
|
+ if (data) emit('refresh')
|
|
|
|
+ } catch {}
|
|
|
|
+ if (!val.url) {
|
|
|
|
+ uni.showToast({ title: '附件地址不存在', icon: 'none' })
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ preview(val.url)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 更多操作
|
|
|
|
+const handleLoadMore = (val) => {
|
|
|
|
+ if (!actionItems(val).length) {
|
|
|
|
+ itemData.value = {}
|
|
|
|
+ uni.showToast({ title: '暂无更多操作', icon: 'none' })
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ itemData.value = val
|
|
|
|
+ popup.value.open()
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 关闭操作弹窗
|
|
|
|
+const handleClosePopup = () => {
|
|
|
|
+ popup.value.close()
|
|
|
|
+ itemData.value = {}
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 加入储备
|
|
|
|
+const handleJoinToTalentPool = async (item) => {
|
|
|
|
+ if (!item.userId) {
|
|
|
|
+ uni.showToast({ title: '用户ID不存在', icon: 'none' })
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ try {
|
|
|
|
+ await joinToTalentPool(item.userId)
|
|
|
|
+ uni.showToast({ title: '加入成功', icon: 'none' })
|
|
|
|
+ handleClosePopup()
|
|
|
|
+ emit('refresh')
|
|
|
|
+ } catch {
|
|
|
|
+ handleClosePopup()
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 邀请面试
|
|
|
|
+const handleInterviewInvite = (item) => {
|
|
|
|
+ if (item?.job?.status === '1') {
|
|
|
|
+ uni.showToast({ title: '职位已关闭', icon: 'none' })
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ uni.navigateTo({
|
|
|
|
+ url: `/pagesB/InviteInterview/index?id=${item.userId}&jobId=${item.job.id}`
|
|
|
|
+ })
|
|
|
|
+ handleClosePopup()
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 不合适
|
|
|
|
+const handleEliminate = async (item) => {
|
|
|
|
+ if (!item.userId) {
|
|
|
|
+ uni.showToast({ title: '用户ID不存在', icon: 'none' })
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ const query = {
|
|
|
|
+ bizId: item.id,
|
|
|
|
+ jobId: item.job.id,
|
|
|
|
+ userId: item.userId,
|
|
|
|
+ type: props.current === 0 ? '0' : '1' // 投递简历0 已邀约1
|
|
|
|
+ }
|
|
|
|
+ // 招聘会职位则带id
|
|
|
|
+ if (item?.jobFairId) query.jobFairId = item.jobFairId
|
|
|
|
+ try {
|
|
|
|
+ await joinEliminate(query)
|
|
|
|
+ uni.showToast({ title: '操作成功', icon: 'none' })
|
|
|
|
+ handleClosePopup()
|
|
|
|
+ emit('refresh')
|
|
|
|
+ } catch {
|
|
|
|
+ handleClosePopup()
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 取消不合适
|
|
|
|
+const handleCancelEliminate = async (item) => {
|
|
|
|
+ if (!item.id) {
|
|
|
|
+ uni.showToast({ title: 'ID不存在', icon: 'none' })
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ try {
|
|
|
|
+ await personCvUnfitCancel(item.id)
|
|
|
|
+ uni.showToast({ title: '操作成功', icon: 'none' })
|
|
|
|
+ handleClosePopup()
|
|
|
|
+ emit('refresh')
|
|
|
|
+ } catch {
|
|
|
|
+ handleClosePopup()
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 立即沟通
|
|
|
|
+const handleToCommunicate = async (item) => {
|
|
|
|
+ if (item?.job?.status === '1') {
|
|
|
|
+ uni.showToast({ title: '职位已关闭', icon: 'none' })
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const userId = item.userId
|
|
|
|
+ if (!userId) return
|
|
|
|
+ const channel = await talkToUser({ userId, text: defaultText })
|
|
|
|
+
|
|
|
|
+ const query = {
|
|
|
|
+ id: userId,
|
|
|
|
+ name: item?.person?.name || item?.person?.phone,
|
|
|
|
+ channelID: channel.channelID,
|
|
|
|
+ channelType: channel.channelType,
|
|
|
|
+ avatar: item?.person?.avatar,
|
|
|
|
+ sex: item?.person?.sex,
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const queryStr = Object.keys(query).reduce((r, v) => {
|
|
|
|
+ if (!query[v]) {
|
|
|
|
+ return r
|
|
|
|
+ }
|
|
|
|
+ return r += `${v}=${encodeURIComponent(query[v])}&`
|
|
|
|
+ }, '?')
|
|
|
|
+ uni.navigateTo({
|
|
|
|
+ url: `/pagesA/chart/index${queryStr.slice(0, -1)}`
|
|
|
|
+ })
|
|
|
|
+ handleClosePopup()
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 结算
|
|
|
|
+const handleSettlement = async (item) => {
|
|
|
|
+ if (!item.id) {
|
|
|
|
+ uni.showToast({ title: 'ID不存在', icon: 'none' })
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ try {
|
|
|
|
+ await hireJobCvRelSettlement(item.id)
|
|
|
|
+ uni.showToast({ title: '操作成功', icon: 'none' })
|
|
|
|
+ handleClosePopup()
|
|
|
|
+ emit('refresh')
|
|
|
|
+
|
|
|
|
+ // 更新账户信息
|
|
|
|
+ setTimeout(async () => {
|
|
|
|
+ await user.getAccountInfo()
|
|
|
|
+ }, 2000)
|
|
|
|
+ } catch {
|
|
|
|
+ handleClosePopup()
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 入职
|
|
|
|
+const handleEnterByEnterprise = async (item) => {
|
|
|
|
+ console.log(item, '====入职====')
|
|
|
|
+ if (!item.id) {
|
|
|
|
+ uni.showToast({ title: 'ID不存在', icon: 'none' })
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ try {
|
|
|
|
+ await personEntryByEnterprise(item.id)
|
|
|
|
+ uni.showToast({ title: '操作成功', icon: 'none' })
|
|
|
|
+ handleClosePopup()
|
|
|
|
+ emit('refresh')
|
|
|
|
+ } catch {
|
|
|
|
+ handleClosePopup()
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const actionItems = (item) => {
|
|
|
|
+ const arr = []
|
|
|
|
+ if (props.current === 0) arr.push({ title: '邀请面试', click: handleInterviewInvite }, { title: '立即沟通', click: handleToCommunicate })
|
|
|
|
+ if ([0, 1].includes(props.current)) arr.push({ title: '不合适', click: handleEliminate })
|
|
|
|
+ if (props.current === 4) arr.push({ title: '取消不合适', click: handleCancelEliminate })
|
|
|
|
+ if (props.current === 2 && item?.job?.hire) arr.push({ title: '结算', click: handleSettlement })
|
|
|
|
+ if (props.current === 1 && ['3', '4'].includes(item.status)) arr.push({ title: '入职', click: handleEnterByEnterprise })
|
|
|
|
+ // 面试后才能够加入储备
|
|
|
|
+ if ([1, 2, 3].includes(props.current) && !item.inTalentPool) arr.push({ title: '加入储备', click: handleJoinToTalentPool })
|
|
|
|
+ return arr
|
|
|
|
+}
|
|
|
|
+</script>
|
|
|
|
+
|
|
|
|
+<style scoped lang="scss">
|
|
|
|
+.user-avatar {
|
|
|
|
+ position: relative;
|
|
|
|
+ &-img {
|
|
|
|
+ width: 45px;
|
|
|
|
+ height: 45px;
|
|
|
|
+ border-radius: 50%;
|
|
|
|
+ }
|
|
|
|
+ &-sex {
|
|
|
|
+ position: absolute;
|
|
|
|
+ right: 0;
|
|
|
|
+ bottom: 2px;
|
|
|
|
+ width: 20px;
|
|
|
|
+ height: 20px;
|
|
|
|
+ background-color: #fff;
|
|
|
|
+ border-radius: 50%;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+.action {
|
|
|
|
+ font-size: 28rpx;
|
|
|
|
+ &-item {
|
|
|
|
+ text-align: center;
|
|
|
|
+ width: 90vw;
|
|
|
|
+ border-bottom: 1px solid #eee;
|
|
|
|
+ height:44px;
|
|
|
|
+ line-height: 44px;
|
|
|
|
+ margin: 0 auto;
|
|
|
|
+ color: #00B760;
|
|
|
|
+ background-color: #fff !important;
|
|
|
|
+ &:first-child {
|
|
|
|
+ border-radius: 5px 5px 0 0;
|
|
|
|
+ }
|
|
|
|
+ &:last-child {
|
|
|
|
+ border-radius: 0 0 5px 5px;
|
|
|
|
+ border-bottom: none;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+.big-cancel-button {
|
|
|
|
+ width: 90vw;
|
|
|
|
+ height:44px;
|
|
|
|
+ line-height: 44px;
|
|
|
|
+ margin: 10px auto;
|
|
|
|
+ color: #fe574a;
|
|
|
|
+ background-color: #fff !important;
|
|
|
|
+ font-size: 28rpx;
|
|
|
|
+}
|
|
|
|
+.sub-li-bottom {
|
|
|
|
+ display: flex;
|
|
|
|
+ justify-content: space-between;
|
|
|
|
+ // align-items: flex-end;
|
|
|
|
+ margin-top: 10px;
|
|
|
|
+ font-size: 13px;
|
|
|
|
+ &-item {
|
|
|
|
+ width: 50%;
|
|
|
|
+ height: 35px;
|
|
|
|
+ line-height: 35px;
|
|
|
|
+ text-align: center;
|
|
|
|
+ margin-right: 15px;
|
|
|
|
+ background-color: #f7f8fa;
|
|
|
|
+ border-radius: 4px;
|
|
|
|
+ &:nth-child(2) {
|
|
|
|
+ margin-right: 0;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+</style>
|