|
@@ -0,0 +1,1012 @@
|
|
|
+<template>
|
|
|
+ <view class="box">
|
|
|
+ <view class="box-top">
|
|
|
+ <view class="box-top-title">
|
|
|
+ {{ info.name }}
|
|
|
+ <text class="subText">
|
|
|
+ {{ info?.postName && info?.postName !== 'null' && info?.postName !== 'undefined' ? info.postName : '' }}
|
|
|
+ <text v-if="info?.postName && info?.postName !== 'null' && info?.postName !== 'undefined' && info.enterpriseName" class="gun">|</text>
|
|
|
+ {{ formatName(info.enterpriseName) }}
|
|
|
+ </text>
|
|
|
+ </view>
|
|
|
+ <!-- <view class="box-top-content" v-if="interview.length">
|
|
|
+ <view v-for="val in interview" :key="val.id" class="color-666">
|
|
|
+ <view class="box-top-content-t">
|
|
|
+ <view class="font-weight-bold color-primary">
|
|
|
+ <text>{{ val.job.name }}</text>
|
|
|
+ <text v-if="!val.job.payFrom && !val.job.payTo" class="ml-3">面议</text>
|
|
|
+ <text v-else class="ml-3">{{ val.job.payFrom ? val.job.payFrom + '-' : '' }}{{ val.job.payTo }}</text>
|
|
|
+ </view>
|
|
|
+ <view :style="`color: ${val.statusColor};`" >
|
|
|
+ {{ val.statusText }}
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="mt-1 font-size-14 ellipsis" style="max-width: 100%;">
|
|
|
+ <view class="py-1">面试时间:{{ timesTampChange(val.time, 'Y-M-D h:m') }}</view>
|
|
|
+ <view class="py-1">面试地点:{{ val.address }}</view>
|
|
|
+ <view class="py-1">联系电话:{{ val.invitePhone }}</view>
|
|
|
+ </view>
|
|
|
+ <view class="bottom">
|
|
|
+ <view class="tipsText" @click="handleToCenter">在“个人中心-面试”中管理我的面试</view>
|
|
|
+ <view v-if="val.status === '0'" class="btnBox">
|
|
|
+ <button size="mini" type="warn" @click="handleRefuse(val)">拒绝邀请</button>
|
|
|
+ <button size="mini" type="primary" @click="handleAgree(val)">接受邀请</button>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view> -->
|
|
|
+ <uni-notice-bar v-if="hasWaitingProcessingInterview" show-get-more single text="您有待处理的面试邀请,点击查看详情" @click="handleToCenter"/>
|
|
|
+ </view>
|
|
|
+ <!-- newsId 需要和聊天列表里面的id对应 永远取最后列表中的最后一个就可以做到发送消息即时滚动到底部 -->
|
|
|
+ <scroll-view ref="chatRef" :scroll-with-animation="scrollAnimation" :scroll-into-view="newsId" class="box-main" scroll-y="true">
|
|
|
+ <view class="box-main-more" v-if="hasMore">
|
|
|
+ <text @click="handleMore">查看更多</text>
|
|
|
+ </view>
|
|
|
+ <view v-for="(val, index) in items" :key="val.id" :id="'s'+val.id+index">
|
|
|
+ <view class="box-main-time">{{ timesTampChange(+(val.timestamp.padEnd(13, '0'))) }}</view>
|
|
|
+ <template v-if="val.payload?.type === 102">
|
|
|
+ <view class="jobCard">
|
|
|
+ <!-- <view style="display: flex;">
|
|
|
+ <image v-if="info.jobFairId" src="/static/svg/jobFair.svg" class=" ss-m-r-10" style="width: 20px; height: 20px;"></image>
|
|
|
+ </view> -->
|
|
|
+ <view class="jobCard-title"> {{ formatName(val.payload?.content?.positionInfo?.name) }}</view>
|
|
|
+ <view
|
|
|
+ v-if="!val.payload?.content?.positionInfo?.payFrom && !val.payload?.content?.positionInfo?.payTo"
|
|
|
+ class="jobCard-subtitle">
|
|
|
+ 薪酬待遇: 面议
|
|
|
+ </view>
|
|
|
+ <view
|
|
|
+ v-else
|
|
|
+ class="jobCard-subtitle"
|
|
|
+ >
|
|
|
+ 薪酬待遇:
|
|
|
+ {{ val.payload?.content?.positionInfo?.payFrom ? val.payload?.content?.positionInfo?.payFrom + ' - ' : '' }}
|
|
|
+ {{ val.payload?.content?.positionInfo?.payTo }}
|
|
|
+ </view>
|
|
|
+ <view class="jobCard-tag">
|
|
|
+ <view
|
|
|
+ v-for="(v, i) in (val.payload?.content?.positionInfo?.enterprise?.welfareList || [])"
|
|
|
+ :key="val.message_id + v + i"
|
|
|
+ style="margin: 10rpx"
|
|
|
+ >
|
|
|
+ <uni-tag
|
|
|
+ :text="v"
|
|
|
+ type="success"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="jobCard-divider"></view>
|
|
|
+ <view class="jobCard-subtitle text-right">
|
|
|
+ <v-avatar size="24">
|
|
|
+ <v-img :src="val.payload?.content?.positionInfo?.contact?.avatar"></v-img>
|
|
|
+ </v-avatar>
|
|
|
+ {{ val.payload?.content?.positionInfo?.contact?.name }}
|
|
|
+ {{ val.payload?.content?.positionInfo?.contact?.postNameCn }}
|
|
|
+ {{ formatName(val.payload?.content?.positionInfo?.enterprise?.anotherName || val.payload?.content?.positionInfo?.enterprise?.name) }}
|
|
|
+ </view>
|
|
|
+ <div class="jobCard-subtitle text-right">
|
|
|
+ 地址:{{ val.payload?.content?.positionInfo?.address }}
|
|
|
+ </div>
|
|
|
+ </view>
|
|
|
+ </template>
|
|
|
+ <view :class="['message-view_item', val.from_uid === IM.uid ? 'is-self' : 'is-other']">
|
|
|
+ <view class="image">
|
|
|
+ <image
|
|
|
+ :data-target="getUserAvatar(info.avatar, info.sex, info.channelID === 'system' ? true : false)"
|
|
|
+ class="header"
|
|
|
+ :src="(
|
|
|
+ val.from_uid === IM.uid ?
|
|
|
+ getUserAvatar(useUserStore.baseInfo?.avatar, useUserStore.baseInfo?.sex) :
|
|
|
+ getUserAvatar(info.avatar, info.sex, info.channelID === 'system' ? true : false)
|
|
|
+ )"
|
|
|
+ ></image>
|
|
|
+ </view>
|
|
|
+ <!-- 显示沟通职位 -->
|
|
|
+ <template v-if="val.payload?.type === 102">
|
|
|
+ <view class="message-text" :class="val.from_uid === IM.uid ? 'active' : ''">
|
|
|
+ {{ val.payload?.content.text }}
|
|
|
+ </view>
|
|
|
+ </template>
|
|
|
+ <!-- 发起面试邀请 -->
|
|
|
+ <view class="message-text none" v-else-if="val.payload?.type === 101">
|
|
|
+ <uni-tag text="发起了面试邀请" custom-style="background-color: #00B760; border-color: #00B760; color: #fff;" />
|
|
|
+ </view>
|
|
|
+ <view class="message-text none" v-else-if="val.payload?.type === 103">
|
|
|
+ <uni-tag text="拒绝了面试邀请" type="error" />
|
|
|
+ </view>
|
|
|
+ <view class="message-text none" v-else-if="val.payload?.type === 104">
|
|
|
+ <uni-tag text="接受了面试邀请" custom-style="background-color: #00B760; border-color: #00B760; color: #fff;" />
|
|
|
+ </view>
|
|
|
+ <view v-else-if="val.payload.type === 105" class="text-end">
|
|
|
+ <uni-tag
|
|
|
+ v-if="val.from_uid === IM.uid"
|
|
|
+ :text="val.payload.content?.type === 1 ? '附件简历已发送' : '简历请求已发送'"
|
|
|
+ custom-style="background-color: #00B760; border-color: #00B760; color: #fff;"
|
|
|
+ />
|
|
|
+ <view
|
|
|
+ v-if="val.payload.content?.type !== 2 || val.from_uid !== IM.uid"
|
|
|
+ class="message-text card"
|
|
|
+ >
|
|
|
+ <view class="text-left">
|
|
|
+ <text v-if="val.payload.content?.type === 1">{{
|
|
|
+ val.payload.content?.query?.title || '附件简历' }}
|
|
|
+ </text>
|
|
|
+ <text v-if="val.payload.content?.type === 2">
|
|
|
+ 我想要一份您的简历,您是否同意
|
|
|
+ </text>
|
|
|
+ </view>
|
|
|
+ <view class="btn-actions">
|
|
|
+ <text class="btn" v-if="val.payload.content?.type === 1" @tap="handlePreview(val.payload)">点击预览附件简历</text>
|
|
|
+ <text class="btn" v-if="val.payload.content?.type === 2" @tap="handleFindResume">点击发送附件简历</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view v-else-if="val.payload.type === -1" class="message-text" :class="{ active: val.from_uid === IM.uid}">
|
|
|
+ {{ val.payload?.content?.text }}
|
|
|
+ </view>
|
|
|
+ <view v-else class="message-text" :class="{ active: val.from_uid === IM.uid}">
|
|
|
+ {{ val.payload?.content }}
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </scroll-view>
|
|
|
+
|
|
|
+ <view class="box-bottom" v-if="channelItem?.channelID !== 'system'">
|
|
|
+ <view class="box-bottom-tool" style="display: flex; justify-content: space-between;">
|
|
|
+ <text class="toolBtn" :class="{ disabled: !isSendResume }" @tap="handleFindResume">{{ isSendResume ? '简历已投递' : '发送简历' }}</text>
|
|
|
+ <!-- <uni-tag :text="isSendResume ? '简历已投递' : '发送简历'" :disabled="isSendResume" type="success" @tap="handleFindResume"/> -->
|
|
|
+ <!-- <uni-tag text="发 送" type="success" @tap="handleSend"/> -->
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="d-flex align-end textBox" v-if="channelItem?.channelID !== 'system'">
|
|
|
+ <textarea
|
|
|
+ v-model="inputValue"
|
|
|
+ :cursor-spacing="25"
|
|
|
+ :show-confirm-bar="false"
|
|
|
+ :disable-default-padding="true"
|
|
|
+ confirm-type="send"
|
|
|
+ auto-height
|
|
|
+ @confirm="handleSend"
|
|
|
+ />
|
|
|
+ <text class="submitBtn" @tap="handleSend">发 送</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <uni-popup ref="positionPopup" background-color="#fff">
|
|
|
+ <view style="max-width: 85vw;">
|
|
|
+ <view class="popup-title" style="min-width: 260px;">
|
|
|
+ <text>请选择要投递的职位</text>
|
|
|
+ <uni-icons type="closeempty" size="20" @tap="positionPopupClose"></uni-icons>
|
|
|
+ </view>
|
|
|
+ <view v-for="job in entPositionList" :key="job.value" class="popup-content" @tap="selectJobId = job.value">
|
|
|
+ <view class="iconBox">
|
|
|
+ <uni-icons
|
|
|
+ v-show="selectJobId === job.value"
|
|
|
+ type="checkmarkempty"
|
|
|
+ size="20"
|
|
|
+ :color="selectJobId === job.value ? '#43AC57' : '#999'"></uni-icons>
|
|
|
+ </view>
|
|
|
+ <text class="text" :class="selectJobId === job.value ? 'active' : ''">{{ job.label }}</text>
|
|
|
+ </view>
|
|
|
+ <view v-if="entPositionTotal > 5" class="popup-upload ss-m-x-30" @click="changePositionData">
|
|
|
+ <text style="color: #43AC57;">{{ entPositionListLastData ? '没有更多职位了~ 再选一遍' : '换一批'}}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="popup-actions">
|
|
|
+ <button class="default" type="default" @click="selectPositionSubmit">确认</button>
|
|
|
+ </view>
|
|
|
+ </uni-popup>
|
|
|
+
|
|
|
+ <uni-popup ref="popup" background-color="#fff">
|
|
|
+ <view class="popup-title" style="min-width: 260px;">
|
|
|
+ <text>发送简历选择</text>
|
|
|
+ <uni-icons type="closeempty" size="20" @tap="handleClose"></uni-icons>
|
|
|
+ </view>
|
|
|
+ <view v-if="isStudent" class="ss-p-x-50" style="width: 272px;">
|
|
|
+ <studentDeliveryForm ref="studentDeliveryFormRef" />
|
|
|
+ </view>
|
|
|
+ <view v-for="resume in resumeList" :key="resume.id" class="popup-content" @tap="resumeCheck = resume">
|
|
|
+ <view class="iconBox">
|
|
|
+ <uni-icons
|
|
|
+ v-show="resumeCheck.id === resume.id"
|
|
|
+ type="checkmarkempty"
|
|
|
+ size="20"
|
|
|
+ :color="resumeCheck.id === resume.id ? '#43AC57' : '#999'"></uni-icons>
|
|
|
+ </view>
|
|
|
+ <text class="text" :class="resumeCheck.id === resume.id ? 'active' : ''">{{ resume.title }}</text>
|
|
|
+ </view>
|
|
|
+ <view v-if="!resumeList.length" class="popup-upload" @click="handleUploadResume">
|
|
|
+ <view class="popup-upload-box">
|
|
|
+ <uni-icons type="plusempty" size="50" color="#f1f1f1"></uni-icons>
|
|
|
+ </view>
|
|
|
+ <text>温馨提示:您还未上传过简历,点击选取微信聊天文件投递。请在手机上打开此小程序进行文件上传,暂不支持在桌面版小程序中上传文件。</text>
|
|
|
+ </view>
|
|
|
+ <view v-if="resumeList.length" class="popup-actions">
|
|
|
+ <button class="default" type="default" @click="handleSendResume">发送简历</button>
|
|
|
+ </view>
|
|
|
+ </uni-popup>
|
|
|
+
|
|
|
+ <!-- <uni-popup ref="confirm" type="dialog">
|
|
|
+ <uni-popup-dialog
|
|
|
+ :type="isAgree ? 'success' : 'warn'"
|
|
|
+ cancelText="取消"
|
|
|
+ confirmText="确认"
|
|
|
+ title="系统提示"
|
|
|
+ :content="isAgree ? '确认接受面试吗?' : '确认拒绝面试吗?'"
|
|
|
+ @confirm="handleConfirm"
|
|
|
+ @close="handleCloseConfirm"
|
|
|
+ ></uni-popup-dialog>
|
|
|
+ </uni-popup> -->
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { ref, watch, onMounted, computed } from 'vue'
|
|
|
+import { onLoad } from '@dcloudio/uni-app'
|
|
|
+import { useIMStore } from '@/store/im'
|
|
|
+import { userStore } from '@/store/user'
|
|
|
+import { initConnect, send, initChart, getMoreMessages, toChannel } from '@/hooks/useIM'
|
|
|
+import { getDict } from '@/hooks/useDictionaries'
|
|
|
+import { timesTampChange } from '@/utils/date'
|
|
|
+import { getUserAvatar } from '@/utils/avatar'
|
|
|
+import { formatName } from '@/utils/getText'
|
|
|
+import { preview } from '@/utils/preview'
|
|
|
+import { getPersonResumeCv, saveResume } from '@/api/user'
|
|
|
+import { uploadFile } from '@/api/file'
|
|
|
+import { getInterviewInviteListByInviteUserId, getMessageType } from '@/api/common'
|
|
|
+// import { userInterviewInviteReject } from '@/api/personalCenter'
|
|
|
+import {
|
|
|
+ getJobAdvertisedSearch,
|
|
|
+ jobCvRelSend,
|
|
|
+ jobCvRelCheckSend,
|
|
|
+ jobCvRelHireSend
|
|
|
+} from '@/api/position'
|
|
|
+import studentDeliveryForm from '@/components/studentDeliveryForm'
|
|
|
+
|
|
|
+const useUserStore = userStore()
|
|
|
+const IM = useIMStore()
|
|
|
+const info = ref({})
|
|
|
+const chatRef = ref()
|
|
|
+const items = ref([])
|
|
|
+const channelItem = ref(null)
|
|
|
+const hasMore = ref(false)
|
|
|
+
|
|
|
+const popup = ref()
|
|
|
+const resumeCheck = ref({})
|
|
|
+const resumeList = ref([]) // 简历列表
|
|
|
+
|
|
|
+const pageSize = ref(1)
|
|
|
+
|
|
|
+// 求职者面试列表
|
|
|
+const interview = ref([])
|
|
|
+// 求职端-获取求职者与当前邀请人的面试记录
|
|
|
+const statusList = ref([])
|
|
|
+const inputValue = ref('')
|
|
|
+
|
|
|
+// const isAgree = ref(false)
|
|
|
+// const confirm = ref()
|
|
|
+// const chooseInvite = ref(null)
|
|
|
+
|
|
|
+const newsId = ref('') // newsId 需要和聊天列表里面的id对应 永远取最后列表中的最后一个就可以做到发送消息即时滚动到底部
|
|
|
+const scrollAnimation = ref(false)
|
|
|
+
|
|
|
+const isSendResume = ref(false)
|
|
|
+const positionInfo = ref({})
|
|
|
+const isEmployment = ref('-1')
|
|
|
+
|
|
|
+const isStudent = ref(false) // 已测试,待开放上线
|
|
|
+// const isStudent = ref(useUserStore.baseInfo?.type && Boolean(Number(useUserStore.baseInfo.type) === 1))
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ setTimeout(() => {
|
|
|
+ scrollAnimation.value = true
|
|
|
+ }, 1500)
|
|
|
+})
|
|
|
+
|
|
|
+const {
|
|
|
+ conversationList,
|
|
|
+ // updateConversation,
|
|
|
+ updateUnreadCount,
|
|
|
+ // deleteConversations,
|
|
|
+ resetUnread
|
|
|
+} = initConnect(async (successful) => {
|
|
|
+ if (!successful) {
|
|
|
+ uni.showToast({
|
|
|
+ title: '发送失败',
|
|
|
+ icon: 'none',
|
|
|
+ mask: true,
|
|
|
+ })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ inputValue.value = ''
|
|
|
+ // chatRef.value.reset()
|
|
|
+ // // 发送成功
|
|
|
+ const { list } = await getMoreMessages(1, channelItem.value)
|
|
|
+ // updateConversation()
|
|
|
+ items.value = list.value
|
|
|
+ // chatRef.value.scrollBottom()
|
|
|
+})
|
|
|
+
|
|
|
+watch(
|
|
|
+ () => conversationList.value,
|
|
|
+ async (val) => {
|
|
|
+ if (!channelItem.value) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const { list } = await getMoreMessages(1, channelItem.value)
|
|
|
+ if (list.value.length) {
|
|
|
+ const item = list.value[list.value.length - 1]
|
|
|
+ const arr = [101, 103, 104]
|
|
|
+ if (arr.includes(item.payload?.type)) {
|
|
|
+ getInterviewInviteList()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ items.value = list.value
|
|
|
+ setScrollBottom()
|
|
|
+ // 清除未读消息
|
|
|
+ resetUnread(channelItem.value)
|
|
|
+ },
|
|
|
+ {
|
|
|
+ deep: true,
|
|
|
+ immediate: true
|
|
|
+ }
|
|
|
+)
|
|
|
+
|
|
|
+async function init(userId, enterpriseId) {
|
|
|
+ const { channel, list, more } = await initChart(userId, enterpriseId)
|
|
|
+ hasMore.value = more
|
|
|
+ channelItem.value = channel.value
|
|
|
+ items.value = list.value
|
|
|
+ setScrollBottom()
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+const setScrollBottom = () => {
|
|
|
+ if (items.value?.length) {
|
|
|
+ const lastOne = items.value[items.value.length-1]
|
|
|
+ const index = items.value.length-1
|
|
|
+ newsId.value = 's' + lastOne.id + index // newsId 需要和聊天列表里面的id对应 永远取最后列表中的最后一个就可以做到发送消息即时滚动到底部
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const hasWaitingProcessingInterview = ref(false) // 是否有待接受的面试邀请
|
|
|
+async function getInterviewInviteList () {
|
|
|
+ if (!info.value.id) return
|
|
|
+ const { data } = await getInterviewInviteListByInviteUserId(info.value.id)
|
|
|
+ interview.value = data ? data.slice(0, 1).map(e => {
|
|
|
+ const statusItem = statusList.value.find(_e => _e.value === e.status)
|
|
|
+ const statusText = statusItem?.label || ''
|
|
|
+ const statusColor = ['5', '98', '99'].includes(e.status)
|
|
|
+ return {
|
|
|
+ ...e,
|
|
|
+ statusColor: statusColor ? '#FE574A' : '#0E8E80',
|
|
|
+ statusText
|
|
|
+ }
|
|
|
+ }) : []
|
|
|
+ hasWaitingProcessingInterview.value = interview.value.some(e => e.status === '0')
|
|
|
+}
|
|
|
+
|
|
|
+const getStatusList = async () => {
|
|
|
+ try {
|
|
|
+ const { data } = await getDict('menduner_interview_invite_status')
|
|
|
+ if (data.data.length) {
|
|
|
+ statusList.value = data.data
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function handleSend () {
|
|
|
+ if (!inputValue.value) {
|
|
|
+ uni.showToast({ title: '不能发送空白信息', icon: 'none' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ send(inputValue.value, channelItem.value)
|
|
|
+}
|
|
|
+
|
|
|
+function handleToCenter () {
|
|
|
+ uni.navigateTo({
|
|
|
+ url: '/pagesA/interview/index?index=1'
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+// 预览简历
|
|
|
+function handlePreview (payload) {
|
|
|
+ if (!payload?.content?.query?.src) {
|
|
|
+ uni.showToast({ title: '简历地址不存在', icon: 'none' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ preview(payload.content.query.src)
|
|
|
+}
|
|
|
+
|
|
|
+// 关闭职位列表窗口
|
|
|
+function positionPopupClose () {
|
|
|
+ positionPopup.value.close()
|
|
|
+}
|
|
|
+
|
|
|
+// 打开职位列表窗口
|
|
|
+function positionPopupOpen () {
|
|
|
+ positionPopup.value.open('center')
|
|
|
+}
|
|
|
+
|
|
|
+// 选中职位并投递
|
|
|
+const selectJobId = ref('')
|
|
|
+const positionPopup = ref()
|
|
|
+const selectPositionSubmit = async () => {
|
|
|
+ if (!selectJobId.value) return uni.showToast({ title: '请选择要投递的职位', icon: 'none', duration: 3000 })
|
|
|
+ positionPopupClose()
|
|
|
+ handleFindResume() // 打开简历列表选择
|
|
|
+}
|
|
|
+
|
|
|
+const pageLoading = ref(false)
|
|
|
+const entPositionTotal = ref(0)
|
|
|
+const entPositionList = ref([])
|
|
|
+const entPositionListParams = ref({ pageNo: 1, pageSize: 5 })
|
|
|
+const entPositionListLastData = computed(() => entPositionListParams.value.pageNo * entPositionListParams.value.pageSize >= entPositionTotal.value)
|
|
|
+// 职位列表
|
|
|
+const getRecruitPositionList = async () => {
|
|
|
+ const enterpriseId = info.value?.enterpriseId || null
|
|
|
+ if (!enterpriseId) return uni.showToast({ title: '访问企业错误!', icon: 'none', duration: 3000 })
|
|
|
+
|
|
|
+ pageLoading.value = true
|
|
|
+ const res = await getJobAdvertisedSearch({ ...entPositionListParams.value, enterpriseId })
|
|
|
+ const { list = [], total: number = 0 } = res?.data || {}
|
|
|
+ if (!list?.length) return uni.showToast({ title: '企业暂无招聘中的职位,无法进行投递!', icon: 'none', duration: 3000 })
|
|
|
+
|
|
|
+ entPositionTotal.value = number
|
|
|
+ entPositionList.value = list.map(j => {
|
|
|
+ const e = j?.job || null
|
|
|
+ if (!e) return e
|
|
|
+ const salary = e.payFrom && e.payTo ? `${e.payFrom ? e.payFrom + '-' : ''}${e.payTo}${e.payName ? '/' + e.payName : ''}` : '面议'
|
|
|
+ return {
|
|
|
+ label: `${formatName(e.name)}_${e.areaName ? e.area?.str : '全国'} ${salary}`,
|
|
|
+ value: e.id,
|
|
|
+ data: e
|
|
|
+ }
|
|
|
+ }).filter(Boolean)
|
|
|
+
|
|
|
+ setTimeout(() => { pageLoading.value = false }, 300)
|
|
|
+}
|
|
|
+
|
|
|
+const changePositionData = () => {
|
|
|
+ entPositionListParams.value.pageNo = entPositionListLastData.value ? 1 : entPositionListParams.value.pageNo + 1
|
|
|
+ selectJobId.value = ''
|
|
|
+ getRecruitPositionList()
|
|
|
+}
|
|
|
+
|
|
|
+// 获取简历
|
|
|
+async function handleFindResume () {
|
|
|
+ if (isSendResume.value) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // 没有基于职位接收到的沟通,弹出职位列表让求职者选择。否则无法投递简历。
|
|
|
+ if (!positionInfo.value.id && !selectJobId.value) {
|
|
|
+ await getRecruitPositionList()
|
|
|
+ if (entPositionTotal.value) positionPopupOpen()
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 获取简历列表
|
|
|
+ const { data } = await getPersonResumeCv()
|
|
|
+ if (data.length === 0) {
|
|
|
+ uni.showToast({
|
|
|
+ title: '您还未上传过简历,请先上传简历后再投递',
|
|
|
+ icon: 'none',
|
|
|
+ mask: true,
|
|
|
+ duration: 3000
|
|
|
+ })
|
|
|
+ }
|
|
|
+ resumeList.value = data || []
|
|
|
+ resumeCheck.value = data && data.length ? data[0] : ''
|
|
|
+ popup.value.open('center')
|
|
|
+ } finally {
|
|
|
+ uni.hideLoading()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 关闭简历窗口
|
|
|
+function handleClose () {
|
|
|
+ popup.value.close()
|
|
|
+}
|
|
|
+
|
|
|
+const studentDeliveryFormRef = ref()
|
|
|
+
|
|
|
+// 发送简历
|
|
|
+async function handleSendResume () {
|
|
|
+ if (!Object.keys(resumeCheck.value).length) {
|
|
|
+ uni.showToast({ title: '请选择要投递的简历', icon: 'none' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ let practice = null
|
|
|
+ if (isStudent.value) {
|
|
|
+ practice = await studentDeliveryFormRef.value.getQueryParams()
|
|
|
+ if (!practice) return
|
|
|
+ }
|
|
|
+
|
|
|
+ const text = {
|
|
|
+ remark: '发送简历',
|
|
|
+ query: {
|
|
|
+ src: resumeCheck.value.url,
|
|
|
+ title: resumeCheck.value.title,
|
|
|
+ id: resumeCheck.value.id,
|
|
|
+ },
|
|
|
+ type: 1
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ if (isEmployment.value !== '-1') {
|
|
|
+ await jobCvRelHireSend({
|
|
|
+ jobId: positionInfo.value.id || selectJobId.value,
|
|
|
+ // ...(jobFairId && { jobFairId }),
|
|
|
+ url: resumeCheck.value.url,
|
|
|
+ recommendUserId: isEmployment.value,
|
|
|
+ ...(practice && { practice }),
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ await jobCvRelSend({
|
|
|
+ jobId: positionInfo.value.id || selectJobId.value,
|
|
|
+ // ...(jobFairId && { jobFairId }),
|
|
|
+ title: resumeCheck.value.title,
|
|
|
+ url: resumeCheck.value.url,
|
|
|
+ type: positionInfo.value.hire ? 1 : 0,
|
|
|
+ ...(practice && { practice }),
|
|
|
+ })
|
|
|
+ }
|
|
|
+ isSendResume.value = true
|
|
|
+ send (JSON.stringify(text), channelItem.value, 105)
|
|
|
+ popup.value.close()
|
|
|
+ } catch (error) {
|
|
|
+ if (error?.msg === '该职位已投递') {
|
|
|
+ isSendResume.value = true
|
|
|
+ }
|
|
|
+ popup.value.close()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 拒绝邀请
|
|
|
+// function handleRefuse (val) {
|
|
|
+// isAgree.value = false
|
|
|
+// chooseInvite.value = val
|
|
|
+// confirm.value.open()
|
|
|
+// }
|
|
|
+
|
|
|
+// 接受邀请
|
|
|
+// function handleAgree (val) {
|
|
|
+// isAgree.value = true
|
|
|
+// chooseInvite.value = val
|
|
|
+// confirm.value.open()
|
|
|
+// }
|
|
|
+
|
|
|
+// 确认
|
|
|
+// async function handleConfirm () {
|
|
|
+// // 拒绝
|
|
|
+// if (!isAgree.value) {
|
|
|
+// await userInterviewInviteReject(chooseInvite.value.id)
|
|
|
+// } else {
|
|
|
+// await userInterviewInviteReject(chooseInvite.value.id)
|
|
|
+// }
|
|
|
+// uni.showToast({ title: '操作成功', icon: 'none' })
|
|
|
+// send(JSON.stringify({ id: chooseInvite.value.id }), channelItem.value, isAgree.value ? 104 : 103)
|
|
|
+// }
|
|
|
+
|
|
|
+// 关闭
|
|
|
+// function handleCloseConfirm () {
|
|
|
+// confirm.value.close()
|
|
|
+// }
|
|
|
+
|
|
|
+// 查看更多
|
|
|
+async function handleMore () {
|
|
|
+ try {
|
|
|
+ uni.showLoading({
|
|
|
+ title: '加载中...'
|
|
|
+ })
|
|
|
+ pageSize.value++
|
|
|
+ const { list, more } = await getMoreMessages(pageSize.value, channelItem.value)
|
|
|
+ items.value.unshift(...list.value)
|
|
|
+ hasMore.value = more
|
|
|
+ } finally {
|
|
|
+ uni.hideLoading()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 上传简历
|
|
|
+function handleUploadResume () {
|
|
|
+ wx.chooseMessageFile({
|
|
|
+ count: 1,
|
|
|
+ type: 'file',
|
|
|
+ success (res) {
|
|
|
+ // 限制文件上传大小
|
|
|
+ const size = res.tempFiles[0].size
|
|
|
+ if (size / (1024*1024) > 20) {
|
|
|
+ uni.showToast({ icon: 'none', title: '文件大小不能超过20M' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ const title = res.tempFiles[0].name
|
|
|
+ const path = res.tempFiles[0].path
|
|
|
+ const test = /\.(pdf|docx|doc)$/.test(title)
|
|
|
+ if (!test) {
|
|
|
+ uni.showToast({
|
|
|
+ icon: 'none',
|
|
|
+ title: '请上传pdf、doc、docx类型的文件',
|
|
|
+ duration: 2000
|
|
|
+ })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ //效验是否为支持的文件格式
|
|
|
+ uploadFile(path, 'attachment').then(async (res) => {
|
|
|
+ if (!res.data) {
|
|
|
+ uni.showToast({
|
|
|
+ title: '上传失败',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ await saveResume({ title, url: res.data })
|
|
|
+ uni.showToast({
|
|
|
+ title: '上传成功',
|
|
|
+ icon: 'success'
|
|
|
+ })
|
|
|
+ handleFindResume()
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+// 获取职位信息
|
|
|
+async function getMessageTypeSync () {
|
|
|
+ try {
|
|
|
+ const { data } = await getMessageType({
|
|
|
+ fromUid: IM.uid,
|
|
|
+ channelId: channelItem.value.channelID,
|
|
|
+ type: 102,
|
|
|
+ page: {
|
|
|
+ current: 1,
|
|
|
+ size: 1,
|
|
|
+ orders: [
|
|
|
+ { column: 'message_seq', asc: false }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ })
|
|
|
+ if (!data.records || !data.records.length) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const _item = data.records.pop()
|
|
|
+ const _itemJSON = JSON.parse(_item.payload)
|
|
|
+ const _content = JSON.parse(_itemJSON.content)
|
|
|
+ positionInfo.value = _content.positionInfo
|
|
|
+ const { data: check } = await jobCvRelCheckSend({ jobId: _content.positionInfo.id })
|
|
|
+ isSendResume.value = check
|
|
|
+ } catch (error) {
|
|
|
+ console.log(345, error)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// let jobFairId = ''
|
|
|
+onLoad(async (options) => {
|
|
|
+ info.value = Object.keys(options).reduce((r, k) => {
|
|
|
+ r[k] = decodeURIComponent(options[k])
|
|
|
+ return r
|
|
|
+ }, {})
|
|
|
+ // jobFairId = info.value.jobFairId
|
|
|
+ isEmployment.value = info.value.isEmployment
|
|
|
+ channelItem.value = toChannel(info.value.channelID, info.value.channelType)
|
|
|
+
|
|
|
+ if (channelItem.value.channelID === 'system') {
|
|
|
+ const { list, more } = await getMoreMessages(1, channelItem.value)
|
|
|
+ hasMore.value = more
|
|
|
+ items.value = list.value
|
|
|
+ setScrollBottom()
|
|
|
+ // 清除未读消息
|
|
|
+ resetUnread(channelItem.value)
|
|
|
+ // 更新未读消息
|
|
|
+ updateUnreadCount()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ await init(info.value.id, info.value.enterpriseId)
|
|
|
+ // 获取最新的职位信息
|
|
|
+ await getMessageTypeSync(info.value.id)
|
|
|
+
|
|
|
+ await getStatusList()
|
|
|
+ getInterviewInviteList()
|
|
|
+ // 清除未读消息
|
|
|
+ resetUnread(channelItem.value)
|
|
|
+ // 更新未读消息
|
|
|
+ updateUnreadCount()
|
|
|
+})
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.white {
|
|
|
+ color: #FFF !important;
|
|
|
+}
|
|
|
+.text-left {
|
|
|
+ text-align: left !important;
|
|
|
+}
|
|
|
+.text-right {
|
|
|
+ text-align: right !important;
|
|
|
+}
|
|
|
+.box {
|
|
|
+ width: 100%;
|
|
|
+ height: 100vh;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ &-top {
|
|
|
+ &-title {
|
|
|
+ padding: 0 60rpx;
|
|
|
+ box-sizing: border-box;
|
|
|
+ width: 100%;
|
|
|
+ height: 80rpx;
|
|
|
+ line-height: 80rpx;
|
|
|
+ // text-align: center;
|
|
|
+ border-bottom: 2rpx solid #EEE;
|
|
|
+ overflow: hidden;
|
|
|
+ white-space: nowrap;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ .subText {
|
|
|
+ font-size: .85em;
|
|
|
+ color: #999;
|
|
|
+ .gun {
|
|
|
+ padding: 0 10rpx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &-content {
|
|
|
+ padding: 20rpx 50rpx;
|
|
|
+ padding-bottom: 20rpx;
|
|
|
+ border-bottom: 2rpx solid #eee;
|
|
|
+ .color-666 {
|
|
|
+ color: #666;
|
|
|
+ }
|
|
|
+ .font-weight-bold {
|
|
|
+ font-weight: bold;
|
|
|
+ }
|
|
|
+ .color-primary {
|
|
|
+ color: #009688;
|
|
|
+ }
|
|
|
+ .ml-3 {
|
|
|
+ margin-left: 40rpx;
|
|
|
+ }
|
|
|
+ .mt-1 {
|
|
|
+ margin-top: 12rpx;
|
|
|
+ }
|
|
|
+ .font-size-14 {
|
|
|
+ font-size: 24rpx;
|
|
|
+ }
|
|
|
+ .py-1 {
|
|
|
+ padding: 4rpx 0;
|
|
|
+ }
|
|
|
+ .tipsText {
|
|
|
+ font-size: .75em;
|
|
|
+ color: #999;
|
|
|
+ }
|
|
|
+ &-t {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ }
|
|
|
+ .btnBox {
|
|
|
+ display: flex;
|
|
|
+ padding: 20rpx 60rpx;
|
|
|
+ justify-content: space-around;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ &-main {
|
|
|
+ flex: 1;
|
|
|
+ height: 0;
|
|
|
+ padding: 40rpx;
|
|
|
+ // overflow-y: auto;
|
|
|
+ box-sizing: border-box;
|
|
|
+ &-more {
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ color: #24bc3e;
|
|
|
+ font-size: .9em;
|
|
|
+ padding: 20rpx 0;
|
|
|
+ }
|
|
|
+ &-time {
|
|
|
+ user-select: none;
|
|
|
+ position: relative;
|
|
|
+ top: 16rpx;
|
|
|
+ margin: 40rpx 0;
|
|
|
+ text-align: center;
|
|
|
+ max-height: 40rpx;
|
|
|
+ text-align: center;
|
|
|
+ font-weight: 400;
|
|
|
+ font-size: .85em;
|
|
|
+ color: #999;
|
|
|
+ }
|
|
|
+ .jobCard {
|
|
|
+ padding: 30rpx;
|
|
|
+ background: #E2F2F0;
|
|
|
+ color: #009688 ;
|
|
|
+ margin-top: 20rpx;
|
|
|
+ max-width: unset;
|
|
|
+ margin-right: 0;
|
|
|
+ &-title {
|
|
|
+ font-size: 1.2em;
|
|
|
+ }
|
|
|
+ &-subtitle {
|
|
|
+ padding: 10rpx 0;
|
|
|
+ // font-size: .5em;
|
|
|
+ }
|
|
|
+ &-divider {
|
|
|
+ width: 100%;
|
|
|
+ height: 2rpx;
|
|
|
+ margin: 20rpx 0;
|
|
|
+ background: #ddd;
|
|
|
+ }
|
|
|
+ &-tag {
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .message-view_item {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ align-items: flex-start;
|
|
|
+ margin: 16rpx 0;
|
|
|
+ position: relative;
|
|
|
+ .image {
|
|
|
+ width: 60rpx;
|
|
|
+ height: 60rpx;
|
|
|
+ border-radius: 180rpx;
|
|
|
+ // flex-grow: 1;
|
|
|
+ // flex-shrink: 0;
|
|
|
+ overflow: hidden;
|
|
|
+ .header {
|
|
|
+ width: 60rpx;
|
|
|
+ height: 60rpx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .text-end {
|
|
|
+ text-align: right !important;
|
|
|
+ width: 400rpx;
|
|
|
+ margin-right: 20rpx;
|
|
|
+ }
|
|
|
+ .message-text {
|
|
|
+ overflow-wrap: break-word;
|
|
|
+ background-color: #f0f2f5;
|
|
|
+ border-radius: 12rpx;
|
|
|
+ max-width: 75%;
|
|
|
+ padding: 20rpx;
|
|
|
+ &.active {
|
|
|
+ background: #d5e6e8;
|
|
|
+ }
|
|
|
+ &.card {
|
|
|
+ background: #E2F2F0;
|
|
|
+ color: #009688 ;
|
|
|
+ margin-top: 20rpx;
|
|
|
+ max-width: unset;
|
|
|
+ margin-right: 0;
|
|
|
+ .btn-actions {
|
|
|
+ margin: 40rpx auto 20rpx auto ;
|
|
|
+ text-align: center;
|
|
|
+ .btn {
|
|
|
+ padding: 10rpx 30rpx;
|
|
|
+ background: #C8E7D8;
|
|
|
+ color: #43AC57;
|
|
|
+ font-size: .75em;
|
|
|
+ border-radius: 10rpx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &.none {
|
|
|
+ padding: 10rpx 0;
|
|
|
+ background-color: unset;
|
|
|
+ }
|
|
|
+ &.active {
|
|
|
+ background: #d5e6e8;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .is-self {
|
|
|
+ flex-direction: row-reverse;
|
|
|
+ display: flex;
|
|
|
+ .message-text {
|
|
|
+ margin-right: 20rpx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .is-other {
|
|
|
+ .message-text {
|
|
|
+ margin-left: 20rpx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &-bottom {
|
|
|
+ max-height: 300rpx;
|
|
|
+ border-top: 2rpx solid #EEE;
|
|
|
+ background: rgba(230, 230, 230, 0.5);
|
|
|
+ padding: 20rpx 40rpx;
|
|
|
+ box-sizing: border-box;
|
|
|
+ &-tool {
|
|
|
+ margin-bottom: 30rpx;
|
|
|
+ .toolBtn {
|
|
|
+ padding: 12rpx 20rpx;
|
|
|
+ font-size: 24rpx;
|
|
|
+ background: #18bc37;
|
|
|
+ color: #FFF;
|
|
|
+ border-radius: 10rpx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .textBox {
|
|
|
+ align-items: flex-end;
|
|
|
+ }
|
|
|
+ textarea {
|
|
|
+ border-radius: 10rpx;
|
|
|
+ width: 100%;
|
|
|
+ min-height: 80rpx;
|
|
|
+ max-height: 180rpx;
|
|
|
+ padding: 20rpx;
|
|
|
+ box-sizing: border-box;
|
|
|
+ background: #FFF;
|
|
|
+ }
|
|
|
+ .submitBtn {
|
|
|
+ width: 140rpx;
|
|
|
+ line-height: 80rpx;
|
|
|
+ height: 80rpx;
|
|
|
+ font-size: 28rpx;
|
|
|
+ background: #18bc37;
|
|
|
+ color: #FFF;
|
|
|
+ margin-left: 20rpx;
|
|
|
+ text-align: center;
|
|
|
+ border-radius: 10rpx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .popup-title {
|
|
|
+ padding: 30rpx 20rpx;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ border-bottom: 2rpx solid #DDD;
|
|
|
+ }
|
|
|
+ .popup-content {
|
|
|
+ padding: 20rpx 40rpx;
|
|
|
+ color: #999;
|
|
|
+ display: flex;
|
|
|
+ align-content: center;
|
|
|
+ justify-items: center;
|
|
|
+ .iconBox {
|
|
|
+ width: 40rpx;
|
|
|
+ }
|
|
|
+ .text {
|
|
|
+ margin-left: 20rpx;
|
|
|
+ &.active {
|
|
|
+ color: #00B760;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .popup-upload {
|
|
|
+ // display: flex;
|
|
|
+ // align-items: center;
|
|
|
+ // justify-content: center;
|
|
|
+ // flex-direction: column;
|
|
|
+ // width: 70%;
|
|
|
+ width: 80vw;
|
|
|
+ font-size: .75em;
|
|
|
+ color: #999;
|
|
|
+ padding: 40rpx;
|
|
|
+ &-box {
|
|
|
+ width: 200rpx;
|
|
|
+ height: 200rpx;
|
|
|
+ text-align: center;
|
|
|
+ line-height: 200rpx;
|
|
|
+ border: 4rpx solid #ddd;
|
|
|
+ border-radius: 8rpx;
|
|
|
+ margin: 0 auto;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .popup-actions {
|
|
|
+ padding: 60rpx;
|
|
|
+ .default {
|
|
|
+ background: #00B760;
|
|
|
+ color: #DDD;
|
|
|
+ font-size: .9em;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|