岗位聚合

校招 & 体制内岗位一站式聚合,精准匹配你的职业方向

加载中...

// State let currentCategory = 'campus'; let currentPage = 1; let cascadeState = { province: '', city: '', district: '', step: 0 }; let filterOptions = { industries: [], cities: [], batch_names: [], company_types: [] }; // 中国行政区划数据(省→市→区县 三级级联) const CHINA_REGIONS = { "北京市":{"c":["东城区","西城区","朝阳区","丰台区","石景山区","海淀区","门头沟区","房山区","通州区","顺义区","昌平区","大兴区","怀柔区","平谷区","密云区","延庆区"]}, "上海市":{"c":["黄浦区","徐汇区","长宁区","静安区","普陀区","虹口区","杨浦区","闵行区","宝山区","嘉定区","浦东新区","金山区","松江区","青浦区","奉贤区","崇明区"]}, "天津市":{"c":["和平区","河东区","河西区","南开区","河北区","红桥区","东丽区","西青区","津南区","北辰区","武清区","宝坻区","滨海新区","宁河区","静海区","蓟州区"]}, "重庆市":{"c":["万州区","涪陵区","渝中区","大渡口区","江北区","沙坪坝区","九龙坡区","南岸区","北碚区","綦江区","大足区","渝北区","巴南区","黔江区","长寿区","江津区","合川区","永川区","南川区","璧山区","铜梁区","潼南区","荣昌区","开州区","梁平区","武隆区"]}, "河北省":{"石家庄市":{"c":["长安区","桥西区","新华区","井陉矿区","裕华区","藁城区","鹿泉区","栾城区"]},"唐山市":{},"秦皇岛市":{},"邯郸市":{},"邢台市":{},"保定市":{},"张家口市":{},"承德市":{},"沧州市":{},"廊坊市":{},"衡水市":{}}, "山西省":{"太原市":{"c":["小店区","迎泽区","杏花岭区","尖草坪区","万柏林区","晋源区"]},"大同市":{},"阳泉市":{},"长治市":{},"晋城市":{},"朔州市":{},"晋中市":{},"运城市":{},"忻州市":{},"临汾市":{},"吕梁市":{}}, "内蒙古自治区":{"呼和浩特市":{},"包头市":{},"乌海市":{},"赤峰市":{},"通辽市":{},"鄂尔多斯市":{},"呼伦贝尔市":{},"巴彦淖尔市":{},"乌兰察布市":{}}, "辽宁省":{"沈阳市":{"c":["和平区","沈河区","大东区","皇姑区","铁西区","苏家屯区","浑南区","沈北新区","于洪区","辽中区"]},"大连市":{"c":["中山区","西岗区","沙河口区","甘井子区","旅顺口区","金州区","普兰店区"]},"鞍山市":{},"抚顺市":{},"本溪市":{},"丹东市":{},"锦州市":{},"营口市":{},"阜新市":{},"辽阳市":{},"盘锦市":{},"铁岭市":{},"朝阳市":{},"葫芦岛市":{}}, "吉林省":{"长春市":{},"吉林市":{},"四平市":{},"辽源市":{},"通化市":{},"白山市":{},"松原市":{},"白城市":{},"延边朝鲜族自治州":{}}, "黑龙江省":{"哈尔滨市":{},"齐齐哈尔市":{},"鸡西市":{},"鹤岗市":{},"双鸭山市":{},"大庆市":{},"伊春市":{},"佳木斯市":{},"七台河市":{},"牡丹江市":{},"黑河市":{},"绥化市":{}}, "江苏省":{"南京市":{"c":["玄武区","秦淮区","建邺区","鼓楼区","浦口区","栖霞区","雨花台区","江宁区","六合区","溧水区","高淳区"]},"无锡市":{},"徐州市":{},"常州市":{},"苏州市":{"c":["虎丘区","吴中区","相城区","姑苏区","吴江区","苏州工业园区"]},"南通市":{},"连云港市":{},"淮安市":{},"盐城市":{},"扬州市":{},"镇江市":{},"泰州市":{},"宿迁市":{}}, "浙江省":{"杭州市":{"c":["上城区","拱墅区","西湖区","滨江区","萧山区","余杭区","富阳区","临安区","临平区","钱塘区"]},"宁波市":{},"温州市":{},"嘉兴市":{},"湖州市":{},"绍兴市":{},"金华市":{},"衢州市":{},"舟山市":{},"台州市":{},"丽水市":{}}, "安徽省":{"合肥市":{"c":["瑶海区","庐阳区","蜀山区","包河区"]},"芜湖市":{},"蚌埠市":{},"淮南市":{},"马鞍山市":{},"淮北市":{},"铜陵市":{},"安庆市":{},"黄山市":{},"滁州市":{},"阜阳市":{},"宿州市":{},"六安市":{},"亳州市":{},"池州市":{},"宣城市":{}}, "福建省":{"福州市":{},"厦门市":{},"莆田市":{},"三明市":{},"泉州市":{},"漳州市":{},"南平市":{},"龙岩市":{},"宁德市":{}}, "江西省":{"南昌市":{},"景德镇市":{},"萍乡市":{},"九江市":{},"新余市":{},"鹰潭市":{},"赣州市":{},"吉安市":{},"宜春市":{},"抚州市":{},"上饶市":{}}, "山东省":{"济南市":{"c":["历下区","市中区","槐荫区","天桥区","历城区","长清区","章丘区","济阳区","莱芜区","钢城区"]},"青岛市":{},"淄博市":{},"枣庄市":{},"东营市":{},"烟台市":{},"潍坊市":{},"济宁市":{},"泰安市":{},"威海市":{},"日照市":{},"临沂市":{},"德州市":{},"聊城市":{},"滨州市":{},"菏泽市":{}}, "河南省":{"郑州市":{"c":["中原区","二七区","管城回族区","金水区","上街区","惠济区"]},"开封市":{},"洛阳市":{},"平顶山市":{},"安阳市":{},"鹤壁市":{},"新乡市":{"c":["红旗区","卫滨区","凤泉区","牧野区","新乡县","获嘉县","原阳县","延津县","封丘县","长垣市","卫辉市","辉县市"]},"焦作市":{},"濮阳市":{},"许昌市":{},"漯河市":{},"三门峡市":{},"南阳市":{},"商丘市":{},"信阳市":{},"周口市":{},"驻马店市":{},"济源市":{}}, "湖北省":{"武汉市":{"c":["江岸区","江汉区","硚口区","汉阳区","武昌区","青山区","洪山区","东西湖区","汉南区","蔡甸区","江夏区","黄陂区","新洲区"]},"黄石市":{},"十堰市":{},"宜昌市":{},"襄阳市":{},"鄂州市":{},"荆门市":{},"孝感市":{},"荆州市":{},"黄冈市":{},"咸宁市":{},"随州市":{},"恩施土家族苗族自治州":{}}, "湖南省":{"长沙市":{},"株洲市":{},"湘潭市":{},"衡阳市":{},"邵阳市":{},"岳阳市":{},"常德市":{},"张家界市":{},"益阳市":{},"郴州市":{},"永州市":{},"怀化市":{},"娄底市":{},"湘西土家族苗族自治州":{}}, "广东省":{"广州市":{"c":["越秀区","海珠区","荔湾区","天河区","白云区","黄埔区","花都区","番禺区","南沙区","从化区","增城区"]},"深圳市":{"c":["罗湖区","福田区","南山区","宝安区","龙岗区","盐田区","龙华区","坪山区","光明区"]},"珠海市":{},"汕头市":{},"佛山市":{},"韶关市":{},"湛江市":{},"肇庆市":{},"江门市":{},"茂名市":{},"惠州市":{},"梅州市":{},"汕尾市":{},"河源市":{},"阳江市":{},"清远市":{},"东莞市":{},"中山市":{},"潮州市":{},"揭阳市":{},"云浮市":{}}, "广西壮族自治区":{"南宁市":{},"柳州市":{},"桂林市":{},"梧州市":{},"北海市":{},"防城港市":{},"钦州市":{},"贵港市":{},"玉林市":{},"百色市":{},"贺州市":{},"河池市":{},"来宾市":{},"崇左市":{}}, "海南省":{"海口市":{},"三亚市":{},"三沙市":{},"儋州市":{}}, "四川省":{"成都市":{"c":["锦江区","青羊区","金牛区","武侯区","成华区","龙泉驿区","青白江区","新都区","双流区","郫都区","温江区","新津区"]},"自贡市":{},"攀枝花市":{},"泸州市":{},"德阳市":{},"绵阳市":{},"广元市":{},"遂宁市":{},"内江市":{},"乐山市":{},"南充市":{},"眉山市":{},"宜宾市":{},"广安市":{},"达州市":{},"雅安市":{},"巴中市":{},"资阳市":{}}, "贵州省":{"贵阳市":{},"六盘水市":{},"遵义市":{},"安顺市":{},"毕节市":{},"铜仁市":{}}, "云南省":{"昆明市":{},"曲靖市":{},"玉溪市":{},"保山市":{},"昭通市":{},"丽江市":{},"普洱市":{},"临沧市":{}}, "西藏自治区":{"拉萨市":{},"日喀则市":{},"昌都市":{},"林芝市":{},"山南市":{},"那曲市":{}}, "陕西省":{"西安市":{"c":["新城区","碑林区","莲湖区","未央区","雁塔区","阎良区","临潼区","长安区","高陵区","鄠邑区"]},"铜川市":{},"宝鸡市":{},"咸阳市":{},"渭南市":{},"延安市":{},"汉中市":{},"榆林市":{},"安康市":{},"商洛市":{}}, "甘肃省":{"兰州市":{},"嘉峪关市":{},"金昌市":{},"白银市":{},"天水市":{},"武威市":{},"张掖市":{},"平凉市":{},"酒泉市":{},"庆阳市":{},"定西市":{},"陇南市":{}}, "青海省":{"西宁市":{},"海东市":{}}, "宁夏回族自治区":{"银川市":{},"石嘴山市":{},"吴忠市":{},"固原市":{},"中卫市":{}}, "新疆维吾尔自治区":{"乌鲁木齐市":{},"克拉玛依市":{},"吐鲁番市":{},"哈密市":{}}, "台湾省":{"台北市":{},"高雄市":{},"台中市":{},"台南市":{},"基隆市":{},"新竹市":{},"嘉义市":{}}, "香港特别行政区":{"c":["中西区","湾仔区","东区","南区","油尖旺区","深水埗区","九龙城区","黄大仙区","观塘区","荃湾区","屯门区","元朗区","北区","大埔区","沙田区","西贡区","离岛区"]}, "澳门特别行政区":{"c":["花地玛堂区","花王堂区","望德堂区","大堂区","风顺堂区"]} }; // Init document.addEventListener('DOMContentLoaded', () => { if (window.SmartCV) SmartCV.updateNavUser(); loadFilters(); loadJobs(); }); function switchCategory(cat) { currentCategory = cat; currentPage = 1; document.getElementById('tab-campus').classList.toggle('active', cat === 'campus'); document.getElementById('tab-gov').classList.toggle('active', cat === 'gov'); loadJobs(); } async function loadFilters() { try { const data = await SmartCV.api.get('/jobs/filters'); filterOptions = { industries: data.industries || [], cities: data.cities || [], batch_names: data.batch_names || [], company_types: data.company_types || [] }; // Populate batch select const batchSel = document.getElementById('batch-select'); filterOptions.batch_names.forEach(b => { const opt = document.createElement('option'); opt.value = b; opt.textContent = b; batchSel.appendChild(opt); }); // Populate company type select const ctSel = document.getElementById('company-type-select'); filterOptions.company_types.forEach(ct => { const opt = document.createElement('option'); opt.value = ct; opt.textContent = ct; ctSel.appendChild(opt); }); // Cascade city selector is built dynamically on click } catch (e) { console.error('Failed to load filters:', e); } } // --- 省市区级联逻辑 (单一多级下拉) --- function toggleCascade() { var panel = document.getElementById('cascade-panel'); var arrow = document.getElementById('cascade-arrow'); if (panel.classList.contains('hidden')) { panel.classList.remove('hidden'); arrow.style.transform = 'rotate(180deg)'; renderCascadeLevel(0); } else { closeCascadePanel(); } } function closeCascadePanel() { document.getElementById('cascade-panel').classList.add('hidden'); document.getElementById('cascade-arrow').style.transform = 'rotate(0deg)'; } function renderCascadeLevel(level) { var backBtn = document.getElementById('cascade-back'); var headerText = document.getElementById('cascade-header-text'); var optionsDiv = document.getElementById('cascade-options'); cascadeState.step = level; if (level === 0) { backBtn.classList.add('hidden'); headerText.textContent = '选择省份'; var provinces = Object.keys(CHINA_REGIONS).sort(function(a, b) { return a.localeCompare(b, 'zh'); }); var html = '
全部省份
'; provinces.forEach(function(p) { var cls = cascadeState.province === p ? ' selected' : ''; var check = cascadeState.province === p ? '' : ''; html += '
' + p + '' + check + '
'; }); html += '
'; optionsDiv.innerHTML = html; } else if (level === 1) { backBtn.classList.remove('hidden'); headerText.textContent = cascadeState.province; var cities = CHINA_REGIONS[cascadeState.province]; var cityNames = Object.keys(cities).sort(function(a, b) { return a.localeCompare(b, 'zh'); }); var html = '
全部城市
'; cityNames.forEach(function(c) { var cls = cascadeState.city === c ? ' selected' : ''; var check = cascadeState.city === c ? '' : ''; html += '
' + c + '' + check + '
'; }); html += '
'; optionsDiv.innerHTML = html; } else if (level === 2) { backBtn.classList.remove('hidden'); headerText.textContent = cascadeState.city; var cityData = CHINA_REGIONS[cascadeState.province] && CHINA_REGIONS[cascadeState.province][cascadeState.city]; var districts = (cityData && cityData.c) ? cityData.c : []; var html = '
全部区县
'; districts.forEach(function(d) { var cls = cascadeState.district === d ? ' selected' : ''; var check = cascadeState.district === d ? '' : ''; html += '
' + d + '' + check + '
'; }); html += '
'; optionsDiv.innerHTML = html; } optionsDiv.scrollTop = 0; } function selectProvince(province) { cascadeState.province = province; cascadeState.city = ''; cascadeState.district = ''; if (!province) { closeCascadePanel(); updateCascadeButton(); loadJobs(); return; } renderCascadeLevel(1); } function selectCity(city) { cascadeState.city = city; cascadeState.district = ''; if (!city) { closeCascadePanel(); updateCascadeButton(); loadJobs(); return; } var cityData = CHINA_REGIONS[cascadeState.province] && CHINA_REGIONS[cascadeState.province][city]; if (!cityData || !cityData.c || cityData.c.length === 0) { closeCascadePanel(); updateCascadeButton(); loadJobs(); return; } renderCascadeLevel(2); } function selectDistrict(district) { cascadeState.district = district; closeCascadePanel(); updateCascadeButton(); loadJobs(); } function cascadeBack() { if (cascadeState.step === 2) { cascadeState.district = ''; renderCascadeLevel(1); } else if (cascadeState.step === 1) { cascadeState.city = ''; renderCascadeLevel(0); } } function updateCascadeButton() { var btnText = document.getElementById('cascade-btn-text'); if (cascadeState.district) { btnText.textContent = cascadeState.district; btnText.className = 'text-slate-900 dark:text-white'; } else if (cascadeState.city) { btnText.textContent = cascadeState.city; btnText.className = 'text-slate-900 dark:text-white'; } else if (cascadeState.province) { btnText.textContent = cascadeState.province; btnText.className = 'text-slate-900 dark:text-white'; } else { btnText.textContent = '全部城市'; btnText.className = 'text-slate-400'; } } // Click outside to close cascade panel document.addEventListener('click', function(e) { var panel = document.getElementById('cascade-panel'); if (panel && !panel.classList.contains('hidden') && !e.target.closest('.cascade-container')) { closeCascadePanel(); } }); // Get all city/district names for a province from CHINA_REGIONS function getProvinceCities(provinceName) { var data = CHINA_REGIONS[provinceName]; if (!data) { // Try with suffix data = CHINA_REGIONS[provinceName + '市'] || CHINA_REGIONS[provinceName + '省']; } if (!data) return []; // Direct-controlled municipality (has 'c' array directly) if (data.c && Object.keys(data).length === 1) { return [provinceName.replace(/省|市|自治区|壮族|回族|维吾尔/g, '')]; } // Normal province with cities as keys — strip "市" suffix to match DB short names var keys = Object.keys(data); if (keys.length === 1 && keys[0] === 'c') { return [provinceName.replace(/省|市|自治区|壮族|回族|维吾尔/g, '')]; } return keys.map(function(k) { return k.replace(/市$/, ''); }); } // Build city parameter: level 0=exact, 1=broaden (all province cities), 2=nationwide function buildCityParam(level) { if (level >= 2) return null; if (level === 1 && cascadeState.province) { // Broaden to all cities in the province (or municipality name) var cities = getProvinceCities(cascadeState.province); if (cities.length > 0) return cities.join(','); } // level 0 (exact match) — strip "市" suffix to match DB short names like "南京" if (cascadeState.district) return cascadeState.district; if (cascadeState.city) return cascadeState.city.replace(/市$/, ''); if (cascadeState.province) { return cascadeState.province.replace(/省|市|自治区|壮族|回族|维吾尔/g, ''); } return null; } function hasCityFilter() { return !!(cascadeState.province || cascadeState.city || cascadeState.district); } async function loadJobs() { const loading = document.getElementById('loading-spinner'); loading.classList.remove('hidden'); const params = new URLSearchParams(); params.set('category', currentCategory); params.set('page', currentPage); params.set('page_size', '20'); const batchName = document.getElementById('batch-select').value; if (batchName) params.set('batch_name', batchName); const companyType = document.getElementById('company-type-select').value; if (companyType) params.set('company_type', companyType); const education = document.getElementById('education-select').value; if (education) params.set('education', education); const keyword = document.getElementById('keyword-input').value.trim(); if (keyword) params.set('keyword', keyword); const sortBy = document.getElementById('sort-select').value; params.set('sort_by', sortBy); try { // Level 0: exact cascade match var cityParam = buildCityParam(0); if (cityParam) params.set('city', cityParam); var data = await SmartCV.api.get('/jobs?' + params.toString()); var usedLevel = 0; // Fallback: if 0 results and has city filter if (data.total === 0 && hasCityFilter()) { // Level 1: broaden (district→city, city→province cities) params.set('city', buildCityParam(1)); data = await SmartCV.api.get('/jobs?' + params.toString()); usedLevel = 1; // Level 2: nationwide (remove city filter) if (data.total === 0) { params.delete('city'); data = await SmartCV.api.get('/jobs?' + params.toString()); usedLevel = 2; } } renderJobs(data); loadApplicationStatuses(data.items); // Show fallback hint var hint = ''; if (usedLevel > 0 && data.total > 0) { var origCity = buildCityParam(0) || ''; if (usedLevel === 1) { hint = '(' + SmartCV.escapeHtml(origCity) + '暂无岗位,已扩展搜索范围)'; } else if (usedLevel === 2) { hint = '(' + SmartCV.escapeHtml(origCity) + '暂无岗位,已显示全国岗位)'; } } document.getElementById('result-count').textContent = '共 ' + data.total + ' 个岗位' + hint; } catch (e) { console.error('Failed to load jobs:', e); document.getElementById('result-count').textContent = '加载失败,请重试'; document.getElementById('job-list').innerHTML = '

加载失败,请刷新页面重试

'; } finally { loading.classList.add('hidden'); } } async function loadApplicationStatuses(items) { if (!SmartCV.auth.isLoggedIn()) return; if (!items || items.length === 0) return; try { var data = await SmartCV.api.get('/applications?status=all&page=1&page_size=100'); if (!data || !data.items) return; var statusMap = {}; for (var i = 0; i < data.items.length; i++) { if (data.items[i].job_posting_id) { statusMap[data.items[i].job_posting_id] = data.items[i].status; } } var badges = document.querySelectorAll('.job-status-badge'); var STATUS_STYLES = { interested: 'bg-blue-50 dark:bg-blue-900/20 text-blue-600 dark:text-blue-400 border-blue-200 dark:border-blue-800', preparing: 'bg-amber-50 dark:bg-amber-900/20 text-amber-600 dark:text-amber-400 border-amber-200 dark:border-amber-800', applied: 'bg-emerald-50 dark:bg-emerald-900/20 text-emerald-600 dark:text-emerald-400 border-emerald-200 dark:border-emerald-800', interview: 'bg-purple-50 dark:bg-purple-900/20 text-purple-600 dark:text-purple-400 border-purple-200 dark:border-purple-800', offer: 'bg-rose-50 dark:bg-rose-900/20 text-rose-600 dark:text-rose-400 border-rose-200 dark:border-rose-800', rejected: 'bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 border-red-200 dark:border-red-800', withdrawn: 'bg-slate-50 dark:bg-slate-800 text-slate-500 dark:text-slate-400 border-slate-200 dark:border-slate-700', expired: 'bg-slate-50 dark:bg-slate-800 text-slate-500 dark:text-slate-400 border-slate-200 dark:border-slate-700' }; var STATUS_LABELS = { interested: '感兴趣', preparing: '准备中', applied: '已投递', interview: '面试中', offer: '已录用', rejected: '未通过', withdrawn: '已取消', expired: '已过期' }; badges.forEach(function(badge) { var jobId = badge.getAttribute('data-job-id'); var status = statusMap[jobId]; if (status && STATUS_STYLES[status]) { badge.className = 'job-status-badge inline-block px-2 py-0.5 rounded-full text-xs font-medium border mb-1 ' + STATUS_STYLES[status]; badge.textContent = STATUS_LABELS[status] || status; badge.classList.remove('hidden'); } }); } catch (e) { // silently fail } } function renderJobs(data) { const container = document.getElementById('job-list'); if (!data.items || data.items.length === 0) { container.innerHTML = `

暂未找到匹配的岗位

试试调整筛选条件或切换分类

`; document.getElementById('pagination').innerHTML = ''; return; } container.innerHTML = data.items.map((job, i) => { const deadline = job.deadline ? new Date(job.deadline) : null; let deadlineClass = 'deadline-normal'; let deadlineText = '长期有效'; let daysLeft = null; if (deadline) { const today = new Date(); today.setHours(0, 0, 0, 0); const diffDays = Math.ceil((deadline - today) / (1000 * 60 * 60 * 24)); daysLeft = diffDays; if (diffDays < 0) { deadlineClass = 'deadline-urgent'; deadlineText = '已截止'; } else if (diffDays <= 3) { deadlineClass = 'deadline-urgent'; deadlineText = `剩余 ${diffDays} 天`; } else if (diffDays <= 7) { deadlineClass = 'deadline-soon'; deadlineText = `剩余 ${diffDays} 天`; } else { deadlineClass = 'deadline-normal'; deadlineText = `${job.deadline} 截止`; } } const tags = Array.isArray(job.tags) ? job.tags : []; const catLabel = job.category === 'campus' ? '校招' : '体制内'; return `
${catLabel} ${job.sub_category ? `${job.sub_category}` : ''} ${job.is_pinned ? ' 置顶' : ''}

${SmartCV.escapeHtml(job.title)}

${SmartCV.escapeHtml(job.company_name)} ${job.city ? `${SmartCV.escapeHtml(job.city)}` : ''} ${job.education_required ? `${SmartCV.escapeHtml(job.education_required)}` : ''} ${job.salary_range ? `${SmartCV.escapeHtml(job.salary_range)}` : ''}

${daysLeft !== null && daysLeft <= 3 && daysLeft >= 0 ? '' : ''} ${deadlineText}

${job.view_count || 0} 次浏览

${job.headcount ? `

招 ${job.headcount} 人

` : ''}
${tags.length > 0 ? `
${tags.map(t => `${SmartCV.escapeHtml(t)}`).join('')}
` : ''}
`; }).join(''); // Pagination - smart pagination with prev/next and window const pagDiv = document.getElementById('pagination'); if (data.total_pages <= 1) { pagDiv.innerHTML = ''; return; } const cp = data.page; // current page const tp = data.total_pages; // total pages const windowSize = 3; // pages to show on each side of current page let pages = []; // Always include page 1 pages.push(1); // Calculate range around current page let rangeStart = Math.max(2, cp - windowSize); let rangeEnd = Math.min(tp - 1, cp + windowSize); // Add ellipsis and first range boundary if (rangeStart > 2) { pages.push('...'); } // Add pages in range for (let p = rangeStart; p <= rangeEnd; p++) { pages.push(p); } // Add ellipsis and last page if (rangeEnd < tp - 1) { pages.push('...'); } // Always include last page (if > 1) if (tp > 1) { pages.push(tp); } let pagHTML = ''; // Prev button pagHTML += ``; // Page buttons for (const p of pages) { if (p === '...') { pagHTML += ''; } else if (p === cp) { pagHTML += `${p}`; } else { pagHTML += ``; } } // Next button pagHTML += ``; // Page info + jump to page pagHTML += `${cp} / ${tp} 页`; pagHTML += ``; pagDiv.innerHTML = pagHTML; } function goToPage(p) { currentPage = p; loadJobs(); // Scroll to job list area const jobList = document.getElementById('job-list'); if (jobList) { jobList.scrollIntoView({ behavior: 'smooth', block: 'start' }); } } function jumpToPage() { const input = document.getElementById('jump-page-input'); if (!input) return; let p = parseInt(input.value, 10); if (isNaN(p) || p < 1) { p = 1; } const maxPage = parseInt(input.max, 10); if (p > maxPage) { p = maxPage; } input.value = p; currentPage = p; loadJobs(); const jobList = document.getElementById('job-list'); if (jobList) { jobList.scrollIntoView({ behavior: 'smooth', block: 'start' }); } } // Subscribe Modal function openSubscribeModal() { if (!SmartCV.auth.isLoggedIn()) { window.location.href = '/auth.html?redirect=/jobs.html'; return; } document.getElementById('subscribe-modal').classList.remove('hidden'); document.getElementById('subscribe-modal').classList.add('flex'); document.getElementById('sub-name').value = ''; document.getElementById('sub-name').focus(); } function closeSubscribeModal() { document.getElementById('subscribe-modal').classList.add('hidden'); document.getElementById('subscribe-modal').classList.remove('flex'); } async function createSubscription() { const name = document.getElementById('sub-name').value.trim(); if (!name) { SmartCV.toast('请输入订阅名称', 'warning'); return; } const body = { name: name, category: currentCategory, batch_name: document.getElementById('batch-select').value || null, company_type: document.getElementById('company-type-select').value || null, location: cascadeState.district || cascadeState.city || cascadeState.province || null, education_level: document.getElementById('education-select').value || null, keyword: document.getElementById('keyword-input').value.trim() || null }; try { await SmartCV.api.post('/jobs/subscriptions', body); SmartCV.toast('订阅创建成功', 'success'); closeSubscribeModal(); } catch (e) { SmartCV.toast('订阅失败: ' + (e.message || '未知错误'), 'error'); } }