vian %!s(int64=5) %!d(string=hai) anos
pai
achega
d002339295

+ 2 - 0
config/gulpConfig.js

@@ -71,6 +71,8 @@ module.exports = {
         'lib/jquery-contextmenu/!*.js',*/
         //'lib/lodash/lodash.js',
         // 'test/tmp_data/test_ration_calc/ration_calc_base.js',
+        'lib/pinyinjs/pinyin_dict_firstletter.js',
+        'lib/pinyinjs/pinyinUtil.js',
         'web/building_saas/main/js/models/main_consts.js',
         'web/over_write/config/compilation_config.js',
         'public/web/common_util.js',

+ 372 - 0
lib/pinyinjs/pinyinUtil.js

@@ -0,0 +1,372 @@
+
+/**
+ * 汉字与拼音互转工具,根据导入的字典文件的不同支持不同
+ * 对于多音字目前只是将所有可能的组合输出,准确识别多音字需要完善的词库,而词库文件往往比字库还要大,所以不太适合web环境。
+ * @start 2016-09-26
+ * @last 2016-09-29
+ */
+;(function(global, factory) {
+	if (typeof module === "object" && typeof module.exports === "object") {
+		module.exports = factory(global);
+	} else {
+		factory(global);
+	}
+})(typeof window !== "undefined" ? window : this, function(window) {
+
+	var toneMap = 
+	{
+		"ā": "a1",
+		"á": "a2",
+		"ǎ": "a3",
+		"à": "a4",
+		"ō": "o1",
+		"ó": "o2",
+		"ǒ": "o3",
+		"ò": "o4",
+		"ē": "e1",
+		"é": "e2",
+		"ě": "e3",
+		"è": "e4",
+		"ī": "i1",
+		"í": "i2",
+		"ǐ": "i3",
+		"ì": "i4",
+		"ū": "u1",
+		"ú": "u2",
+		"ǔ": "u3",
+		"ù": "u4",
+		"ü": "v0",
+		"ǖ": "v1",
+		"ǘ": "v2",
+		"ǚ": "v3",
+		"ǜ": "v4",
+		"ń": "n2",
+		"ň": "n3",
+		"": "m2"
+	};
+
+	var dict = {}; // 存储所有字典数据
+	var pinyinUtil =
+	{
+		/**
+		 * 解析各种字典文件,所需的字典文件必须在本JS之前导入
+		 */
+		parseDict: function()
+		{
+			// 如果导入了 pinyin_dict_firstletter.js
+			if(window.pinyin_dict_firstletter)
+			{
+				dict.firstletter = pinyin_dict_firstletter;
+			}
+			// 如果导入了 pinyin_dict_notone.js
+			if(window.pinyin_dict_notone)
+			{
+				dict.notone = {};
+				dict.py2hz = pinyin_dict_notone; // 拼音转汉字
+				for(var i in pinyin_dict_notone)
+				{
+					var temp = pinyin_dict_notone[i];
+					for(var j=0, len=temp.length; j<len; j++)
+					{
+						if(!dict.notone[temp[j]]) dict.notone[temp[j]] = i; // 不考虑多音字
+					}
+				}
+			}
+			// 如果导入了 pinyin_dict_withtone.js
+			if(window.pinyin_dict_withtone)
+			{
+				dict.withtone = {}; // 汉字与拼音映射,多音字用空格分开,类似这种结构:{'大': 'da tai'}
+				var temp = pinyin_dict_withtone.split(',');
+				for(var i=0, len = temp.length; i<len; i++)
+				{
+					// 这段代码耗时28毫秒左右,对性能影响不大,所以一次性处理完毕
+					dict.withtone[String.fromCharCode(i + 19968)] = temp[i]; // 这里先不进行split(' '),因为一次性循环2万次split比较消耗性能
+				}
+
+				// 拼音 -> 汉字
+				if(window.pinyin_dict_notone)
+				{
+					// 对于拼音转汉字,我们优先使用pinyin_dict_notone字典文件
+					// 因为这个字典文件不包含生僻字,且已按照汉字使用频率排序
+					dict.py2hz = pinyin_dict_notone; // 拼音转汉字
+				}
+				else
+				{
+					// 将字典文件解析成拼音->汉字的结构
+					// 与先分割后逐个去掉声调相比,先一次性全部去掉声调然后再分割速度至少快了3倍,前者大约需要120毫秒,后者大约只需要30毫秒(Chrome下)
+					var notone = pinyinUtil.removeTone(pinyin_dict_withtone).split(',');
+					var py2hz = {}, py, hz;
+					for(var i=0, len = notone.length; i<len; i++)
+					{
+						hz = String.fromCharCode(i + 19968); // 汉字
+						py = notone[i].split(' '); // 去掉了声调的拼音数组
+						for(var j=0; j<py.length; j++)
+						{
+							py2hz[py[j]] = (py2hz[py[j]] || '') + hz;
+						}
+					}
+					dict.py2hz = py2hz;
+				}
+			}
+		},
+		/**
+		 * 根据汉字获取拼音,如果不是汉字直接返回原字符
+		 * @param chinese 要转换的汉字
+		 * @param splitter 分隔字符,默认用空格分隔
+		 * @param withtone 返回结果是否包含声调,默认是
+		 * @param polyphone 是否支持多音字,默认否
+		 */
+		getPinyin: function(chinese, splitter, withtone, polyphone)
+		{
+			if(!chinese || /^ +$/g.test(chinese)) return '';
+			splitter = splitter == undefined ? ' ' : splitter;
+			withtone = withtone == undefined ? true : withtone;
+			polyphone = polyphone == undefined ? false : polyphone;
+			var result = [];
+			if(dict.withtone) // 优先使用带声调的字典文件
+			{
+				var noChinese = '';
+				for (var i=0, len = chinese.length; i < len; i++)
+				{
+					var pinyin = dict.withtone[chinese[i]];
+					if(pinyin)
+					{
+						// 如果不需要多音字,默认返回第一个拼音,后面的直接忽略
+						// 所以这对数据字典有一定要求,常见字的拼音必须放在最前面
+						if(!polyphone) pinyin = pinyin.replace(/ .*$/g, '');
+						if(!withtone) pinyin = this.removeTone(pinyin); // 如果不需要声调
+						//空格,把noChinese作为一个词插入
+						noChinese && ( result.push( noChinese), noChinese = '' );
+						result.push( pinyin ); 
+					}
+					else if ( !chinese[i] || /^ +$/g.test(chinese[i]) ){
+						//空格,把noChinese作为一个词插入
+						noChinese && ( result.push( noChinese), noChinese = '' );
+					}
+					else{
+						noChinese += chinese[i];
+					}
+				}
+				if ( noChinese ){
+					result.push( noChinese);
+					noChinese = '';
+				}
+			}
+			else if(dict.notone) // 使用没有声调的字典文件
+			{
+				if(withtone) console.warn('pinyin_dict_notone 字典文件不支持声调!');
+				if(polyphone) console.warn('pinyin_dict_notone 字典文件不支持多音字!');
+				var noChinese = '';
+				for (var i=0, len = chinese.length; i < len; i++)
+				{
+					var temp = chinese.charAt(i),
+						pinyin = dict.notone[temp];
+					if ( pinyin ){ //插入拼音
+						//空格,把noChinese作为一个词插入
+						noChinese && ( result.push( noChinese), noChinese = '' );
+						result.push( pinyin );
+					}
+					else if ( !temp || /^ +$/g.test(temp) ){
+						//空格,插入之前的非中文字符
+						noChinese && ( result.push( noChinese), noChinese = '' );
+					}
+					else {
+						//非空格,关联到noChinese中
+						noChinese += temp;
+					}
+				}
+
+				if ( noChinese ){
+					result.push( noChinese );
+					noChinese = '';
+				}
+			}
+			else
+			{
+				throw '抱歉,未找到合适的拼音字典文件!';
+			}
+			if(!polyphone) return result.join(splitter);
+			else
+			{
+				if(window.pinyin_dict_polyphone) return parsePolyphone(chinese, result, splitter, withtone);
+				else return handlePolyphone(result, ' ', splitter);
+			}
+		},
+		/**
+		 * 获取汉字的拼音首字母
+		 * @param str 汉字字符串,如果遇到非汉字则原样返回
+		 * @param polyphone 是否支持多音字,默认false,如果为true,会返回所有可能的组合数组
+		 */
+		getFirstLetter: function(str, polyphone)
+		{
+			polyphone = polyphone == undefined ? false : polyphone;
+			if(!str || /^ +$/g.test(str)) return '';
+			if(dict.firstletter) // 使用首字母字典文件
+			{
+				var result = [];
+				for(var i=0; i<str.length; i++)
+				{
+					var unicode = str.charCodeAt(i);
+					var ch = str.charAt(i);
+					if(unicode >= 19968 && unicode <= 40869)
+					{
+						ch = dict.firstletter.all.charAt(unicode-19968);
+						if(polyphone) ch = dict.firstletter.polyphone[unicode] || ch;
+					}
+					result.push(ch);
+				}
+				if(!polyphone) return result.join(''); // 如果不用管多音字,直接将数组拼接成字符串
+				else return handlePolyphone(result, '', ''); // 处理多音字,此时的result类似于:['D', 'ZC', 'F']
+			}
+			else
+			{
+				var py = this.getPinyin(str, ' ', false, polyphone);
+				py = py instanceof Array ? py : [py];
+				var result = [];
+				for(var i=0; i<py.length; i++)
+				{
+					result.push(py[i].replace(/(^| )(\w)\w*/g, function(m,$1,$2){return $2.toUpperCase();}));
+				}
+				if(!polyphone) return result[0];
+				else return simpleUnique(result);
+			}
+		},
+		/**
+		 * 拼音转汉字,只支持单个汉字,返回所有匹配的汉字组合
+		 * @param pinyin 单个汉字的拼音,可以包含声调
+		 */
+		getHanzi: function(pinyin)
+		{
+			if(!dict.py2hz)
+			{
+				throw '抱歉,未找到合适的拼音字典文件!';
+			}
+			return dict.py2hz[this.removeTone(pinyin)] || '';
+		},
+		/**
+		 * 获取某个汉字的同音字,本方法暂时有问题,待完善
+		 * @param hz 单个汉字
+		 * @param sameTone 是否获取同音同声调的汉字,必须传进来的拼音带声调才支持,默认false
+		 */
+		getSameVoiceWord: function(hz, sameTone)
+		{
+			sameTone = sameTone || false
+			return this.getHanzi(this.getPinyin(hz, ' ', false))
+		},
+		/**
+		 * 去除拼音中的声调,比如将 xiǎo míng tóng xué 转换成 xiao ming tong xue
+		 * @param pinyin 需要转换的拼音
+		 */
+		removeTone: function(pinyin)
+		{
+			return pinyin.replace(/[āáǎàōóǒòēéěèīíǐìūúǔùüǖǘǚǜńň]/g, function(m){ return toneMap[m][0]; });
+		},
+		/**
+		 * 将数组拼音转换成真正的带标点的拼音
+		 * @param pinyinWithoutTone 类似 xu2e这样的带数字的拼音
+		 */
+		getTone: function(pinyinWithoutTone)
+		{
+			var newToneMap = {};
+			for(var i in toneMap) newToneMap[toneMap[i]] = i;
+			return (pinyinWithoutTone || '').replace(/[a-z]\d/g, function(m) {
+				return newToneMap[m] || m;
+			});
+		}
+	};
+
+
+	/**
+	 * 处理多音字,将类似['D', 'ZC', 'F']转换成['DZF', 'DCF']
+	 * 或者将 ['chang zhang', 'cheng'] 转换成 ['chang cheng', 'zhang cheng']
+	 */
+	function handlePolyphone(array, splitter, joinChar)
+	{
+		splitter = splitter || '';
+		var result = [''], temp = [];
+		for(var i=0; i<array.length; i++)
+		{
+			temp = [];
+			var t = array[i].split(splitter);
+			for(var j=0; j<t.length; j++)
+			{
+				for(var k=0; k<result.length; k++)
+					temp.push(result[k] + (result[k]?joinChar:'') + t[j]);
+			}
+			result = temp;
+		}
+		return simpleUnique(result);
+	}
+
+	/**
+	 * 根据词库找出多音字正确的读音
+	 * 这里只是非常简单的实现,效率和效果都有一些问题
+	 * 推荐使用第三方分词工具先对句子进行分词,然后再匹配多音字
+	 * @param chinese 需要转换的汉字
+	 * @param result 初步匹配出来的包含多个发音的拼音结果
+	 * @param splitter 返回结果拼接字符
+	 */
+	function parsePolyphone(chinese, result, splitter, withtone)
+	{
+		var poly = window.pinyin_dict_polyphone;
+		var max = 7; // 最多只考虑7个汉字的多音字词,虽然词库里面有10个字的,但是数量非常少,为了整体效率暂时忽略之
+		var temp = poly[chinese];
+		if(temp) // 如果直接找到了结果
+		{
+			temp = temp.split(' ');
+			for(var i=0; i<temp.length; i++)
+			{
+				result[i] = temp[i] || result[i];
+				if(!withtone) result[i] = pinyinUtil.removeTone(result[i]);
+			}
+			return result.join(splitter);
+		}
+		for(var i=0; i<chinese.length; i++)
+		{
+			temp = '';
+			for(var j=0; j<max && (i+j)<chinese.length; j++)
+			{
+				if(!/^[\u2E80-\u9FFF]+$/.test(chinese[i+j])) break; // 如果碰到非汉字直接停止本次查找
+				temp += chinese[i+j];
+				var res = poly[temp];
+				if(res) // 如果找到了多音字词语
+				{
+					res = res.split(' ');
+					for(var k=0; k<=j; k++)
+					{
+						if(res[k]) result[i+k] = withtone ? res[k] : pinyinUtil.removeTone(res[k]);
+					}
+					break;
+				}
+			}
+		}
+		// 最后这一步是为了防止出现词库里面也没有包含的多音字词语
+		for(var i=0; i<result.length; i++)
+		{
+			result[i] = result[i].replace(/ .*$/g, '');
+		}
+		return result.join(splitter);
+	}
+
+	// 简单数组去重
+	function simpleUnique(array)
+	{
+		var result = [];
+		var hash = {};
+		for(var i=0; i<array.length; i++)
+		{
+			var key = (typeof array[i]) + array[i];
+			if(!hash[key])
+			{
+				result.push(array[i]);
+				hash[key] = true;
+			}
+		}
+		return result;
+	}
+
+	pinyinUtil.parseDict();
+	pinyinUtil.dict = dict;
+	window.pinyinUtil = pinyinUtil;
+
+});

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 8 - 0
lib/pinyinjs/pinyin_dict_firstletter.js


+ 16 - 35
modules/pm/facade/pm_facade.js

@@ -866,14 +866,6 @@ function summarizeToParent(parent, child, fields = null) {
     for (let field of fields) {
         parent[field] = scMathUtil.roundTo(parseFloat(parent[field]) + parseFloat(child[field]), decimal);
     }
-   /* const decimal = -2;
-    parent.engineeringCost = scMathUtil.roundTo(parseFloat(parent.engineeringCost) + parseFloat(child.engineeringCost), decimal);
-    parent.subEngineering = scMathUtil.roundTo(parseFloat(parent.subEngineering) + parseFloat(child.subEngineering), decimal);
-    parent.measure = scMathUtil.roundTo(parseFloat(parent.measure) + parseFloat(child.measure), decimal);
-    parent.safetyConstruction = scMathUtil.roundTo(parseFloat(parent.safetyConstruction) + parseFloat(child.safetyConstruction), decimal);
-    parent.other = scMathUtil.roundTo(parseFloat(parent.other) + parseFloat(child.other), decimal);
-    parent.charge = scMathUtil.roundTo(parseFloat(parent.charge) + parseFloat(child.charge), decimal);
-    parent.tax = scMathUtil.roundTo(parseFloat(parent.tax) + parseFloat(child.tax), decimal);*/
 }
 
 function getBuildingArea(projFeature){
@@ -1049,13 +1041,6 @@ async function getSummaryInfo(projectIDs, feeFields = null){
     for (let data of feeFields) {
         flagFieldMapping[data.k] = data.v;
     }
-    /*flagFieldMapping[billsFlags.ENGINEERINGCOST] = 'engineeringCost';
-    flagFieldMapping[billsFlags.SUB_ENGINERRING] = 'subEngineering';
-    flagFieldMapping[billsFlags.MEASURE] = 'measure';
-    flagFieldMapping[billsFlags.SAFETY_CONSTRUCTION] = 'safetyConstruction';
-    flagFieldMapping[billsFlags.OTHER] = 'other';
-    flagFieldMapping[billsFlags.CHARGE] = 'charge';
-    flagFieldMapping[billsFlags.TAX] = 'tax';*/
     let projects = await projectModel.find({ID: {$in : projectIDs}, projType: projectType.project, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]});
     //设置建设项目的总建筑面积
     for(let project of projects){
@@ -1071,7 +1056,6 @@ async function getSummaryInfo(projectIDs, feeFields = null){
                 }
             }
         }
-        //IDMapping[project.ID] = {engineeringCost: 0, subEngineering: 0, measure: 0, safetyConstruction: 0, other: 0, charge: 0, tax: 0, estimate: 0, rate: 0, buildingArea: grossArea, perCost: ''};
         IDMapping[project.ID] = {estimate: 0, rate: 0, buildingArea: grossArea, perCost: ''};
         initFees(IDMapping[project.ID], feeFields);
         console.log(IDMapping[project.ID]);
@@ -1084,7 +1068,6 @@ async function getSummaryInfo(projectIDs, feeFields = null){
     let engIDs = [];
     for(let eng of engineerings){
         engIDs.push(eng.ID);
-        //IDMapping[eng.ID] = {engineeringCost: 0, subEngineering: 0, measure: 0, safetyConstruction: 0, other: 0, charge: 0, tax: 0, estimate: 0, rate: 0, buildingArea: '', perCost: ''};
         IDMapping[eng.ID] = {estimate: 0, rate: 0, buildingArea: '', perCost: ''};
         initFees(IDMapping[eng.ID], feeFields);
     }
@@ -1095,8 +1078,6 @@ async function getSummaryInfo(projectIDs, feeFields = null){
     if(tenders.length > 0){
         for(let tender of tenders){
             tenderIDs.push(tender.ID);
-            /*IDMapping[tender.ID] = {engineeringCost: 0, subEngineering: 0, measure: 0, safetyConstruction: 0, other: 0, charge: 0, tax: 0, rate: 0, estimate: 0,
-                buildingArea: '', perCost: '',changeMark:tender.changeMark,property:tender.property};*/
             IDMapping[tender.ID] = {rate: 0, estimate: 0, buildingArea: '', perCost: '', changeMark:tender.changeMark,property:tender.property};
             initFees(IDMapping[tender.ID], feeFields);
             let buildingArea = getBuildingArea(tender.property.projectFeature);
@@ -1105,8 +1086,6 @@ async function getSummaryInfo(projectIDs, feeFields = null){
             }
         }
         //需要获取的清单固定类别综合合价:工程造价、分部分项、措施项目、安全文明施工专项、规费、其他项目、税金...
-        /*let needFlags = [billsFlags.ENGINEERINGCOST, billsFlags.SUB_ENGINERRING, billsFlags.MEASURE,
-            billsFlags.SAFETY_CONSTRUCTION, billsFlags.CHARGE, billsFlags.OTHER, billsFlags.TAX];*/
         let needFlags = feeFields.map(data => data.k);
         //获取单位工程汇总金额需要用到的所有清单
         let allBills = await billsModel.find({projectID: {$in: tenderIDs}, 'flags.flag': {$in: needFlags}, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]},
@@ -1139,8 +1118,9 @@ async function getSummaryInfo(projectIDs, feeFields = null){
             let engInfo = IDMapping[tender.ParentID];
             tenderInfo.rate = engInfo.engineeringCost == 0 ? 0 : scMathUtil.roundTo(tenderInfo.engineeringCost * 100 / engInfo.engineeringCost, rateDecimal);
             //单方造价
-            tenderInfo.perCost = tenderInfo.buildingArea.toString().trim() === '' || tenderInfo.buildingArea == 0 ?
-                                 tenderInfo.buildingArea.toString().trim() : scMathUtil.roundTo(tenderInfo.engineeringCost / tenderInfo.buildingArea, perCostDecimal);
+            tenderInfo.perCost = tenderInfo.buildingArea.toString().trim() === '' || tenderInfo.buildingArea == 0 
+                ? tenderInfo.buildingArea.toString().trim() 
+                : scMathUtil.roundTo(tenderInfo.engineeringCost / tenderInfo.buildingArea, perCostDecimal);
         }
         for(let eng of engineerings){
             let engInfo = IDMapping[eng.ID];
@@ -1151,8 +1131,9 @@ async function getSummaryInfo(projectIDs, feeFields = null){
         for(let project of projects){
             let projectInfo = IDMapping[project.ID];
             projectInfo.rate = 100;
-            projectInfo.perCost = projectInfo.buildingArea.toString().trim() === '' || projectInfo.buildingArea == 0 ?
-                                  projectInfo.buildingArea.toString().trim() : scMathUtil.roundTo(projectInfo.engineeringCost / projectInfo.buildingArea, perCostDecimal);
+            projectInfo.perCost = projectInfo.buildingArea.toString().trim() === '' || projectInfo.buildingArea == 0 
+            ? projectInfo.buildingArea.toString().trim() 
+            : scMathUtil.roundTo(projectInfo.engineeringCost / projectInfo.buildingArea, perCostDecimal);
         }
     }
     return IDMapping;
@@ -1397,33 +1378,33 @@ async function getProjectByGranularity(tenderID, granularity, userID, versionNam
         ENGINEERING: 2,
         TENDER: 3
     };
-    let theTender = await projectModel.findOne({userID: userID, ID: tenderID}); //加上session的userID,防止tenderID被篡改过
+    let theTender = await projectModel.findOne({userID: userID, ID: tenderID}).lean(); //加上session的userID,防止tenderID被篡改过
     if (!theTender) {
         return null;
     }
-    let theEngineering = await projectModel.findOne({ID: theTender.ParentID});
+    let theEngineering = await projectModel.findOne({ID: theTender.ParentID}).lean();
     if (!theEngineering) {
         return null;
     }
-    let constructionProject = await projectModel.findOne({ID: theEngineering.ParentID});
+    let constructionProject = await projectModel.findOne({ID: theEngineering.ParentID}).lean();
     if (!constructionProject) {
         return null;
     }
     let engineerings;
     if (granularity === GRANULARITY.PROJECT) {
-        engineerings = await projectModel.find({ParentID: constructionProject.ID, $or: notDeleted});
+        engineerings = await projectModel.find({ParentID: constructionProject.ID, $or: notDeleted}).lean();
         for (let eng of engineerings) {
-            eng._doc.children = await projectModel.find({ParentID: eng.ID, $or: notDeleted});
+            eng.children = await projectModel.find({ParentID: eng.ID, $or: notDeleted}).lean();
         }
     } else {
         engineerings = [theEngineering];
         if (granularity === GRANULARITY.ENGINEERING) {
-            theEngineering._doc.children = await projectModel.find({ParentID: theEngineering.ID, $or: notDeleted});
+            theEngineering.children = await projectModel.find({ParentID: theEngineering.ID, $or: notDeleted}).lean();
         } else {
-            theEngineering._doc.children = [theTender];
+            theEngineering.children = [theTender];
         }
     }
-    constructionProject._doc.children = engineerings;
+    constructionProject.children = engineerings;
     //获取汇总信息
     let feeFields = [
         {k: billsFlags.ENGINEERINGCOST, v: 'engineeringCost'},
@@ -1440,12 +1421,12 @@ async function getProjectByGranularity(tenderID, granularity, userID, versionNam
         {k: billsFlags.CLAIM_VISA, v: 'claimVisa'},
         {k: billsFlags.TAX, v: 'tax'}
     ];
-    constructionProject._doc.summaryInfo = await getSummaryInfo([constructionProject.ID], feeFields);
+    constructionProject.summaryInfo = await getSummaryInfo([constructionProject.ID], feeFields);
     //获取编制软件信息: 软件公司;软件名;版本号;授权信息; base64
     let product = await productModel.findOne({});
     let company = product.company || '珠海纵横创新软件有限公司',
         version = product.version || '';
-    constructionProject._doc.softInfo = `${company};${versionName};${version};${userID}`;
+    constructionProject.softInfo = `${company};${versionName};${version};${userID}`;
     return constructionProject;
 }
 

+ 2 - 0
web/building_saas/main/html/main.html

@@ -2367,6 +2367,8 @@
     <script type="text/javascript" src="/lib/jspdf/jspdf.min.js"></script>
     <!-- inject:js -->
     <!--<script type="text/javascript" src="/test/tmp_data/test_ration_calc/ration_calc_base.js"></script>-->
+    <script src="/lib/pinyinjs/pinyin_dict_firstletter.js"></script>
+    <script src="/lib/pinyinjs/pinyinUtil.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/models/main_consts.js"></script>
     <script type="text/javascript" src="/web/over_write/config/compilation_config.js"></script>
     <script type="text/javascript" src="/public/web/common_util.js"></script>

+ 15 - 1
web/building_saas/main/js/models/exportStdInterfaceBase.js

@@ -339,6 +339,19 @@ const XML_EXPORT_BASE = (() => {
         }
         return fee[fields[1]] || 0;
     }
+    // 获取节点的汇总价格
+    function getAggregateFee(nodes) {
+        let total = nodes.reduce((acc, node) => {
+            const price = getFee(node.data.fees, 'common.totalFee');
+            return acc += price;
+        }, 0);
+        return scMathUtil.roundTo(total, -2);
+    }
+    // 获取固定类别行的费用
+    function getFeeByFlag(items, flag, feeFields) {
+        const node = items.find(node => node.getFlag() === flag);
+        return node ? getFee(node.data.fees, feeFields) : '0';
+    }
     /*
      * 根据key获取对应的基本信息、工程特征数据
      * @param  {Array}data
@@ -770,13 +783,14 @@ const XML_EXPORT_BASE = (() => {
         return infos;
     }
     
-
     const UTIL = Object.freeze({
         deWeightHints,
         isDef,
         hasValue,
         setTimeoutSync,
         getFee,
+        getAggregateFee,
+        getFeeByFlag,
         getPlainAttrs,
         getValueByKey,
         getRelGLJ,

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1027 - 371
web/building_saas/main/js/models/exportStdInterface_gd18.js