修复竞争比和按钮问题
This commit is contained in:
@@ -4,6 +4,8 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>职位信息爬虫工具</title>
|
||||
<!-- SheetJS库用于导出XLSX -->
|
||||
<script src="/static/js/xlsx.full.min.js"></script>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
@@ -331,7 +333,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="action-buttons">
|
||||
<button class="btn" onclick="fetchAllPositions()">自动抓取全部职位</button>
|
||||
<button class="btn" id="fetch-all-btn" onclick="debouncedFetchAllPositions()">自动抓取全部职位</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -339,7 +341,7 @@
|
||||
<div class="form-section">
|
||||
<h2>职位信息结果</h2>
|
||||
<div class="action-buttons" style="margin-bottom: 15px;">
|
||||
<button class="btn btn-secondary" id="export-btn" onclick="exportCsv()" disabled>导出CSV</button>
|
||||
<button class="btn btn-secondary" id="export-btn" onclick="exportXlsx()" disabled>导出XLSX</button>
|
||||
</div>
|
||||
<div id="result-message"></div>
|
||||
<div class="table-container" id="result-table" style="display: none;">
|
||||
@@ -372,6 +374,24 @@
|
||||
let lastResults = [];
|
||||
let isCrawling = false; // 爬取状态标志
|
||||
|
||||
// 防抖函数
|
||||
function debounce(func, wait) {
|
||||
let timeout;
|
||||
return function executedFunction(...args) {
|
||||
const later = () => {
|
||||
clearTimeout(timeout);
|
||||
func(...args);
|
||||
};
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(later, wait);
|
||||
};
|
||||
}
|
||||
|
||||
// 防抖包装的抓取函数(300ms防抖)
|
||||
const debouncedFetchAllPositions = debounce(() => {
|
||||
fetchAllPositions();
|
||||
}, 300);
|
||||
|
||||
// 页面加载时自动加载用户配置
|
||||
window.onload = function() {
|
||||
loadUserConfig();
|
||||
@@ -710,6 +730,12 @@
|
||||
|
||||
// 自动抓取全部职位代码并逐条获取详情(流式展示,避免超时)
|
||||
async function fetchAllPositions() {
|
||||
// 如果正在爬取,直接返回
|
||||
if (isCrawling) {
|
||||
showMessage('result-message', '正在爬取中,请勿重复点击', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
const selectedDsdm = getSelectedDsdm();
|
||||
const examid = document.getElementById('examid').value.trim();
|
||||
const bmid = document.getElementById('bmid').value.trim();
|
||||
@@ -733,10 +759,19 @@
|
||||
return;
|
||||
}
|
||||
|
||||
// 开始爬取,禁用导出按钮
|
||||
// 开始爬取,禁用所有相关按钮
|
||||
isCrawling = true;
|
||||
document.getElementById('export-btn').disabled = true;
|
||||
document.getElementById('export-btn').textContent = '爬取中...';
|
||||
const fetchBtnStart = document.getElementById('fetch-all-btn');
|
||||
const exportBtnStart = document.getElementById('export-btn');
|
||||
|
||||
if (fetchBtnStart) {
|
||||
fetchBtnStart.disabled = true;
|
||||
fetchBtnStart.textContent = '爬取中...';
|
||||
}
|
||||
if (exportBtnStart) {
|
||||
exportBtnStart.disabled = true;
|
||||
exportBtnStart.textContent = '爬取中...';
|
||||
}
|
||||
|
||||
// 清空旧数据
|
||||
lastResults = [];
|
||||
@@ -796,20 +831,22 @@
|
||||
|
||||
// 爬取完成,恢复按钮状态
|
||||
isCrawling = false;
|
||||
document.getElementById('export-btn').disabled = false;
|
||||
document.getElementById('export-btn').textContent = '导出CSV';
|
||||
showMessage('result-message', `爬取完成!共处理 ${processedCodes} 个职位`, 'success');
|
||||
|
||||
showMessage('result-message', `完成,共 ${lastResults.length} 条成功,失败 ${codes.length - lastResults.length} 条`, 'success');
|
||||
const fetchBtnEnd = document.getElementById('fetch-all-btn');
|
||||
const exportBtnEnd = document.getElementById('export-btn');
|
||||
|
||||
// 爬取完成,启用导出按钮
|
||||
isCrawling = false;
|
||||
document.getElementById('export-btn').disabled = false;
|
||||
document.getElementById('export-btn').textContent = '导出CSV';
|
||||
if (fetchBtnEnd) {
|
||||
fetchBtnEnd.disabled = false;
|
||||
fetchBtnEnd.textContent = '自动抓取全部职位';
|
||||
}
|
||||
if (exportBtnEnd) {
|
||||
exportBtnEnd.disabled = false;
|
||||
exportBtnEnd.textContent = '导出XLSX';
|
||||
}
|
||||
showMessage('result-message', `爬取完成!共处理 ${processedCodes} 个职位`, 'success');
|
||||
}
|
||||
|
||||
// 导出CSV
|
||||
function exportCsv() {
|
||||
// 导出XLSX
|
||||
function exportXlsx() {
|
||||
if (isCrawling) {
|
||||
showMessage('result-message', '爬取进行中,请等待完成后再导出', 'error');
|
||||
return;
|
||||
@@ -818,8 +855,17 @@
|
||||
showMessage('result-message', '暂无数据可导出', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查SheetJS库是否加载
|
||||
if (typeof XLSX === 'undefined') {
|
||||
showMessage('result-message', '导出库加载失败,请刷新页面重试', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
// 准备数据
|
||||
const headers = ['省份','地区','招聘单位/用人司局','职位名称','职位代码','招聘人数','审核通过人数','竞争比'];
|
||||
const lines = [headers.join(',')];
|
||||
const data = [headers];
|
||||
|
||||
lastResults.forEach(item => {
|
||||
const row = [
|
||||
item.sbmc || '',
|
||||
@@ -829,18 +875,58 @@
|
||||
item.zwdm || '',
|
||||
item.zprs || 0,
|
||||
item.bkrs || 0,
|
||||
item.competition_ratio || '0:0'
|
||||
item.competition_ratio || '0:0' // 使用与网页显示一致的竞争比格式
|
||||
];
|
||||
lines.push(row.map(v => `"${String(v).replace(/"/g, '""')}"`).join(','));
|
||||
data.push(row);
|
||||
});
|
||||
const blob = new Blob([lines.join('\n')], { type: 'text/csv;charset=utf-8;' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = 'positions.csv';
|
||||
link.click();
|
||||
URL.revokeObjectURL(url);
|
||||
showMessage('result-message', '已导出CSV', 'success');
|
||||
|
||||
// 创建工作簿
|
||||
const wb = XLSX.utils.book_new();
|
||||
const ws = XLSX.utils.aoa_to_sheet(data);
|
||||
|
||||
// 设置列宽
|
||||
const colWidths = [
|
||||
{ wch: 10 }, // 省份
|
||||
{ wch: 15 }, // 地区
|
||||
{ wch: 25 }, // 招聘单位/用人司局
|
||||
{ wch: 25 }, // 职位名称
|
||||
{ wch: 15 }, // 职位代码
|
||||
{ wch: 12 }, // 招聘人数
|
||||
{ wch: 15 }, // 审核通过人数
|
||||
{ wch: 12 } // 竞争比
|
||||
];
|
||||
ws['!cols'] = colWidths;
|
||||
|
||||
// 设置表头样式(如果需要)
|
||||
const headerRange = XLSX.utils.decode_range(ws['!ref']);
|
||||
for (let col = headerRange.s.c; col <= headerRange.e.c; col++) {
|
||||
const cellAddress = XLSX.utils.encode_cell({ r: 0, c: col });
|
||||
if (!ws[cellAddress]) continue;
|
||||
ws[cellAddress].s = {
|
||||
font: { bold: true },
|
||||
fill: { fgColor: { rgb: "E0E0E0" } },
|
||||
alignment: { horizontal: "center", vertical: "center" }
|
||||
};
|
||||
}
|
||||
|
||||
// 竞争比列设置为文本格式,防止被当作数字或日期
|
||||
const competitionColIndex = 7; // 第8列
|
||||
for (let r = 1; r < data.length; r++) { // 从第2行开始,跳过表头
|
||||
const addr = XLSX.utils.encode_cell({ r, c: competitionColIndex });
|
||||
if (ws[addr]) {
|
||||
ws[addr].t = 's';
|
||||
ws[addr].z = '@';
|
||||
}
|
||||
}
|
||||
|
||||
// 将工作表添加到工作簿
|
||||
XLSX.utils.book_append_sheet(wb, ws, '职位信息');
|
||||
|
||||
// 导出文件
|
||||
const fileName = 'positions_' + new Date().toISOString().slice(0, 10).replace(/-/g, '') + '.xlsx';
|
||||
XLSX.writeFile(wb, fileName);
|
||||
|
||||
showMessage('result-message', '已导出XLSX', 'success');
|
||||
}
|
||||
|
||||
// 显示消息
|
||||
|
||||
Reference in New Issue
Block a user