189 lines
6.4 KiB
Vue
189 lines
6.4 KiB
Vue
<template>
|
||
<!-- 待投递岗位列表面板 — 右侧面板显示全部待投递岗位(滚动分页) -->
|
||
<div class="agent-pending-job-list-panel">
|
||
<!-- 顶部标题栏 -->
|
||
<div class="agent-pending-job-list-panel__header">
|
||
<span class="agent-pending-job-list-panel__title">待投递岗位列表</span>
|
||
<!-- 关闭按钮 -->
|
||
<button class="agent-pending-job-list-panel__close-btn" @click="emit('close')">
|
||
<svg viewBox="0 0 24 24" fill="none">
|
||
<circle cx="12" cy="12" r="10" fill="#1A1A2E" />
|
||
<path d="M8 8l8 8M16 8l-8 8" stroke="#fff" stroke-width="1.5" stroke-linecap="round" />
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
|
||
<!-- 列表内容(可滚动,触底加载更多) -->
|
||
<div ref="listRef" class="agent-pending-job-list-panel__list" @scroll="handleScroll">
|
||
<!-- 岗位项 -->
|
||
<div
|
||
v-for="job in jobList"
|
||
:key="job.id"
|
||
class="agent-pending-job-list-panel__item"
|
||
>
|
||
<!-- 左侧信息区域 -->
|
||
<div class="agent-pending-job-list-panel__info">
|
||
<!-- 公司 Logo -->
|
||
<div class="agent-pending-job-list-panel__logo">
|
||
<svg viewBox="0 0 24 24" fill="none">
|
||
<rect x="3" y="7" width="18" height="14" rx="2" stroke="currentColor" stroke-width="1.5"/>
|
||
<path d="M7 7V5a2 2 0 012-2h6a2 2 0 012 2v2" stroke="currentColor" stroke-width="1.5"/>
|
||
</svg>
|
||
</div>
|
||
<!-- 岗位详情 -->
|
||
<div class="agent-pending-job-list-panel__detail">
|
||
<div class="agent-pending-job-list-panel__company">{{ job.companyShortName || job.companyName }}</div>
|
||
<div class="agent-pending-job-list-panel__position">{{ job.title }}</div>
|
||
<!-- 标签 -->
|
||
<div class="agent-pending-job-list-panel__tags">
|
||
<span v-if="job.regionName" class="agent-pending-job-list-panel__tag">{{ job.regionName }}</span>
|
||
<span v-if="job.categoryName" class="agent-pending-job-list-panel__tag">{{ job.categoryName }}</span>
|
||
<span v-for="tag in (job.tags || []).slice(0, 2)" :key="tag" class="agent-pending-job-list-panel__tag">{{ tag }}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 右侧:匹配度 + 移出按钮 -->
|
||
<div class="agent-pending-job-list-panel__right">
|
||
<!-- 匹配度环形 -->
|
||
<div class="agent-pending-job-list-panel__score">
|
||
<svg class="agent-pending-job-list-panel__ring" viewBox="0 0 44 44">
|
||
<circle cx="22" cy="22" r="18" fill="none" stroke="#E8E8E8" stroke-width="3" />
|
||
<circle
|
||
cx="22" cy="22" r="18" fill="none"
|
||
stroke="#4FC2C9" stroke-width="3"
|
||
stroke-linecap="round"
|
||
:stroke-dasharray="2 * Math.PI * 18"
|
||
:stroke-dashoffset="2 * Math.PI * 18 * (1 - (job.matchScore || 0) / 100)"
|
||
transform="rotate(-90 22 22)"
|
||
/>
|
||
</svg>
|
||
<span class="agent-pending-job-list-panel__score-text">{{ job.matchScore || 0 }}%</span>
|
||
</div>
|
||
<!-- 移出按钮 -->
|
||
<button
|
||
class="agent-pending-job-list-panel__remove-btn"
|
||
:disabled="removingIds.includes(job.id)"
|
||
@click="handleRemove(job)"
|
||
>移出</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 加载更多提示 -->
|
||
<div v-if="loadingMore" class="agent-pending-job-list-panel__loading">加载中...</div>
|
||
<!-- 没有更多数据 -->
|
||
<div v-if="noMore && jobList.length > 0" class="agent-pending-job-list-panel__no-more">暂无更多数据</div>
|
||
<!-- 空状态 -->
|
||
<div v-if="!loading && jobList.length === 0" class="agent-pending-job-list-panel__empty">暂无待投递岗位</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref, onMounted } from 'vue'
|
||
import { fetchAgentTaskList } from '@/api/jobs'
|
||
import { cancelApplyJob } from '@/api/agent'
|
||
import type { JobListItem } from '@/api/jobs'
|
||
|
||
/** 事件 */
|
||
const emit = defineEmits<{
|
||
/** 关闭面板 */
|
||
(e: 'close'): void
|
||
/** 移除岗位后通知父组件 */
|
||
(e: 'removed', jobId: string): void
|
||
}>()
|
||
|
||
/** 岗位列表数据 */
|
||
const jobList = ref<JobListItem[]>([])
|
||
|
||
/** 当前页码 */
|
||
const currentPage = ref(1)
|
||
|
||
/** 每页条数 */
|
||
const pageSize = 30
|
||
|
||
/** 是否正在加载首页 */
|
||
const loading = ref(false)
|
||
|
||
/** 是否正在加载更多 */
|
||
const loadingMore = ref(false)
|
||
|
||
/** 是否没有更多数据 */
|
||
const noMore = ref(false)
|
||
|
||
/** 正在移除中的岗位 ID 列表 */
|
||
const removingIds = ref<string[]>([])
|
||
|
||
/** 列表容器 ref */
|
||
const listRef = ref<HTMLElement | null>(null)
|
||
|
||
/** 加载待投递列表 */
|
||
async function loadList(page: number) {
|
||
if (page === 1) {
|
||
loading.value = true
|
||
} else {
|
||
loadingMore.value = true
|
||
}
|
||
try {
|
||
const res = await fetchAgentTaskList({ pageNum: page, pageSize, tab: 1 })
|
||
if (res.code === '0' && res.data) {
|
||
const list = res.data.list || []
|
||
if (page === 1) {
|
||
jobList.value = list
|
||
} else {
|
||
jobList.value.push(...list)
|
||
}
|
||
/* 判断是否还有更多数据 */
|
||
const total = Number(res.data.total || 0)
|
||
if (jobList.value.length >= total || list.length < pageSize) {
|
||
noMore.value = true
|
||
}
|
||
}
|
||
} catch {
|
||
console.error('[AgentPendingJobListPanel] 加载待投递列表失败')
|
||
} finally {
|
||
loading.value = false
|
||
loadingMore.value = false
|
||
}
|
||
}
|
||
|
||
/** 滚动触底加载更多 */
|
||
function handleScroll() {
|
||
if (!listRef.value || loadingMore.value || noMore.value) return
|
||
const { scrollTop, scrollHeight, clientHeight } = listRef.value
|
||
/* 距离底部 50px 时触发加载 */
|
||
if (scrollTop + clientHeight >= scrollHeight - 50) {
|
||
currentPage.value++
|
||
loadList(currentPage.value)
|
||
}
|
||
}
|
||
|
||
/** 移出岗位 */
|
||
async function handleRemove(job: JobListItem) {
|
||
if (removingIds.value.includes(job.id)) return
|
||
removingIds.value.push(job.id)
|
||
try {
|
||
await cancelApplyJob(job.id)
|
||
/* 从列表中移除 */
|
||
const idx = jobList.value.findIndex(j => j.id === job.id)
|
||
if (idx !== -1) {
|
||
jobList.value.splice(idx, 1)
|
||
}
|
||
emit('removed', job.id)
|
||
ElMessage.success('已移除')
|
||
} catch {
|
||
ElMessage.error('移除失败,请重试')
|
||
} finally {
|
||
removingIds.value = removingIds.value.filter(id => id !== job.id)
|
||
}
|
||
}
|
||
|
||
onMounted(() => {
|
||
loadList(1)
|
||
})
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
@use '../assets/styles/components/agent-pending-job-list-panel';
|
||
</style>
|