214 lines
7.5 KiB
Vue
214 lines
7.5 KiB
Vue
<template>
|
||
<!-- 投递任务抽屉 — 从浏览器右侧弹出,包含待投递和已完成两个tab -->
|
||
<Teleport to="body">
|
||
<Transition name="agent-task-drawer">
|
||
<div v-if="visible" class="agent-task-drawer-mask" @click.self="handleClose">
|
||
<div class="agent-task-drawer">
|
||
<!-- 顶部标题栏 -->
|
||
<div class="agent-task-drawer__header mb10">
|
||
<div class="agent-task-drawer__header-left">
|
||
<!-- 关闭按钮 -->
|
||
<div class="agent-task-drawer__close" @click="handleClose">
|
||
<svg viewBox="0 0 24 24" fill="none" class="agent-task-drawer__close-icon">
|
||
<path d="M18 6L6 18M6 6l12 12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||
</svg>
|
||
</div>
|
||
<span class="agent-task-drawer__title">投递任务</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Tab 切换按钮 -->
|
||
<div class="agent-task-drawer__tabs">
|
||
<button
|
||
class="agent-task-drawer__tab"
|
||
:class="{ 'agent-task-drawer__tab--active': activeTab === 'pending' }"
|
||
@click="switchTab('pending')"
|
||
>待投递 {{ pendingList.length }}</button>
|
||
<button
|
||
class="agent-task-drawer__tab"
|
||
:class="{ 'agent-task-drawer__tab--active': activeTab === 'completed' }"
|
||
@click="switchTab('completed')"
|
||
>已完成 {{ completedList.length }}</button>
|
||
</div>
|
||
|
||
<!-- 列表内容 -->
|
||
<div class="agent-task-drawer__body">
|
||
<!-- 待投递列表 -->
|
||
<template v-if="activeTab === 'pending'">
|
||
<div v-if="pendingLoading" class="agent-task-drawer__empty">加载中...</div>
|
||
<div v-else-if="pendingList.length === 0" class="agent-task-drawer__empty">暂无待投递岗位</div>
|
||
<div
|
||
v-for="job in pendingList"
|
||
:key="job.id"
|
||
class="agent-task-drawer__card"
|
||
>
|
||
<div class="agent-task-drawer__card-info">
|
||
<div class="agent-task-drawer__card-title">{{ job.title }}</div>
|
||
<div class="agent-task-drawer__card-company">
|
||
<img v-if="job.companyLogoUrl" :src="job.companyLogoUrl" class="agent-task-drawer__card-logo" :alt="job.companyShortName" />
|
||
<svg v-else class="agent-task-drawer__card-logo-placeholder" 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>
|
||
<span>{{ job.companyShortName || job.companyName }}</span>
|
||
</div>
|
||
</div>
|
||
<button
|
||
class="agent-task-drawer__remove-btn"
|
||
:disabled="removingIds.includes(job.id)"
|
||
@click="handleRemove(job)"
|
||
>移出任务</button>
|
||
</div>
|
||
</template>
|
||
|
||
<!-- 已完成列表 -->
|
||
<template v-else>
|
||
<div v-if="completedLoading" class="agent-task-drawer__empty">加载中...</div>
|
||
<div v-else-if="completedList.length === 0" class="agent-task-drawer__empty">暂无已完成岗位</div>
|
||
<div
|
||
v-for="job in completedList"
|
||
:key="job.id"
|
||
class="agent-task-drawer__card"
|
||
>
|
||
<div class="agent-task-drawer__card-info">
|
||
<div class="agent-task-drawer__card-title">{{ job.title }}</div>
|
||
<div class="agent-task-drawer__card-company">
|
||
<img v-if="job.companyLogoUrl" :src="job.companyLogoUrl" class="agent-task-drawer__card-logo" :alt="job.companyShortName" />
|
||
<svg v-else class="agent-task-drawer__card-logo-placeholder" 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>
|
||
<span>{{ job.companyShortName || job.companyName }}</span>
|
||
</div>
|
||
</div>
|
||
<!-- 已完成状态不显示移出按钮 -->
|
||
</div>
|
||
</template>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</Transition>
|
||
</Teleport>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref, watch } from 'vue'
|
||
import { fetchAgentTaskList } from '@/api/jobs'
|
||
import { cancelApplyJob } from '@/api/agent'
|
||
import type { JobListItem } from '@/api/jobs'
|
||
|
||
// ==================== Props ====================
|
||
|
||
const props = defineProps<{
|
||
/** 是否显示抽屉 */
|
||
visible: boolean
|
||
}>()
|
||
|
||
// ==================== 事件 ====================
|
||
|
||
const emit = defineEmits<{
|
||
/** 关闭抽屉 */
|
||
(e: 'close'): void
|
||
/** 更新visible */
|
||
(e: 'update:visible', val: boolean): void
|
||
/** 移除岗位后通知父组件刷新列表 */
|
||
(e: 'removed', jobId: string): void
|
||
}>()
|
||
|
||
// ==================== 状态 ====================
|
||
|
||
/** 当前激活的 Tab */
|
||
const activeTab = ref<'pending' | 'completed'>('pending')
|
||
|
||
/** 待投递列表 */
|
||
const pendingList = ref<JobListItem[]>([])
|
||
|
||
/** 已完成列表 */
|
||
const completedList = ref<JobListItem[]>([])
|
||
|
||
/** 待投递加载状态 */
|
||
const pendingLoading = ref(false)
|
||
|
||
/** 已完成加载状态 */
|
||
const completedLoading = ref(false)
|
||
|
||
/** 正在移除中的岗位 ID 列表 */
|
||
const removingIds = ref<string[]>([])
|
||
|
||
// ==================== 监听 ====================
|
||
|
||
/** 打开时加载数据 */
|
||
watch(() => props.visible, (val) => {
|
||
if (val) {
|
||
loadPendingList()
|
||
loadCompletedList()
|
||
}
|
||
})
|
||
|
||
// ==================== 方法 ====================
|
||
|
||
/** 切换 Tab */
|
||
function switchTab(tab: 'pending' | 'completed') {
|
||
activeTab.value = tab
|
||
}
|
||
|
||
/** 加载待投递列表(pageSize=200) */
|
||
async function loadPendingList() {
|
||
pendingLoading.value = true
|
||
try {
|
||
const res = await fetchAgentTaskList({ pageNum: 1, pageSize: 200, tab: 1 })
|
||
if (res.code === '0' && res.data) {
|
||
pendingList.value = res.data.list || []
|
||
}
|
||
} catch {
|
||
console.error('[AgentTaskListDropdown] 加载待投递列表失败')
|
||
} finally {
|
||
pendingLoading.value = false
|
||
}
|
||
}
|
||
|
||
/** 加载已完成列表(pageSize=300) */
|
||
async function loadCompletedList() {
|
||
completedLoading.value = true
|
||
try {
|
||
const res = await fetchAgentTaskList({ pageNum: 1, pageSize: 300, tab: 2 })
|
||
if (res.code === '0' && res.data) {
|
||
completedList.value = res.data.list || []
|
||
}
|
||
} catch {
|
||
console.error('[AgentTaskListDropdown] 加载已完成列表失败')
|
||
} finally {
|
||
completedLoading.value = false
|
||
}
|
||
}
|
||
|
||
/** 移出岗位 */
|
||
async function handleRemove(job: JobListItem) {
|
||
if (removingIds.value.includes(job.id)) return
|
||
removingIds.value.push(job.id)
|
||
try {
|
||
await cancelApplyJob(job.id)
|
||
const idx = pendingList.value.findIndex(j => j.id === job.id)
|
||
if (idx !== -1) {
|
||
pendingList.value.splice(idx, 1)
|
||
}
|
||
emit('removed', job.id)
|
||
ElMessage.success('已移除')
|
||
} catch {
|
||
ElMessage.error('移除失败')
|
||
} finally {
|
||
removingIds.value = removingIds.value.filter(id => id !== job.id)
|
||
}
|
||
}
|
||
|
||
/** 关闭抽屉 */
|
||
function handleClose() {
|
||
emit('close')
|
||
emit('update:visible', false)
|
||
}
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
@use '../assets/styles/components/agent-task-list-dropdown';
|
||
</style>
|