yangg 2 月之前
父节点
当前提交
67e03b33de

+ 5 - 1
src/views/JobApplication/list/components/smSnotification.vue

@@ -534,7 +534,11 @@ const processedTemplate = computed(() => {
   // 替换模板中的变量
   template = template.replace(/\${name}/g, editForm.candidateName || '');
   template = template.replace(/\${job}/g, editForm.position || '');
-  
+  template = template.replace(/\${company}/g, '')
+  template = template.replace(/\${date}/g, '')
+  template = template.replace(/\${code}/g, '')//${code}
+  template = template.replace(/\${time}/g, '')
+  console.log(Session.get('userInfo'));
   return template;
 });
 </script>

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

@@ -102,11 +102,11 @@
 									Authorization: `Bearer ${Session.get('token')}`
 								}"
 								:on-success="handleImportSuccess"
-								:on-error="handleImportError"
+								:on-error="handleImportError"D
 								accept=".xlsx,.xls"
 							>
 								<el-button type="primary" size="small">
-									<el-icon><Upload /></el-icon>
+									<el-icon><Download /></el-icon>
 									导入
 								</el-button>
 							</el-upload>

+ 43 - 3
src/views/system/home/index.vue

@@ -20,8 +20,8 @@
 											<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>
+											<span class="todo-tag">{{ getPendingCandidatesCount() }}位候选人待处理</span>
+											<span class="todo-text">{{ getLatestApplicationTime() }}</span>
 										</div>
 									</div>
 									<div class="todo-item-right">
@@ -131,7 +131,7 @@
 						<p style="margin-top: 20px; font-size: 12px;  color:#808080;">通过情况概览</p>
 						<div class="demo-collapse">
 							<el-collapse v-model="activeCollapse">
-								<el-collapse-item :title="`在此期间共计${Math.min(filteredCandidates.filter(c => Number(c.comprehensive_score) > 60).length, 5)} 位候选人${selectedStatus==2?'通过面试':'被录用'}`" name="1">
+								<el-collapse-item :title="`在此期间共计${Math.min(filteredCandidates.filter(c => Number(c.comprehensive_score) > 60).length, 5)} 位候选人${selectedStatus==='2'?'通过面试':'被录用'}`" name="1">
 									<div class="score-list">
 										<div class="score-item clickable-item" v-for="item in filteredCandidates.filter(c => Number(c.comprehensive_score) > 60).slice(0, 5)" :key="item.id" @click="handleCandidateClick(item)">
 											<div class="score-name">{{ item.applicant_name || item.name }}</div>
@@ -1018,6 +1018,44 @@ export default defineComponent({
 			}
 		};
 		
+		// 获取待处理候选人数量
+		const getPendingCandidatesCount = () => {
+			if (!state.filteredCandidates || state.filteredCandidates.length === 0) {
+				return 0;
+			}
+			// 统计状态为2(已面试)的候选人数量
+			return state.filteredCandidates.filter(candidate => 
+				candidate.status === 2 || candidate.status === '2'
+			).length;
+		};
+
+		// 获取最新投递时间
+		const getLatestApplicationTime = () => {
+			if (!state.filteredCandidates || state.filteredCandidates.length === 0) {
+				return '暂无投递';
+			}
+
+			// 找到最新的投递时间
+			const latestApplication = state.filteredCandidates.reduce((latest, current) => {
+				const currentTime = current.created_at || current.application_time || '';
+				const latestTime = latest.created_at || latest.application_time || '';
+				const currentDate = new Date(currentTime);
+				const latestDate = new Date(latestTime);
+				return currentDate > latestDate ? current : latest;
+			});
+
+			const date = new Date();
+			
+			// 格式化为"YYYY年MM月DD日 HH:mm"
+			const year = date.getFullYear();
+			const month = (date.getMonth() + 1).toString().padStart(2, '0');
+			const day = date.getDate().toString().padStart(2, '0');
+			const hours = date.getHours().toString().padStart(2, '0');
+			const minutes = date.getMinutes().toString().padStart(2, '0');
+			console.log(year,month,day,hours,minutes)
+			return `${year}年${month}月${day}日 ${hours}:${minutes}最新投递`;
+		};
+
 		return {
 			homeLineRef,
 			homePieRef,
@@ -1031,6 +1069,8 @@ export default defineComponent({
 			getStatusClass,
 			formatTime,
 			passRate,
+			getLatestApplicationTime,
+			getPendingCandidatesCount,
 			...toRefs(state),
 		};
 	},

+ 59 - 16
src/views/talent/list/crud.tsx

@@ -212,23 +212,66 @@ export const createCrudOptions = function ({ crudExpose, context}: CreateCrudOpt
 									tenant_id: Session.get('tenant_id'),
 									status: '1,2,3,4,5',
 								});
-								console.log(response);
-								if (response.code === 2000 ) {
-									// 从响应中获取下载链接和文件名
+
+								if (response.code === 2000) {
 									const downloadUrl = response.data.minio_url;
-									const fileName = response.data.file_name;
-									
-									// 创建一个隐藏的a标签来触发下载
-									const link = document.createElement('a');
-									link.href = downloadUrl;
-									link.download = fileName; // 设置下载文件名
-									link.target = '_blank';
-									link.style.display = 'none';
-									document.body.appendChild(link);
-									link.click();
-									document.body.removeChild(link);
-									
-									successMessage('导出成功,文件开始下载');
+									let fileName = response.data.file_name;
+
+									// 处理文件名中的特殊字符
+									fileName = decodeURIComponent(fileName).replace(/[<>:"/\\|?*]+/g, '_');
+
+									// 使用 Blob 处理下载
+									try {
+										const blob = await fetch(downloadUrl).then(res => res.blob());
+										
+										// 根据文件扩展名设置正确的 MIME 类型
+										const fileExtension = fileName.split('.').pop()?.toLowerCase();
+										let mimeType = 'application/octet-stream'; // 默认类型
+										
+										if (fileExtension === 'xlsx' || fileExtension === 'xls') {
+											mimeType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
+										} else if (fileExtension === 'csv') {
+											mimeType = 'text/csv';
+										}
+
+										const blobUrl = window.URL.createObjectURL(new Blob([blob], { type: mimeType }));
+										
+										// 创建下载链接
+										const link = document.createElement('a');
+										link.href = blobUrl;
+										link.download = fileName;
+										link.style.display = 'none';
+										
+										// 兼容不同浏览器的下载方式
+										if (window.navigator.msSaveOrOpenBlob) {
+											// IE10+
+											window.navigator.msSaveOrOpenBlob(blob, fileName);
+										} else {
+											// 其他现代浏览器
+											document.body.appendChild(link);
+											
+											if (link.click) {
+												link.click();
+											} else {
+												// 触发点击的备选方案
+												const event = document.createEvent('MouseEvents');
+												event.initEvent('click', true, true);
+												link.dispatchEvent(event);
+											}
+											
+											document.body.removeChild(link);
+										}
+										
+										// 清理 Blob URL
+										setTimeout(() => {
+											window.URL.revokeObjectURL(blobUrl);
+										}, 100);
+
+										successMessage('导出成功,文件开始下载');
+									} catch (fetchError) {
+										console.error('下载文件失败:', fetchError);
+										warningMessage('下载文件失败,请检查网络连接');
+									}
 								} else {
 									warningMessage('导出失败:' + (response.msg || '未知错误'));
 								}

+ 58 - 16
src/views/talent/overseas/crud.tsx

@@ -215,23 +215,65 @@ export const createCrudOptions = function ({ crudExpose, context}: CreateCrudOpt
 									tenant_id: Session.get('tenant_id'),
 									status: '6,7',
 								});
-								console.log(response);
-								if (response.code === 2000 ) {
-									// 从响应中获取下载链接和文件名
+								if (response.code === 2000) {
 									const downloadUrl = response.data.minio_url;
-									const fileName = response.data.file_name;
-									
-									// 创建一个隐藏的a标签来触发下载
-									const link = document.createElement('a');
-									link.href = downloadUrl;
-									link.download = fileName; // 设置下载文件名
-									link.target = '_blank';
-									link.style.display = 'none';
-									document.body.appendChild(link);
-									link.click();
-									document.body.removeChild(link);
-									
-									successMessage('导出成功,文件开始下载');
+									let fileName = response.data.file_name;
+
+									// 处理文件名中的特殊字符
+									fileName = decodeURIComponent(fileName).replace(/[<>:"/\\|?*]+/g, '_');
+
+									// 使用 Blob 处理下载
+									try {
+										const blob = await fetch(downloadUrl).then(res => res.blob());
+										
+										// 根据文件扩展名设置正确的 MIME 类型
+										const fileExtension = fileName.split('.').pop()?.toLowerCase();
+										let mimeType = 'application/octet-stream'; // 默认类型
+										
+										if (fileExtension === 'xlsx' || fileExtension === 'xls') {
+											mimeType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
+										} else if (fileExtension === 'csv') {
+											mimeType = 'text/csv';
+										}
+
+										const blobUrl = window.URL.createObjectURL(new Blob([blob], { type: mimeType }));
+										
+										// 创建下载链接
+										const link = document.createElement('a');
+										link.href = blobUrl;
+										link.download = fileName;
+										link.style.display = 'none';
+										
+										// 兼容不同浏览器的下载方式
+										if (window.navigator.msSaveOrOpenBlob) {
+											// IE10+
+											window.navigator.msSaveOrOpenBlob(blob, fileName);
+										} else {
+											// 其他现代浏览器
+											document.body.appendChild(link);
+											
+											if (link.click) {
+												link.click();
+											} else {
+												// 触发点击的备选方案
+												const event = document.createEvent('MouseEvents');
+												event.initEvent('click', true, true);
+												link.dispatchEvent(event);
+											}
+											
+											document.body.removeChild(link);
+										}
+										
+										// 清理 Blob URL
+										setTimeout(() => {
+											window.URL.revokeObjectURL(blobUrl);
+										}, 100);
+
+										successMessage('导出成功,文件开始下载');
+									} catch (fetchError) {
+										console.error('下载文件失败:', fetchError);
+										warningMessage('下载文件失败,请检查网络连接');
+									}
 								} else {
 									warningMessage('导出失败:' + (response.msg || '未知错误'));
 								}