|
@@ -1,118 +1,277 @@
|
|
|
<template>
|
|
|
<fs-page>
|
|
|
<div class="job-application-container">
|
|
|
- <div class="sidebar">
|
|
|
- <div class="tree-container">
|
|
|
- <!-- 职位分类 -->
|
|
|
- <div class="category-title" @click="togglePositionList">
|
|
|
- <el-icon><Briefcase /></el-icon>
|
|
|
- <span>职位</span>
|
|
|
- <el-icon class="expand-icon" :class="{ 'is-expanded': showPositionList }">
|
|
|
- <ArrowRight />
|
|
|
- </el-icon>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 职位列表 -->
|
|
|
- <div v-if="showPositionList" class="position-list">
|
|
|
- <!-- 全部职位 -->
|
|
|
- <div class="tree-item" :class="{ active: activeNode === 'position-all' }" @click="handleNodeClick({ type: 'all', id: 'position-all' })">
|
|
|
- <div class="item-content">
|
|
|
- <span>全部</span>
|
|
|
+ <!-- 添加顶部标签页 -->
|
|
|
+ <div class="tabs-container">
|
|
|
+ <el-tabs v-model="activeTab" type="card" @tab-click="handleTabClick">
|
|
|
+ <el-tab-pane label="职位申请" name="application">
|
|
|
+ <!-- 第一个tab:保留现有功能 -->
|
|
|
+ <div class="tab-content">
|
|
|
+ <div class="sidebar">
|
|
|
+ <div class="tree-container">
|
|
|
+ <!-- 职位分类 -->
|
|
|
+ <div class="category-title" @click="togglePositionList">
|
|
|
+ <el-icon><Briefcase /></el-icon>
|
|
|
+ <span>职位</span>
|
|
|
+ <el-icon class="expand-icon" :class="{ 'is-expanded': showPositionList }">
|
|
|
+ <ArrowRight />
|
|
|
+ </el-icon>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 职位列表 -->
|
|
|
+ <div v-if="showPositionList" class="position-list">
|
|
|
+ <!-- 全部职位 -->
|
|
|
+ <div class="tree-item" :class="{ active: activeNode === 'position-all' }" @click="handleNodeClick({ type: 'all', id: 'position-all' })">
|
|
|
+ <div class="item-content">
|
|
|
+ <span>全部</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 职位列表项 -->
|
|
|
+ <div
|
|
|
+ v-for="position in positions"
|
|
|
+ :key="'position-' + position.id"
|
|
|
+ class="tree-item"
|
|
|
+ :class="{ active: activeNode === 'position-' + position.id }"
|
|
|
+ @click="handleNodeClick({ type: 'position', value: position.title, id: 'position-' + position.id })"
|
|
|
+ >
|
|
|
+ <div class="item-content">
|
|
|
+ <el-icon><ArrowRight /></el-icon>
|
|
|
+ <span>{{ position.title }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="item-count" v-if="position.count">{{ position.count }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 全部 -->
|
|
|
+ <div class="tree-item" :class="{ active: activeNode === 'all' }" @click="handleNodeClick({ type: 'all' })">
|
|
|
+ <div class="item-content">
|
|
|
+ <el-icon><Grid /></el-icon>
|
|
|
+ <span>全部</span>
|
|
|
+ </div>
|
|
|
+ <div class="item-count">{{ totalCount }}人</div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 待安排 -->
|
|
|
+ <div class="tree-item" :class="{ active: activeNode === 'status-0' }" @click="handleNodeClick({ type: 'status', value: 0, id: 'status-0' })">
|
|
|
+ <div class="item-content">
|
|
|
+ <el-icon><Message /></el-icon>
|
|
|
+ <span>待通知</span>
|
|
|
+ </div>
|
|
|
+ <div class="item-count" v-if="statusCounts[1]">{{ statusCounts[1] }}</div>
|
|
|
+ </div>
|
|
|
+ <!-- 待安排 -->
|
|
|
+ <div class="tree-item" :class="{ active: activeNode === 'status-1' }" @click="handleNodeClick({ type: 'status', value: 1, id: 'status-1' })">
|
|
|
+ <div class="item-content">
|
|
|
+ <el-icon><Clock /></el-icon>
|
|
|
+ <span>已通知待面试</span>
|
|
|
+ </div>
|
|
|
+ <div class="item-count" v-if="statusCounts[1]">{{ statusCounts[5] }}</div>
|
|
|
+ </div>
|
|
|
+ <!-- 推进中 -->
|
|
|
+ <div class="tree-item" :class="{ active: activeNode === 'status-2' }" @click="handleNodeClick({ type: 'status', value: 2, id: 'status-2' })">
|
|
|
+ <div class="item-content">
|
|
|
+ <el-icon><ArrowRight /></el-icon>
|
|
|
+ <span>已面试待处理</span>
|
|
|
+ </div>
|
|
|
+ <div class="item-count" v-if="statusCounts[2]">{{ statusCounts[2] }}</div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 已入职 -->
|
|
|
+ <div class="tree-item" :class="{ active: activeNode === 'status-3' }" @click="handleNodeClick({ type: 'status', value: 3, id: 'status-3' })">
|
|
|
+ <div class="item-content">
|
|
|
+ <el-icon><Check /></el-icon>
|
|
|
+ <span>已录用</span>
|
|
|
+ </div>
|
|
|
+ <div class="item-count" v-if="statusCounts[3]">{{ statusCounts[3] }}</div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 待召回 -->
|
|
|
+ <div class="tree-item" :class="{ active: activeNode === 'status-4' }" @click="handleNodeClick({ type: 'status', value: 4, id: 'status-4' })">
|
|
|
+ <div class="item-content">
|
|
|
+ <el-icon><RefreshRight /></el-icon>
|
|
|
+ <span>拒不录用</span>
|
|
|
+ </div>
|
|
|
+ <div class="item-count" v-if="statusCounts[4]">{{ statusCounts[4] }}</div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 职位列表项 -->
|
|
|
- <div
|
|
|
- v-for="position in positions"
|
|
|
- :key="'position-' + position.id"
|
|
|
- class="tree-item"
|
|
|
- :class="{ active: activeNode === 'position-' + position.id }"
|
|
|
- @click="handleNodeClick({ type: 'position', value: position.title, id: 'position-' + position.id })"
|
|
|
- >
|
|
|
- <div class="item-content">
|
|
|
- <el-icon><ArrowRight /></el-icon>
|
|
|
- <span>{{ position.title }}</span>
|
|
|
+ <div class="content">
|
|
|
+ <fs-crud ref="crudRef" v-bind="crudBinding">
|
|
|
+ <template #actionbar-right>
|
|
|
+ <div class="action-button-wrapper">
|
|
|
+ <el-upload
|
|
|
+ class="upload-demo"
|
|
|
+ :action="uploadUrl"
|
|
|
+ :headers="{
|
|
|
+ Authorization: `Bearer ${Session.get('token')}`
|
|
|
+ }"
|
|
|
+ :on-success="handleImportSuccess"
|
|
|
+ :on-error="handleImportError"
|
|
|
+ accept=".xlsx,.xls"
|
|
|
+ >
|
|
|
+ <el-button type="primary" size="small">
|
|
|
+ <el-icon><Download /></el-icon>
|
|
|
+ 导入
|
|
|
+ </el-button>
|
|
|
+ </el-upload>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </fs-crud>
|
|
|
</div>
|
|
|
- <div class="item-count" v-if="position.count">{{ position.count }}</div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <!-- 全部 -->
|
|
|
- <div class="tree-item" :class="{ active: activeNode === 'all' }" @click="handleNodeClick({ type: 'all' })">
|
|
|
- <div class="item-content">
|
|
|
- <el-icon><Grid /></el-icon>
|
|
|
- <span>全部</span>
|
|
|
- </div>
|
|
|
- <div class="item-count">{{ totalCount }}人</div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 待安排 -->
|
|
|
- <div class="tree-item" :class="{ active: activeNode === 'status-0' }" @click="handleNodeClick({ type: 'status', value: 0, id: 'status-0' })">
|
|
|
- <div class="item-content">
|
|
|
- <el-icon><Message /></el-icon>
|
|
|
- <span>待通知</span>
|
|
|
- </div>
|
|
|
- <div class="item-count" v-if="statusCounts[1]">{{ statusCounts[1] }}</div>
|
|
|
- </div>
|
|
|
- <!-- 待安排 -->
|
|
|
- <div class="tree-item" :class="{ active: activeNode === 'status-1' }" @click="handleNodeClick({ type: 'status', value: 1, id: 'status-1' })">
|
|
|
- <div class="item-content">
|
|
|
- <el-icon><Clock /></el-icon>
|
|
|
- <span>已通知待面试</span>
|
|
|
- </div>
|
|
|
- <div class="item-count" v-if="statusCounts[1]">{{ statusCounts[5] }}</div>
|
|
|
- </div>
|
|
|
- <!-- 推进中 -->
|
|
|
- <div class="tree-item" :class="{ active: activeNode === 'status-2' }" @click="handleNodeClick({ type: 'status', value: 2, id: 'status-2' })">
|
|
|
- <div class="item-content">
|
|
|
- <el-icon><ArrowRight /></el-icon>
|
|
|
- <span>已面试待处理</span>
|
|
|
- </div>
|
|
|
- <div class="item-count" v-if="statusCounts[2]">{{ statusCounts[2] }}</div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 已入职 -->
|
|
|
- <div class="tree-item" :class="{ active: activeNode === 'status-3' }" @click="handleNodeClick({ type: 'status', value: 3, id: 'status-3' })">
|
|
|
- <div class="item-content">
|
|
|
- <el-icon><Check /></el-icon>
|
|
|
- <span>已录用</span>
|
|
|
- </div>
|
|
|
- <div class="item-count" v-if="statusCounts[3]">{{ statusCounts[3] }}</div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 待召回 -->
|
|
|
- <div class="tree-item" :class="{ active: activeNode === 'status-4' }" @click="handleNodeClick({ type: 'status', value: 4, id: 'status-4' })">
|
|
|
- <div class="item-content">
|
|
|
- <el-icon><RefreshRight /></el-icon>
|
|
|
- <span>拒不录用</span>
|
|
|
</div>
|
|
|
- <div class="item-count" v-if="statusCounts[4]">{{ statusCounts[4] }}</div>
|
|
|
- </div>
|
|
|
-
|
|
|
+ </el-tab-pane>
|
|
|
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="content">
|
|
|
- <fs-crud ref="crudRef" v-bind="crudBinding">
|
|
|
- <template #actionbar-right>
|
|
|
- <div class="action-button-wrapper">
|
|
|
- <el-upload
|
|
|
- class="upload-demo"
|
|
|
- :action="uploadUrl"
|
|
|
- :headers="{
|
|
|
- Authorization: `Bearer ${Session.get('token')}`
|
|
|
- }"
|
|
|
- :on-success="handleImportSuccess"
|
|
|
- :on-error="handleImportError"D
|
|
|
- accept=".xlsx,.xls"
|
|
|
- >
|
|
|
- <el-button type="primary" size="small">
|
|
|
- <el-icon><Download /></el-icon>
|
|
|
- 导入
|
|
|
- </el-button>
|
|
|
- </el-upload>
|
|
|
+ <el-tab-pane label="待通知列表" name="resume">
|
|
|
+ <!-- 第二个tab:待通知列表 -->
|
|
|
+ <div class="tab-content">
|
|
|
+ <div class="notification-container">
|
|
|
+ <!-- 搜索表单 -->
|
|
|
+ <div class="search-form">
|
|
|
+ <el-form :model="notificationSearchForm" :inline="true" size="default">
|
|
|
+ <el-form-item label="姓名">
|
|
|
+ <el-input
|
|
|
+ v-model="notificationSearchForm.name"
|
|
|
+ placeholder="请输入姓名"
|
|
|
+ clearable
|
|
|
+ style="width: 200px"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="手机号">
|
|
|
+ <el-input
|
|
|
+ v-model="notificationSearchForm.phone"
|
|
|
+ placeholder="请输入手机号"
|
|
|
+ clearable
|
|
|
+ style="width: 200px"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="职位">
|
|
|
+ <el-select
|
|
|
+ v-model="notificationSearchForm.position"
|
|
|
+ placeholder="请选择职位"
|
|
|
+ clearable
|
|
|
+ style="width: 200px"
|
|
|
+ >
|
|
|
+ <el-option label="全部" value="" />
|
|
|
+ <el-option
|
|
|
+ v-for="position in positions"
|
|
|
+ :key="position.id"
|
|
|
+ :label="position.title"
|
|
|
+ :value="position.title"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="申请时间">
|
|
|
+ <el-date-picker
|
|
|
+ v-model="notificationSearchForm.dateRange"
|
|
|
+ type="daterange"
|
|
|
+ range-separator="至"
|
|
|
+ start-placeholder="开始日期"
|
|
|
+ end-placeholder="结束日期"
|
|
|
+ format="YYYY-MM-DD"
|
|
|
+ value-format="YYYY-MM-DD"
|
|
|
+ style="width: 300px"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item>
|
|
|
+ <el-button type="primary" @click="handleNotificationSearch">
|
|
|
+ <el-icon><Search /></el-icon>
|
|
|
+ 搜索
|
|
|
+ </el-button>
|
|
|
+ <el-button @click="handleNotificationReset">
|
|
|
+ <el-icon><Refresh /></el-icon>
|
|
|
+ 重置
|
|
|
+ </el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 操作按钮 -->
|
|
|
+ <div class="action-bar">
|
|
|
+ <div class="left-actions">
|
|
|
+ <el-button type="primary" @click="handleBatchNotify" :disabled="!selectedNotificationRows.length">
|
|
|
+ <el-icon><Message /></el-icon>
|
|
|
+ 批量通知
|
|
|
+ </el-button>
|
|
|
+ <!-- <el-button type="success" @click="handleBatchInterview" :disabled="!selectedNotificationRows.length">
|
|
|
+ <el-icon><Clock /></el-icon>
|
|
|
+ 安排面试
|
|
|
+ </el-button> -->
|
|
|
+ </div>
|
|
|
+ <!-- <div class="right-actions">
|
|
|
+ <el-button @click="handleNotificationRefresh">
|
|
|
+ <el-icon><Refresh /></el-icon>
|
|
|
+ 刷新
|
|
|
+ </el-button>
|
|
|
+ </div> -->
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 数据表格 -->
|
|
|
+ <div class="table-container">
|
|
|
+ <el-table
|
|
|
+ :data="notificationList"
|
|
|
+ @selection-change="handleNotificationSelectionChange"
|
|
|
+ :loading="notificationLoading"
|
|
|
+ style="width: 100%"
|
|
|
+ height="calc(100vh - 400px)"
|
|
|
+ >
|
|
|
+ <el-table-column type="selection" width="55" />
|
|
|
+ <el-table-column prop="name" label="姓名" width="120" />
|
|
|
+ <el-table-column prop="phone" label="手机号" width="130" />
|
|
|
+ <el-table-column prop="position_title" label="应聘职位" width="150" />
|
|
|
+ <el-table-column prop="apply_time" label="申请时间" width="120" />
|
|
|
+ <el-table-column prop="status" label="状态" width="100">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-tag type="warning">待通知</el-tag>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="source" label="来源" width="100" />
|
|
|
+ <el-table-column prop="remark" label="备注" min-width="150" show-overflow-tooltip />
|
|
|
+ <el-table-column label="操作" width="200" fixed="right">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-button
|
|
|
+ type="primary"
|
|
|
+ size="small"
|
|
|
+ @click="handleNotify(scope.row)"
|
|
|
+ >
|
|
|
+ 通知
|
|
|
+ </el-button>
|
|
|
+ <el-button
|
|
|
+ type="success"
|
|
|
+ size="small"
|
|
|
+ @click="handleInterview(scope.row)"
|
|
|
+ >
|
|
|
+ 安排面试
|
|
|
+ </el-button>
|
|
|
+ <el-button
|
|
|
+ type="info"
|
|
|
+ size="small"
|
|
|
+ @click="handleViewDetail(scope.row)"
|
|
|
+ >
|
|
|
+ 查看详情
|
|
|
+ </el-button>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 分页 -->
|
|
|
+ <div class="pagination-container">
|
|
|
+ <el-pagination
|
|
|
+ v-model:current-page="notificationPagination.current"
|
|
|
+ v-model:page-size="notificationPagination.size"
|
|
|
+ :page-sizes="[10, 20, 50, 100]"
|
|
|
+ :total="notificationPagination.total"
|
|
|
+ layout="total, sizes, prev, pager, next, jumper"
|
|
|
+ @size-change="handleNotificationSizeChange"
|
|
|
+ @current-change="handleNotificationCurrentChange"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- </template>
|
|
|
- </fs-crud>
|
|
|
+ </el-tab-pane>
|
|
|
+ </el-tabs>
|
|
|
</div>
|
|
|
</div>
|
|
|
<BatchTagsDialog ref="batchTagsDialogRef" :crudExpose="crudExpose" />
|
|
@@ -127,7 +286,7 @@ import { useFs } from '@fast-crud/fast-crud';
|
|
|
import { createCrudOptions } from './crud';
|
|
|
import { GetPermission } from './api';
|
|
|
import { handleColumnPermission } from '/@/utils/columnPermission';
|
|
|
-import { Grid, Clock, ArrowRight, Check, RefreshRight, Briefcase, Message, Upload } from '@element-plus/icons-vue';
|
|
|
+import { Grid, Clock, ArrowRight, Check, RefreshRight, Briefcase, Message, Upload, Download, Search, Refresh } from '@element-plus/icons-vue';
|
|
|
import BatchTagsDialog from './components/index.vue';
|
|
|
import BatchStatusDialog from './components/BatchStatusDialog.vue';
|
|
|
import smSnotification from './components/smSnotification.vue';
|
|
@@ -138,6 +297,36 @@ import { Session } from '/@/utils/storage';
|
|
|
|
|
|
const route = useRoute();
|
|
|
|
|
|
+// 添加标签页相关变量
|
|
|
+const activeTab = ref('application');
|
|
|
+
|
|
|
+// 待通知列表相关数据
|
|
|
+interface NotificationItem {
|
|
|
+ id: number;
|
|
|
+ name: string;
|
|
|
+ phone: string;
|
|
|
+ position_title: string;
|
|
|
+ apply_time: string;
|
|
|
+ status: string;
|
|
|
+ source: string;
|
|
|
+ remark: string;
|
|
|
+}
|
|
|
+
|
|
|
+const notificationList = ref<NotificationItem[]>([]);
|
|
|
+const notificationLoading = ref(false);
|
|
|
+const selectedNotificationRows = ref<NotificationItem[]>([]);
|
|
|
+const notificationSearchForm = reactive({
|
|
|
+ name: '',
|
|
|
+ phone: '',
|
|
|
+ position: '',
|
|
|
+ dateRange: [] as string[]
|
|
|
+});
|
|
|
+const notificationPagination = reactive({
|
|
|
+ current: 1,
|
|
|
+ size: 20,
|
|
|
+ total: 0
|
|
|
+});
|
|
|
+
|
|
|
// 定义上传地址
|
|
|
const uploadUrl = `${import.meta.env.VITE_API_URL}/api/job/application/import`;
|
|
|
|
|
@@ -335,6 +524,185 @@ const handleImportError = (error: any) => {
|
|
|
ElMessage.error('导入失败,请检查文件格式或网络连接');
|
|
|
};
|
|
|
|
|
|
+// 处理标签页切换
|
|
|
+const handleTabClick = (tab: any) => {
|
|
|
+ console.log('切换到标签页:', tab.name);
|
|
|
+ // 这里可以根据需要添加标签页切换时的逻辑
|
|
|
+ if (tab.name === 'application') {
|
|
|
+ // 切换到职位申请标签页时的处理
|
|
|
+ console.log('显示职位申请功能');
|
|
|
+ } else if (tab.name === 'resume') {
|
|
|
+ // 切换到待通知列表标签页时的处理
|
|
|
+ console.log('显示待通知列表功能');
|
|
|
+ fetchNotificationList();
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 获取待通知列表数据
|
|
|
+const fetchNotificationList = async () => {
|
|
|
+ notificationLoading.value = true;
|
|
|
+ try {
|
|
|
+ // 构建查询参数
|
|
|
+ const params: Record<string, string | number> = {
|
|
|
+ page: notificationPagination.current,
|
|
|
+ limit: notificationPagination.size,
|
|
|
+ status: 0, // 待通知状态
|
|
|
+ };
|
|
|
+
|
|
|
+ // 添加搜索条件
|
|
|
+ if (notificationSearchForm.name) params.name = notificationSearchForm.name;
|
|
|
+ if (notificationSearchForm.phone) params.phone = notificationSearchForm.phone;
|
|
|
+ if (notificationSearchForm.position) params.position = notificationSearchForm.position;
|
|
|
+
|
|
|
+ // 处理日期范围
|
|
|
+ if (notificationSearchForm.dateRange && notificationSearchForm.dateRange.length === 2) {
|
|
|
+ params.start_date = notificationSearchForm.dateRange[0];
|
|
|
+ params.end_date = notificationSearchForm.dateRange[1];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 调用API获取待通知列表
|
|
|
+ const response = await fetch(`${import.meta.env.VITE_API_URL}/api/job/application/list?${new URLSearchParams(params as Record<string, string>)}`, {
|
|
|
+ headers: {
|
|
|
+ 'Authorization': `Bearer ${Session.get('token')}`,
|
|
|
+ 'Content-Type': 'application/json'
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ const data = await response.json();
|
|
|
+
|
|
|
+ if (data.code === 2000 && data.data) {
|
|
|
+ notificationList.value = data.data.records || [];
|
|
|
+ notificationPagination.total = data.data.total || 0;
|
|
|
+ } else {
|
|
|
+ ElMessage.error(data.message || '获取待通知列表失败');
|
|
|
+ // 如果API调用失败,显示测试数据
|
|
|
+ showTestData();
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取待通知列表失败:', error);
|
|
|
+ ElMessage.error('获取待通知列表失败');
|
|
|
+ // 如果API调用失败,显示测试数据
|
|
|
+ showTestData();
|
|
|
+ } finally {
|
|
|
+ notificationLoading.value = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 显示测试数据
|
|
|
+const showTestData = () => {
|
|
|
+ notificationList.value = [
|
|
|
+ {
|
|
|
+ id: 1,
|
|
|
+ name: '张三',
|
|
|
+ phone: '13800138001',
|
|
|
+ position_title: '前端开发工程师',
|
|
|
+ apply_time: '2024-01-15',
|
|
|
+ status: '待通知',
|
|
|
+ source: '智联招聘',
|
|
|
+ remark: '有3年前端开发经验,熟悉Vue.js'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 2,
|
|
|
+ name: '李四',
|
|
|
+ phone: '13800138002',
|
|
|
+ position_title: 'Java开发工程师',
|
|
|
+ apply_time: '2024-01-14',
|
|
|
+ status: '待通知',
|
|
|
+ source: 'BOSS直聘',
|
|
|
+ remark: '5年Java开发经验,熟悉Spring框架'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 3,
|
|
|
+ name: '王五',
|
|
|
+ phone: '13800138003',
|
|
|
+ position_title: 'UI设计师',
|
|
|
+ apply_time: '2024-01-13',
|
|
|
+ status: '待通知',
|
|
|
+ source: '拉勾网',
|
|
|
+ remark: '有设计作品集,擅长移动端设计'
|
|
|
+ }
|
|
|
+ ];
|
|
|
+ notificationPagination.total = 3;
|
|
|
+};
|
|
|
+
|
|
|
+// 搜索待通知列表
|
|
|
+const handleNotificationSearch = () => {
|
|
|
+ notificationPagination.current = 1;
|
|
|
+ fetchNotificationList();
|
|
|
+};
|
|
|
+
|
|
|
+// 重置搜索条件
|
|
|
+const handleNotificationReset = () => {
|
|
|
+ Object.assign(notificationSearchForm, {
|
|
|
+ name: '',
|
|
|
+ phone: '',
|
|
|
+ position: '',
|
|
|
+ dateRange: []
|
|
|
+ });
|
|
|
+ notificationPagination.current = 1;
|
|
|
+ fetchNotificationList();
|
|
|
+};
|
|
|
+
|
|
|
+// 刷新待通知列表
|
|
|
+const handleNotificationRefresh = () => {
|
|
|
+ fetchNotificationList();
|
|
|
+};
|
|
|
+
|
|
|
+// 处理表格选择变化
|
|
|
+const handleNotificationSelectionChange = (selection: NotificationItem[]) => {
|
|
|
+ selectedNotificationRows.value = selection;
|
|
|
+};
|
|
|
+
|
|
|
+// 处理分页大小变化
|
|
|
+const handleNotificationSizeChange = (size: number) => {
|
|
|
+ notificationPagination.size = size;
|
|
|
+ notificationPagination.current = 1;
|
|
|
+ fetchNotificationList();
|
|
|
+};
|
|
|
+
|
|
|
+// 处理当前页变化
|
|
|
+const handleNotificationCurrentChange = (current: number) => {
|
|
|
+ notificationPagination.current = current;
|
|
|
+ fetchNotificationList();
|
|
|
+};
|
|
|
+
|
|
|
+// 单个通知
|
|
|
+const handleNotify = (row: NotificationItem) => {
|
|
|
+ // 这里可以调用短信通知组件
|
|
|
+ smSnotificationRef.value.open([row]);
|
|
|
+};
|
|
|
+
|
|
|
+// 安排面试
|
|
|
+const handleInterview = (row: NotificationItem) => {
|
|
|
+ // 这里可以调用批量状态修改组件
|
|
|
+ batchStatusDialogRef.value.open([row]);
|
|
|
+};
|
|
|
+
|
|
|
+// 查看详情
|
|
|
+const handleViewDetail = (row: NotificationItem) => {
|
|
|
+ // 这里可以跳转到详情页面或打开详情弹窗
|
|
|
+ console.log('查看详情:', row);
|
|
|
+ ElMessage.info('查看详情功能开发中...');
|
|
|
+};
|
|
|
+
|
|
|
+// 批量通知
|
|
|
+const handleBatchNotify = () => {
|
|
|
+ if (selectedNotificationRows.value.length === 0) {
|
|
|
+ ElMessage.warning('请选择要通知的申请');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ smSnotificationRef.value.open(selectedNotificationRows.value);
|
|
|
+};
|
|
|
+
|
|
|
+// 批量安排面试
|
|
|
+const handleBatchInterview = () => {
|
|
|
+ if (selectedNotificationRows.value.length === 0) {
|
|
|
+ ElMessage.warning('请选择要安排面试的申请');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ batchStatusDialogRef.value.open(selectedNotificationRows.value);
|
|
|
+};
|
|
|
+
|
|
|
// 页面打开后获取列表数据
|
|
|
onMounted(async () => {
|
|
|
// 获取职位列表
|
|
@@ -426,12 +794,132 @@ const getPositionList = async () => {
|
|
|
<style scoped>
|
|
|
.job-application-container {
|
|
|
display: flex;
|
|
|
+ flex-direction: column;
|
|
|
height: 100%;
|
|
|
+ margin-top: 15px;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+/* 标签页容器样式 */
|
|
|
+.tabs-container {
|
|
|
+ background-color: #fff;
|
|
|
+ border-radius: 8px;
|
|
|
+ margin-bottom: 10px;
|
|
|
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
|
+}
|
|
|
+
|
|
|
+.tabs-container :deep(.el-tabs__header) {
|
|
|
+ margin: 0;
|
|
|
+ padding: 0 20px;
|
|
|
+ height: auto;
|
|
|
+}
|
|
|
+
|
|
|
+.tabs-container :deep(.el-tabs__nav-wrap) {
|
|
|
+ padding: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.tabs-container :deep(.el-tabs__item) {
|
|
|
+ height: 50px;
|
|
|
+ line-height: 50px;
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 500;
|
|
|
+}
|
|
|
+
|
|
|
+.tabs-container :deep(.el-tabs__content) {
|
|
|
+ padding: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 标签页内容样式 */
|
|
|
+.tab-content {
|
|
|
+ display: flex;
|
|
|
+ height: calc(100vh - 200px);
|
|
|
+}
|
|
|
+
|
|
|
+/* 简历库样式 */
|
|
|
+.resume-container {
|
|
|
+ width: 100%;
|
|
|
+ padding: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.resume-header {
|
|
|
+ text-align: center;
|
|
|
+ margin-bottom: 40px;
|
|
|
+}
|
|
|
+
|
|
|
+.resume-header h3 {
|
|
|
+ font-size: 24px;
|
|
|
+ color: #303133;
|
|
|
+ margin-bottom: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.resume-header p {
|
|
|
+ color: #909399;
|
|
|
+ font-size: 14px;
|
|
|
+}
|
|
|
+
|
|
|
+.resume-content {
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ min-height: 300px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 待通知列表样式 */
|
|
|
+.notification-container {
|
|
|
+ width: 100%;
|
|
|
+ padding: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.search-form {
|
|
|
+ background-color: #fff;
|
|
|
+ padding: 20px;
|
|
|
+ border-radius: 8px;
|
|
|
+ margin-bottom: 16px;
|
|
|
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
|
+}
|
|
|
+
|
|
|
+.action-bar {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ background-color: #fff;
|
|
|
+ padding: 16px 20px;
|
|
|
+ border-radius: 8px;
|
|
|
+ margin-bottom: 16px;
|
|
|
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
|
+}
|
|
|
+
|
|
|
+.left-actions {
|
|
|
+ display: flex;
|
|
|
+ gap: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.right-actions {
|
|
|
+ display: flex;
|
|
|
+ gap: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.table-container {
|
|
|
+ background-color: #fff;
|
|
|
+ border-radius: 8px;
|
|
|
+ margin-bottom: 16px;
|
|
|
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+.pagination-container {
|
|
|
+ background-color: #fff;
|
|
|
+ padding: 16px 20px;
|
|
|
+ border-radius: 8px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
|
}
|
|
|
|
|
|
+/* 原有的侧边栏和内容样式 */
|
|
|
.sidebar {
|
|
|
overflow: auto;
|
|
|
- margin-top: 10px;
|
|
|
+ margin-top: 0;
|
|
|
width: 200px;
|
|
|
margin-right: 5px;
|
|
|
flex-shrink: 0;
|