123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356 |
- /**
- * 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 = compilation._id;
- 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:compilation._id,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"] = compilation._id;
- //特殊处理重庆的,地区选择非“通用”时,搜索范围应是当前选择的地区,加上“通用”中的信息价。
- 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 && data.keyWord){
- 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"] = compilation._id;
- 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);
- const marketPrice = gljUtil.calcMarketPriceByInfoPrice(infoPrice,obj.purchaseFeeRate,data.decimal,scMathUtil);
- let doc = {'market_price':marketPrice,'priceFrom':data.priceFrom,infoPrice};
- 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;
- }
|