yangg 1 долоо хоног өмнө
parent
commit
2246563d75

+ 36 - 2
src/views/JobApplication/list/index.vue

@@ -107,6 +107,9 @@ import BatchTagsDialog from './components/index.vue';
 import BatchStatusDialog from './components/BatchStatusDialog.vue';
 import smSnotification from './components/smSnotification.vue';
 import { getApplicationStatusSummary } from './api';
+import { useRoute } from 'vue-router';
+
+const route = useRoute();
 
 const { crudBinding, crudRef, crudExpose, crudOptions, resetCrudOptions } = useFs({ 
 	createCrudOptions,
@@ -299,8 +302,39 @@ onMounted(async () => {
 	// 重置crudBinding
 	resetCrudOptions(newOptions);
 	
-	// 刷新
-	crudExpose.doRefresh();
+	// 处理URL参数
+	const urlStatus = route.query.status;
+	console.log(urlStatus)
+	if (urlStatus) {
+		// 根据URL状态参数设置活动节点
+		const statusValue = Number(urlStatus);
+		switch (statusValue) {
+			case 0:
+				activeNode.value = 'status-1';
+				break;
+			case 2:
+				activeNode.value = 'status-2';
+				break;
+			case 3:
+				activeNode.value = 'status-3';
+				break;
+			case 4:
+				activeNode.value = 'status-4';
+				break;
+			default:
+				activeNode.value = 'all';
+		}
+		
+		// 使用doSearch进行带状态参数的搜索
+		crudExpose.doSearch({
+			form: {
+				status: statusValue
+			}
+		});
+	} else {
+		// 没有URL参数时,执行普通刷新
+		crudExpose.doRefresh();
+	}
 });
 </script>
 

+ 602 - 39
src/views/system/home/index.vue

@@ -5,7 +5,7 @@
 			<el-col :span="18">
 				<el-row :gutter="12" class="home-card-one mb15">
 					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
-						<div class="home-card-one-title">上午好,{{}}。这是今日的人才情况动态。</div>
+						<div class="home-card-one-title">{{greeting}},{{name}}老师。这是今日的人才情况动态。</div>
 					</el-col>
 				</el-row>
 				<el-row :gutter="10" class="home-card-two mb15">
@@ -13,10 +13,16 @@
 						<div class="home-card-item" style="margin-bottom: 10px;">
 							<div class="home-card-item-title">待办事项</div>
 							<div class="todo-list">
-								<div class="todo-item">
+								<div class="todo-item clickable" @click="handleTodoItemClick('interviewed-pending')">
+									
 									<div class="todo-item-left">
-										<span class="todo-tag">4位候选人待处理</span>
-										<span class="todo-text">2025年6月12日  15:00最新投递</span>
+										<div class="item_icon">
+											<img src="../../../assets/首页图标1.png" alt="">
+										</div>
+										<div class="todo-item-text">
+											<span class="todo-tag">4位候选人待处理</span>
+											<span class="todo-text">2025年6月12日  15:00最新投递</span>
+										</div>
 									</div>
 									<div class="todo-item-right">
 										<el-icon size="20"><ArrowRightBold /></el-icon>
@@ -45,47 +51,108 @@
 					<div class="home-card-item">
 						<!-- <div class="home-card-item-title">快捷操作</div> -->
 						<div class="home-card-item-content">
-							<el-select placeholder="Select" style="margin-right: 5px;">
-								<el-option label="Option 1" value="1" />
-								<el-option label="Option 2" value="2" />
-								<el-option label="Option 3" value="3" />
+							<el-select 
+								v-model="selectedStatus" 
+								placeholder="请选择面试状态" 
+								style="margin-right: 5px; width: 120px;"
+								@change="handleFilterChange"
+							>
+								<el-option label="全部状态" value="" />
+								<el-option label="待面试" value="0" />
+								<el-option label="已面试" value="2" />
+								<el-option label="已录用" value="3" />
+								<el-option label="已拒绝" value="4" />
 							</el-select>
-							<el-select placeholder="Select" style="margin-right: 5px;">
-								<el-option label="Option 1" value="1" />
-								<el-option label="Option 2" value="2" />
-								<el-option label="Option 3" value="3" />
+							<el-select 
+								v-model="selectedPosition" 
+								placeholder="请选择职位" 
+								style="margin-right: 5px; width: 120px;"
+								@change="handleFilterChange"
+							>
+								<el-option label="全部职位" value="" />
+								<el-option 
+									v-for="position in positions" 
+									:key="position.id" 
+									:label="position.title" 
+									:value="position.id" 
+								/>
 							</el-select>
-							<el-select placeholder="Select" style="margin-right: 5px;">
-								<el-option label="Option 1" value="1" />
-								<el-option label="Option 2" value="2" />
-								<el-option label="Option 3" value="3" />
+							<el-select 
+								v-model="selectedTimeRange" 
+								placeholder="请选择时间范围" 
+								style="margin-right: 5px; width: 120px;"
+								@change="handleFilterChange"
+							>
+								<el-option label="全部时间" value="" />
+								<el-option label="今天" value="today" />
+								<el-option label="最近3天" value="3days" />
+								<el-option label="最近7天" value="7days" />
+								<el-option label="最近30天" value="30days" />
 							</el-select>
 						</div>
+						<!-- <p style="margin-top: 20px; font-size: 12px; color:#808080;">筛选结果</p>
+						
+					
+						<div class="candidate-list" v-loading="candidateLoading">
+							<div v-if="filteredCandidates.length === 0" class="no-data">
+								<el-empty description="暂无符合条件的候选人" />
+							</div>
+							<div v-else>
+								<div 
+									v-for="candidate in filteredCandidates.slice(0, 5)" 
+									:key="candidate.id"
+									class="candidate-item"
+									@click="handleCandidateClick(candidate)"
+								>
+									<div class="candidate-info">
+										<div class="candidate-name">{{ candidate.applicant_name || candidate.name }}</div>
+										<div class="candidate-details">
+											<span class="candidate-position">{{ candidate.position_title || '未知职位' }}</span>
+											<span class="candidate-status" :class="getStatusClass(candidate.status)">
+												{{ getStatusText(candidate.status) }}
+											</span>
+										</div>
+									</div>
+									<div class="candidate-time">
+										{{ formatTime(candidate.created_at || candidate.application_time) }}
+									</div>
+								</div>
+								<div v-if="filteredCandidates.length > 5" class="more-candidates">
+									<el-button 
+										type="text" 
+										@click="viewAllCandidates"
+										style="color: #409EFF; font-size: 12px;"
+									>
+										查看全部 {{ filteredCandidates.length }} 位候选人 →
+									</el-button>
+								</div>
+							</div>
+						</div> -->
 						<p style="margin-top: 20px; font-size: 12px;  color:#808080;">通过情况概览</p>
 						<div class="demo-collapse">
-							<el-collapse >
-								<el-collapse-item title="在此期间共计  2 位候选人通过面试" name="1">
+							<el-collapse v-model="activeCollapse">
+								<el-collapse-item :title="`在此期间共计${Math.min(filteredCandidates.length, 5)} 位候选人通过面试`" name="1">
 									<div class="score-list">
-										<div class="score-item">
-											<div class="score-name">张老三</div>
-											<div class="score-name">男</div>
-											<div class="score-name">25岁</div>
-											<div class="score-name">2年经验</div>
-											<div class="score-value">82%</div>
+										<div class="score-item clickable-item" v-for="item in filteredCandidates.slice(0, 5)" :key="item.id" @click="handleCandidateClick(item)">
+											<div class="score-name">{{ item.applicant_name || item.name }}</div>
+											<div class="score-name">{{ item.applicant_gender_display || '' }}</div>
+											<!-- <div class="score-name">25岁</div> -->
+											<div class="score-name">{{item.position_title}}</div>
+											<div class="score-value">{{item.comprehensive_score}}</div>
 										</div>
-										<div class="score-item">
+										<!-- <div class="score-item">
 											<div class="score-name">李老四</div>  
 											<div class="score-name">男</div>
 											<div class="score-name">42岁</div>
 											<div class="score-name">5年经验</div>
 											<div class="score-value">65%</div>
-										</div>
+										</div> -->
 									</div>
 								</el-collapse-item>
 							</el-collapse>
 						</div>
 						<p style="margin-top: 20px; font-size: 12px;  color:#808080;">招聘情况总览</p>
-						<p style="font-size: 14px;  color:#808080;">共计 10 位候选人参与面试,通过率 <span style="color: #409EFF;">20%</span></p>
+						<p style="font-size: 14px;  color:#808080;">共计 {{ totalCandidates }} 位候选人参与面试,通过率 <span style="color: #409EFF;">{{ passRate }}%</span></p>
 												<!-- 这里可以添加右侧内容 -->
 					</div>
 				</div>
@@ -118,7 +185,7 @@
 </template>
 
 <script lang="ts">
-import { toRefs, reactive, defineComponent, onMounted, ref, watch, nextTick, onActivated } from 'vue';
+import { toRefs, reactive, defineComponent, onMounted, ref, watch, nextTick, onActivated, computed } from 'vue';
 import * as echarts from 'echarts';
 import { storeToRefs } from 'pinia';
 import { useThemeConfig } from '/@/stores/themeConfig';
@@ -139,6 +206,25 @@ interface ApiData {
 	}>;
 }
 
+// 定义职位接口
+interface Position {
+	id: number | string;
+	title: string;
+}
+
+// 定义候选人接口
+interface Candidate {
+	id: number | string;
+	applicant_name?: string;
+	name?: string;
+	position_title?: string;
+	status: number | string;
+	created_at?: string;
+	application_time?: string;
+	applicant_gender_display?: string;
+	comprehensive_score?: number | string;
+}
+
 let global: any = {
 	homeChartOne: null,
 	homeChartTwo: null,
@@ -162,7 +248,7 @@ export default defineComponent({
 					num1: '0',
 					num2: '0',
 					num3: '申请总数',
-					num4: 'fa fa-meetup',
+					num4: 'fa fa-file-text-o',
 					color1: '#6690F9',
 					color2: '--next-color-primary-lighter',
 					color3: '--el-color-primary',
@@ -170,8 +256,8 @@ export default defineComponent({
 				{
 					num1: '0',
 					num2: '0',
-					num3: '职位总数',
-					num4: 'iconfont icon-ditu',
+					num3: '面试岗位数',
+					num4: 'fa fa-briefcase',
 					color1: '#6690F9',
 					color2: '--next-color-success-lighter',
 					color3: '--el-color-success',
@@ -180,7 +266,7 @@ export default defineComponent({
 					num1: '0',
 					num2: '0',
 					num3: '问题总数',
-					num4: 'iconfont icon-zaosheng',
+					num4: 'fa fa-question-circle',
 					color1: '#6690F9',
 					color2: '--next-color-warning-lighter',
 					color3: '--el-color-warning',
@@ -188,13 +274,15 @@ export default defineComponent({
 				{
 					num1: '0',
 					num2: '0',
-					num3: '报告总数',
-					num4: 'fa fa-github-alt',
+					num3: '在职奇才',
+					num4: 'fa fa-user',
 					color1: '#6690F9',
 					color2: '--next-color-danger-lighter',
 					color3: '--el-color-danger',
 				},
 			],
+			// 控制折叠面板展开状态
+			activeCollapse: ['1'], // 初始化展开name为"1"的面板
 			homeThree: [
 				{
 					icon: 'iconfont icon-yangan',
@@ -258,8 +346,31 @@ export default defineComponent({
 				color: '#303133',
 			},
 			apiData: null as ApiData | null,
+			name:'',
+			greeting: '',
+			selectedStatus: '',
+			selectedPosition: '',
+			selectedTimeRange: '',
+			candidateLoading: false,
+			filteredCandidates: [] as Candidate[],
+			positions: [] as Position[],
+			totalCandidates: 0,
+			passedCandidates: 0,
 		});
 		const router = useRouter();
+		
+		// 获取问候语
+		const getGreeting = () => {
+			const hour = new Date().getHours();
+			if (hour >= 0 && hour < 12) {
+				return '上午好';
+			} else if (hour >= 12 && hour < 18) {
+				return '下午好';
+			} else {
+				return '晚上好';
+			}
+		};
+		
 		// 折线图
 		const initLineChart = () => {
 			if (!global.dispose.some((b: any) => b === global.homeChartOne)) global.homeChartOne.dispose();
@@ -553,8 +664,12 @@ export default defineComponent({
 		// 页面加载时
 		onMounted(() => {
 			fetchApiData();
+			fetchPositions();
+			fetchCandidates();
+			fetchAllCandidatesForStats(); // 获取统计数据
 			initEchartsResize();
-			
+			state.name = Session.get('userInfo').name?.charAt(0) || '';
+			state.greeting = getGreeting();
 			console.log(Session.get('userInfo'));
 		});
 		// 由于页面缓存原因,keep-alive
@@ -638,7 +753,7 @@ export default defineComponent({
 			const routes = [
 				'/JobApplication/list/index', // 申请总数
 				'/position/list',    // 职位总数
-				'/questionBank/list',    // 问题总数
+				'/talent/list/index',    // 问题总数
 				'/JobApplication/list/index'       // 报告总数
 			];
 			
@@ -646,11 +761,271 @@ export default defineComponent({
 				router.push(routes[index]);
 			}
 		};
+		
+		// 处理待办事项点击跳转功能
+		const handleTodoItemClick = (status: string) => {
+			// 跳转到求职申请列表页面,并传递状态参数
+			router.push({
+				path: '/JobApplication/list/index',
+				query: {
+					status: 3 // 传递状态参数,用于页面筛选已面试待处理的候选人
+				}
+			});
+		};
+		
+		// 获取职位列表
+		const fetchPositions = async () => {
+			try {
+				const res = await fetch(`${import.meta.env.VITE_API_URL}/api/system/job/list?page=1&limit=100&tenant_id=1`, {
+					method: 'GET',
+					headers: {
+						'Authorization': 'JWT ' + Session.get('token'),
+						'Content-Type': 'application/json'
+					}
+				});
+				const data = await res.json();
+				
+				if (data.code === 2000 && data.data) {
+					state.positions = data.data.map((item: any) => ({
+						id: item.id,
+						title: item.title || item.name || item.job_name,
+					}));
+				} else {
+					console.error('获取职位列表失败:', data.msg || '未知错误');
+				}
+			} catch (error) {
+				console.error('获取职位列表异常:', error);
+				// 设置默认职位
+				state.positions = [{ id: 1, title: '流水线操作工' }];
+			}
+		};
+		
+		// 获取候选人列表
+		const fetchCandidates = async (params: any = {}) => {
+			state.candidateLoading = true;
+			try {
+				const queryParams = new URLSearchParams({
+					page: '1',
+					limit: '50',
+					tenant_id: '1',
+					...params
+				});
+				
+				const res = await fetch(`${import.meta.env.VITE_API_URL}/api/system/job_applications/?${queryParams}`, {
+					method: 'GET',
+					headers: {
+						'Authorization': 'JWT ' + Session.get('token'),
+						'Content-Type': 'application/json'
+					}
+				});
+				const data = await res.json();
+				
+				if (data.code === 2000 && data.data) {
+					state.filteredCandidates = data.data;
+					// 更新统计信息
+					updateCandidateStats(data.data);
+				} else {
+					state.filteredCandidates = [];
+					console.error('获取候选人列表失败:', data.msg || '未知错误');
+				}
+			} catch (error) {
+				console.error('获取候选人列表异常:', error);
+				state.filteredCandidates = [];
+			} finally {
+				state.candidateLoading = false;
+			}
+		};
+		
+		// 处理筛选变化
+		const handleFilterChange = () => {
+			const params: any = {};
+			
+			// 状态筛选
+			if (state.selectedStatus !== '') {
+				params.status = state.selectedStatus;
+			}
+			
+			// 职位筛选
+			if (state.selectedPosition !== '') {
+				params.position_id = state.selectedPosition;
+			}
+			
+			// 时间筛选
+			if (state.selectedTimeRange !== '') {
+				const timeFilter = getTimeFilter(state.selectedTimeRange);
+				if (timeFilter) {
+					params.date_from = timeFilter.from;
+					params.date_to = timeFilter.to;
+				}
+			}
+			
+			fetchCandidates(params);
+		};
+		
+		// 获取时间筛选范围
+		const getTimeFilter = (range: string) => {
+			const now = new Date();
+			const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
+			
+			switch (range) {
+				case 'today':
+					return {
+						from: today.toISOString().split('T')[0],
+						to: today.toISOString().split('T')[0]
+					};
+				case '3days':
+					const threeDaysAgo = new Date(today);
+					threeDaysAgo.setDate(today.getDate() - 3);
+					return {
+						from: threeDaysAgo.toISOString().split('T')[0],
+						to: today.toISOString().split('T')[0]
+					};
+				case '7days':
+					const sevenDaysAgo = new Date(today);
+					sevenDaysAgo.setDate(today.getDate() - 7);
+					return {
+						from: sevenDaysAgo.toISOString().split('T')[0],
+						to: today.toISOString().split('T')[0]
+					};
+				case '30days':
+					const thirtyDaysAgo = new Date(today);
+					thirtyDaysAgo.setDate(today.getDate() - 30);
+					return {
+						from: thirtyDaysAgo.toISOString().split('T')[0],
+						to: today.toISOString().split('T')[0]
+					};
+				default:
+					return null;
+			}
+		};
+		
+		// 获取状态文本
+		const getStatusText = (status: number | string) => {
+			const statusMap: Record<string, string> = {
+				'0': '待面试',
+				'1': '待面试',
+				'2': '已面试',
+				'3': '已录用',
+				'4': '已拒绝'
+			};
+			return statusMap[String(status)] || '未知状态';
+		};
+		
+		// 获取状态样式类
+		const getStatusClass = (status: number | string) => {
+			const classMap: Record<string, string> = {
+				'0': 'status-pending',
+				'1': 'status-pending',
+				'2': 'status-interviewed',
+				'3': 'status-hired',
+				'4': 'status-rejected'
+			};
+			return classMap[String(status)] || 'status-unknown';
+		};
+		
+		// 格式化时间
+		const formatTime = (timeStr: string) => {
+			if (!timeStr) return '';
+			const date = new Date(timeStr);
+			const now = new Date();
+			const diff = now.getTime() - date.getTime();
+			const days = Math.floor(diff / (1000 * 60 * 60 * 24));
+			
+			if (days === 0) {
+				return '今天';
+			} else if (days === 1) {
+				return '昨天';
+			} else if (days < 7) {
+				return `${days}天前`;
+			} else {
+				return date.toLocaleDateString('zh-CN', {
+					month: 'short',
+					day: 'numeric'
+				});
+			}
+		};
+		
+		// 处理候选人点击
+		const handleCandidateClick = (candidate: any) => {
+			// 跳转到候选人详情页面
+			const baseUrl = window.location.origin;
+			const url = `${baseUrl}/#/JobApplication/report/report?id=${candidate.id}&tenant_id=${1}&application_id=${candidate.applicant}`;
+			window.open(url, '_blank');
+			
+		};
+		
+		// 查看全部候选人
+		const viewAllCandidates = () => {
+			const query: any = {};
+			
+			// 传递当前筛选条件
+			if (state.selectedStatus !== '') {
+				query.status = state.selectedStatus;
+			}
+			if (state.selectedPosition !== '') {
+				query.position_id = state.selectedPosition;
+			}
+			
+			router.push({
+				path: '/JobApplication/list/index',
+				query
+			});
+		};
+		
+		// 更新候选人统计信息
+		const updateCandidateStats = (candidates: Candidate[]) => {
+			state.totalCandidates = candidates.length;
+			// 计算通过人数(状态为3表示已录用)
+			state.passedCandidates = candidates.filter(candidate => 
+				candidate.status === 3 || candidate.status === '3'
+			).length;
+		};
+		
+		// 计算通过率
+		const passRate = computed(() => {
+			if (state.totalCandidates === 0) return '0';
+			return ((state.passedCandidates / state.totalCandidates) * 100).toFixed(1);
+		});
+		
+		// 页面加载时获取所有候选人数据用于统计
+		const fetchAllCandidatesForStats = async () => {
+			try {
+				const queryParams = new URLSearchParams({
+					page: '1',
+					limit: '1000', // 获取更多数据用于统计
+					tenant_id: '1'
+				});
+				
+				const res = await fetch(`${import.meta.env.VITE_API_URL}/api/system/job_applications/?${queryParams}`, {
+					method: 'GET',
+					headers: {
+						'Authorization': 'JWT ' + Session.get('token'),
+						'Content-Type': 'application/json'
+					}
+				});
+				const data = await res.json();
+				
+				if (data.code === 2000 && data.data) {
+					updateCandidateStats(data.data);
+				}
+			} catch (error) {
+				console.error('获取候选人统计数据异常:', error);
+			}
+		};
+		
 		return {
 			homeLineRef,
 			homePieRef,
 			homeBarRef,
 			handleCardClick,
+			handleTodoItemClick,
+			handleFilterChange,
+			handleCandidateClick,
+			viewAllCandidates,
+			getStatusText,
+			getStatusClass,
+			formatTime,
+			passRate,
 			...toRefs(state),
 		};
 	},
@@ -753,11 +1128,11 @@ $homeNavLengh: 8;
 	}
 	.home-right {
 		.home-card-item {
-			height: 500px;
+			height: 600px;
 			border-radius: 16px;
 			transition: all ease 0.3s;
 			padding: 20px;
-			overflow: hidden;
+			overflow: auto;
 			background: var(--el-color-white);
 			color: var(--el-text-color-primary);
 			border: 1px solid var(--next-border-color-light);
@@ -807,22 +1182,75 @@ $homeNavLengh: 8;
 	.todo-list {
 		padding: 10px 20px; 
 		margin-top: 15px;
-		margin-left: 50px;
+		margin-left: 10px;
 		.todo-item {
 			display: flex;
 			justify-content: space-between;
 			align-items: center;
 			padding: 8px 0;
 			border-bottom: 1px solid var(--next-border-color-light);
+			transition: all 0.3s ease;
+			background: #fff;
+			
+			// 可点击样式
+			&.clickable {
+				cursor: pointer;
+				padding: 12px 16px;
+				border-radius: 8px;
+				margin: 8px 0;
+				// background: var(--el-fill-color-lighter);
+				border-bottom: none;
+				
+				&:hover {
+					background: #f2f2f2;
+					transform: translateY(-2px);
+					box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+				}
+				
+				&:active {
+					transform: translateY(0);
+				}
+			}
+			
 			.todo-item-left {
 				display: flex;
+				align-items: flex-start;
+				.item_icon{
+				width: 40px;
+				height: 40px;
+				img{
+					width: 100%;
+					height: 100%;
+				}
+				
+			}.todo-item-text{
+					display: flex;
 				flex-direction: column;
 				align-items: flex-start;
+				}
 				.todo-tag {
 					margin-right: 10px;
+					font-weight: 500;
+					// color: var(--el-color-primary);
+				}
+				.todo-text {
+					font-size: 12px;
+					color: var(--el-text-color-secondary);
+					margin-top: 4px;
+				}
+			}
+			
+			.todo-item-right {
+				.el-icon {
+					// color: var(--el-color-primary);
+					transition: transform 0.3s ease;
 				}
 			}
 			
+			&.clickable:hover .todo-item-right .el-icon {
+				transform: translateX(4px);
+			}
+			
 			&:last-child {
 				border-bottom: none;
 			}
@@ -848,16 +1276,151 @@ $homeNavLengh: 8;
 			background: var(--el-fill-color-light);
 			border-radius: 4px;
 			
+			// 可点击样式
+			&.clickable-item {
+				cursor: pointer;
+				transition: all 0.3s ease;
+				
+				&:hover {
+					background: var(--el-color-primary-light-9);
+					transform: translateY(-1px);
+					box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+				}
+				
+				&:active {
+					transform: translateY(0);
+				}
+			}
+			
 			.score-name {
 				font-size: 14px;
 				color: var(--el-text-color-primary);
+				flex: 0 0 auto; // 不伸缩,固定宽度
+				
+				&:nth-child(1) {
+					width: 60px; // 姓名宽度
+					text-align: left;
+				}
+				
+				&:nth-child(2) {
+					width: 30px; // 性别宽度
+					text-align: center;
+				}
+				
+				&:nth-child(3) {
+					width: 80px; // 职位宽度
+					text-align: left;
+					overflow: hidden;
+					text-overflow: ellipsis;
+					white-space: nowrap;
+				}
 			}
 			
 			.score-value {
 				font-size: 14px;
 				color: var(--el-color-primary);
 				font-weight: 500;
+				width: 50px; // 分数宽度
+				text-align: right;
+				flex: 0 0 auto;
+			}
+		}
+	}
+	
+	// 候选人列表样式
+	.candidate-list {
+		max-height: 300px;
+		overflow-y: auto;
+		
+		.no-data {
+			text-align: center;
+			padding: 20px 0;
+			color: var(--el-text-color-secondary);
+		}
+		
+		.candidate-item {
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+			padding: 10px 5px;
+			border-bottom: 1px solid var(--el-border-color-light);
+			cursor: pointer;
+			transition: all 0.3s ease;
+			
+			&:hover {
+				background: var(--el-fill-color-light);
+				transform: translateX(2px);
+			}
+			
+			&:last-child {
+				border-bottom: none;
 			}
+			
+			.candidate-info {
+				flex: 1;
+				
+				.candidate-name {
+					font-size: 14px;
+					font-weight: 500;
+					color: var(--el-text-color-primary);
+					margin-bottom: 4px;
+				}
+				
+				.candidate-details {
+					display: flex;
+					gap: 8px;
+					align-items: center;
+					
+					.candidate-position {
+						font-size: 12px;
+						color: var(--el-text-color-secondary);
+					}
+					
+					.candidate-status {
+						font-size: 12px;
+						padding: 2px 6px;
+						border-radius: 12px;
+						
+						&.status-pending {
+							background: #e6f4ff;
+							color: #1890ff;
+						}
+						
+						&.status-interviewed {
+							background: #fff7e6;
+							color: #fa8c16;
+						}
+						
+						&.status-hired {
+							background: #f6ffed;
+							color: #52c41a;
+						}
+						
+						&.status-rejected {
+							background: #fff2f0;
+							color: #ff4d4f;
+						}
+						
+						&.status-unknown {
+							background: #f5f5f5;
+							color: #999;
+						}
+					}
+				}
+			}
+			
+			.candidate-time {
+				font-size: 12px;
+				color: var(--el-text-color-secondary);
+				white-space: nowrap;
+			}
+		}
+		
+		.more-candidates {
+			text-align: center;
+			padding: 10px 0;
+			border-top: 1px solid var(--el-border-color-lighter);
+			margin-top: 5px;
 		}
 	}
 }