123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- <!-- 面试 -->
- <template>
- <v-card class="pa-5" style="height: 100%;font-size: 14px;">
- <div class="d-flex justify-space-between">
- <div class="d-flex mb-3">
- <!-- 职位 -->
- <v-autocomplete
- v-model="query.jobId"
- :items="positionItems"
- density="compact"
- variant="outlined"
- item-title="label"
- item-value="value"
- clearable
- hide-details
- label="职位"
- color="primary"
- style="width: 300px;"
- class="mr-3"
- ></v-autocomplete>
- <v-select
- v-model="query.status"
- :items="statusList"
- density="compact"
- variant="outlined"
- item-title="label"
- item-value="value"
- clearable
- hide-details
- label="面试状态"
- color="primary"
- style="width: 300px;"
- ></v-select>
- <v-btn color="primary" class="half-button ml-3" @click="handleSearch">查 询</v-btn>
- <v-btn class="half-button ml-3" variant="outlined" color="primary" @click="handleReset">重 置</v-btn>
- </div>
- </div>
- <v-divider class="mb-3"></v-divider>
- <div class="d-flex">
- <div>
- <div class="d-flex justify-space-between px-5">
- <div v-if="selectDateValue">
- <span>{{ timesTampChange(selectDateValue).slice(0, 10) }}</span>
- <span class="ml-2" style="cursor: pointer;" @click="handleClear">{{ $t('common.cleanUp') }}</span>
- </div>
- <div v-else class="color-999">{{ $t('interview.noDateSelected') }}</div>
- <v-btn color="primary" variant="text" size="small" @click="selectDateValue = new Date()">{{ $t('interview.today') }}</v-btn>
- </div>
- <v-date-picker
- v-model="selectDateValue"
- color="primary"
- :hide-header="true"
- @update:modelValue="handleChangeDate"
- class="mr-3"
- >
- </v-date-picker>
- </div>
- <v-divider style="height: auto;" class="mr-5" vertical></v-divider>
- <div style="flex: 1;overflow: hidden;">
- <div v-if="items.length">
- <div
- class="listItem d-flex align-center pa-3 mb-3"
- v-for="(item, index) in items" :key="'item_' + index"
- >
- <div class="d-flex align-center">
- <span class="mr-5 font-size-16" style="color: orange;">{{ timesTampChange(item.time) }}</span>
- <v-avatar class="mr-2" size=40 :image="item?.person?.avatar || 'https://minio.citupro.com/dev/menduner/7.png'"></v-avatar>
- <div class="d-flex flex-column mr-3" style="width: 110px;">
- <span class="ellipsis mb-1">{{ item?.person?.name }}</span>
- <span class="ellipsis" style="color: var(--color-999);">{{ item?.job?.name }}</span>
- </div>
- </div>
- <div class="d-flex align-center right-item">
- <div style="min-width: 80px;text-align: center;">
- <v-icon v-if="item?.phone" class="mx-1" size="20" color="primary">mdi-phone-outline</v-icon>
- <span>{{ item?.phone || '-' }}</span>
- </div>
- <div>
- <!-- 面试类型: 线下面试 -->
- <span v-if="item.type === '1'">
- <v-icon class="mx-3" size="20" color="primary">mdi-account-multiple-outline</v-icon>
- <span>{{ $t('interview.offlineInterview') }}</span>
- </span>
- <!-- 面试类型: 线上面试 -->
- <span v-else class="d-flex">
- <v-icon class="mx-3 mt-2" size="20" color="primary">mdi mdi-video-account</v-icon>
- <span class="d-flex flex-column">
- <span>{{ $t('interview.onlineInterview') }}</span>
- <span style="color: var(--color-999);">腾讯会议</span>
- </span>
- </span>
- </div>
- <!-- 面试状态: '待接受'/'已取消' -->
- <div :style="{ 'color': item.status !== '99' ? 'orange' :'var(--color-999)'}">
- <v-icon size="30">mdi mdi-circle-small</v-icon>
- <span>{{ statusList.find(e => e.value === item.status)?.label }}</span>
- </div>
- <div>
- <span v-if="editStatus.indexOf(item.status)" class="font-size-15 color-primary" @click="handleActionClick(2, item)">修改面试</span>
- <v-menu>
- <template v-slot:activator="{ props }">
- <v-icon v-bind="props" class="mx-3" size="20" color="primary">mdi-dots-horizontal</v-icon>
- </template>
- <v-list>
- <v-list-item
- v-for="(k, index) in actionItems"
- :key="index"
- :value="index"
- color="primary"
- @click="handleActionClick(k.value, item)"
- >
- <v-list-item-title>{{ k.title }}</v-list-item-title>
- </v-list-item>
- </v-list>
- </v-menu>
- </div>
- </div>
- </div>
- <CtPagination
- v-if="total > 0"
- :total="total"
- :page="query.pageNo"
- :limit="query.pageSize"
- @handleChange="handleChangePage"
- ></CtPagination>
- </div>
- <Empty v-else :elevation="false"></Empty>
- </div>
- </div>
- </v-card>
- <!-- 修改面试 -->
- <CtDialog :visible="showInvite" :widthType="2" titleClass="text-h6" title="面试邀请" @close="handleClose" @submit="handleSubmit">
- <InvitePage v-if="showInvite" ref="inviteRef" :itemData="itemData" :position="positionItems"></InvitePage>
- </CtDialog>
- <CtDialog :visible="cancelInvite" :widthType="2" titleClass="text-h6" title="取消面试" @close="handleCancelClose" @submit="handleCancelSubmit">
- <TextInput v-model="cancelQuery.reason" :item="textItems"></TextInput>
- </CtDialog>
- </template>
- <script setup>
- defineOptions({ name: 'enterprise-interview'})
- import { ref } from 'vue'
- import { getInterviewInvitePage, saveInterviewInvite, cancelInterviewInvite } from '@/api/recruit/enterprise/interview'
- import InvitePage from './components/invite.vue'
- import { getDict } from '@/hooks/web/useDictionaries'
- import Snackbar from '@/plugins/snackbar'
- import { getJobAdvertised } from '@/api/enterprise'
- import { dealDictArrayData } from '@/utils/position'
- import { timesTampChange, getStartAndEndOfDay } from '@/utils/date'
- const cancelInvite = ref(false)
- const showInvite = ref(false)
- const inviteRef = ref()
- const items = ref([])
- const cancelQuery = ref({
- id: null,
- reason: null
- })
- const editStatus = ['99', '1', '0']
- const statusList = ref()
- const itemData = ref({})
- // 状态
- const actionItems = ref([
- // { title: '沟通', value: 1 },
- // { title: '修改面试', value: 2 },
- { title: '取消面试', value: 3 },
- // { title: '面试记录', value: 4 }
- ])
- const total = ref(0)
- const query = ref({
- pageSize: 10,
- pageNo: 1,
- status: null,
- jobId: null,
- time: []
- })
- const textItems = ref({
- type: 'text',
- label: '取消原因 *',
- clearable: true
- })
- // 状态字典
- const getStatusList = async () => {
- const { data } = await getDict('menduner_interview_invite_status')
- statusList.value = data
- }
- getStatusList()
- // 列表
- const getData = async () => {
- const { list, total: number } = await getInterviewInvitePage(query.value)
- items.value = list
- total.value = number
- }
- getData()
- // 分页
- const handleChangePage = (e) => {
- query.value.pageNo = e
- getData()
- }
- // 日期选择
- const selectDateValue = ref(null)
- const handleChangeDate = () => {
- const time = getStartAndEndOfDay(selectDateValue.value)
- if (!time || !time.length) return delete query.value.time
- query.value.time = time
- query.value.pageNo = 1
- getData()
- }
- // 清除
- const handleClear = () => {
- query.value.pageNo = 1
- selectDateValue.value = null
- delete query.value.time
- getData()
- }
- const handleSearch = () => {
- query.value.pageNo = 1
- getData()
- }
- const handleReset = () => {
- query.value = {
- pageSize: 10,
- pageNo: 1,
- status: null,
- jobId: null,
- time: []
- }
- selectDateValue.value = null
- getData()
- }
- // 职位
- const positionItems = ref([])
- const getPositionList = async () => {
- const data = await getJobAdvertised({ hire: false })
- if (!data.length) return
- const list = dealDictArrayData([], data)
- positionItems.value = list.map(e => {
- return { label: `${e.name}${e.areaName ? '_' + e.areaName : ''} ${e.payFrom}-${e.payTo}/${e.payName}`, value: e.id }
- })
- }
- getPositionList()
- // 操作按钮
- const handleActionClick = (value, item) => {
- // 修改
- if (value === 2) {
- itemData.value = item
- showInvite.value = true
- }
- // 取消
- if (value === 3) {
- cancelQuery.value.id = item.id
- cancelInvite.value = true
- }
- }
- // 修改面试
- const handleClose = () => {
- itemData.value = {}
- showInvite.value = false
- }
- const handleSubmit = async () => {
- const query = inviteRef.value.getQuery()
- if (!Object.keys(query).length) return
- await saveInterviewInvite(query)
- Snackbar.success('操作成功')
- handleClose()
- getData()
- }
- // 取消面试
- const handleCancelClose = () => {
- cancelInvite.value = false
- cancelQuery.value = {
- id: null,
- reason: null
- }
- }
- const handleCancelSubmit = async () => {
- if (!cancelQuery.value.reason) return Snackbar.warning('请填写取消原因')
- await cancelInterviewInvite(cancelQuery.value)
- Snackbar.success('操作成功')
- handleCancelClose()
- getData()
- }
- </script>
- <style scoped lang="scss">
- .listItem {
- cursor: pointer;
- width: 100%;
- min-width: 600px;
- overflow: auto;
- height: 76px;
- border: 1px solid #e5e6eb;
- border-radius: 5px;
-
- &:hover {
- background-color: var(--color-f8);
- }
- .right-item {
- width: 100%;
- div {
- width: 25%;
- }
- }
- }
- </style>
|