/** * Created by zhang on 2020/7/20 */ module.exports={ getOptions, getDataByCondition, getClassByAreaID, mutiApplyInfoPrice }; const mongoose = require('mongoose'); let infoLibModel = mongoose.model("std_price_info_lib"); let infoClassModel = mongoose.model("std_price_info_class"); let infoItemsModel = mongoose.model("std_price_info_items"); let infoAreasModel = mongoose.model("std_price_info_areas"); let unitPriceModel = mongoose.model("unit_price"); let _ = require("lodash"); let gljUtil = require('../../../public/web/gljUtil'); const scMathUtil = require('../../../public/scMathUtil').getUtil(); let projectfacade = require('./project_facade'); // 载入模块 var Segment = require('segment'); // 创建实例 var segment = new Segment(); // 使用默认的识别模块及字典,载入字典文件需要1秒,仅初始化时执行一次即可 segment.useDefault(); let nodejieba = require('../../dict/jieba'); let nameWeightMap ={ // '普通':-99 } async function getOptions(data,compilation){//data 是预留对象,暂时不用 let compilationID = '5b52b027fd3bb0000b257cf8'; let areaMap={}; let periodMap={}; let areas =await infoAreasModel.find({"compilationID":compilationID}).lean(); let libList = await infoLibModel.find({"compilationID":compilationID}).lean(); for(let l of libList){ // for(let area of l.areas){ // if(!areaMap[area]) areas.push(area); // } //2020-05 let periodArray = l.period.split("-"); periodMap[periodArray[0]]?periodMap[periodArray[0]].push(periodArray[1]):periodMap[periodArray[0]]=[periodArray[1]] } for(let key in periodMap){ periodMap[key] = _.sortBy(periodMap[key]); } return {areas:areas,periodMap:periodMap} } async function getClassByAreaID(data,compilation){ //要先知道根据期数和编办查找库ID let newList = []; let lib = await infoLibModel.findOne({compilationID:'5b52b027fd3bb0000b257cf8',period:data.period}) if(lib){ let tList =await getClassList(data.areaID,lib.ID); newList.push(...tList); if(data.commonInfoPriceID){ cList = await getClassList(data.commonInfoPriceID,lib.ID); newList.push(...cList); } } async function getClassList(areaID,libID){ let temList = []; let infoClass = await infoClassModel.find({areaID:areaID,libID:libID}).lean(); let parentMap=_.groupBy(infoClass, 'ParentID'); for(let key in parentMap){ parentMap[key] = projectfacade.sortChildren(parentMap[key]); } if(parentMap && parentMap['-1']){ getChildern(parentMap['-1'],temList,parentMap) } return temList; } function getChildern(children,list,pm){ for(let c of children){ list.push(c); if(pm[c.ID]){ getChildern(pm[c.ID],list,pm) } } } return newList; } async function getDataByCondition(data,compilation){ let result = {}; data.condition["compilationID"] = '5b52b027fd3bb0000b257cf8'; //特殊处理重庆的,地区选择非“通用”时,搜索范围应是当前选择的地区,加上“通用”中的信息价。 if (data.condition.commonInfoPriceID) { let idArray = [data.condition.areaID,data.condition.commonInfoPriceID]; data.condition.areaID = {$in: idArray} delete data.condition.commonInfoPriceID; } //根据地区+期数+材料编号的前4位与信息价材料的分类编号匹配,如果有数据,则显示数据出来。 //先按编号匹配 if (data.code) { result = await getDataByCode(data.code, data); if (result.totalSize > 0) return result; //如果分类编码有结果,但是确没有匹配的条数,说明关键字没匹配上,直接返回没有信息价 if(result.allItems > 0 && result.totalSize === 0){ return result; } } //编号匹配不上的情况: //有关键字的情况 if (data.keyWord) { return await getDataByKeyWord(data.keyWord,data); } //查询所有的情况 if(data.lastID){ //有最后一行说明是查询下一页 data.condition["_id"] = {$gt:mongoose.Types.ObjectId(data.lastID)}; }else{ result.totalSize = await infoItemsModel.find(data.condition).count(); } result.items = await infoItemsModel.find(data.condition).lean().sort({"_id":1}).limit(50); return result; } async function getDataByCode(code, data) { let condition = { ...data.condition }; condition.code = code; /* 2021-03-31 先按编号去取,所有匹配结果再过滤,不能再分类了 let totalSize = await infoItemsModel.find(condition).count(); if (data.lastID) { //有最后一行说明是查询下一页 condition["_id"] = {$gt:mongoose.Types.ObjectId(data.lastID)}; } let items = []; if (totalSize > 0) { items = await infoItemsModel.find(condition).lean().sort({"_id":1}).limit(50); } */ //新需求 --------- let allItems = await infoItemsModel.find(condition).lean().sort({"_id":1}); let items = []; if(data.keyWord && allItems.length > 1){ for(let item of allItems){ if(item.name.indexOf(data.keyWord) != -1) items.push(item) //有完全匹配的,就不用编码下的返回所有数据了 } } //没有完全匹配的,分词匹配关键字 if (items.length === 0){ let nameArray = nodejieba.cut(data.keyWord); nameArray = cusSegment(nameArray,data.keyWord); let result = getMatchPrice(allItems,nameArray); items = result.items; } let totalSize = items.length; //新需求结束 --------- return {totalSize,items,allItems} } async function getDataByKeyWord(keyword, data) { //先按全字匹配 let fullResult =await getDataByFullKeyWord(keyword, data); if(fullResult.totalSize > 0) return fullResult; //如果没有才按模糊匹配 return await getDataByFuzzyMatch(keyword, data); } //按全关键字匹配 async function getDataByFullKeyWord(keyword, data){ let items = []; data.condition.name = new RegExp(keyword); items = await infoItemsModel.find(data.condition).lean().sort({"_id":1}); delete data.condition.name; return{totalSize:items.length,items} } function handelThreeWord(word){ let arr = []; getArr(word[0]+word[1],arr); getArr(word[1]+word[2],arr); if(arr.length > 0) return arr; return[word]; function getArr(tem,list){ let nameArray = segment.doSegment(tem, { simple: true, //不返回词性 stripPunctuation: true //去除标点符号 }); //说明是一个词 if(nameArray.length == 1) list.push(tem) } } function getShortNameArray(nameArray){ let newArray = []; for(let n of nameArray){ if(n.length >= 5){ newArray.push(...nodejieba.cutSmall(n,3)) }else{ newArray.push(n); } } return newArray; } function getMatchPrice(allInfoPrice,nameArray,needHandleLongWord = true){ let items = []; let maxNum = 0;//最大匹配数 let matchMap = {};//匹配储存 let handleLongWord = false; if(needHandleLongWord){ for(let na of nameArray){ if(na.length >= 5) handleLongWord = true; } } for (let info of allInfoPrice) { //specs let mstring = info.name + info.specs; mstring = mstring.replace(/混凝土/g, "砼"); info.mstring = mstring; let matchCount = 0; for (let na of nameArray) { if (mstring.indexOf(na) != -1) { matchCount++; if(needHandleLongWord && na.length >= 5) handleLongWord = false//有5个字的,并且匹配上了,这里就为false不用再处理一次了 } } if (matchCount > 0) { matchMap[matchCount] ? matchMap[matchCount].push(info) : matchMap[matchCount] = [info]; if (matchCount > maxNum) maxNum = matchCount; } } if (maxNum > 0) items = matchMap[maxNum]; totalSize = items.length return {totalSize,items,handleLongWord}; } //自定义特殊处理 function cusSegment(nameArray,keyword){ let temArr = []; for (let a of nameArray) { //混凝土 和 砼 统一认成砼 if (a == "混凝土") a = '砼'; if(a == '砼'||a == '砖' ){ temArr.push(a); }else if(a.length > 1){ //如果是三个字的词,优先识别成两个字 if(a.length == 3){ let sArr = handelThreeWord(a); temArr.push(...sArr); }else{ temArr.push(a); } } } if (keyword.length == 1 && temArr.length == 0) temArr.push(keyword); return temArr; } //模糊匹配 async function getDataByFuzzyMatch(keyword, data){ let nameArray = []; if (keyword.length < 3) { nameArray.push(keyword) } else { nameArray = nodejieba.cut(keyword) } //自定义处理 nameArray = cusSegment(nameArray,keyword); console.log(nameArray); let allInfoPrice = await infoItemsModel.find(data.condition).lean().sort({"_id":1}); let {totalSize,items,handleLongWord} = getMatchPrice(allInfoPrice,nameArray) if(handleLongWord === true){ nameArray = getShortNameArray(nameArray); console.log(`二次匹配:[${nameArray}]`); let newResult = getMatchPrice(allInfoPrice,nameArray,false) totalSize = newResult.totalSize; items = newResult.items; } //关键词按权重排序,为了给结果排序 nameArray = _.sortBy(nameArray,(name)=>{ if(nameWeightMap[name]) return nameWeightMap[name]*-1;//sortBy是升序排序,我们要的是权重越小排到越后即倒序 所以这里乘以-1 return 1 }) //按匹配位置排序 如[ '橡胶', '胶圈', '给水' ] 先显示橡胶 items = _.sortBy(items,(item)=>{ let ms = item.mstring; for(let i = 0;i < nameArray.length;i ++){ if (ms.indexOf(nameArray[i]) != -1) return i; } }) return {totalSize,items} } async function mutiApplyInfoPrice(data,compilation){ data.condition["compilationID"] = '5b52b027fd3bb0000b257cf8'; let infoPrices = await infoItemsModel.find(data.condition).lean(); let tasks = []; let projectGLJMap = {}; for(let info of infoPrices){ let index = gljUtil.getIndex(info,["name","specs","unit"]); if(data.pgljMap[index]){ for(let obj of data.pgljMap[index]){ let infoPrice = gljUtil.getInfoMarketPrice(info,data.taxType); infoPrice = scMathUtil.roundToString(infoPrice,data.decimal); let doc = {'market_price':infoPrice,'priceFrom':data.priceFrom}; let task = { updateOne:{ filter:{'id':obj.unitPriceID}, update:doc } }; tasks.push(task); projectGLJMap[obj.pgljID] = {index:obj.fullIndex,doc:doc}; } } } if(tasks.length > 0) await unitPriceModel.bulkWrite(tasks); return projectGLJMap; }