package cn.timer.api.controller.extension;

import cn.timer.api.aspect.lang.annotation.Log;
import cn.timer.api.aspect.lang.enums.BusinessType;
import cn.timer.api.bean.extension.*;
import cn.timer.api.bean.extension.param.CandidateRecordParam;
import cn.timer.api.utils.ExtensionResult;
import cn.timer.api.utils.ExtensionResultUtil;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.log4j.Log4j;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author wuqingjun
 * @email 284718418@qq.com
 * @date 2021/12/13
 */
@RestController
@Api(tags = "1.0简历助手登陆")
@Transactional
@RequestMapping(value = "/api/recruitment", produces = { "application/json" })
@Slf4j
public class ExtensionLoginController {


	@Autowired
	private HttpSession session;

	@Resource
	private HttpServletRequest httpServletRequest;
	/**
	 * token令牌获取企业信息,绑定企业
	 *
	 * @param token
	 * @return
	 */
	@GetMapping(value = "/api/resume_assistant/valid_token")
	@ApiOperation(value = "1.token令牌获取企业信息,绑定企业", httpMethod = "GET", notes = "接口发布说明")
	@ApiOperationSupport(order = 1)
	@Log(title = "token令牌获取企业信息,绑定企业", businessType = BusinessType.OTHER)
	public ExtensionResult valid_token(@RequestParam("token") String token) {
		session.setAttribute("ui", token);
		ExtensionCompany entity = new ExtensionCompany();
		entity.setValid(Boolean.TRUE);
		entity.setCompany_name("广东优领科技服务有限公司");
		return ExtensionResultUtil.data(entity);
	}
	/**
	 * 获取部门信息
	 * @return
	 */
	@GetMapping(value = "/api/resume_assistant/job_positions")
	@ApiOperation(value = "2.获取部门信息", httpMethod = "GET", notes = "接口发布说明")
	@ApiOperationSupport(order = 2)
	@Log(title = "获取部门信息", businessType = BusinessType.OTHER)
	public ExtensionResult job_positions() {
		String token = "",version="";
		if (StringUtils.isEmpty(httpServletRequest.getHeader("accesstoken"))) {
			token = httpServletRequest.getHeader("accesstoken");
		}
		if(StringUtils.isEmpty(httpServletRequest.getHeader("assistant_version"))){
			version = httpServletRequest.getHeader("assistant_version");
		}
		List<ExtensionJobPositions> list = new ArrayList<>();
		ExtensionJobPositions entity = new ExtensionJobPositions();
		entity.setId("c2206616-ff93-4a9a-b03c-770c58339bae");
		entity.setCity_name("广州");
		entity.setDep_id("58782bf9-3dd6-4bfa-8f00-efd87576a572");
		entity.setDep_name("企划部");
		entity.setName("程序员");
		entity.setProvince_name("广东");
		entity.setStatus(1);
		entity.setTown_name("白云区");
		entity.setWork_place_name("A写字楼");
		list.add(entity);
		return ExtensionResultUtil.data(list);
	}
	/**
	 * 获取配置信息
	 * @return
	 */
	@GetMapping(value = "/api/resume_assistant/config_v2")
	@ApiOperation(value = "3.获取配置信息", httpMethod = "GET", notes = "接口发布说明")
	@ApiOperationSupport(order = 3)
	@Log(title = "获取配置信息", businessType = BusinessType.OTHER)
	public ExtensionResult config_v2(@RequestParam("type") String type) {
		String token = "",version="";
		if (StringUtils.isEmpty(httpServletRequest.getHeader("accesstoken"))) {
			token = httpServletRequest.getHeader("accesstoken");
		}
		if(StringUtils.isEmpty(httpServletRequest.getHeader("assistant_version"))){
			version = httpServletRequest.getHeader("assistant_version");
		}
		ExtensionJobConfig jobConfig = new ExtensionJobConfig();

		Map<String,Object> configMap = new HashMap<>(10);
		ExtensionCore core = new ExtensionCore();
		core.setParseResume("async function parseResume(options = {}) {\nlet { config, matches, store } = options\nlet currentUrl = window.location.href\nlet { $ } = Vue.$ctx\n// 2.1.2新增\nlet { waitLoaded } = Vue.$Util\n// 数字版本号 如:211, 212\nconst version = Number(Vue.$Config.version.replace(/\\./g, ''))\n\n// 212以及版本兼容处理新状态\nversion < 212 && window.$CompatibleNewCandidateStatus()\n\n// 解析失败\nconst parseError = () => {\nreturn {\nstatus: 'parse-error',\nmsg: {\ntype: 'error',\nmessage: $TipsConfig.RESUME_PARSE_ERROR\n}\n}\n}\n\n// 解析加载中\nconst parseLoading = () => {\nreturn {\nstatus: 'parse-error',\nmsg: {\ntype: 'error',\nmessage: $TipsConfig.RESUME_LOADING\n}\n}\n}\n\n// 解析api数据\nconst parseApiData = async (data) => {\nif (!data) {\nreturn null\n}\n\nlet {\nname,\nsex,\nageNum,\nworkYear,\nhighestEducation,\nupdateTime,\nheadPic,\nbirthYear,\nbirthMonth,\nbirthDate,\nliveCity = '',\nuserId,\nresumeId,\nexpectJob: { positionName: expectJobPositionName },\nlatestWorkExperience: { positionName: latestWorkExperiencePositionName },\nworkExperiences: [{ companyName: lastCompanyName = '' }],\neducationExperiences: [{ professional = '', schoolName = '' }]\n} = data\n\nlet negotiable = false\nlet salary_min = null\nlet salary_max = null\nlet salary_text = data.expectJob.salarys || ''\nif (salary_text.includes('面议')) {\nnegotiable = true\nsalary_min = salary_max = -1\n} else if (salary_text.includes('2k以下')) {\nsalary_max = '2000'\n} else {\nlet salary_matchs = /^(\\d+)k-(\\d+)k$/.exec(salary_text)\nif (salary_matchs && salary_matchs.length === 3) {\nsalary_min = +salary_matchs[1] * 1000\nsalary_max = +salary_matchs[2] * 1000\n}\n}\n\nconst model = {\nname, // 姓名\njob_position: expectJobPositionName || latestWorkExperiencePositionName, // 应聘职位\nsex: $Utils.dataFilter.sex(sex), // 性别\nage: $Utils.dataFilter.age(ageNum), // 年龄\nwork_experience: $Utils.dataFilter.work_experience(workYear), // 工作年限\neducation: $Utils.dataFilter.education(highestEducation), // 学历\nschool: schoolName, // 毕业院校\nlast_company: lastCompanyName, // 最近工作单位\nchannel: matches.channel,\nmobile: '',\nemail: '',\nupdateTime,\navatar: headPic\n? `https://www.lgstatic.com/thumbnail_100x100${headPic.startsWith('/') ? headPic : '/' + headPic}`\n: '',\ndeliver_resume_by_self: null,\nbirthday:\nbirthYear !== -1\n? birthYear + '-' + birthMonth + '-' + (birthDate.length === 1 ? '0' + birthDate : birthDate)\n: '',\nlive_place: liveCity,\nnegotiable,\nsalary_min,\nsalary_max,\nmajor_name: professional, // 毕业专业\nlast_job_position: latestWorkExperiencePositionName, // 最近职位\nresume_origin_id: userId || resumeId\n}\n\nreturn model\n}\n\n// 是否能继续(包含详情区域)\nlet canNext = await waitLoaded('.resume-content .basic-info')\nif (!canNext) {\nreturn parseLoading()\n}\n\n// 不存在检索key\nconst resumeFetchKey = decodeURIComponent(Vue.$Util.queryString(currentUrl, 'resumeFetchKey'))\nif (!resumeFetchKey) {\nreturn parseError()\n}\n\n// 正文区域\nlet $html = $('.resume-content')\n\n// 设置等待,提高命中率\n// await Vue.$Util.sleep(config.waiting.default)\n\nlet model = {\nname: '', // 姓名\njob_position: '', // 应聘职位\nsex: '', // 性别\nage: '', // 年龄\nwork_experience: 0, // 工作年限\neducation: '', // 学历\nschool: '', // 毕业院校\nlast_company: '', // 最近工作单位\nchannel: matches.channel,\nmobile: '',\nemail: '',\nupdateTime: '', // 简历更新时间\navatar: '', // 头像地址\ndeliver_resume_by_self: null, // 是否自己投递\nbirthday: '', // 生日\nlive_place: '', // 现居住地\nresume_origin_url: '', // currentUrl, // 简历原始地址\nresume_origin_id: '', // 简历原始id\nsalary_min: null, // 期望月薪最小值\nsalary_max: null, // 期望月薪最大值\nnegotiable: false, // 面议\nmajor_name: '', // 专业\nlast_job_position: '', // 最近职位\nwork_start_dt: '', // 工作开始时间\nhtml_content_type: 'HTML' // 详情页内容的类型\n}\n\nlet messageBase = {\nmodel,\napiModel: null,\nmergeModel: null\n}\n\nconsole.time('api解析耗时')\n// 通过api获取数据\nlet apiData = null\ntry {\nlet [data1] = await Promise.all([\n$.ajax({\nurl: `/search/resume/fetchResume.json`,\n// data: JSON.stringify({}), // post\ndata: { resumeFetchKey },\ntype: 'GET',\ncontentType: 'application/json',\nbeforeSend(xhr) {\n// xhr.setRequestHeader('accesstoken', '...')\n}\n})\n])\nif (typeof data1 === 'string') {\ndata1 = JSON.parse(data1)\n}\n// 1 成功, -1 失败\nif (data1.state === 1 && data1.content && data1.content.data && data1.content.data.data) {\napiData = data1.content.data.data\n}\n} catch (data) {\nconsole.log(data)\n}\nconsole.timeEnd('api解析耗时')\n\nif (apiData) {\nconsole.warn(apiData)\nmessageBase.apiModel = await parseApiData(apiData.resume)\n}\n\n// 最后一步合并基础model和apiModel\nmessageBase.mergeModel = Vue.$Util.mergeModelValidData(messageBase.model, messageBase.apiModel)\nconsole.log('捕获到基础数据:', messageBase)\n\nif (messageBase.mergeModel.name.endsWith('**')) {\nmessageBase.mergeModel.name = messageBase.mergeModel.name.replace(\n/\\*\\*/g,\n{ 1: '先生', 2: '女士' }[messageBase.mergeModel.sex] || ''\n)\n}\n\nif (!messageBase.mergeModel.resume_origin_id) {\nreturn parseError()\n}\n\nlet $content = $($html).clone()\n$content.find('img').each((index, dom) => (dom.src = dom.src))\nif (\n$content\n.find('.p-name')\n.text()\n.includes('**')\n) {\n$('.p-name>span', $content).text(messageBase.mergeModel.name)\n}\n$('.plus-advertis-wrap,i.icon-lg-man,i.icon-lg-woman,.p-status,.logo-wrapper,.post-msg', $content).remove()\ncontent = $content.prop('outerHTML')\nreturn {\nstatus: 'parse-done',\nmsg: '解析成功',\ndata: Object.assign(messageBase, {\ntype: 'html',\ncontent: $Utils.buildHtml({\nlink: config.link.html,\ncss: config.css.html,\ncontent\n})\n})\n}\n}\n");
		jobConfig.setCore(core);

		jobConfig.setDisabled(false);

		Map<String,Integer> waitingMap = new HashMap<>(4);
		waitingMap.put("default",500);
		waitingMap.put("html",500);
//		waitingMap.put("pdf",1000);
//		waitingMap.put("image",3000);
		jobConfig.setWaiting(waitingMap);

		jobConfig.setDisabled_reason("暂停拉勾网简历解析服务,稍后恢复!");

		List<String> linkList = new ArrayList<>();
		linkList.add("https://pub-cdn.2haohr.com/share/resume-extension/link/lagou/lagou2-html2.css");
		ExtensionLink link = new ExtensionLink();
		link.setHtml(linkList);
		jobConfig.setLink(link);

		ExtensionCss css = new ExtensionCss();
		css.setHtml(".resume-info{margin-top: 50px;}.resume-content{width:657px;margin:0 auto;}.resume-basic{height:206px;border-bottom:1px solid #f1f1f1;background:#fafafa;border-radius:5px 5px 0 0;position:relative;}.item-user-img-border{float:left;}overflow: hidden;border-radius: 50%;float: left;.resume-basic{height:206px;border-bottom:1px solid #f1f1f1;background:#fafafa;border-radius:5px 5px 0 0;position:relative}.resume-basic .logo-wrapper{height:88px;width:88px;position:absolute;margin:50px;border-radius:50%;cursor:pointer;border:1px solid rgba(0,0,0,.03)}.resume-basic .user-logo{width:88px;height:88px;border-radius:50%;float:left;cursor:pointer}.resume-basic .basic-info{float:left;color:#333;margin-top:50px;position:relative;}.resume-basic .basic-info .icon-lg-man{font-size:14px;color:#57bad7;margin:11px 0 0 13px;position:absolute}.resume-basic .basic-info .icon-lg-woman{font-size:14px;color:#f17d7e;margin:11px 0 0 13px;position:absolute}.resume-basic .basic-info .p-name{font-size:26px;line-height:37px;font-weight:700;margin-bottom:10px}.resume-basic .basic-info .p-nor{font-size:14px;line-height:20px;margin-bottom:20px}.resume-basic .basic-info .p-nor .label:before{content:\"/\";position:relative;margin:0 6px}.resume-basic .basic-info .p-nor .label:first-child:before{content:\"\"}.resume-basic .basic-info .p-nor .pure-green{color:#00b38a}.resume-basic .basic-info .p-nor2{font-size:14px;line-height:20px}.resume-basic .basic-info .p-nor2:first-child{margin:20px 0 10px}.resume-basic .plus-a{position:absolute;right:50px;top:83px;z-index:1}.resume-section .expect-list .expect-item:first-child,.resume-section .expect-list .expect-item:nth-child(4){width:206px}body * {font-family: \"微软雅黑\", \"Microsoft Yahei\" !important;}@media print{.resume-section {width: 100%;}}");
		jobConfig.setCss(css);

		configMap.put("lagou4",jobConfig);


		/********************config_line*********************/
		jobConfig = new ExtensionJobConfig();
		core = new ExtensionCore();
		core.setParseResume("async function parseResume(options = {}) {\nconst { config, matches, store } = options\nconst currentUrl = window.location.href\nconst { $, _ } = Vue.$ctx\n// 2.1.2新增\nconst { waitLoaded, executeScript, queryString } = Vue.$Util\n// 数字版本号 如:211, 212\nconst version = Number(Vue.$Config.version.replace(/\\./g, ''))\n\n// 212以及版本兼容处理新状态\nversion < 212 && window.$CompatibleNewCandidateStatus()\n\n// 得到期待薪资\nconst getSalary = salary_text => {\nlet negotiable = false\nlet salary_min = null\nlet salary_max = null\n\nif (salary_text.includes('面议')) {\nnegotiable = true\nsalary_min = salary_max = -1\n} else {\nconst salary_matchs = /^(\\d+)-(\\d+)K$/.exec(salary_text)\nif (salary_matchs && salary_matchs.length === 3) {\nsalary_min = +salary_matchs[1] * 1000\nsalary_max = +salary_matchs[2] * 1000\n}\n}\nreturn { negotiable, salary_min, salary_max }\n}\n\n// 得到内容\nconst getContent = (content = '') => {\nif (!content) {\nreturn content\n}\nconst $content = $(`<div>${content}</div>`)\n$('img', $content).map((idx, dom) => {\ndom.src = dom.src\n})\n$('input:hidden, .resume-anonymous-geek-card, i.iboss-zhuanfa', $content).remove()\nreturn $content.html()\n}\n\n// 解析失败\nconst parseError = () => {\nreturn {\nstatus: 'parse-error',\nmsg: {\ntype: 'error',\nmessage: $TipsConfig.RESUME_PARSE_ERROR\n}\n}\n}\n\n// 解析加载中\nconst parseLoading = () => {\nreturn {\nstatus: 'parse-error',\nmsg: {\ntype: 'error',\nmessage: $TipsConfig.RESUME_LOADING\n}\n}\n}\n\n// 得到一个model结构\nconst getModel = () => {\nreturn {\nname: '', // 姓名\njob_position: '', // 应聘职位\nsex: '', // 性别\nage: '', // 年龄\nwork_experience: 0, // 工作年限\neducation: '', // 学历\nschool: '', // 毕业院校\nlast_company: '', // 最近工作单位\nchannel: matches.channel,\nmobile: '',\nemail: '',\nupdateTime: '', // 简历更新时间\navatar: '', // 头像地址\ndeliver_resume_by_self: null, // 是否自己投递\nbirthday: '', // 生日\nlive_place: '', // 现居住地\nresume_origin_url: '', // 简历原始地址\nresume_origin_id: '', // 简历原始id\nsalary_min: null, // 期望月薪最小值\nsalary_max: null, // 期望月薪最大值\nnegotiable: false, // 面议\nmajor_name: '', // 专业\nlast_job_position: '', // 最近职位\nwork_start_dt: '', // 工作开始时间\nhtml_content_type: 'HTML' // 详情页内容的类型\n}\n}\n\n// 是否能继续(包含详情区域)\nconst canNext = await waitLoaded('#resume-page .item-base')\nif (!canNext) {\nreturn parseLoading()\n}\n\n// 内容区域\nconst contentDom = document.querySelector('#resume-page .resume-item-content')\nif (!contentDom) {\nreturn parseError()\n}\n\n// 展开问答\nconst moreAskDom = document.querySelector('#resume-page .show-item')\nif (moreAskDom) {\nmoreAskDom.click()\nawait Vue.$Util.sleep(0)\n}\n\nconst expectId = queryString(currentUrl, 'expectId')\nconst securityId = queryString(currentUrl, 'securityId')\nconst lid = queryString(currentUrl, 'lid')\n\nconst [geekApiData] = await Promise.all([\n$.ajax({\nurl: `https://m.zhipin.com/wapi/zpboss/h5/geek/detail/get`,\ndata: {\nexpectId,\nsecurityId,\nlid,\n_: Date.now()\n},\ntype: 'GET',\ncontentType: 'application/json',\nbeforeSend(xhr) {\n// xhr.setRequestHeader('accesstoken', '...')\n}\n})\n])\n\nconst {\nzpData: { geekDetailInfo }\n} = geekApiData\n\n// 获取简历数据\nif (!geekDetailInfo) {\nreturn parseError()\n}\n\n/* eslint-disable */\nlet {\ngeekBaseInfo: {\nname = '',\nuserId,\nworkYears,\ngender,\nageDesc,\ndegreeCategory,\nemail = '',\nlarge = '',\ntiny = ''\n},\nshowExpectPosition: { salaryDesc = '', positionName = '', updateTime = '', addTime = '', locationName = '' },\ngeekWorkExpList = [],\ngeekEduExpList = []\n} = geekDetailInfo\n/* eslint-enable */\n\nname = _(name).trim('*')\n\nconst model = getModel()\nmodel.resume_origin_id = userId\nmodel.resume_origin_url = currentUrl\n\nconst messageBase = {\nmodel,\napiModel: null,\nmergeModel: null\n}\n\nconst { negotiable = false, salary_min = null, salary_max = null } = getSalary(salaryDesc)\n\nmessageBase.apiModel = {\nname, // 姓名\njob_position: positionName || geekWorkExpList.map(item => item.positionName).join('/') || '', // 应聘职位\nsex: { 0: 2, 1: 1 }[gender] || null, // 性别\nage: $Utils.dataFilter.age(ageDesc), // 年龄\nwork_experience: $Utils.dataFilter.work_experience(workYears), // 工作年限\neducation: $Utils.dataFilter.education(degreeCategory), // 学历\nschool: geekEduExpList.length ? geekEduExpList[0].school : '', // 毕业院校\nlast_company: geekWorkExpList.length ? geekWorkExpList[0].company : '', // 最近工作单位\n// channel: matches.channel,\nmobile: '',\nemail,\nupdateTime: updateTime || addTime,\navatar: large || tiny,\ndeliver_resume_by_self: null,\n// birthday: apiData.resumeVo.birthYear !== -1 ? apiData.resumeVo.birthYear + '-' + apiData.resumeVo.birthMonth + '-' + (apiData.resumeVo.birthDate.length === 1 ? '0' + apiData.resumeVo.birthDate : apiData.resumeVo.birthDate) : '',\nlive_place: locationName,\nnegotiable,\nsalary_min,\nsalary_max,\nmajor_name: geekEduExpList.length ? geekEduExpList[0].major : '', // 毕业专业\nlast_job_position: geekWorkExpList.length ? geekWorkExpList[0].positionName : '' // 最近职位\n}\n\n// 最后一步合并基础model和apiModel\nmessageBase.mergeModel = Vue.$Util.mergeModelValidData(messageBase.model, messageBase.apiModel)\nconsole.log('捕获到基础数据:', messageBase)\n\ncontent = getContent(contentDom.outerHTML)\n\nreturn {\nstatus: 'parse-done',\nmsg: '解析成功',\ndata: Object.assign(messageBase, {\ntype: 'html',\ncontent: $Utils.buildHtml({\nlink: config.link.html,\ncss: config.css.html,\ncontent\n})\n})\n}\n}\n");
		jobConfig.setCore(core);

		jobConfig.setDisabled(false);

		waitingMap = new HashMap<>(4);
		waitingMap.put("default",300);
		waitingMap.put("html",300);
//		waitingMap.put("pdf",1000);
//		waitingMap.put("image",3000);
		jobConfig.setWaiting(waitingMap);

		jobConfig.setDisabled_reason("暂停智联招聘简历解析服务,稍后恢复!");

		linkList = new ArrayList<>();
		linkList.add("https://pub-cdn.2haohr.com/share/resume-extension/link/zhipin/zhipin-html.css");
		link = new ExtensionLink();
		link.setHtml(linkList);
		jobConfig.setLink(link);

		css = new ExtensionCss();
		css.setHtml("body * {font-family: '微软雅黑', 'Microsoft Yahei' !important;}@media print{.resume-item-content {}}.resume-item .item-text .text {white-space: pre-line;max-width:600px;}.pic-container .img img,.img-box img, img{max-width: 100%}.resume-certificate .item-right.close{max-height: 74px;overflow: hidden;color: #61687C;padding-left: 13px;position: relative;vertical-align: top;}.resume-certificate ul li{font-family: PingFangSC-Regular;float: left;padding-left: 10px;padding-right: 10px;height: 24px;line-height: 24px;border: 1px solid #d0d1d6;border-radius: 2px;margin-right: 10px;}");
		jobConfig.setCss(css);

		configMap.put("zhaopin2",jobConfig);

		/********************config_line*********************/
		jobConfig = new ExtensionJobConfig();
		core = new ExtensionCore();
		core.setParseResume("async function parseResume(options = {}) {\nconst { config, matches, store } = options\nconst currentUrl = window.location.href\nconst { $, _ } = Vue.$ctx\n// 数字版本号 如:211, 212\nconst version = Number(Vue.$Config.version.replace(/\\./g, ''))\n\n// 212以及版本兼容处理新状态\nversion < 212 && window.$CompatibleNewCandidateStatus()\n\n//! 兼容智联招聘无法匹配招聘职位,下一版本需移除\nawait Vue.$Util.sleep(500)\n\n// 获取简历内容区域\nconst $html = document.querySelector('.resume-detail')\n// 未发现简历内容区域,简历解析失败(未获取到简历内容)\nif (!$html) {\nreturn {\nstatus: 'parse-error',\nmsg: $TipsConfig.RESUME_PARSE_ERROR\n}\n}\n\nif ($($html).find('.resume-abnormal__tip').length) {\nreturn {\nstatus: 'parse-error',\nmsg: {\ntype: 'warning',\nmessage: $($html).find('.resume-abnormal__tip').text(),\nnoParseButton: false\n// paddingTop: 132\n}\n}\n}\n\n// 展开全部求职意向\nconst dom1 = document.querySelector('button[zp-stat-id=\"rd_resume_all_job_intention\"]')\ndom1 && dom1.click()\n\nconst updateTime = ''\nlet resumeId = ''\n// 新方式-获取顶层上下文数据\nconst { data = {} } = await Vue.$Store.dispatch(\n'content/getContextData',\n'window.__INITIAL_STATE__.store.resumeDetail.resumes[window.__INITIAL_STATE__.key]'\n)\nconsole.log('上下文数据', data)\n// 简历id,优先取用户id,没有用户id时找简历id\nif (data.candidate) {\nresumeId = data.user.id || data.resumeNumber || data.resume.id\n}\n// // 简历更新时间,没有简历更新时间时在log里找最近投递时间\n// if (data.logList && data.logList.length) {\n// const logList = data.logList\n// const lastLog = logList[logList.length - 1]\n// if (lastLog) {\n// updateTime = Vue.$Util.formatDate(\n// `${lastLog.eventYear}${lastLog.eventDay} ${lastLog.eventHour}`,\n// 'YYYY-MM-DD HH:mm:ss'\n// )\n// }\n// }\n// // 最近投递时间不存在时,取用户的最近活跃时间\n// if (!updateTime) {\n// updateTime = Vue.$Util.formatDate(data.user.lastActiveTime, 'YYYY-MM-DD HH:mm:ss')\n// }\n\nconst model = {\nname: '', // 姓名\njob_position: '', // 应聘职位\nsex: '', // 性别\nage: '', // 年龄\nwork_experience: 0, // 工作年限\neducation: '', // 学历\nschool: '', // 毕业院校\nlast_company: '', // 最近工作单位\nchannel: matches.channel,\nmobile: '',\nemail: '',\nupdateTime, // 简历更新时间\navatar: '', // 头像地址\ndeliver_resume_by_self: null, // 是否自己投递\nbirthday: '', // 生日\nlive_place: '', // 现居住地\nresume_origin_url: '', // 简历原始地址\nresume_origin_id: resumeId, // 简历原始id\nsalary_min: null, // 期望月薪最小值\nsalary_max: null, // 期望月薪最大值\nnegotiable: false, // 面议\nmajor_name: '', // 专业\nlast_job_position: '', // 最近职位\nwork_start_dt: '', // 工作开始时间\nhtml_content_type: 'HTML', // 详情页内容的类型\nis_virtual_mobile: false, // 是否虚拟手机号\ncomment: '' // 备注\n}\n\n// 意向职位\nmodel.job_position = data.job.title || ''\nif (!model.job_position && data.resume.purposes && data.resume.purposes.length) {\nmodel.job_position = _.uniq(data.resume.purposes.map(item => item.jobTypeLabel)).join('/')\n}\n\nif (!model.job_position && data.resume.workExperiences && data.resume.workExperiences.length) {\nmodel.job_position = _.uniq(data.resume.workExperiences.map(item => item.jobTitle)).join('/')\n}\n\n// 薪资范围\nconst salaryLabels = data.resume.purposes.map(item => item.salaryLabel) || []\nconst salary = salaryLabels.length ? salaryLabels[0].replace('/月', '') : ''\nif (salary === '保密') {\n} else if (salary === '1K以下') {\nmodel.salary_max = 1000\n} else if (salary === '100K以上') {\nmodel.salary_min = 100000\n} else if (salary === '面议') {\nmodel.negotiable = true\nmodel.salary_min = model.salary_max = -1\n} else {\nconst salary_arr = salary.split('-')\nif (salary_arr[0] && salary_arr[0].includes('千')) {\nmodel.salary_min = +salary_arr[0].trim().replace(/千/g, '') * 1000 || ''\n} else if (salary_arr[0] && salary_arr[0].includes('万')) {\nmodel.salary_min = +salary_arr[0].trim().replace(/万/g, '') * 10000 || ''\n} else if (salary_arr[0] && salary_arr[0].includes('K')) {\nmodel.salary_min = +salary_arr[0].trim().replace(/K/g, '') * 1000 || ''\n}\nif (salary_arr[1] && salary_arr[1].includes('千')) {\nmodel.salary_max = +salary_arr[1].trim().replace(/千/g, '') * 1000 || ''\n} else if (salary_arr[1] && salary_arr[1].includes('万')) {\nmodel.salary_max = +salary_arr[1].trim().replace(/万/g, '') * 10000 || ''\n} else if (salary_arr[1] && salary_arr[1].includes('K')) {\nmodel.salary_max = +salary_arr[1].trim().replace(/K/g, '') * 1000 || ''\n}\n}\n\n// 姓名\nmodel.name = data.user.name || ''\n// 手机号\nif (!data.user.phoneVirtual && !data.user.phone.includes('#')) {\nmodel.mobile = data.user.phone || ''\n} else if (data.user.phone) {\n// 手机号是虚拟号码,填充到备注中\nmodel.comment = '虚拟手机号:' + data.user.phone.replace('#', '转')\nmodel.is_virtual_mobile = true\n}\n// 解析其他位置的手机号\nif (!model.mobile) {\nconst greeting = (data.candidate && data.candidate.greeting) || (data.user && data.user.messageBubble)\nconst matches = greeting.match(/\\d{11}/)\nif (matches && matches[0]) {\nmodel.mobile = matches[0]\n}\n}\n// 邮箱\nmodel.email = data.user.email || ''\n// 头像\nmodel.avatar = data.user.avatar || ''\n// 最近工作单位\nconst orgNames = data.resume.workExperiences.map(item => item.orgName) || []\nmodel.last_company = orgNames[0] || ''\n// 学历\nmodel.education = $Utils.dataFilter.education(data.user.maxEducationLabel || '')\n// 性别\nmodel.sex = $Utils.dataFilter.sex(data.user.genderLabel || '')\n// 毕业院校\nconst educationExperiences = data.resume.educationExperiences || []\nmodel.school = educationExperiences.length ? educationExperiences[0].schoolName : ''\n// 专业\nmodel.major_name = educationExperiences.length ? educationExperiences[0].major : ''\n// 工作经验\nmodel.work_experience = $Utils.dataFilter.work_experience(data.user.workYearsLabel || '')\n// 现居住地\nmodel.live_place = (data.user.cityLabel || '').replace('现居', '')\n// 原始链接\nmodel.resume_origin_url = currentUrl\n// 年龄\nmodel.age = data.user.age || ''\n// 生日\nconst birthMonth = (data.user.birthMonth || '').toString()\nconst year = (data.user.birthYear || '').toString()\nconst month = birthMonth.length === 2 ? birthMonth : '0' + birthMonth\nconst days = '01'\nif (year && month && days) {\nmodel.birthday = year + '-' + month + '-' + days\n}\n\n// 最近职位\nconst workExperiences = data.resume.workExperiences || []\nconst jobTitles = workExperiences.map(item => item.jobTitle)\nmodel.last_job_position = jobTitles.length ? jobTitles[0] : ''\n\nconst messageBase = {\nmodel,\napiModel: null,\nmergeModel: null\n}\n\n// 最后一步合并基础model和apiModel\nmessageBase.mergeModel = Vue.$Util.mergeModelValidData(messageBase.model, messageBase.apiModel)\nconst jpIndex = (messageBase.mergeModel.job_position || '').lastIndexOf('(')\nif (jpIndex > -1) {\nmessageBase.mergeModel.job_position = messageBase.mergeModel.job_position.substr(0, jpIndex)\n}\nif (!messageBase.mergeModel.job_position && messageBase.mergeModel.last_job_position) {\nmessageBase.mergeModel.job_position = messageBase.mergeModel.last_job_position\n}\nconsole.log('捕获到基础数据:', messageBase)\n\n// 检查mobile是否无效\nif (version < 212 && !$Validator.checkMobile(messageBase.mergeModel.mobile)) {\nreturn {\nstatus: 'parse-error',\nmsg: $TipsConfig.RESUME_NO_CONTACT\n}\n}\n\n// 获取简历内容\nconst $content = $($html).clone()\n$content.find('img').each((index, dom) => (dom.src = dom.src))\n// 移除无用的属性\n$content.find('[onclick]').each((index, dom) => {\n$(dom).removeAttr('onclick')\n})\n$content.find('[href^=\"javascript\"],[href]').each((index, dom) => {\n$(dom).removeAttr('href')\n})\n// 移除无用的样式\n$('.resume-basic__contact .has-text:eq(0)', $content).removeClass('is-ml-20').removeClass('is-ml-8')\n$('.resume-basic__contact .has-text:eq(1)', $content).removeClass('is-ml-8')\n$('.resume-content__block-name', $content).removeClass('resume-content__block-name')\n$('.resume-basic .is-flex.is-align-middle', $content).removeClass('is-align-middle')\n// 移除无用的元素\n$(\n'.resume-basic__active,.resume-basic__state,.resume-basic__portrait-hover,canvas,.resume-basic__phone-icon',\n$content\n).remove()\n// 移除简历附件区域\n$('.resume-content__title:contains(\"简历附件\")', $content).parent().remove()\n\nconst content = $content.prop('outerHTML')\nreturn {\nstatus: 'parse-done',\nmsg: '解析成功',\ndata: Object.assign(messageBase, {\ntype: 'html',\ncontent: $Utils.buildHtml({\nlink: config.link.html,\ncss: config.css.html,\ncontent\n})\n})\n}\n}\n");
		jobConfig.setCore(core);

		//jobConfig.setDisabled(false);

//		waitingMap = new HashMap<>(4);
//		waitingMap.put("default",300);
//		waitingMap.put("html",300);
//		waitingMap.put("pdf",1000);
//		waitingMap.put("image",3000);
//		jobConfig.setWaiting(waitingMap);

//		jobConfig.setDisabled_reason("暂停智联招聘简历解析服务,稍后恢复!");

		linkList = new ArrayList<>();
		linkList.add("https://fecdn1.zhaopin.cn/rd6_zhaopin_com/im-plugin.8296a4.css");
		link = new ExtensionLink();
		link.setHtml(linkList);
		jobConfig.setLink(link);

		css = new ExtensionCss();
		css.setHtml(".km-image__inner{border-radius: 50%;width:100%;height:100%}.resume-content__block-item{flex-basis: 28%;padding-right: 16px;}.km-timeline {color: #7a8193;font-variant: tabular-nums;-webkit-font-feature-settings: \"tnum\";font-feature-settings: \"tnum\";}.km-timeline__item {position: relative;padding: 0 0 16px;}.km-timeline--thin .km-timeline__item-dot {width: 6px;height: 6px;}.km-timeline__item-dot {width: 8px;height: 8px;border-radius: 290486px;border: 1px solid #3d7eff;background: #fff;position: absolute;z-index: 1;left:-1px;}.km-timeline--thin .km-timeline__item-line {left: 2px;-webkit-transform: scale3d(0.3, 1, 1);transform: scale3d(0.3, 1, 1);}.km-timeline__item-line {position: absolute;top: 4px;left: 3px;height: 100%;display: block;width: 2px;background-image: -webkit-gradient(linear, left top, left bottom, from(#e2e4ee), color-stop(50%, #e2e4ee), color-stop(50%, transparent));background-image: linear-gradient(to bottom, #e2e4ee 0%, #e2e4ee 50%, transparent 50%);background-size: 2px 8px;background-repeat: repeat-y;}.km-timeline--thin .km-timeline__item-content {margin-left: 22px;}.km-timeline__item-content {position: relative;margin-left: 24px;top: -5px;}.is-block {display: block;}.is-flex {display: flex;}.is-inline {display: inline;}.is-inline-block {display: inline-block;}.is-inline-fle {display: inline-fle;}.is-mw100 { max-width: 100%; }.is-mw0 { min-width: 0; }.is-width-100 { width: 100%; }.is-marginless { margin: 0 !important; }.is-paddingless { padding: 0 !important; }.is-radiusless { border-radius: 0 !important; }.is-shadowless { box-shadow: none !important; }.is-justify-center { justify-content: center; }.is-justify-end { justify-content: flex-end; }.is-justify-space-between { justify-content: space-between; }.is-justify-space-around { justify-content: space-around; }.is-justify-stretch { justify-content: stretch; }.is-align-middle { align-items: center; }.is-align-start { align-items: flex-start; }.is-align-stretch { align-items: stretch; }.is-align-end { align-items: flex-end; }.is-align-baseline { align-items: baseline; }.is-direction-column { flex-direction: column; }.is-direction-row { flex-direction: row; }.is-hidden { display: none !important; }.is-invisible { visibility: hidden !important; }.is-margin-0{margin: 0;}.is-margin-4{margin: 4px;}.is-margin-8{margin: 8px;}.is-margin-12{margin: 12px;}.is-margin-16{margin: 16px;}.is-margin-20{margin: 20px;}.is-margin-24{margin: 24px;}.is-margin-32{margin: 32px;}.is-margin-40{margin: 40px;}.is-mt-0{margin-top: 0;}.is-mt-4{margin-top: 4px;}.is-mt-8{margin-top: 8px;}.is-mt-12{margin-top: 12px;}.is-mt-16{margin-top: 16px;}.is-mt-20{margin-top: 20px;}.is-mt-24{margin-top: 24px;}.is-mt-32{margin-top: 32px;}.is-mt-40{margin-top: 40px;}.is-mb-0{margin-bottom: 0};}.is-mb-4{margin-bottom: 4px;}.is-mb-8{margin-bottom: 8px;}.is-mb-12{margin-bottom: 12px;}.is-mb-16{margin-bottom: 16px;}.is-mb-20{margin-bottom: 20px;}.is-mb-24{margin-bottom: 24px;}.is-mb-32{margin-bottom: 32px;}.is-mb-40{margin-bottom: 40px;}.is-ml-0{margin-left: 0};}.is-ml-4{margin-left: 4px;}.is-ml-8{margin-left: 8px;}.is-ml-12{margin-left: 12px;}.is-ml-16{margin-left: 16px;}.is-ml-20{margin-left: 20px;}.is-ml-24{margin-left: 24px;}.is-ml-32{margin-left: 32px;}.is-ml-40{margin-left: 40px;}.is-mr-0{margin-right: 0};}.is-mr-4{margin-right: 4px;}.is-mr-8{margin-right: 8px;}.is-mr-12{margin-right: 12px;}.is-mr-16{margin-right: 16px;}.is-mr-20{margin-right: 20px;}.is-mr-24{margin-right: 24px;}.is-mr-32{margin-right: 32px;}.is-mr-40{margin-right: 40px;}.is-padding-0 {padding: 0;}.is-padding-4 {padding: 4px;}.is-padding-8 {padding: 8px;}.is-padding-12 {padding: 12px;}.is-padding-16 {padding: 16px;}.is-padding-20 {padding: 20px;}.is-padding-24 {padding: 24px;}.is-padding-32 {padding: 32px;}.is-padding-40 {padding: 40px;}.is-pt-0 {padding-top: 0;}.is-pt-4 {padding-top: 4px;}.is-pt-8 {padding-top: 8px;}.is-pt-12 {padding-top: 12px;}.is-pt-16 {padding-top: 16px;}.is-pt-20 {padding-top: 20px;}.is-pt-24 {padding-top: 24px;}.is-pt-32 {padding-top: 32px;}.is-pt-40 {padding-top: 40px;}.is-pb-0 {padding-bottom: 0;}.is-pb-4 {padding-bottom: 4px;}.is-pb-8 {padding-bottom: 8px;}.is-pb-12 {padding-bottom: 12px;}.is-pb-16 {padding-bottom: 16px;}.is-pb-20 {padding-bottom: 20px;}.is-pb-24 {padding-bottom: 24px;}.is-pb-32 {padding-bottom: 32px;}.is-pb-40 {padding-bottom: 40px;}.is-pl-0 {padding-left: 0;}.is-pl-4 {padding-left: 4px;}.is-pl-8 {padding-left: 8px;}.is-pl-12 {padding-left: 12px;}.is-pl-16 {padding-left: 16px;}.is-pl-20 {padding-left: 20px;}.is-pl-24 {padding-left: 24px;}.is-pl-32 {padding-left: 32px;}.is-pl-40 {padding-left: 40px;}.is-pr-0 {padding-right: 0;}.is-pr-4 {padding-right: 4px;}.is-pr-8 {padding-right: 8px;}.is-pr-12 {padding-right: 12px;}.is-pr-16 {padding-right: 16px;}.is-pr-20 {padding-right: 20px;}.is-pr-24 {padding-right: 24px;}.is-pr-32 {padding-right: 32px;}.is-pr-40 {padding-right: 40px;}.resume-detail--default .resume-basic,.resume-detail--default .resume-content{padding:16px}body * {font-family: '微软雅黑', 'Microsoft Yahei' !important;}@media print{@page {size: A4;margin: 5.5mm;} .resume-detail--default .resume-basic,.resume-detail--default .resume-content{padding:0}}");
		jobConfig.setCss(css);

		configMap.put("zhaopin3",jobConfig);

		/********************config_line*********************/
		jobConfig = new ExtensionJobConfig();
		core = new ExtensionCore();
		core.setParseResume("async function parseResume(options = {}) {\nconst { config, matches, store } = options\nconst currentUrl = window.location.href\nconst { $, _ } = Vue.$ctx\n// 数字版本号 如:211, 212\nconst version = Number(Vue.$Config.version.replace(/\\./g, ''))\n\n// 重新解析简历\nconst reParseResume = () => {\n// 重新解析\nVue.$Store.commit('content/update', {\njob_position_id_change: 0\n})\nVue.$Store.dispatch('content/reParseResume')\nconsole.log('重新触发解析')\n}\n\n// 监听候选人切换\nif (document.querySelector('aside.im-aside')) {\n// 是否有创建监听器\nif (!window._observer_im) {\nwindow._observer_im = new MutationObserver(mutationsList => {\nfor (const mutation of mutationsList) {\nconst { type } = mutation\nswitch (type) {\ncase 'childList':\nbreak\ncase 'attributes':\nif (mutation.target.classList.contains('is-active')) {\n// 选中牛人变更\nreParseResume()\n}\nbreak\ndefault:\nbreak\n}\n}\n})\n// 开始观察\nwindow._observer_im.observe(document.querySelector('aside.im-aside'), {\nattributes: true,\nchildList: true,\nsubtree: true\n})\nconsole.log('创建window._observer_im')\n} else {\nconsole.log('已创建过window._observer_im')\n}\n}\n\n// 检查是否选中了候选人\nconst activeDom = document.querySelector('.km-list__item.is-active')\nif (!activeDom) {\nreturn {\nstatus: 'parse-error',\nmsg: {\ntype: 'info',\nmessage: '请从左侧列表中选择您要聊天的候选人', // $('.im-main-empty__text').text(),\nparseButtonText: '开始解析',\nnoParseButton: true,\npaddingTop: 132\n}\n}\n}\n\n// 智联官方推荐官\nif (document.querySelector('.km-list__item.is-active [title^=\"推荐官\"] + .official-icon')) {\nreturn {\nstatus: 'parse-error',\nmsg: {\ntype: 'info',\nmessage: '请选择候选人', // $('.im-main-empty__text').text(),\nparseButtonText: '',\nnoParseButton: true,\npaddingTop: 132\n}\n}\n}\n\n// 获取激活会话\nlet activeSession = null\nconst urlSessionId = window.location.pathname.replace('/im/index', '').replace('/im/', '')\nfor (let i = 0; i < 20; i++) {\nconst rs = await Vue.$Store.dispatch(\n'content/getContextData',\n`JSON.parse(JSON.stringify(document.querySelector('.km-list__item.is-active').__vue__.$parent.activeSession || window.__INITIAL_STATE__.sessions.find(item => item.resumeNumber === document.querySelector('.km-list__item.is-active').__vue__.$children[0].session.resumeNumber)))`\n)\nconst data = rs?.data\nactiveSession = data\nif (!activeSession) {\nawait Vue.$Util.sleep(500)\n} else {\nbreak\n}\n}\nif (!activeSession) {\nreturn {\nstatus: 'parse-error',\nmsg: window.$TipsConfig.RESUME_LOADING\n}\n}\n\n// 在线简历加载中\nlet nodata = null\nfor (let i = 0; i < 40; i++) {\nif ((nodata = $('.im-resume-detail__main .km-skeleton--loading').css('display') === 'block')) {\nawait Vue.$Util.sleep(250)\n} else {\nbreak\n}\n}\nif (nodata) {\nreturn parseLoading()\n}\n\n// 获取简历内容区域\nconst $html = document.querySelector('.resume-detail')\n// 未发现简历内容区域,简历解析失败(未获取到简历内容)\nif (!$html) {\nreturn {\nstatus: 'parse-error',\nmsg: $TipsConfig.RESUME_PARSE_ERROR\n}\n}\n\nif ($($html).find('.resume-abnormal__tip').length) {\nreturn {\nstatus: 'parse-error',\nmsg: {\ntype: 'warning',\nmessage: $($html).find('.resume-abnormal__tip').text(),\nnoParseButton: false\n// paddingTop: 132\n}\n}\n}\n\n// 展开全部求职意向\nconst dom1 = document.querySelector('button[zp-stat-id=\"rd_resume_all_job_intention\"]')\ndom1 && dom1.click()\n\nconst { resumeNumber, jobNumber, userId, resumeLanguage, userWeChat } = activeSession\n\nconst { data } = await $.ajax({\nurl: `https://rd6.zhaopin.com/api/resume/detail?_=${Date.now()}`,\ndata: JSON.stringify({\njobNumber,\nresumeNumber,\nresumeLanguage,\nk: '',\nt: ''\n}),\ntype: 'POST',\ncontentType: 'application/json'\n})\n\nconst updateTime = ''\nconst resumeId = userId || resumeNumber || data.resume.id\nconst model = {\nname: '', // 姓名\njob_position: '', // 应聘职位\nsex: '', // 性别\nage: '', // 年龄\nwork_experience: 0, // 工作年限\neducation: '', // 学历\nschool: '', // 毕业院校\nlast_company: '', // 最近工作单位\nchannel: matches.channel,\nmobile: '',\nemail: '',\nupdateTime, // 简历更新时间\navatar: '', // 头像地址\ndeliver_resume_by_self: null, // 是否自己投递\nbirthday: '', // 生日\nlive_place: '', // 现居住地\nresume_origin_url: '', // 简历原始地址\nresume_origin_id: resumeId, // 简历原始id\nsalary_min: null, // 期望月薪最小值\nsalary_max: null, // 期望月薪最大值\nnegotiable: false, // 面议\nmajor_name: '', // 专业\nlast_job_position: '', // 最近职位\nwork_start_dt: '', // 工作开始时间\nhtml_content_type: 'HTML', // 详情页内容的类型\nis_virtual_mobile: false, // 是否虚拟手机号\ncomment: '' // 备注\n}\n\n// 意向职位\nmodel.job_position = data.job.title || ''\nif (!model.job_position && data.resume.purposes && data.resume.purposes.length) {\nmodel.job_position = _.uniq(data.resume.purposes.map(item => item.jobTypeLabel)).join('/')\n}\n\nif (!model.job_position && data.resume.workExperiences && data.resume.workExperiences.length) {\nmodel.job_position = _.uniq(data.resume.workExperiences.map(item => item.jobTitle)).join('/')\n}\n\n// const job_positions = []\n// // 意向职位\n// job_positions.push(data.job.title || '')\n// if (data.resume.purposes && data.resume.purposes.length) {\n// job_positions.push(...data.resume.purposes.map(item => item.jobTypeLabel))\n// }\n// if (data.resume.workExperiences && data.resume.workExperiences.length) {\n// job_positions.push(...data.resume.workExperiences.map(item => item.jobTitle))\n// }\n// model.job_position = _.uniq(job_positions).join('/')\n\n// 薪资范围\nconst salaryLabels = data.resume.purposes.map(item => item.salaryLabel) || []\nconst salary = salaryLabels.length ? salaryLabels[0].replace('/月', '') : ''\nif (salary === '保密') {\n} else if (salary === '1K以下') {\nmodel.salary_max = 1000\n} else if (salary === '100K以上') {\nmodel.salary_min = 100000\n} else if (salary === '面议') {\nmodel.negotiable = true\nmodel.salary_min = model.salary_max = -1\n} else {\nconst salary_arr = salary.split('-')\nif (salary_arr[0] && salary_arr[0].includes('千')) {\nmodel.salary_min = +salary_arr[0].trim().replace(/千/g, '') * 1000 || ''\n} else if (salary_arr[0] && salary_arr[0].includes('万')) {\nmodel.salary_min = +salary_arr[0].trim().replace(/万/g, '') * 10000 || ''\n} else if (salary_arr[0] && salary_arr[0].includes('K')) {\nmodel.salary_min = +salary_arr[0].trim().replace(/K/g, '') * 1000 || ''\n}\nif (salary_arr[1] && salary_arr[1].includes('千')) {\nmodel.salary_max = +salary_arr[1].trim().replace(/千/g, '') * 1000 || ''\n} else if (salary_arr[1] && salary_arr[1].includes('万')) {\nmodel.salary_max = +salary_arr[1].trim().replace(/万/g, '') * 10000 || ''\n} else if (salary_arr[1] && salary_arr[1].includes('K')) {\nmodel.salary_max = +salary_arr[1].trim().replace(/K/g, '') * 1000 || ''\n}\n}\n\n// 姓名\nmodel.name = data.user.name || ''\n// 邮箱\nmodel.email = data.user.email || ''\n// 头像\nmodel.avatar = data.user.avatar || ''\n// 最近工作单位\nconst orgNames = data.resume.workExperiences.map(item => item.orgName) || []\nmodel.last_company = orgNames[0] || ''\n// 学历\nmodel.education = $Utils.dataFilter.education(data.user.maxEducationLabel || '')\n// 性别\nmodel.sex = $Utils.dataFilter.sex(data.user.genderLabel || '')\n// 毕业院校\nconst educationExperiences = data.resume.educationExperiences || []\nmodel.school = educationExperiences.length ? educationExperiences[0].schoolName : ''\n// 专业\nmodel.major_name = educationExperiences.length ? educationExperiences[0].major : ''\n// 工作经验\nmodel.work_experience = $Utils.dataFilter.work_experience(data.user.workYearsLabel || '')\n// 现居住地\nmodel.live_place = (data.user.cityLabel || '').replace('现居', '')\n// 原始链接\nmodel.resume_origin_url = currentUrl\n// 年龄\nmodel.age = data.user.age || ''\n// 生日\nconst birthMonth = (data.user.birthMonth || '').toString()\nconst year = (data.user.birthYear || '').toString()\nconst month = birthMonth.length === 2 ? birthMonth : '0' + birthMonth\nconst days = '01'\nif (year && month && days) {\nmodel.birthday = year + '-' + month + '-' + days\n}\n\n// 最近职位\nconst workExperiences = data.resume.workExperiences || []\nconst jobTitles = workExperiences.map(item => item.jobTitle)\nmodel.last_job_position = jobTitles.length ? jobTitles[0] : ''\n\n// 通过接口获取到的虚拟手机号可能跟页面上的对不上,似乎有缓存,暂且取页面上的数据,避免造成测试困扰\n// data.user.phone\nconst phone =\n$('.resume-basic__phone-icon+div').text().trim().replace(/\\s+/g, '').replace('分机号', '#').split('(')[0] || ''\n\n// 手机号\nif (!model.mobile && phone && !data.user.phoneVirtual && !phone.includes('#')) {\n// 非虚拟手机号,优先级最高\nmodel.mobile = phone\n}\nif (!model.mobile && userWeChat && $Validator.checkMobile(userWeChat)) {\n// 从微信解析手机号\nmodel.mobile = userWeChat\n}\n// 全局处理\n// if (!model.mobile && model.email) {\n// // 从邮箱解析手机号\n// const target = model.email.split('@')[0] || ''\n// if (target && $Validator.checkMobile(target)) {\n// model.mobile = target\n// }\n// }\nif (!model.mobile && phone.includes('#')) {\n// 手机号是虚拟号码,填充到备注中\nmodel.comment = '虚拟手机号:' + phone.replace('#', '转')\nmodel.is_virtual_mobile = true\n}\nif (!model.mobile) {\n// 解析其他位置的手机号\nconst greeting = (data.candidate && data.candidate.greeting) || (data.user && data.user.messageBubble)\nconst matches = greeting.match(/\\d{11}/)\nif (matches && matches[0]) {\nmodel.mobile = matches[0]\n}\n}\n\nconst messageBase = {\nmodel,\napiModel: null,\nmergeModel: null\n}\n\n// 最后一步合并基础model和apiModel\nmessageBase.mergeModel = Vue.$Util.mergeModelValidData(messageBase.model, messageBase.apiModel)\nconst jpIndex = (messageBase.mergeModel.job_position || '').lastIndexOf('(')\nif (jpIndex > -1) {\nmessageBase.mergeModel.job_position = messageBase.mergeModel.job_position.substr(0, jpIndex)\n}\nif (!messageBase.mergeModel.job_position && messageBase.mergeModel.last_job_position) {\nmessageBase.mergeModel.job_position = messageBase.mergeModel.last_job_position\n}\nconsole.log('捕获到基础数据:', messageBase)\n\n// 获取简历内容\nconst $content = $($html).clone()\n$content.find('img').each((index, dom) => (dom.src = dom.src))\n// 移除无用的属性\n$content.find('[onclick]').each((index, dom) => {\n$(dom).removeAttr('onclick')\n})\n$content.find('[href^=\"javascript\"],[href]').each((index, dom) => {\n$(dom).removeAttr('href')\n})\n// $content.removeClass('resume-detail--small').addClass('resume-detail--small')\n// 移除无用的样式\n$('.resume-basic__contact .has-text:eq(0)', $content).removeClass('is-ml-20').removeClass('is-ml-8')\n$('.resume-basic__contact .has-text:eq(1)', $content).removeClass('is-ml-8')\n$('.resume-content__block-name', $content).removeClass('resume-content__block-name')\n$('.resume-basic .is-flex.is-align-middle', $content).removeClass('is-align-middle')\n// 移除无用的元素\n$(\n'.resume-basic__active,.resume-basic__state,.resume-basic__portrait-hover,canvas,.resume-basic__phone-icon',\n$content\n).remove()\n// 移除简历附件区域\n$('.resume-content__title:contains(\"简历附件\")', $content).parent().remove()\n\nconst content = $content.prop('outerHTML')\nreturn {\nstatus: 'parse-done',\nmsg: '解析成功',\ndata: Object.assign(messageBase, {\ntype: 'html',\ncontent: $Utils.buildHtml({\nlink: config.link.html,\ncss: config.css.html,\ncontent\n})\n})\n}\n}\n");
		jobConfig.setCore(core);

		//jobConfig.setDisabled(false);

//		waitingMap = new HashMap<>(4);
//		waitingMap.put("default",300);
//		waitingMap.put("html",300);
//		waitingMap.put("pdf",1000);
//		waitingMap.put("image",3000);
//		jobConfig.setWaiting(waitingMap);

//		jobConfig.setDisabled_reason("暂停智联招聘简历解析服务,稍后恢复!");

		linkList = new ArrayList<>();
		linkList.add("https://fecdn1.zhaopin.cn/rd6_zhaopin_com/im-plugin.8296a4.css");
		link = new ExtensionLink();
		link.setHtml(linkList);
		jobConfig.setLink(link);

		css = new ExtensionCss();
		css.setHtml(".km-image__inner{border-radius: 50%;width:100%;height:100%}.resume-content__block-item{flex-basis: 28%;padding-right: 16px;}.km-timeline {color: #7a8193;font-variant: tabular-nums;-webkit-font-feature-settings: \"tnum\";font-feature-settings: \"tnum\";}.km-timeline__item {position: relative;padding: 0 0 16px;}.km-timeline--thin .km-timeline__item-dot {width: 6px;height: 6px;}.km-timeline__item-dot {width: 8px;height: 8px;border-radius: 290486px;border: 1px solid #3d7eff;background: #fff;position: absolute;z-index: 1;left:-1px;}.km-timeline--thin .km-timeline__item-line {left: 2px;-webkit-transform: scale3d(0.3, 1, 1);transform: scale3d(0.3, 1, 1);}.km-timeline__item-line {position: absolute;top: 4px;left: 3px;height: 100%;display: block;width: 2px;background-image: -webkit-gradient(linear, left top, left bottom, from(#e2e4ee), color-stop(50%, #e2e4ee), color-stop(50%, transparent));background-image: linear-gradient(to bottom, #e2e4ee 0%, #e2e4ee 50%, transparent 50%);background-size: 2px 8px;background-repeat: repeat-y;}.km-timeline--thin .km-timeline__item-content {margin-left: 22px;}.km-timeline__item-content {position: relative;margin-left: 24px;top: -5px;}.is-block {display: block;}.is-flex {display: flex;}.is-inline {display: inline;}.is-inline-block {display: inline-block;}.is-inline-fle {display: inline-fle;}.is-mw100 { max-width: 100%; }.is-mw0 { min-width: 0; }.is-width-100 { width: 100%; }.is-marginless { margin: 0 !important; }.is-paddingless { padding: 0 !important; }.is-radiusless { border-radius: 0 !important; }.is-shadowless { box-shadow: none !important; }.is-justify-center { justify-content: center; }.is-justify-end { justify-content: flex-end; }.is-justify-space-between { justify-content: space-between; }.is-justify-space-around { justify-content: space-around; }.is-justify-stretch { justify-content: stretch; }.is-align-middle { align-items: center; }.is-align-start { align-items: flex-start; }.is-align-stretch { align-items: stretch; }.is-align-end { align-items: flex-end; }.is-align-baseline { align-items: baseline; }.is-direction-column { flex-direction: column; }.is-direction-row { flex-direction: row; }.is-hidden { display: none !important; }.is-invisible { visibility: hidden !important; }.is-margin-0{margin: 0;}.is-margin-4{margin: 4px;}.is-margin-8{margin: 8px;}.is-margin-12{margin: 12px;}.is-margin-16{margin: 16px;}.is-margin-20{margin: 20px;}.is-margin-24{margin: 24px;}.is-margin-32{margin: 32px;}.is-margin-40{margin: 40px;}.is-mt-0{margin-top: 0;}.is-mt-4{margin-top: 4px;}.is-mt-8{margin-top: 8px;}.is-mt-12{margin-top: 12px;}.is-mt-16{margin-top: 16px;}.is-mt-20{margin-top: 20px;}.is-mt-24{margin-top: 24px;}.is-mt-32{margin-top: 32px;}.is-mt-40{margin-top: 40px;}.is-mb-0{margin-bottom: 0};}.is-mb-4{margin-bottom: 4px;}.is-mb-8{margin-bottom: 8px;}.is-mb-12{margin-bottom: 12px;}.is-mb-16{margin-bottom: 16px;}.is-mb-20{margin-bottom: 20px;}.is-mb-24{margin-bottom: 24px;}.is-mb-32{margin-bottom: 32px;}.is-mb-40{margin-bottom: 40px;}.is-ml-0{margin-left: 0};}.is-ml-4{margin-left: 4px;}.is-ml-8{margin-left: 8px;}.is-ml-12{margin-left: 12px;}.is-ml-16{margin-left: 16px;}.is-ml-20{margin-left: 20px;}.is-ml-24{margin-left: 24px;}.is-ml-32{margin-left: 32px;}.is-ml-40{margin-left: 40px;}.is-mr-0{margin-right: 0};}.is-mr-4{margin-right: 4px;}.is-mr-8{margin-right: 8px;}.is-mr-12{margin-right: 12px;}.is-mr-16{margin-right: 16px;}.is-mr-20{margin-right: 20px;}.is-mr-24{margin-right: 24px;}.is-mr-32{margin-right: 32px;}.is-mr-40{margin-right: 40px;}.is-padding-0 {padding: 0;}.is-padding-4 {padding: 4px;}.is-padding-8 {padding: 8px;}.is-padding-12 {padding: 12px;}.is-padding-16 {padding: 16px;}.is-padding-20 {padding: 20px;}.is-padding-24 {padding: 24px;}.is-padding-32 {padding: 32px;}.is-padding-40 {padding: 40px;}.is-pt-0 {padding-top: 0;}.is-pt-4 {padding-top: 4px;}.is-pt-8 {padding-top: 8px;}.is-pt-12 {padding-top: 12px;}.is-pt-16 {padding-top: 16px;}.is-pt-20 {padding-top: 20px;}.is-pt-24 {padding-top: 24px;}.is-pt-32 {padding-top: 32px;}.is-pt-40 {padding-top: 40px;}.is-pb-0 {padding-bottom: 0;}.is-pb-4 {padding-bottom: 4px;}.is-pb-8 {padding-bottom: 8px;}.is-pb-12 {padding-bottom: 12px;}.is-pb-16 {padding-bottom: 16px;}.is-pb-20 {padding-bottom: 20px;}.is-pb-24 {padding-bottom: 24px;}.is-pb-32 {padding-bottom: 32px;}.is-pb-40 {padding-bottom: 40px;}.is-pl-0 {padding-left: 0;}.is-pl-4 {padding-left: 4px;}.is-pl-8 {padding-left: 8px;}.is-pl-12 {padding-left: 12px;}.is-pl-16 {padding-left: 16px;}.is-pl-20 {padding-left: 20px;}.is-pl-24 {padding-left: 24px;}.is-pl-32 {padding-left: 32px;}.is-pl-40 {padding-left: 40px;}.is-pr-0 {padding-right: 0;}.is-pr-4 {padding-right: 4px;}.is-pr-8 {padding-right: 8px;}.is-pr-12 {padding-right: 12px;}.is-pr-16 {padding-right: 16px;}.is-pr-20 {padding-right: 20px;}.is-pr-24 {padding-right: 24px;}.is-pr-32 {padding-right: 32px;}.is-pr-40 {padding-right: 40px;}.resume-detail--default .resume-basic,.resume-detail--default .resume-content{padding:16px}body * {font-family: '微软雅黑', 'Microsoft Yahei' !important;}@media print{@page {size: A4;margin: 5.5mm;} .resume-detail--default .resume-basic,.resume-detail--default .resume-content{padding:0}}");
		jobConfig.setCss(css);

		configMap.put("zhaopin4",jobConfig);
		/********************config_line*********************/
		List<ExtensionMatches> matchesList = new ArrayList<>();

		ExtensionMatches matches = new ExtensionMatches();
		matches.setInject_delay(1000);
		matches.setMatches("*://easy.lagou.com/can/new/detail*.htm*");
		matches.setPattern(".*:\\/\\/easy.lagou.com\\/can\\/new\\/detail.*.htm.*");
		matches.setAuto_parse(true);
		matches.setDisabled(false);
		matches.setChannel_name("拉勾网");
		matches.setKey("lagou");
		matches.setReparse(false);
		matches.setChannel("lagou");
		matchesList.add(matches);

		matches = new ExtensionMatches();
		matches.setInject_delay(1000);
		matches.setMatches("*://easy.lagou.com/can/new/detail*.htm*");
		matches.setPattern(".*:\\/\\/easy.lagou.com\\/can\\/new\\/detail.*.htm.*");
		matches.setAuto_parse(true);
		matches.setDisabled(false);
		matches.setChannel_name("拉勾网");
		matches.setKey("lagou");
		matches.setReparse(false);
		matches.setChannel("lagou");
		matchesList.add(matches);

		matches = new ExtensionMatches();
		matches.setMatches("^https://ihr.zhaopin.com/resume/manage/$");
		matches.setPattern("^https:\\/\\/ihr.zhaopin.com\\/resume\\/manage\\/$");
		matches.setAuto_parse(false);
		matches.setDisabled(false);
		matches.setChannel_name("智联招聘");
		matches.setKey("zhaopin");
		matches.setReparse(true);
		matches.setChannel("zhaopin");
		matchesList.add(matches);

		matches = new ExtensionMatches();
		matches.setMatches("^https://ihr.zhaopin.com/resume/details/*");
		matches.setPattern("^https:\\/\\/ihr.zhaopin.com\\/resume\\/details\\/.*");
		matches.setAuto_parse(true);
		matches.setDisabled(false);
		matches.setChannel_name("智联招聘");
		matches.setKey("zhaopin");
		matches.setReparse(true);
		matches.setChannel("zhaopin");
		matchesList.add(matches);

		matches = new ExtensionMatches();
		matches.setMatches("^https://rd5.zhaopin.com/resume/detail\\?tabId=*");
		matches.setPattern("^https:\\/\\/rd5.zhaopin.com\\/resume\\/detail\\?tabId=.*");
		matches.setAuto_parse(true);
		matches.setDisabled(false);
		matches.setChannel_name("智联招聘");
		matches.setKey("zhaopin2");
		matches.setReparse(false);
		matches.setChannel("zhaopin");
		matchesList.add(matches);

		matches = new ExtensionMatches();
		matches.setMatches("^https://rd5.zhaopin.com/resume/detail\\?keyword=*");
		matches.setPattern("^https:\\/\\/rd5.zhaopin.com\\/resume\\/detail\\?keyword=.*");
		matches.setAuto_parse(true);
		matches.setDisabled(false);
		matches.setChannel_name("智联招聘");
		matches.setKey("zhaopin2");
		matches.setReparse(false);
		matches.setChannel("zhaopin");
		matchesList.add(matches);

		matches = new ExtensionMatches();
		matches.setMatches("^https://rd5.zhaopin.com/resume/detail\\?resumeNo=*");
		matches.setPattern("^https:\\/\\/rd5.zhaopin.com\\/resume\\/detail\\?resumeNo=.*");
		matches.setAuto_parse(true);
		matches.setDisabled(false);
		matches.setChannel_name("智联招聘");
		matches.setKey("zhaopin2");
		matches.setReparse(false);
		matches.setChannel("zhaopin");
		matchesList.add(matches);

		matches = new ExtensionMatches();
		matches.setMatches("^https://rd5.zhaopin.com/resume/detail\\?p=*&resumeNo=*");
		matches.setPattern("^https:\\/\\/rd5.zhaopin.com\\/resume\\/detail\\?p=.*&resumeNo=.*");
		matches.setAuto_parse(true);
		matches.setDisabled(false);
		matches.setChannel_name("智联招聘");
		matches.setKey("zhaopin2");
		matches.setReparse(false);
		matches.setChannel("zhaopin");
		matchesList.add(matches);

		matches = new ExtensionMatches();
		matches.setMatches("^{2.1.2}https://rd5.zhaopin.com/resume/detail\\?recordId=*");
		matches.setPattern("^{2.1.2}https:\\/\\/rd5.zhaopin.com\\/resume\\/detail\\?recordId=.*");
		matches.setAuto_parse(true);
		matches.setDisabled(false);
		matches.setChannel_name("智联招聘");
		matches.setKey("zhaopin2");
		matches.setReparse(false);
		matches.setChannel("zhaopin");
		matchesList.add(matches);

		matches = new ExtensionMatches();
		matches.setMatches("^{2.1.2}https://rd5.zhaopin.com/resume/detail\\?applyJobNumber=*");
		matches.setPattern("^{2.1.2}https:\\/\\/rd5.zhaopin.com\\/resume\\/detail\\?applyJobNumber=.*");
		matches.setAuto_parse(true);
		matches.setDisabled(false);
		matches.setChannel_name("智联招聘");
		matches.setKey("zhaopin2");
		matches.setReparse(false);
		matches.setChannel("zhaopin");
		matchesList.add(matches);

		matches = new ExtensionMatches();
		matches.setMatches("^{2.1.5}https://rd6.zhaopin.com/resume/detail*");
		matches.setPattern("^{2.1.5}https:\\/\\/rd6.zhaopin.com\\/resume\\/detail.*");
		matches.setAuto_parse(true);
		matches.setDisabled(false);
		matches.setChannel_name("智联招聘");
		matches.setKey("zhaopin3");
		matches.setReparse(false);
		matches.setChannel("zhaopin");
		matchesList.add(matches);

		matches = new ExtensionMatches();
		matches.setRepeat_inject_reject(true);
		matches.setMatches("^{2.1.7}https://rd6.zhaopin.com/im/*");
		matches.setPattern("^{2.1.7}https:\\/\\/rd6.zhaopin.com\\/im\\/.*");
		matches.setAuto_parse(true);
		matches.setDisabled(false);
		matches.setChannel_name("智联招聘");
		matches.setKey("zhaopin4");
		matches.setReparse(false);
		matches.setChannel("zhaopin");
		matchesList.add(matches);

		matches = new ExtensionMatches();
		matches.setMatches("^{2.1.0}*://passport.zhaopin.com/org/login\\?bkurl=https%3A%2F%2Frd5.zhaopin.com%2Fjob%2Fpublish%3F__job_pos_id%3D*");
		matches.setPattern("^{2.1.0}.*:\\/\\/passport.zhaopin.com\\/org\\/login\\?bkurl=https%3A%2F%2Frd5.zhaopin.com%2Fjob%2Fpublish%3F__job_pos_id%3D.*");
		matches.setDisabled(false);
		matches.setChannel_name("智联招聘");
		matches.setKey("jobpos-zhaopin");
		matches.setType("jobPosition");
		matches.setMethod("login");
		matches.setReparse(true);
		matches.setChannel("jobpos-zhaopin");
		matchesList.add(matches);

		matches = new ExtensionMatches();
		matches.setMatches("^{2.1.0}*://rd5.zhaopin.com/job/publish\\?__job_pos_id=*");
		matches.setPattern("^{2.1.0}.*:\\/\\/rd5.zhaopin.com\\/job\\/publish\\?__job_pos_id=.*");
		matches.setDisabled(false);
		matches.setChannel_name("智联招聘");
		matches.setKey("jobpos-zhaopin");
		matches.setType("jobPosition");
		matches.setMethod("publishJobPos");
		matches.setChannel("jobpos-zhaopin");
		matchesList.add(matches);


		matches = new ExtensionMatches();
		matches.setMatches("^{2.1.5}*://rd6.zhaopin.com/job/publish\\?__job_pos_id=*");
		matches.setPattern("^{2.1.5}.*:\\/\\/rd6.zhaopin.com\\/job\\/publish\\?__job_pos_id=.*");
		matches.setDisabled(false);
		matches.setChannel_name("智联招聘");
		matches.setKey("jobpos-zhaopin");
		matches.setType("jobPosition");
		matches.setMethod("publishJobPos2");
		matches.setChannel("jobpos-zhaopin");
		matchesList.add(matches);

		configMap.put("matches",matchesList);

		/********************config_line*********************/
		configMap.put("message",new ExtensionMessage());

		/********************config_line*********************/
		configMap.put("system",new ExtensionSystem());


		/********************config_line*********************/
		List<String> coreList = new ArrayList<>();
		coreList.add("window.$Utils = {\ndataFilter: {\nage(val) {\nif (val === undefined || val === '' || val === null) {\nreturn null\n} else if (val === -1) {\nreturn null\n} else if (typeof val === 'number') {\nreturn val\n} else if (!isNaN(val)) {\nreturn parseInt(val)\n} else if (typeof val === 'string') {\nvar matchs = val.match(/^.*?(\\d+).*?$/)\nif (matchs && matchs.length === 2) {\nreturn parseInt(matchs[1])\n}\n}\nreturn null\n},\nsex(val) {\nvar rs = {\n'': 0,\n'未知': 0,\n'男': 1,\n'女': 2,\n'1': 1,\n'2': 2\n}\nvar v = rs[val]\nreturn v === undefined ? 0 : v\n},\nwork_experience(val) {\nif (val === undefined || val === '' || val === null) {\nreturn null\n} else if (val === -1) {\nreturn null\n} else if (typeof val === 'number') {\nreturn val\n} else if (!isNaN(val)) {\nreturn parseInt(val)\n} else if (typeof val === 'string') {\nif (val.includes('毕业')) {\nreturn null\n}\nvar matchs = val.match(/^.*?(\\d+).*?$/)\nif (matchs && matchs.length === 2) {\nreturn parseInt(matchs[1])\n}\n}\nreturn null\n},\neducation_enum: {\n'小学': 1,\n'初中': 2,\n'高中': 3,\n'大专': 4,\n'本科': 5,\n'硕士': 6,\n'博士': 7,\n'职高': 8,\n'中专': 9,\n'技校': 10,\n'其他': 11,\n'未填写': 0,\n'初中及以下': 2,\n'中技': 10,\n'MBA': 11,\n'EMBA': 11,\n'MBA/EMBA': 11,\n},\neducation(val) {\nvar rs = window.$Utils.dataFilter.education_enum\nvar v = rs[val]\nreturn v === undefined ? 11 : v\n},\nzhaopin_education(val) {\nvar rs = {\n'9': 2, // 初中\n'7': 3, // 高中\n'5': 4, // 大专\n'4': 5, // 本科\n'3': 6, // 硕士\n'1': 7, // 博士\n'12': 9, // 中转\n'8': 11, // 其它\n'': 0,\n'13': 10, // 中技\n'10': 11, // mba\n'11': 11, // emba\n}\nvar v = rs[val]\nreturn v === undefined ? 11 : v\n},\nsexFilter(val) {\nlet t = Object.assign({'1':'男','2':'女'}, { 0: '' })[val]\nreturn t === undefined ? val : t\n},\neducationFilter(val) {\nlet t = Object.assign({'1':'小学','2':'初中','3':'高中','4':'大专','5':'本科','6':'硕士','7':'博士','8':'职高','9':'中专','10':'技校','11':'其他'}, { 0: '' })[val]\nreturn t === undefined ? val : t\n}\n},\nmetadata: {\nsex: [{\ntext: '男',\nvalue: 1\n},\n{\ntext: '女',\nvalue: 2\n}\n],\neducation: [{\n\"text\": \"小学\",\n\"value\": 1\n},\n{\n\"text\": \"初中\",\n\"value\": 2\n}, {\n\"text\": \"高中\",\n\"value\": 3\n}, {\n\"text\": \"大专\",\n\"value\": 4\n}, {\n\"text\": \"本科\",\n\"value\": 5\n}, {\n\"text\": \"硕士\",\n\"value\": 6\n}, {\n\"text\": \"博士\",\n\"value\": 7\n}, {\n\"text\": \"职高\",\n\"value\": 8\n}, {\n\"text\": \"中专\",\n\"value\": 9\n}, {\n\"text\": \"技校\",\n\"value\": 10\n}, {\n\"text\": \"其他\",\n\"value\": 11\n}\n]\n},\nbuildHtml(options = {\ntitle: '简历预览',\ncss: '',\ncontent: '',\nlink: []\n}) {\nlet html = ''\n\nhtml += '<!DOCTYPE html>'\nhtml += '<html lang=\"zh-CN\">'\nhtml += '<head>'\nhtml += '<meta charset=\"UTF-8\">'\n// html += '<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">'\n// html += '<meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">'\nhtml += '<title>' + (options.title || '简历预览') + '</title>'\n// link\noptions.link && options.link.map(href => {\nhtml += '<link rel=\"stylesheet\" href=\"' + href + '\" type=\"text/css\" />'\n})\n// css\nhtml += '<style>' + (options.css || '') + '</style>'\nhtml += '</head>'\nhtml += '<body>' + (options.content || '') + '</body>'\nhtml += '</html>'\n\nreturn html\n},\n// 处理model\nprocessModel(model) {\nif (!model) {\nreturn model\n}\n\nlet currentYear = new Date().getFullYear()\n\n// 先置空工作开始时间\nmodel.work_start_dt = ''\n// 若工作经验不存在,表示未解析到或应届生,工作开始时间置空\nif (model.work_experience) {\nmodel.work_start_dt = currentYear - model.work_experience + '-01-01'\n}\n\nmodel.name = model.name || '姓名未知'\n\nif (model.name.endsWith('**')) {\nmodel.name = model.name.replace(/\\*\\*/g, {1:'先生',2:'女士'}[model.sex] || '').replace(/\\*/g, '')\n}\n\nif (model.job_position) {\nmodel.job_position = model.job_position.replace(/\\(/g, '(').replace(/\\)/g, ')')\n}\n\nif (model.age) {\nmodel.birthday = (currentYear - model.age) + '-01-01'\n}\n\nif (model.updateTime) {\nmodel.updateTime = Vue.$Util.formatDate(Vue.$Util.parseDate(model.updateTime), 'YYYY-MM-DD HH:mm:ss') || ''\n}\nif (model.birthday) {\nmodel.birthday = Vue.$Util.formatDate(Vue.$Util.parseDate(model.birthday), 'YYYY-MM-DD') || ''\n}\n\nif (model.resume_origin_id) {\nmodel.resume_origin_id = String(model.resume_origin_id)\n}\n\nif (['', null, undefined].includes(model.is_virtual_mobile)) {\nmodel.is_virtual_mobile = false\n}\n\nif (model.email && !$Validator.checkEmail(model.email)) {\nmodel.email = ''\nconsole.log('邮箱地址检查不通过,置空')\n}\n\nif (model.mobile && !$Validator.checkMobile(model.mobile)) {\nmodel.mobile = ''\nconsole.log('手机号码检查不通过,置空')\n}\n\nif (!model.mobile && model.email) {\nconst target = model.email.split('@')[0] || ''\nif (target && $Validator.checkMobile(target)) {\nmodel.mobile = target\nif (model.comment && model.comment.includes('虚拟手机号')) {\nmodel.comment = ''\n}\nconsole.log('从邮箱地址解析手机号')\n}\n}\n\nreturn model\n},\n};");
		coreList.add("window.$Validator = {\n// 验证身份证(匹配效验码方式)\ncheckIdcard(val) {\nif ((/^\\d{15}$/).test(val)) {\nreturn true\n} else if ((/^\\d{17}[0-9xX]$/).test(val)) {\n// 得到出生日期,并效验\nlet temp, year, month, day\ntemp = val.substr(6, 8)\nyear = parseInt(temp.substr(0, 4))\nmonth = parseInt(temp.substr(4, 2))\nday = parseInt(temp.substr(6, 2))\nlet d = new Date(year, month - 1, day)\nif (!(d.getFullYear() === year && (d.getMonth() + 1) === month && d.getDate() === day)) {\nreturn false\n}\n\n// 效验效验码\nlet vs = '1,0,x,9,8,7,6,5,4,3,2'.split(',')\nlet ps = '7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2'.split(',')\nlet ss = val.toLowerCase().split('')\nlet r = 0\nfor (let i = 0; i < 17; i++) {\nr += ps[i] * ss[i]\n}\nreturn (vs[r % 11] === ss[17])\n}\nreturn false\n},\n// 验证身份证(通过正则表达式)\ncheckIdcardByRegular(val) {\nreturn /^(^[1-9]\\d{7}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}$)|(^[1-9]\\d{5}[1-9]\\d{3}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])((\\d{4})|\\d{3}[Xx])$)$/.test(val)\n},\n// 通过身份证获取生日\ngetBirthByIdcard(val) {\n// 身份证验证不通过,返回\nif (!validator.checkIdcard(val)) {\nreturn\n}\nlet dt, temp, year, month, day\n// 411323890901146\nif (val.length === 15) {\ntemp = '19' + val.substr(6, 6)\n} else {\ntemp = val.substr(6, 8)\n}\nyear = temp.substr(0, 4)\nmonth = temp.substr(4, 2)\nday = temp.substr(6, 2)\ndt = new Date(year, month - 1, day)\nreturn dt\n},\n// 通过身份证获取年龄\ngetAgeByIdcard(val) {\n// 身份证验证不通过,返回\nif (!validator.checkIdcard(val)) {\nreturn\n}\nlet birth = this.getBirthByIdcard(val)\nreturn this.getAgeByBirthday(birth)\n},\n// 通过身份证获取性别\ngetGenderByIdcard(val) {\n// 身份证验证不通过,返回\nif (!validator.checkIdcard(val)) {\nreturn\n}\nlet gender // 男1,女2\nif (val.length === 15) { // 第15位代表性别,奇数为男,偶数为女\ngender = parseInt(val.substr(14, 1))\n} else if (val.length === 18) { // 第17位代表性别,奇数为男,偶数为女\ngender = parseInt(val.substr(16, 1))\n}\nreturn gender % 2 === 0 ? 2 : 1\n},\n// 验证email\ncheckEmail(val) {\nif (val && val.toString().length > 100) {\nreturn false\n}\nreturn /^([A-Z0-9]+[_|.|-]?){0,3}[A-Z0-9]+@([A-Z0-9]+[_|-]?[A-Z0-9]+)(\\.[A-Z0-9]{2,20}){0,2}(\\.[A-Z]{2,20})$/i.test(val)\n},\n// 验证手机号\ncheckMobile(val) {\nreturn /^1[0-9]{10}$/.test(val)\n},\n// 验证邮编\ncheckZipcode(val) {\nreturn /^[0-9]{6}$/.test(val)\n},\n// 验证银行卡号(基于Luhn算法)\ncheckBankno(bankno) {\n// 银行卡号长度必须在16到19之间\nif (bankno.length < 16 || bankno.length > 19) {\nreturn false\n}\n// 银行卡号必须全为数字\nlet num = /^\\d*$/\nif (!num.exec(bankno)) {\nreturn false\n}\n// 银行卡号开头6位不符合规范\nlet strBin = '10,18,30,35,37,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,58,60,62,65,68,69,84,87,88,94,95,98,99'\nif (strBin.indexOf(bankno.substring(0, 2)) === -1) {\nreturn false\n}\n// 取出最后一位(与luhm进行比较)\nlet lastNum = parseInt(bankno.substr(bankno.length - 1, 1))\n\n// 前15或18位\nlet first15Num = bankno.substr(0, bankno.length - 1)\nlet newArr = []\n\n// 前15或18位倒序存进数组\nfor (let i = first15Num.length - 1; i > -1; i--) {\nnewArr.push(first15Num.substr(i, 1))\n}\n\nlet arrJiShu = [] // 奇数位*2的积 <9\nlet arrJiShu2 = [] // 奇数位*2的积 >9\nlet arrOuShu = [] // 偶数位数组\nfor (let j = 0; j < newArr.length; j++) {\nif ((j + 1) % 2 === 1) { // 奇数位\nif (parseInt(newArr[j]) * 2 < 9) {\narrJiShu.push(parseInt(newArr[j]) * 2)\n} else {\narrJiShu2.push(parseInt(newArr[j]) * 2)\n}\n} else { // 偶数位\narrOuShu.push(newArr[j])\n}\n}\n\nlet jishu_child1 = [] // 奇数位*2 >9 的分割之后的数组个位数\nlet jishu_child2 = [] // 奇数位*2 >9 的分割之后的数组十位数\nfor (let h = 0; h < arrJiShu2.length; h++) {\njishu_child1.push(parseInt(arrJiShu2[h]) % 10)\njishu_child2.push(parseInt(arrJiShu2[h]) / 10)\n}\n\nlet sumJiShu = 0 // 奇数位*2 < 9 的数组之和\nlet sumOuShu = 0 // 偶数位数组之和\nlet sumJiShuChild1 = 0 // 奇数位*2 >9 的分割之后的数组个位数之和\nlet sumJiShuChild2 = 0 // 奇数位*2 >9 的分割之后的数组十位数之和\nlet sumTotal = 0\nfor (let m = 0; m < arrJiShu.length; m++) {\nsumJiShu = sumJiShu + parseInt(arrJiShu[m])\n}\n\nfor (let n = 0; n < arrOuShu.length; n++) {\nsumOuShu = sumOuShu + parseInt(arrOuShu[n])\n}\n\nfor (let p = 0; p < jishu_child1.length; p++) {\nsumJiShuChild1 = sumJiShuChild1 + parseInt(jishu_child1[p])\nsumJiShuChild2 = sumJiShuChild2 + parseInt(jishu_child2[p])\n}\n// 计算总和\nsumTotal = parseInt(sumJiShu) + parseInt(sumOuShu) + parseInt(sumJiShuChild1) + parseInt(sumJiShuChild2)\n\n// 计算Luhm值\nlet k = parseInt(sumTotal) % 10 === 0 ? 10 : parseInt(sumTotal) % 10\nlet luhm = 10 - k\n\nreturn lastNum === luhm\n},\n// 验证银行卡(通过正则表达式)\ncheckBanknoByRegular(bankno) {\nreturn /^([1-9]{1})(\\d{14,15}|\\d{17,20})$/.test(bankno)\n},\n// 验证护照\ncheckPassport(val) {\nreturn /^[a-zA-Z0-9]{4,20}$/i.test(val)\n},\n// 验证QQ\ncheckQQ(val) {\nreturn /^[1-9]\\d{4,10}$/.test(val)\n},\n// 验证日期\ncheckDate(val) {\nif (typeof val === 'string') { // 是字符串但不能是空字符\nlet splitChar = '-'\nif (val.indexOf('/') > -1) {\nsplitChar = '/'\n}\nlet arr = val.split(splitChar) // 可以被-切成3份,并且第1个是4个字符\nif (arr.length === 3 && arr[0].length === 4) {\nlet year = ~~arr[0] // 全部转换为非负整数\nlet month = ~~arr[1] - 1\nlet date = ~~arr[2]\nlet d = new Date(year, month, date)\nreturn d.getFullYear() === year && d.getMonth() === month && d.getDate() === date\n}\n}\nreturn false\n},\n// 验证年龄,范围[0-100]\ncheckAge(val) {\nif (!/^[0-9]+$/.test(val)) {\nreturn false\n}\nval = +val\nreturn val >= 0 && val <= 100\n},\n// 验证正整数\ncheckPositiveInteger(val) {\nreturn /^[0-9]+$/.test(val)\n},\n// 验证正数(包含小数)\ncheckPositiveNumber(val) {\nreturn /^[0-9]+(\\.[0-9]+)?$/.test(val)\n},\n// 验证整数(包含负数)\ncheckInteger(val) {\nreturn /^-?\\d+$/.test(val)\n},\n// 验证小数(包含整数以及小数)\ncheckDecimal(val) {\nreturn /^-?\\d*\\.?\\d+$/.test(val)\n},\n// 验证姓名\ncheckName(val) {\nif (!/^(?!\\d)[·\\u4E00-\\u9FA5\\u0020A-Za-z0-9]*$/i.test(val) ) {\nreturn false\n}\nreturn val.length <= 100\n},\n// 验证企业名称\ncheckCorpName(val) {\nreturn /^[\\u0020()\\u4E00-\\u9FA5()A-Za-z0-9]*$/i.test(val)\n},\n// 验证url\ncheckUrl(val) {\nreturn /^(ftp|http|https):\\/\\/(\\w+:{0,1}\\w*@)?(\\S+)(:[0-9]+)?(\\/|\\/([\\w#!:.?+=&%@!\\-/]))?$/.test(val)\n},\n// 验证工作年限\ncheckWorkExperience(val) {\nif (!/^[0-9]+$/.test(val)) {\nreturn false\n}\nval = +val\nreturn val >= 0 && val <= 100\n}\n};\nwindow.$Validator.checkFormat = (val, type) => {\nif (val === undefined || val === null || val === '') {\nreturn false\n}\nvar validator = window.$Validator\nswitch (type.toLowerCase()) {\ncase 'idcard': // 验证身份证(匹配效验码方式)\nreturn validator.checkIdcard(val)\ncase 'idcard_regex': // 验证身份证(通过正则表达式)\nreturn validator.checkIdcardByRegular(val)\ncase 'email': // 验证email\nreturn validator.checkEmail(val)\ncase 'mobile': // 验证手机号\nreturn validator.checkMobile(val)\ncase 'zipcode': // 验证邮编\nreturn validator.checkZipcode(val)\ncase 'bankno': // 验证银行卡号(基于Luhn算法)\nreturn validator.checkBankno(val)\ncase 'bankno_regex': // 验证银行卡(通过正则表达式)\nreturn validator.checkBanknoByRegular(val)\ncase 'passport': // 验证护照\nreturn validator.checkPassport(val)\ncase 'qq': // 验证QQ\nreturn validator.checkQQ(val)\ncase 'date': // 验证日期\nreturn validator.checkDate(val)\ncase 'age': // 验证年龄,范围[0-100]\nreturn validator.checkAge(val)\ncase 'positive_int': // 验证正整数\nreturn validator.checkPositiveInteger(val)\ncase 'positive_num': // 验证正数(包含小数)\nreturn validator.checkPositiveNumber(val)\ncase 'int': // 验证整数(包含负数)\nreturn validator.checkInteger(val)\ncase 'decimal': // 验证小数(包含整数以及小数)\nreturn validator.checkDecimal(val)\ncase 'name': // 验证姓名\nreturn validator.checkName(val)\ncase 'corp_name': // 验证企业名称\nreturn validator.checkCorpName(val)\ncase 'url': // 验证url\nreturn validator.checkUrl(val)\ncase 'work_experience': // 验证工作年限\nreturn validator.checkWorkExperience(val)\ndefault:\nreturn false\n}\n};\nwindow.$Validator.validate = (type, required = true, typeName) => {\nconst labels = {\n'email': {\nrequired: '请输入' + (typeName || '邮箱地址'),\nerror: (typeName || '邮箱地址') + '格式有误'\n},\n'mobile': {\nrequired: '请输入' + (typeName || '手机号码'),\nerror: (typeName || '手机号码') + '格式有误'\n},\n'bankno': {\nrequired: '请输入' + (typeName || '卡号'),\nerror: (typeName || '卡号') + '格式有误'\n},\n'bankno_regex': {\nrequired: '请输入' + (typeName || '卡号'),\nerror: (typeName || '卡号') + '格式有误'\n},\n'date': {\nrequired: '请输入' + (typeName || '日期'),\nerror: (typeName || '日期') + '格式有误'\n},\n'name': {\nrequired: '请输入' + (typeName || '姓名'),\nerror: (typeName || '姓名') + '格式有误'\n},\n'corp_name': {\nrequired: '请输入' + (typeName || '公司名称'),\nerror: (typeName || '公司名称') + '格式有误'\n},\n'url': {\nrequired: '请输入' + (typeName || '链接地址'),\nerror: (typeName || '链接地址') + '格式有误'\n},\n'work_experience': {\nrequired: '请输入' + (typeName || '工作年限'),\nerror: (typeName || '工作年限') + '格式有误'\n},\n'age': {\nrequired: '请输入' + (typeName || '年龄'),\nerror: (typeName || '年龄') + '格式有误'\n}\n}\nreturn (rule, value, callback) => {\nif (!labels[type]) {\nreturn callback()\n}\nif (typeof value === 'string' && value) {\nvalue = value.trim()\n}\nlet label = rule.label || labels[type]\nif (!required && !value) {\nreturn callback()\n}\nif (!value) {\nreturn callback(new Error(label.required))\n}\nif (!window.$Validator.checkFormat(value, type)) {\nreturn callback(new Error(label.error))\n}\ncallback()\n}\n};\n");
		coreList.add("window.$CompatibleNewCandidateStatus = () => {\nVue.$Filter.add({\ncandidateStatus(val) {\nconst t = {\n10: '新候选人',\n11: '初选通过',\n12: '安排面试',\n13: '面试通过',\n20: '已发offer',\n1: '待入职',\n2: '已入职',\n3: '未入职',\n99: '已淘汰',\n// 新版本招聘状态\n30: '待初筛',\n31: '初筛通过',\n32: '初筛淘汰',\n40: '已安排面试',\n41: '已面试',\n42: '面试通过',\n43: '面试淘汰',\n50: '拟录用',\n51: '已发offer',\n52: '待入职',\n53: '已入职',\n54: '撤销录用'\n}[val]\nreturn t === undefined ? val : t\n}\n})\n};");
		coreList.add("window.$CheckMatches = ({ matches }) => {\n// 匹配url进行注入\nlet currentMatches = window._config_.matches.find(matches => {\nlet reg = RegExp(matches.pattern, 'ig')\nreturn reg.test(window.location.href) && [undefined, null, '', 'resume'].includes(matches.type)\n})\n\n// 拒绝访问\nif (!currentMatches || currentMatches.key !== matches.key) {\nreturn {\nstatus: 'parse-error',\nmsg: {\ntype: 'info',\nmessage: '请刷新页面后再解析',\nnoParseButton: true,\npaddingTop: 132\n}\n}\n}\n};");
		coreList.add("window.$SmartMatchJobPosition = (list, keyword = '', match_rate = 0.8) => {\ntry {\nif (!keyword) {\nreturn ''\n}\nconst filterText = (text = '') => {\ntext = text || ''\nreturn text.replace(/\\+/gi, ' ').replace(/\\(/gi, '(').replace(/\\)/gi, ')').trim()\n}\nconst match = ({ keyword = '', list = [], match_rate = 0.8 }) => {\nkeyword = filterText(keyword)\nconst match_count = Math.floor(keyword.replace(/\\//g, '').length * match_rate)\nconst keyword_arr = keyword.split('')\nlet result = []\nlist.map(item => {\nconst rs = { id: item.id, name: item.name, count: 0 }\nlet { name } = item\nname = filterText(name)\nkeyword_arr.map(key => {\nif (name.includes(key)) {\nname = name.replace(new RegExp(key, 'i'), '')\nrs.count++\n}\n})\nresult.push(rs)\n})\nif (!result.some(item => item.count > 0)) {\nreturn\n}\n\nresult = result\n.filter(item => item.count >= match_count)\n.sort((a, b) => {\nif (a.count === b.count) {\nif (a.name.length === keyword.length && b.name.length !== keyword.length) {\nreturn -1\n} else if (a.name.length !== keyword.length && b.name.length === keyword.length) {\nreturn 1\n}\nreturn a.name.length > b.name.length ? 1 : -1\n}\nreturn a.count > b.count ? -1 : 1\n})\n\nreturn {\nmatch_rate,\nmatch_count,\nmatch_list: result,\nmatch_one: result.length ? result[0] : '',\nkeyword\n}\n}\nconst match_list = keyword\n.split('/') // 分割\n.concat([keyword]) // 合并完整关键词\n.map(kw => {\nreturn match({\nkeyword: kw,\nlist,\nmatch_rate\n})\n})\n.filter(item => item && item.match_one && item.match_one.count > 1)\n.map(item => {\nitem.real_rate = item.match_one.real_rate = _.round(\nitem.match_one.count / item.match_one.name.length,\n2\n)\nitem.real_match_count = item.match_one.count\nreturn item\n})\n\nlet rs = _.chain(match_list).sortBy(['real_rate', 'real_match_count']).reverse().head().value()\n\nif (!rs) {\n// 反向匹配\nconst match_one = _.chain(\nlist.filter(\n({ name = '' }) =>\nname.toLowerCase().trim().includes(keyword.toLowerCase().trim()) ||\nkeyword.toLowerCase().trim().includes(name.toLowerCase().trim())\n)\n)\n.head()\n.value()\n\nif (match_one) {\nrs = {\nmatch_one\n}\n}\n}\n\nconsole.warn('[HOT]智能匹配职位结果:', rs)\n\nreturn rs\n} catch (data) {\nVue.$Sentry.CE(data, {\n// 额外数据\nextra: {\nerrormsg: '智能匹配职位异常'\n}\n})\nconsole.error('智能匹配职位异常', data)\nreturn ''\n}\n}\n;");
		configMap.put("core",coreList);

		/********************config_line*********************/
		ExtensionCore core1 = new ExtensionCore();
		core1.setLogin("async function login(options = {}) {\nconst { config, matches, store } = options\nconst { $ } = Vue.$ctx\n\nconst $notify = Vue.$Notice({\ntype: 'info',\nmessage: '请先登录招聘网站才能进行职位发布哦~',\ncustomClass: '',\ndangerouslyUseHTMLString: true,\nduration: 0,\nonClick: async() => {\n// $notify.close()\n}\n})\n\n}");
		core1.setPublishJobPos("async function publishJobPos(options = {}) {\nconst {\nconfig,\nmatches,\nstore,\nbindCorpUrl,\nutil: { waitLoaded, executeScript }\n} = options\nconst { $ } = Vue.$ctx\nconst { htmlToFormattedText } = Vue.$Util\n\nconst job_pos_id = Vue.$Util.queryString(window.location.href, '__job_pos_id')\nif (!job_pos_id) {\nreturn\n}\n\nif (!store.state.jobPos.is_login) {\nwindow.__bindCorpNotice = Vue.$Notice({\ntype: 'warning',\nmessage: `您还未绑定企业,<a href='javascript:window.location.replace(\"${encodeURIComponent(\nbindCorpUrl\n)}\");'>去绑定>></a>`,\ncustomClass: '',\ndangerouslyUseHTMLString: true,\nduration: 0,\nonClick: async () => {}\n})\nreturn\n}\n\nif (window.__bindCorpNotice) {\nwindow.__bindCorpNotice.close()\n}\n\nVue.$Document.loadingStart({\nbackground: 'rgba(255,255,255, 0.5)',\ntext: '正在填充数据,请稍候...',\nlock: false\n})\n\n// 是否能继续\nlet canNext = await waitLoaded('.jqte_editor')\nif (!canNext) {\nVue.$Notice({\ntype: 'warning',\nmessage: '填充数据失败,请刷新页面重试!',\ncustomClass: '',\ndangerouslyUseHTMLString: true,\nduration: 6000,\nonClick: async () => {}\n})\n/* Vue.$Message.warning({\nshowClose: true,\nmessage: '消息',\nduration: 4000\n}) */\nVue.$Document.loadingStop()\nreturn\n}\n\n// 开始填充数据\ntry {\nlet data = await store.dispatch('jobPos/postMessage', {\ncmd: 'api.request',\nurl: `/recruitment/api/resume_assistant/job_position/?job_position_id=${job_pos_id}`,\nmethod: 'GET',\nparams: {}\n})\n\n//! 以下所有填充都必须发生在页面顶层上下文中\n\n// 职位名称\nif (data.name) {\nexecuteScript(`ko.contextFor(document.querySelector('.k-form')).$data.form.jobTitle('${data.name}')`)\n}\n\n// // 职位类别,调用搜索接口,选取第一项填充\n// executeScript(\n// `\n// (async() => {\n// let {code = 0, data = []} = await $.ajax({\n// url: 'https://rd5.zhaopin.com/api/rd/search/job',\n// data: {\n// _: ${Date.now()},\n// keyword: '${data.name}',\n// size: 30,\n// /* 'x-zp-page-request-id': zpPageRequestId, */\n// /* 'x-zp-client-id': getCookie('x-zp-client-id') */\n// },\n// type: 'GET',\n// contentType: 'application/json',\n// beforeSend(xhr) { /* xhr.setRequestHeader('', ''); */ }\n// });\n// if (code === 0 && data.length) {\n// let id = data[0].level3.intKey;\n// let name = data[0].level3.itemValue;\n// ko.contextFor(document.querySelector('.k-form')).$data.form.jobSubType(id);\n// ko.contextFor(document.querySelector('.k-form')).$data.form.newJobSubType({id, name});\n// }\n// })()\n// `\n// )\n\n// 工作性质\nif (data.work_type === 2) {\n// 当2号工作性质为实习生时\nexecuteScript(`ko.contextFor(document.querySelector('.k-form')).$data.form.employmentType(4)`)\n} else if (data.work_type === 1) {\n// 当2号工作性质为兼职时智联招聘填充兼职\nexecuteScript(`ko.contextFor(document.querySelector('.k-form')).$data.form.employmentType(1)`)\n}\n\n// 工作地址\nif (data.work_place_name) {\nexecuteScript(\n`ko.contextFor(document.querySelector('.city-selector-address')).$data.queryAddress('${data.work_place_name}')`\n)\n}\n\n// 月薪范围\n// 最低\n// 薪资单位\nlet salary_unit = data.salary_unit // 2号薪资单位为“元/月”时填充\nif (salary_unit === 6) {\nlet salary_min = data.salary_min\nlet salary_max = data.salary_max\nlet salary_min_exists = ![null, undefined, '', -1].includes(salary_min)\nlet salary_max_exists = ![null, undefined, '', -1].includes(salary_max)\nif (salary_min_exists || salary_max_exists) {\nexecuteScript(\n`ko.contextFor(document.querySelector('.k-form')).$data.form.salary('${salary_min}-${salary_max}')`\n)\n}\n}\n\n// 最低学历\nlet education = data.education\nif (education !== null) {\nlet education_zhaopin = {\n0: {\n// '不限'\nlabel: '学历不限',\nvalue: '-1'\n},\n3: {\n// '高中及以上'\nlabel: '高中',\nvalue: '7'\n},\n4: {\n// '大专及以上'\nlabel: '大专',\nvalue: '5'\n},\n5: {\n// '本科及以上'\nlabel: '本科',\nvalue: '4'\n},\n6: {\n// '硕士及以上'\nlabel: '硕士',\nvalue: '3'\n},\n7: {\n// '博士'\nlabel: '博士',\nvalue: '1'\n},\n2: {\n// 初中及以下\nlabel: '初中及以下',\nvalue: '9'\n},\n9: {\n// 中专/中技\nlabel: '中专/中技',\nvalue: '12'\n},\n13: {\n// MBA/EMBA\nlabel: 'MBA/EMBA',\nvalue: '10'\n}\n}[education]\nif (education_zhaopin) {\n// 先设置内层组件值\nexecuteScript(\n`ko.contextFor(document.querySelector('[placeholder=\"请选择学历\"]')).$data.value(${education_zhaopin.value})`\n)\n// 再设置表单选中值\nexecuteScript(\n`ko.contextFor(document.querySelector('.k-form')).$data.form.education(${education_zhaopin.value})`\n)\n}\n}\n\n// 工作年限\nlet work_experience = data.work_experience\nif (work_experience !== null) {\nlet work_experience_zhaopin = {\n0: {\n// '不限'\nlabel: '经验不限',\nvalue: '-1'\n},\n1: {\n// '1年以下'\nlabel: '1年以下',\nvalue: '1'\n},\n2: {\n// '1-3年'\nlabel: '1-3年',\nvalue: '103'\n},\n3: {\n// '3-5年'\nlabel: '3-5年',\nvalue: '305'\n},\n4: {\n// '5-10年'\nlabel: '5-10年',\nvalue: '510'\n},\n5: {\n// '10年以上'\nlabel: '10年以上',\nvalue: '1099'\n}\n}[work_experience]\nif (work_experience_zhaopin) {\nexecuteScript(\n`ko.contextFor(document.querySelector('.k-form')).$data.form.workAge(${work_experience_zhaopin.value})`\n)\n}\n}\n\n// 职位描述\ndata.position_description &&\nexecuteScript(\n`ko.contextFor(document.querySelector('.k-form')).$data.form.jobDescription('${data.position_description}')`\n)\n\n// 招聘人数\n![null, undefined, ''].includes(data.position_total) &&\nexecuteScript(`ko.contextFor(document.querySelector('.k-form')).$data.form.quantity(${data.position_total})`)\n\nVue.$Notice({\ntype: 'success',\nmessage: `<p>【${data.name}】职位信息已自动填充到当前页面!</p>`,\ncustomClass: '',\ndangerouslyUseHTMLString: true,\nduration: 0,\nonClick: async () => {}\n})\n} catch (error) {\nconsole.error(error)\nVue.$Sentry.CE(error)\nlet message = `职位信息填充失败,请刷新页面重试!`\nif (error.resultcode === 404) {\nmessage = `职位信息填充失败!<br/>无招聘职位访问权限或数据已被删除`\n}\nVue.$Notice({\ntype: 'error',\nmessage,\ncustomClass: '',\ndangerouslyUseHTMLString: true,\nduration: 0,\nonClick: async () => {}\n})\n} finally {\nVue.$Document.loadingStop()\n}\n\n}");
		core1.setPublishJobPos2("async function publishJobPos2(options = {}) {\nconst {\nconfig,\nmatches,\nstore,\nbindCorpUrl,\nutil: { waitLoaded, executeScript }\n} = options\nconst { $ } = Vue.$ctx\nconst { htmlToFormattedText } = Vue.$Util\n\nconst job_pos_id = Vue.$Util.queryString(window.location.href, '__job_pos_id')\nif (!job_pos_id) {\nreturn\n}\n\nif (!store.state.jobPos.is_login) {\nwindow.__bindCorpNotice = Vue.$Notice({\ntype: 'warning',\nmessage: `您还未绑定企业,<a href='javascript:window.location.replace(\"${encodeURIComponent(\nbindCorpUrl\n)}\");'>去绑定>></a>`,\ncustomClass: '',\ndangerouslyUseHTMLString: true,\nduration: 0,\nonClick: async () => {}\n})\nreturn\n}\n\nif (window.__bindCorpNotice) {\nwindow.__bindCorpNotice.close()\n}\n\nVue.$Document.loadingStart({\nbackground: 'rgba(255,255,255, 0.5)',\ntext: '正在填充数据,请稍候...',\nlock: false\n})\n\n// 是否能继续\nlet canNext = await waitLoaded('.jqte_editor')\nif (!canNext) {\nVue.$Notice({\ntype: 'warning',\nmessage: '填充数据失败,请刷新页面重试!',\ncustomClass: '',\ndangerouslyUseHTMLString: true,\nduration: 6000,\nonClick: async () => {}\n})\n/* Vue.$Message.warning({\nshowClose: true,\nmessage: '消息',\nduration: 4000\n}) */\nVue.$Document.loadingStop()\nreturn\n}\n\n// 开始填充数据\ntry {\nlet data = await store.dispatch('jobPos/postMessage', {\ncmd: 'api.request',\nurl: `/recruitment/api/resume_assistant/job_position/?job_position_id=${job_pos_id}`,\nmethod: 'GET',\nparams: {}\n})\n\n//! 以下所有填充都必须发生在页面顶层上下文中\n\n// 职位名称+职位类别\nif (data.name) {\nexecuteScript(`\n;(() => {\nconst input = document.querySelector('[placeholder=\"请输入职位名称\"]');\nif (!input) {\nreturn;\n}\ninput.focus();\nconst parent = input.parentNode;\nif (!parent.__vue__) {\nreturn;\n}\nparent.__vue__.$emit('input', '${data.name}');\nconst unwatch = parent.__vue__.$parent.$watch('options', (val = []) => {\nif (val.length) {\nparent.__vue__.$parent.$nextTick(() => {\ndocument.body.click();\n});\n}\n});\ninput.blur();\nconsole.log('职位名称已填充');\n})()\n`)\n}\n\n// 最低学历\nlet education = data.education\nif (education !== null) {\nlet education_zhaopin = {\n0: {\n// '不限'\nlabel: '学历不限',\nvalue: '-1'\n},\n3: {\n// '高中及以上'\nlabel: '高中',\nvalue: '7'\n},\n4: {\n// '大专及以上'\nlabel: '大专',\nvalue: '5'\n},\n5: {\n// '本科及以上'\nlabel: '本科',\nvalue: '4'\n},\n6: {\n// '硕士及以上'\nlabel: '硕士',\nvalue: '3'\n},\n7: {\n// '博士'\nlabel: '博士',\nvalue: '1'\n},\n2: {\n// 初中及以下\nlabel: '初中及以下',\nvalue: '9'\n},\n9: {\n// 中专/中技\nlabel: '中专/中技',\nvalue: '12'\n},\n13: {\n// MBA/EMBA\nlabel: 'MBA/EMBA',\nvalue: '10'\n}\n}[education]\nif (education_zhaopin) {\nexecuteScript(\n`;(() => {\ndocument.querySelector('.km-form').__vue__.$parent.job.education = ${education_zhaopin.value};\nconsole.log('学历已填充');\n})()`\n)\n}\n}\n\n// 工作年限\nlet work_experience = data.work_experience\nif (work_experience !== null) {\nlet work_experience_zhaopin = {\n0: {\n// '不限'\nlabel: '经验不限',\nvalue: -1\n},\n1: {\n// '1年以下'\nlabel: '1年以下',\nvalue: 1\n},\n2: {\n// '1-3年'\nlabel: '1-3年',\nvalue: 103\n},\n3: {\n// '3-5年'\nlabel: '3-5年',\nvalue: 305\n},\n4: {\n// '5-10年'\nlabel: '5-10年',\nvalue: 510\n},\n5: {\n// '10年以上'\nlabel: '10年以上',\nvalue: 1099\n}\n}[work_experience]\nif (work_experience_zhaopin) {\nexecuteScript(\n`;(() => {\ndocument.querySelector('.km-form').__vue__.$parent.job.workAge = ${work_experience_zhaopin.value};\nconsole.log('工作年限已填充');\n})()`\n)\n}\n}\n\n// 工作性质\nif (data.work_type === 2) {\n// 当2号工作性质为实习生时\nexecuteScript(\n`;(() => {\ndocument.querySelector('.km-form').__vue__.$parent.job.employmentType = 4;\nconsole.log('工作性质-实习已填充');\n})()`\n)\n} else if (data.work_type === 1) {\n// 当2号工作性质为兼职时智联招聘填充兼职\nexecuteScript(\n`;(() => {\ndocument.querySelector('.km-form').__vue__.$parent.job.employmentType = 1;\nconsole.log('工作性质-兼职已填充');\n})()`\n)\n}\n\n// 招聘人数\nif (![null, undefined, ''].includes(data.position_total)) {\nexecuteScript(\n`;(() => {\ndocument.querySelector('.km-form').__vue__.$parent.job.quantity = ${data.position_total};\nconsole.log('招聘人数已填充');\n})()`\n)\n}\n\n// 薪资范围,就近算法,获取最近的薪资范围选项\nexecuteScript(`\nconst getClosestNum = (targetNums = [], num, smallestPriority = false) => {\nlet min = Math.min(...targetNums);\nlet max = Math.max(...targetNums);\nif (num <= min) {\nreturn min;\n}\nif (num >= max) {\nreturn max;\n}\nlet map = {};\nlet rs = [];\ntargetNums.map(val => {\nlet value = Math.abs(val - num);\nif (map[value] === undefined) {\nmap[value] = [val];\n} else {\nmap[value].push(val);\n}\nrs.push(value);\n});\nlet rsMin = Math.min(...rs);\nif (smallestPriority) {\nreturn Math.min(...map[rsMin]);\n}\nreturn Math.max(...map[rsMin]);\n}\n`)\n\n// 月薪范围\n// 最低\n// 薪资单位\nlet salary_unit = data.salary_unit // 2号薪资单位为“元/月”时填充\nif (salary_unit === 6) {\nlet salary_min = data.salary_min\nlet salary_max = data.salary_max\nlet salary_min_exists = ![null, undefined, '', -1].includes(salary_min)\nlet salary_max_exists = ![null, undefined, '', -1].includes(salary_max)\n\n// 填充最低薪资\nif (salary_min_exists) {\nif (salary_min < 1000) {\n// 小于1000,特殊处理\nexecuteScript(`;(() => {\ndocument.querySelector('.km-form').__vue__.$parent.job.minSalary = 0;\n})()`)\n} else {\n// 大于等于1000\nexecuteScript(`;(() => {\nconst salary_min_match = getClosestNum(\ndocument.querySelector('.km-form').__vue__.$parent.minSalaryList.map(item => item.lowerValue),\n${salary_min},\ntrue\n);\nif (salary_min_match) {\ndocument.querySelector('.km-form').__vue__.$parent.job.minSalary = salary_min_match;\nconsole.log('最低薪资已填充', salary_min_match);\n}\n})()`)\n}\n}\n\n// 填充最高薪资\nif (salary_max_exists) {\nexecuteScript(`;(() => {\nconst salary_max_match = getClosestNum(\ndocument.querySelector('.km-form').__vue__.$parent.maxSalaryList.map(item => item.upperValue),\n${salary_max}\n);\nif (salary_max_match) {\ndocument.querySelector('.km-form').__vue__.$parent.job.maxSalary = salary_max_match;\n}\n})()`)\n}\n}\n\n// 职位描述\ndata.position_description &&\nexecuteScript(\n`;(() => {\nconst editor = document.querySelector('.jqte_editor');\neditor && editor.focus();\nconst vm = document.querySelector('.km-form').__vue__.$parent;\nif (vm) {\nvm.$refs.jobEditor.setData('${data.position_description}');\nvm.onBlurDescription();\nsetTimeout(() => {\neditor && editor.blur();\n}, 250);\nconsole.log('职位描述已填充');\n}\n})()`\n)\n\nVue.$Notice({\ntype: 'success',\nmessage: `<p>【${data.name}】职位信息已自动填充到当前页面!</p>`,\ncustomClass: '',\ndangerouslyUseHTMLString: true,\nduration: 0,\nonClick: async () => {}\n})\n} catch (error) {\nconsole.error(error)\nVue.$Sentry.CE(error)\nlet message = `职位信息填充失败,请刷新页面重试!`\nif (error.resultcode === 404) {\nmessage = `职位信息填充失败!<br/>无招聘职位访问权限或数据已被删除`\n}\nVue.$Notice({\ntype: 'error',\nmessage,\ncustomClass: '',\ndangerouslyUseHTMLString: true,\nduration: 0,\nonClick: async () => {}\n})\n} finally {\nVue.$Document.loadingStop()\n}\n\n}");
		configMap.put("jobpos-zhaopin",core1);

		/********************config_line 中国人才热线*********************/
		ExtensionCore core2 = new ExtensionCore();
		core2.setLogin("async function login(options = {}) {\nconst { config, matches, store } = options\nconst { $ } = Vue.$ctx\n\nconst $notify = Vue.$Notice({\ntype: 'info',\nmessage: '请先登录招聘网站才能进行职位发布哦~',\ncustomClass: '',\ndangerouslyUseHTMLString: true,\nduration: 0,\nonClick: async() => {\n// $notify.close()\n}\n})\n\n}");
		core2.setPublishJobPos("async function publishJobPos(options = {}) {\nconst {\nconfig,\nmatches,\nstore,\nbindCorpUrl,\nutil: { waitLoaded, executeScript }\n} = options\nconst { $ } = Vue.$ctx\nconst { htmlToFormattedText } = Vue.$Util\n\nconst job_pos_id = Vue.$Util.queryString(window.location.href, '__job_pos_id')\nif (!job_pos_id) {\nreturn\n}\n\nif (!store.state.jobPos.is_login) {\nwindow.__bindCorpNotice = Vue.$Notice({\ntype: 'warning',\nmessage: `您还未绑定企业,<a href='javascript:window.location.replace(\"${encodeURIComponent(\nbindCorpUrl\n)}\");'>去绑定>></a>`,\ncustomClass: '',\ndangerouslyUseHTMLString: true,\nduration: 0,\nonClick: async () => {}\n})\nreturn\n}\n\nif (window.__bindCorpNotice) {\nwindow.__bindCorpNotice.close()\n}\n\nVue.$Document.loadingStart({\nbackground: 'rgba(255,255,255, 0.5)',\ntext: '正在填充数据,请稍候...',\nlock: false\n})\n\n// 是否能继续\nlet canNext = await waitLoaded('#ueditor_0')\nif (!canNext) {\nVue.$Notice({\ntype: 'warning',\nmessage: '填充数据失败,请刷新页面重试!',\ncustomClass: '',\ndangerouslyUseHTMLString: true,\nduration: 6000,\nonClick: async () => {}\n})\n/* Vue.$Message.warning({\nshowClose: true,\nmessage: '消息',\nduration: 4000\n}) */\nVue.$Document.loadingStop()\nreturn\n}\n\n// 开始填充数据\ntry {\nlet data = await store.dispatch('jobPos/postMessage', {\ncmd: 'api.request',\nurl: `/recruitment/api/resume_assistant/job_position/?job_position_id=${job_pos_id}`,\nmethod: 'GET',\nparams: {}\n})\n\n// 职位名称\ndata.name &&\n$('#txtJobName')\n.val(data.name)\n.blur()\n\n// 工作性质\nif (data.work_type === 2) {\n// 当2号工作性质为实习生时\n$('#chxJobType_FullTime').trigger('click')\n$('#chxJobType_Trainee').trigger('click')\n} else if (data.work_type === 1) {\n// 当2号工作性质为兼职时人才热线填充兼职\n$('#chxJobType_FullTime').trigger('click')\n$('#chxJobType_PartTime').trigger('click')\n}\n\n// 工作经验\nlet work_experience = data.work_experience\nif (work_experience !== null) {\nlet work_experience_cjol = {\n0: {\n// 不限\nlabel: '不限',\nvalue: 0\n},\n/* 1: '1年以下', // cjol 没有 */\n2: {\n// '1-3年'\nlabel: '1年以上',\nvalue: 1\n},\n3: {\n// '3-5年'\nlabel: '3年以上',\nvalue: 3\n},\n4: {\n// '5-10年'\nlabel: '5年以上',\nvalue: 5\n},\n5: {\n// '10年以上'\nlabel: '10年以上',\nvalue: 10\n}\n}[work_experience]\nwork_experience_cjol && $(`#dropdwonWorkYears ul li[data-value=\"${work_experience_cjol.value}\"]`).click()\n}\n\n// 学历要求\nlet education = data.education\nif (education !== null) {\nlet education_cjol = {\n0: {\n// '不限'\nlabel: '初中及以上',\nvalue: 10\n},\n3: {\n// '高中及以上'\nlabel: '高中及以上',\nvalue: 20\n},\n4: {\n// '大专及以上'\nlabel: '大专及以上',\nvalue: 50\n},\n5: {\n// '本科及以上'\nlabel: '本科及以上',\nvalue: 60\n},\n6: {\n// '硕士及以上'\nlabel: '硕士及以上',\nvalue: 70\n},\n7: {\n// '博士'\nlabel: '博士及以上',\nvalue: 80\n}\n}[education]\neducation_cjol && $(`#dropdwonEducation ul li[data-value=\"${education_cjol.value}\"]`).click()\n}\n\n// 招聘人数\n![null, undefined, ''].includes(data.position_total) &&\n$('#RecruitCount')\n.val(data.position_total)\n.blur()\n\n// 薪资单位\nlet salary_unit = data.salary_unit\nif (salary_unit === 6) {\n// 薪资范围\nlet customSalary = document.querySelector('#btnCustomSalary')\ncustomSalary && customSalary.click()\n// 最低\nlet salary_min = data.salary_min\nlet salary_min_exists = ![null, undefined, '', -1].includes(salary_min)\nif (salary_min_exists) {\n$('#txtMinSalary')\n.val(salary_min)\n.trigger('blur')\n}\n// 最高\nlet salary_max = data.salary_max\nlet salary_max_exists = ![null, undefined, '', -1].includes(salary_max)\nif (salary_max_exists) {\n$('#txtMaxSalary')\n.val(salary_max)\n.trigger('blur')\n}\n}\n\n// 职位描述\nif (data.position_description) {\nlet $html = $(`<div>${data.position_description}</div>`)\n$html.find('ul,ol').addClass('list-paddingleft-2')\nlet editorBody = window.frames.ueditor_0.contentDocument.body\neditorBody.innerHTML = $html.html()\n// 触发事件使ue编辑器表单验证生效\neditorBody.click()\n}\n\n// 年龄要求\nlet age_min = data.age_min\nif (![null, undefined, '', -1].includes(age_min)) {\n$('#txtMinAge')\n.val(age_min)\n.trigger('blur')\n}\nlet age_max = data.age_max\nif (![null, undefined, '', -1].includes(age_max)) {\n$('#txtMaxAge')\n.val(age_max)\n.trigger('blur')\n}\n\n// 语言要求,多个\nlet language = data.language_level // '普通话、粤语、闽南语、上海话、英语、日语、俄语、阿拉伯语、法语、德语、西班牙语、葡萄牙语、意大利语、韩语/朝鲜语、其他'\nif (language) {\nlanguage = language.split('、')\nlanguage.slice(0, 1).map((lang, idx) => {\nlet lang_cjol = {\n英语: 5, // 英语\n日语: 10, // 日语\n俄语: 70, // 俄语\n阿拉伯语: 80, // 阿拉伯语\n法语: 30, // 法语\n德语: 40, // 德语\n西班牙语: 50, // 西班牙语\n葡萄牙语: 60, // 葡萄牙语\n意大利语: 110, // 意大利语\n'韩语/朝鲜语': 20 // 韩语/朝鲜语\n}[lang]\nif (lang_cjol !== undefined) {\nif (idx === 0) {\n$(`#dropdwonForginLanguage ul li[data-value=\"${lang_cjol}\"]`).click()\n}\n}\n})\n}\n\nVue.$Notice({\ntype: 'success',\nmessage: `<p>【${data.name}】职位信息已自动填充到当前页面!</p>`,\ncustomClass: '',\ndangerouslyUseHTMLString: true,\nduration: 0,\nonClick: async () => {}\n})\n} catch (error) {\nconsole.error(error)\nVue.$Sentry.CE(error)\nlet message = `职位信息填充失败,请刷新页面重试!`\nif (error.resultcode === 404) {\nmessage = `职位信息填充失败!<br/>无招聘职位访问权限或数据已被删除`\n}\nVue.$Notice({\ntype: 'error',\nmessage,\ncustomClass: '',\ndangerouslyUseHTMLString: true,\nduration: 0,\nonClick: async () => {}\n})\n} finally {\nVue.$Document.loadingStop()\n}\n\n}");
		configMap.put("jobpos-cjol",core2);

		return ExtensionResultUtil.data(configMap);
	}
	/**
	 * 摘要助理
	 * @return
	 */
	@GetMapping(value = "/api/resumeassistant_latestversion")
	@ApiOperation(value = "4.摘要助理", httpMethod = "GET", notes = "接口发布说明")
	@ApiOperationSupport(order = 4)
	@Log(title = "摘要助理", businessType = BusinessType.OTHER)
	public ExtensionResult resumeassistant_latestversion() {
		String token = "",version="";
		if (StringUtils.isEmpty(httpServletRequest.getHeader("accesstoken"))) {
			token = httpServletRequest.getHeader("accesstoken");
		}
		if(StringUtils.isEmpty(httpServletRequest.getHeader("assistant_version"))){
			version = httpServletRequest.getHeader("assistant_version");
		}
		ExtensionResumeassistant entity = new ExtensionResumeassistant();
		entity.setId("3339badc-e3dd-4e5b-985f-7d402e9bd0be");
		entity.setOnline_dt("2021-11-02");
		entity.setVersion_no("2.1.7");
		entity.setContent("优化招聘职位匹配。");
		entity.setDownload_url("https://resume-cdn.2haohr.com/3c14c4db601b4164bb546a9a1057e8ee?attname=2haohr_resume_extension_pd_v2.1.7.crx&e=1639131801&token=kHQPThzbVJmJKaDo5HupfecLjZQcm5BOxUjlENLs:EVUQaPc-9C_bwNEgw1mx54ZNBTE=");
		entity.setZip_download_url("");
		entity.setFile_name("2haohr_resume_extension_pd_v2.1.7.crx");
		entity.setZip_name("");
		entity.setAdd_dt("2021-11-02T19:20:55");
		entity.setUpdate_dt("2021-11-03T09:33:54");
		entity.setAdd_name("幽狼");
		entity.setUpdate_name("幽狼");
		entity.setVersion_url("https://resume-cdn.2haohr.com/3c14c4db601b4164bb546a9a1057e8ee?attname=2haohr_resume_extension_pd_v2.1.7.crx&e=1635855652&token=kHQPThzbVJmJKaDo5Hupfe");
		entity.setZip_url("");
		entity.setAdd_by(304);
		entity.setUpdate_by(304);
		return ExtensionResultUtil.data(entity);
	}
	/**
	 * 匹配到合适的招聘职位
	 * @return
	 */
	@GetMapping(value = "/api/resume_assistant/candidate_record")
	@ApiOperation(value = "5.匹配到合适的招聘职位", httpMethod = "GET", notes = "接口发布说明")
	@ApiOperationSupport(order = 5)
	@Log(title = "匹配到合适的招聘职位", businessType = BusinessType.OTHER)
	public ExtensionResult candidate_record(CandidateRecordParam candidateRecordParam) {
		String token = "",version="";
		if (StringUtils.isEmpty(httpServletRequest.getHeader("accesstoken"))) {
			token = httpServletRequest.getHeader("accesstoken");
		}
		if(StringUtils.isEmpty(httpServletRequest.getHeader("assistant_version"))){
			version = httpServletRequest.getHeader("assistant_version");
		}

		return ExtensionResultUtil.data(new HashMap<>(0));
	}
	/**
	 * 添加到人才库
	 * @return
	 */
	@PostMapping(value = "/api/resume_assistant/talent")
	@ApiOperation(value = "6.匹配到合适的招聘职位", httpMethod = "POST", notes = "接口发布说明")
	@ApiOperationSupport(order = 6)
	@Log(title = "添加到人才库", businessType = BusinessType.OTHER)
	public ExtensionResult talent(@RequestBody ExtensionResume extensionResume) {
		String token = "",version="";
		if (StringUtils.isEmpty(httpServletRequest.getHeader("accesstoken"))) {
			token = httpServletRequest.getHeader("accesstoken");
		}
		if(StringUtils.isEmpty(httpServletRequest.getHeader("assistant_version"))){
			version = httpServletRequest.getHeader("assistant_version");
		}
		try{
			Boolean flage = extensionResume.insertOrUpdate();
			log.info("token:{}",token);
			log.info("version:{}",version);
			log.info("extensionResume:{}",extensionResume.toString());
		} catch(Exception exe){
			exe.printStackTrace();
		}
		Map<String,String> map = new HashMap<>(1);
		map.put("candidate_id",extensionResume.getId().toString());
		return ExtensionResultUtil.data(map);
	}

	/**
	 * 保存到人才库(带“筛选”状态)
	 * @return
	 */
	@PostMapping(value = "/api/resume_assistant/sync_resume")
	@ApiOperation(value = "7.保存到人才库(带“筛选”状态)", httpMethod = "POST", notes = "接口发布说明")
	@ApiOperationSupport(order = 7)
	@Log(title = "保存到人才库(带“筛选”状态)", businessType = BusinessType.OTHER)
	public ExtensionResult sync_resume(@RequestBody ExtensionResume extensionResume) {
		String token = "",version="";
		if (StringUtils.isEmpty(httpServletRequest.getHeader("accesstoken"))) {
			token = httpServletRequest.getHeader("accesstoken");
		}
		if(StringUtils.isEmpty(httpServletRequest.getHeader("assistant_version"))){
			version = httpServletRequest.getHeader("assistant_version");
		}
		try{
			Boolean flage = extensionResume.insertOrUpdate();
			log.info("token:{}",token);
			log.info("version:{}",version);
			log.info("extensionResume:{}",extensionResume.toString());
		} catch(Exception exe){
			exe.printStackTrace();
		}
		Map<String,String> map = new HashMap<>(1);
		map.put("candidate_id",extensionResume.getId().toString());
		return ExtensionResultUtil.data(map);
	}
}