123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917 |
- 'use strict';
- /**
- *
- *
- * @author Zhong
- * @date 2019/6/20
- * @version
- */
- const XML_EXPORT_BASE = (() => {
- // 自检提示的开始记号,区分提示属于哪一部分的类型(eg: 招标、控制价),便于后续做提示的合并去重
- const HINT_START = '--start--';
- // 属性类型
- const TYPE = {
- DATE: 1, //日期类型YYYY-MM-DD
- DATE_TIME: 2, //日期类型YYY-MM-DDTHH:mm:ss
- INT: 3, //整数类型
- DECIMAL: 4, //数值类型,不限制小数位数
- NUM2: 5, //数值类型2:最多两位小数
- BOOL: 6 //布尔型
- };
- // 需要特殊处理的属性类型默认空值(当一个值为undefined、null的时候,默认给赋什么值)
- const DEFAULT_VALUE = {
- [TYPE.INT]: '0',
- [TYPE.DECIMAL]: '0',
- [TYPE.NUM2]: '0',
- [TYPE.BOOL]: 'false'
- };
- // 空白字符处理
- const WHITE_SPACE = {
- COLLAPSE: 1 //移除所有空白字符(换行、回车、空格以及制表符会被替换为空格,开头和结尾的空格会被移除,而多个连续的空格会被缩减为一个单一的空格)
- };
- // 计税方法
- const TAX_TYPE = {
- '1': '一般计税法',
- '2': '简易计税法',
- };
- // 承包人材料调整类型
- const ADJUST_TYPE = {
- info: 'priceInfo', // 造价信息差额调整法
- coe: 'priceCoe' // 价格指数调整法
- };
- // 加载数据间隔,减少服务器压力
- const TIMEOUT_TIME = 400;
- // 导出粒度
- const GRANULARITY = {
- PROJECT: 1, //导出建设项目
- ENGINEERING: 2, //导出单项工程
- TENDER: 3 //导出单位工程
- };
- // 导出的文件类型选项
- const EXPORT_KIND = {
- Tender: 1, //投标
- Bid: 2, //招标
- Control: 3 //控制价
- };
- // 配置项
- const CONFIG = Object.freeze({
- HINT_START,
- TYPE,
- WHITE_SPACE,
- TAX_TYPE,
- ADJUST_TYPE,
- TIMEOUT_TIME,
- GRANULARITY,
- EXPORT_KIND
- });
- // 缓存项 不需要的时候需要清空
- let _cache = {
- // 失败列表
- failList: [],
- // 项目数据(不包含详细数据,项目管理数据)
- projectData: {},
- // 当前导出类型,默认投标
- exportKind: EXPORT_KIND.Tender,
- // 记录拉取的单位工程项目详细数据,导出的时候,可能会导出多个文件,只有导出第一个文件的时候需要请求数据
- tenderDetailMap: {}
- };
- // 返回缓存项
- function getItem(key) {
- return _cache[key] || null;
- }
- // 设置缓存项
- function setItem(key, value) {
- // 与原数据是同类型的数据才可设置成功
- if (_cache[key] &&
- Object.prototype.toString.call(_cache[key]) ===
- Object.prototype.toString.call(value)) {
- _cache[key] = value;
- }
- }
- // 清空缓存项
- function clear() {
- _cache.failList = [];
- _cache.projectData = {};
- _cache.exportKind = EXPORT_KIND.Tender;
- _cache.tenderDetailMap = {};
- }
- const CACHE = Object.freeze({
- getItem,
- setItem,
- clear
- });
- /*
- * 定义不设置一个Node方法统一进入的原因:模板化比较直观,不分开定义节点的话,调用传参也很麻烦而且不直观。
- * 一个节点对应一个构造方法,方便调整配置、方便其他版本开发、接手的人看起来更直观
- * @param {String}name 节点名
- * {Array}attrs 节点属性数据
- * {Array}failList 失败列表
- * @return {void}
- * */
- function Element(name, attrs) {
- this.name = name;
- let checkData = check(name, attrs);
- this.fail = checkData.failHints;
- this.attrs = checkData.filterAttrs;
- handleXMLEntity(this.attrs);
- this.children = [];
- _cache.failList.push(...this.fail);
- }
- /*
- * xml字符实体的处理,这些特殊字符不处理会导致xml文件格式出错:""、<>、&
- * 要先处理&
- * */
- let _xmlEntity = {
- '&': '&',
- '\n': '
',
- '"': '"',
- '\'': ''',
- '<': '<',
- '>': '>'
- };
- // 对每个元素的所有属性值进行特殊字符处理
- function handleXMLEntity(attrs) {
- for (let attr of attrs) {
- if (!attr.value) {
- continue;
- }
- for (let [key, value] of Object.entries(_xmlEntity)) {
- attr.value = attr.value.replace(new RegExp(key, 'g'), value);
- }
- }
- }
- // 获取处理实体字符后的数据
- function getParsedData(arr) {
- return arr.map(data => {
- for (let [key, value] of Object.entries(_xmlEntity)) {
- data = data.replace(new RegExp(key, 'g'), value);
- }
- return data;
- });
- }
- /*
- * 检查
- * 创建节点时检查节点的数据
- * 1.长度限制minLen,maxLen
- * 2.值的限制,固定范围:enumeration
- * @param {String}eleName 节点名称
- * {Array}datas 需要检查的属性数据
- * @return {Object} failHints没通过的属性提示 filterAttrs过滤后的属性数据(失败提示在属性是必须的时候才提示,如果该属性失败了,但是是非必要属性,那么该属性不显示)
- * */
- function check(eleName, datas) {
- let rst = { failHints: [], filterAttrs: [] };
- let dateReg = /([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8])))/;
- for (let data of datas) {
- // 值统一转换成String
- data.value = !hasValue(data.value)
- ? DEFAULT_VALUE[data.type]
- ? DEFAULT_VALUE[data.type]
- : ''
- : String(data.value);
- if (data.whiteSpace && data.whiteSpace === WHITE_SPACE.COLLAPSE) { //处理空格相关
- data.value = data.value.replace(/[\r\n\t]/g, ' ');
- data.value = data.value.trim();
- data.value = data.value.replace(/\s{1,}/g, ' ');
- }
- let isFail = false;
- let tempFail = '';
- // 提示的名称需要处理,有的接口xml属性为英文,需要显示其展示名称
- const name = data.dName || data.name;
- if (data.minLen && data.value.length < data.minLen) {
- isFail = true;
- tempFail = data.failHint
- ? `${data.failHint}字符数不可小于${data.minLen}个。`
- : `${eleName}-“${data.name}”字符数不可小于${data.minLen}个。`;
- } else if (data.maxLen && data.value.length > data.maxLen) {
- isFail = true;
- tempFail = data.failHint
- ? `${data.failHint}字符数不可大于${data.maxLen}个。`
- : `${eleName}-“${data.name}”字符数不可大于${data.maxLen}个。`;
- } else if (data.enumeration && !data.enumeration.includes(data.value)) {
- isFail = true;
- let enumerationHint = data.enumerationHint
- ? data.enumerationHint.join(';')
- : data.enumeration.join(';');
- tempFail = data.failHint
- ? `${data.failHint}只能从“${enumerationHint}”中选择。`
- : `${eleName}-“${data.name}”只能从“${enumerationHint}”中选择。`;
- } else if (data.type && data.type === TYPE.DATE && !dateReg.test(data.value)) {
- isFail = true;
- tempFail = data.failHint
- ? `${data.failHint}日期格式必须是YYYY-MM-DD。`
- : `${eleName}-“${data.name}”日期格式必须是YYYY-MM-DD。`;
- } else if (data.type && data.type === TYPE.INT && !Number.isInteger(parseFloat(data.value))) {
- isFail = true;
- tempFail = data.failHint
- ? `${data.failHint}必须为整数。`
- : `${eleName}-“${data.name}”必须为整数。`;
- } else if (data.type && data.type === TYPE.DECIMAL && isNaN(parseFloat(data.value))) {
- isFail = true;
- tempFail = data.failHint
- ? `${data.failHint}必须为数值。`
- : `${eleName}-“${data.name}”必须为数值。`;
- } else if (data.type && data.type === TYPE.NUM2) {
- let v = parseFloat(data.value);
- if (isNaN(v)) {
- isFail = true;
- tempFail = data.failHint
- ? `${data.failHint}必须为数值。`
- : `${eleName}-“${data.name}”必须为数值。`;
- } else if (!data.value.length || (data.value.split('.').length > 1 && data.value.split('.')[1].length > 2)) {
- isFail = true;
- }
- } else if (data.type && data.type === TYPE.BOOL && !['true', 'false'].includes(String(data.value))) {
- isFail = true;
- tempFail = data.failHint
- ? `${data.failHint}必须为true或false。`
- : `${eleName}-“${data.name}”必须为true或false。`;
- }
- if (!isFail || data.required) {
- rst.filterAttrs.push(data);
- }
- if (isFail && data.required && tempFail) {
- rst.failHints.push(tempFail);
- }
- }
- return rst;
- }
- // 提取各导出类型的自检数据
- function _extractHintParts(failList) {
- let rst = [],
- curPart;
- for (let hint of failList) {
- if (hint === HINT_START) {
- curPart = [];
- rst.push(curPart);
- continue;
- }
- curPart.push(hint);
- }
- return rst;
- }
- // 自检提示去重
- function deWeightHints(failList) {
- let rst = [];
- let hintParts = _extractHintParts(failList);
- // 建设项目提示文本
- let rootHints = [],
- // 单位工程提示文本映射
- tenderMap = {},
- reg = /^<span style="font-weight: bold">单位工程/;
- for (let hintPart of hintParts) {
- // 单位工程xxx提示
- let curTenderHint;
- // 提取建设项目提示、各自单位工程提示
- for (let hint of hintPart) {
- if (reg.test(hint)) {
- curTenderHint = hint;
- if (!tenderMap[curTenderHint]) {
- tenderMap[curTenderHint] = [];
- }
- continue;
- }
- if (curTenderHint) {
- tenderMap[curTenderHint].push(hint);
- } else {
- rootHints.push(hint);
- }
- }
- }
- // 建设项目提示去重,放入结果中
- rootHints = [...new Set(rootHints)];
- rst.push(...rootHints);
- // 单位工程提示放入结果中
- for (let tenderHint in tenderMap) {
- rst.push(tenderHint);
- // 单位工程提示去重
- let tenderHints = [...new Set(tenderMap[tenderHint])];
- rst.push(...tenderHints);
- }
- return rst;
- }
- // 等待一段时间
- function setTimeoutSync(handle, time) {
- return new Promise((resolve, reject) => {
- setTimeout(() => {
- if (handle && typeof handle === 'function') {
- handle();
- }
- resolve();
- }, time);
- });
- }
- // v是否定义了,不为undefined和null
- function isDef(v) {
- return typeof v !== 'undefined' && v !== null;
- }
- function hasValue(v) {
- // v是否有值,不为undefined、null、''
- return typeof v !== 'undefined' && v !== null && v !== '';
- }
- /*
- * 将节点属性数据(attr数组)转换成简单key-value数据
- * @param {Object}ele 元素节点数据Element实例
- * @return {Object}
- * */
- function getPlainAttrs(ele) {
- const obj = {};
- ele.attrs.forEach(attr => obj[attr.name] = attr.value);
- return obj;
- }
- /*
- * 从fees数组中获取相关费用
- * @param {Array}fees 费用数组
- * {String}feeFields 费用字段
- * @return {Number}
- * @example getFee(source.fees, 'common.totalFee')
- * */
- function getFee(fees, feeFields) {
- if (!Array.isArray(fees)) {
- return 0;
- }
- let fields = feeFields.split('.');
- let fee = fees.find(data => data.fieldName === fields[0]);
- if (!fee) {
- return 0;
- }
- 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
- * {String}key
- * @return {String}
- * @example getValueByKey(source.basicInformation, 'projectScale')
- * */
- function getValueByKey(data, key) {
- for (let d of data) {
- if (d.key === key) {
- return d.value;
- }
- if (d.items && d.items.length > 0) {
- let findData = d.items.find(x => x.key === key);
- if (findData) {
- return findData.value;
- }
- }
- }
- return '';
- }
- // 获取关联材料
- function getRelGLJ(allGLJs, gljId) {
- return allGLJs.find(glj => glj.id === gljId);
- }
- // 随机生成机器信息码:CPU信息;硬盘序列号;mac地址;
- // 保存在localStorage中
- function generateHardwareId() {
- const hardwareCacheId = window.localStorage.getItem('hardwareId');
- if (hardwareCacheId) {
- return hardwareCacheId;
- }
- const charList = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D',
- 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
- 'V', 'W', 'X', 'Y', 'Z'];
- function generateCpuId() {
- let id = '';
- let count = 16;
- while (count--) {
- const randomIdx = parseInt(Math.random() * 16);
- id += charList[randomIdx];
- }
- return id;
- }
- function generateDiskId() {
- let id = '';
- let count = 8;
- while (count--) {
- const randomIdx = parseInt(Math.random() * 36);
- id += charList[randomIdx];
- }
- return id;
- }
- function generateMacId() {
- const idList = [];
- let outerCount = 6;
- while (outerCount--) {
- let tempId = '';
- let innerCount = 2;
- while (innerCount--) {
- const randomIdx = parseInt(Math.random() * 16);
- tempId += charList[randomIdx];
- }
- idList.push(tempId);
- }
- return idList.join('-');
- }
- const cpuId = generateCpuId();
- const diskId = generateDiskId();
- const macId = generateMacId();
- const hardwareId = [cpuId, diskId, macId].join(';');
- window.localStorage.setItem('hardwareId', hardwareId);
- return hardwareId;
- }
- // 数组打平成对象
- function arrayToObj(arr) {
- let rst = {};
- for (let data of arr) {
- rst[data.key] = data.value;
- }
- return rst;
- }
- /*
- * 检测层数
- * @param {Number}maxDepth(最大深度)
- * {Object}node(需要检测的清单树节点)
- * @return {Boolean}
- * */
- function validDepth(maxDepth, node) {
- let nodeDepth = node.depth();
- let allNodes = node.getPosterity();
- //检测相对深度
- for (let n of allNodes) {
- let relativeDepth = n.depth() - nodeDepth;
- if (relativeDepth > maxDepth) {
- return false;
- }
- }
- return true;
- }
- /*
- * 检测唯一性,有些属性在规定的数据范围内唯一
- * @param {Object}constraints(约束池)
- * {All}data(检测的数据)
- * {String}hint(提示已存在的内容)
- * {String}subHint(额外提示,有额外提示时,不用data提示)
- * @return {void}
- * */
- function checkUnique(constraints, data, hint, subHint) {
- if (constraints.includes(data)) {
- let failHint = subHint
- ? `${hint}“${subHint}”已存在`
- : `${hint}“${data}”已存在`;
- _cache.failList.push(failHint);
- } else if (data) {
- constraints.push(data);
- }
- }
- //根据数据的NextSiblingID进行排序,返回排序后的数组
- function sortByNext(datas) {
- let target = [],
- temp = {};
- for (let data of datas) {
- temp[data.ID] = { me: data, next: null, prev: null };
- }
- for (let data of datas) {
- let next = temp[data.NextSiblingID] || null;
- temp[data.ID].next = next;
- if (next) {
- next.prev = temp[data.ID];
- }
- }
- let first = null;
- for (let data of datas) {
- let me = temp[data.ID];
- if (!me.prev) {
- first = me;
- }
- }
- if (!first) {
- return datas;
- }
- while (first) {
- target.push(first.me);
- first = first.next;
- }
- return target;
- }
- /*
- * 根据粒度获取项目(不包含详细数据)数据
- * @param {Number}granularity 导出粒度
- * {Number}tenderID 单位工程ID
- * {String}userID 用户ID
- * @return {Object} 返回的数据结构:{children: [{children: []}]} 最外层为建设项目,中间为单项工程,最底层为单位工程
- * */
- async function getProjectByGranularity(granularity, tenderID, userID) {
- let projectData = _cache.projectData;
- // 没有数据,需要拉取
- if (!Object.keys(projectData).length) {
- projectData = await ajaxPost('/pm/api/getProjectByGranularity', { user_id: userID, tenderID: tenderID, granularity: granularity });
- _cache.projectData = projectData;
- }
- return projectData;
- }
- /*
- * 通过getData接口获取单位工程详细数据
- * @param {Number}tenderID 单位工程ID
- * {String}userID 用户ID
- * @return {Object} 跟projectObj.project的数据结构一致
- * */
- async function getTenderDetail(tenderID, userID) {
- // 获取单位工程详细数据
- let tenderDetail = _cache.tenderDetailMap[tenderID];
- if (!tenderDetail) {
- tenderDetail = PROJECT.createNew(tenderID, userID);
- await tenderDetail.loadDataSync();
- // 标记序号
- const count = Object.keys(_cache.tenderDetailMap).length;
- tenderDetail.serialNo = count + 1;
- _cache.tenderDetailMap[tenderID] = tenderDetail;
- }
- return tenderDetail;
- }
- /*
- * 提取要导出的数据
- * @param {Function}entryFunc 提取数据的入口方法
- * {Number}granularity 导出粒度: 1-建设项目、2-单项工程、3-单位工程
- * {Number}exportKind 导出的文件类型:1-投标、2-招标、3-控制价
- * {Number}tenderID 单位工程ID
- * {String}userID 用户ID
- * @return {Array} 数据结构为:[{data: Object, exportKind: Number, fileName: String}]
- * */
- async function extractExportData(entryFunc, granularity, exportKind, tenderID, userID) {
- // 默认导出建设项目
- if (!granularity || ![1, 2, 3].includes(granularity)) {
- granularity = GRANULARITY.PROJECT;
- }
- // 默认导出投标文件
- if (!exportKind || ![1, 2, 3].includes(exportKind)) {
- exportKind = EXPORT_KIND.Tender;
- }
- // 拉取标段数据:建设项目、单项工程、单位工程数据
- let projectData = await getProjectByGranularity(granularity, tenderID, userID);
- if (!projectData) {
- throw '获取项目数据错误';
- }
- // 单项工程、单位工程按照树结构数据进行排序
- projectData.children = sortByNext(projectData.children);
- for (let engData of projectData.children) {
- engData.children = sortByNext(engData.children);
- }
- // 提取相关项目的详细导出数据
- return await entryFunc(userID, exportKind, projectData);
- }
- // 转换基数表达式
- // 1.有子项,则取固定清单对应基数
- // 2.无子项,有基数,a.优先转换为行代号(不可自身) b.不能转换为行代号则找对应字典
- // 3.基数中有无法转换的,根据导出类型决定
- function transformCalcBase(exportKind, tenderDetail, node, { CalcBaseMap, FlagCalcBaseMap }) {
- let expr = node.data.calcBase || '';
- if (node.children.length) {
- let flag = node.getFlag();
- return FlagCalcBaseMap[flag] || '';
- }
- if (expr) {
- let illegal = false;
- let normalBase = _getNormalBase(expr),
- idBase = _getIDBase(expr);
- //普通基数转基数字典
- normalBase.forEach(base => {
- let replaceStr = CalcBaseMap[base];
- //转换成行代号的优先级比较高,进行清单匹配
- let flag = FlagCalcBaseMap[base];
- if (flag) {
- let flagNode = tenderDetail.mainTree.items.find(mNode => mNode.getFlag() === flag);
- //匹配到了 普通基数转换成行引用
- if (flagNode) {
- replaceStr = `F${flagNode.serialNo() + 1}`;
- }
- }
- //存在无法处理的基数
- if (!replaceStr) {
- illegal = true;
- return;
- }
- expr = expr.replace(new RegExp(base, 'g'), replaceStr);
- });
- //id引用转行代号引用
- idBase.forEach(base => {
- let id = base.match(/[^@]+/)[0];
- let theNode = tenderDetail.mainTree.getNodeByID(id),
- rowCode = theNode ? `F${theNode.serialNo() + 1}` : '';
- if (!rowCode) {
- illegal = true;
- return;
- }
- expr = expr.replace(new RegExp(base, 'g'), rowCode);
- });
- //不合法
- // 在我们软件中的基数无法找到映射代号的情况下
- // 导出招标、控制价时,基数为空
- // 导出投标时,基数=综合合价/费率
- if (illegal) {
- if (exportKind === EXPORT_KIND.Bid || exportKind === EXPORT_KIND.Control) {
- return '';
- } else {
- let totalFee = getFee(node.data.fees, 'common.totalFee'),
- feeRate = node.data.feeRate;
- return +feeRate ? scMathUtil.roundTo(totalFee / (feeRate / 100), -2) : totalFee
- }
- }
- return expr;
- }
- //获取普通基数: {xxx}
- function _getNormalBase(str) {
- let reg = /{.+?}/g,
- matchs = str.match(reg);
- return matchs || [];
- }
- //获取id引用基数: @xxx-xxx-xx
- function _getIDBase(str) {
- let reg = /@.{36}/g,
- matchs = str.match(reg);
- return matchs || [];
- }
- }
- // 转换基数说明,根据转换后的基数处理
- //1.行引用转换为对应行的名称
- //2.基数字典转换为中文
- function transformCalcBaseState(tenderDetail, expr, CalcStateMap) {
- if (!expr) {
- return '';
- }
- expr = String(expr);
- //提取基数
- let bases = expr.split(/[\+\-\*\/]/g);
- //提取操作符
- let oprs = expr.match(/[\+\-\*\/]/g);
- //转换后的基数
- let newBase = [];
- let illegal = false;
- for (let base of bases) {
- //行引用转换为名称.
- if (/F\d+/.test(base)) {
- let rowCode = base.match(/\d+/)[0],
- node = tenderDetail.mainTree.items[rowCode - 1];
- if (!node || !node.data.name) {
- illegal = true;
- break;
- }
- newBase.push(node && node.data.name ? node.data.name : '');
- } else if (CalcStateMap[base]) { //字典转换为中文
- newBase.push(CalcStateMap[base]);
- } else if (/^\d+(\.\d+)?$/.test(base)) { //金额
- newBase.push(base);
- } else {
- illegal = true;
- break;
- }
- }
- if (illegal) {
- return '';
- }
- let newExpr = '';
- for (let i = 0; i < newBase.length; i++) {
- newExpr += newBase[i];
- if (oprs && oprs[i]) {
- newExpr += oprs[i];
- }
- }
- return newExpr;
- }
- // 获取工程编号表格相关数据(导出需要弹出工程编号让用户选择)
- function getCodeSheetData(projectData) {
- let curCode = '0';
- let sheetData = [];
- sheetData.push(getObj(projectData));
- projectData.children.forEach(eng => {
- sheetData.push(getObj(eng));
- eng.children.forEach(tender => {
- sheetData.push(getObj(tender));
- });
- });
- //建设项目父ID设置为-1
- if (sheetData.length) {
- sheetData[0].ParentID = -1;
- sheetData[0].code = '';
- }
- return sheetData;
- function getObj(data) {
- return {
- collapsed: false,
- ID: data.ID,
- ParentID: data.ParentID,
- NextSiblingID: data.NextSiblingID,
- name: data.name,
- code: data.code || String(curCode++)
- };
- }
- }
- // 从srcEle节点中获取元素名为eleName的元素
- function getElementFromSrc(srcEle, eleName) {
- if (!srcEle || !srcEle.children || !srcEle.children.length) {
- return [];
- }
- return srcEle.children.filter(ele => ele.name === eleName);
- }
- /*
- * 设置完工程编号后,更新原始数据的工程编号
- * 更新原始数据前需要将编号里的特殊字符进行转换
- * @param {Array}exportData 提取出来的需要导出的数据
- * {Array}codes 工程编号表中填写的工程编号
- * {String}EngineeringName 单项工程元素的名称
- * {String}tenderName 单位工程元素的名称
- * {String}codeName 编号属性的名称
- * @return {void}
- * */
- function setupCode(exportData, codes, EngineeringName, tenderName, codeName) {
- // 转换xml实体字符
- let parsedCodes = getParsedData(codes);
- // 给导出数据里的单项工程、单位工程填上用户设置的工程编号
- exportData.forEach(orgData => {
- let curIdx = 0;
- let engs = getElementFromSrc(orgData.data, EngineeringName);
- engs.forEach(eng => {
- eng.attrs.find(attr => attr.name === codeName).value = parsedCodes[curIdx++];
- let tenders = getElementFromSrc(eng, tenderName);
- tenders.forEach(tender => {
- tender.attrs.find(attr => attr.name === codeName).value = parsedCodes[curIdx++];
- });
- });
- });
- }
- /**
- * 弱自检自检,有错误非强制不可导的自检
- * failList里存的是导出规定属性时,不符合标准规定的错误,存在这种错误就不允许导出
- * 这里的错误是业务上的提示错误,与标准文件规定无关,存在这种错误是允许导出的
- * @return {Array} - 提示信息数组
- */
- function softCheck() {
- const tenderDetailMap = _cache.tenderDetailMap;
- // 检查清单综合单价是否大于最高限价,大于则提示
- function checkMaxPrice(tenderDetail) {
- return tenderDetail.mainTree.items
- .filter(node => calcTools.unitFeeGTMaxPrice(node, 'common.unitFee'))
- .map(node => {
- const code = node.data.code || '';
- const name = node.data.name || '';
- return `第${node.serialNo()}行“${code + name}”,清单综合单价 > 最高限价`;
- });
- }
- const infos = [];
- // 按照获取顺序serialNo(根据树结构)排序
- Object.values(tenderDetailMap)
- .sort((a, b) => a.serialNo - b.serialNo)
- .forEach(tenderDetail => {
- const maxPriceInfos = checkMaxPrice(tenderDetail);
- if (!maxPriceInfos.length) {
- return;
- }
- infos.push(`<span style="font-weight: bold">单位工程“${tenderDetail.projectInfo.name}”下:</span>`);
- infos.push(...maxPriceInfos);
- });
- return infos;
- }
-
- const UTIL = Object.freeze({
- deWeightHints,
- isDef,
- hasValue,
- setTimeoutSync,
- getFee,
- getAggregateFee,
- getFeeByFlag,
- getPlainAttrs,
- getValueByKey,
- getRelGLJ,
- generateHardwareId,
- arrayToObj,
- validDepth,
- checkUnique,
- sortByNext,
- getTenderDetail,
- getProjectByGranularity,
- transformCalcBase,
- transformCalcBaseState,
- getCodeSheetData,
- getElementFromSrc,
- getParsedData,
- setupCode,
- softCheck
- });
- // 开始标签
- function _startTag(ele) {
- let rst = `<${ele.name}`;
- for (let attr of ele.attrs) {
- rst += ` ${attr.name}="${attr.value}"`;
- }
- rst += ele.children.length > 0 ? '>' : '/>';
- return rst;
- }
- // 结束标签
- function _endTag(ele) {
- return `</${ele.name}>`;
- }
- // 拼接成xml字符串
- function _toXMLStr(eles) {
- let rst = '';
- for (let ele of eles) {
- rst += _startTag(ele);
- if (ele.children.length > 0) {
- rst += _toXMLStr(ele.children);
- rst += _endTag(ele);
- }
- }
- return rst;
- }
- //格式化xml字符串
- function _formatXml(text) {
- //去掉多余的空格
- text = '\n' + text.replace(/>\s*?</g, ">\n<");
- //调整格式
- let rgx = /\n(<(([^\?]).+?)(?:\s|\s*?>|\s*?(\/)>)(?:.*?(?:(?:(\/)>)|(?:<(\/)\2>)))?)/mg;
- let nodeStack = [];
- let output = text.replace(rgx, function ($0, all, name, isBegin, isCloseFull1, isCloseFull2, isFull1, isFull2) {
- let isClosed = (isCloseFull1 === '/') || (isCloseFull2 === '/') || (isFull1 === '/') || (isFull2 === '/');
- let prefix = '';
- if (isBegin === '!') {
- prefix = getPrefix(nodeStack.length);
- } else {
- if (isBegin !== '/') {
- prefix = getPrefix(nodeStack.length);
- if (!isClosed) {
- nodeStack.push(name);
- }
- } else {
- nodeStack.pop();
- prefix = getPrefix(nodeStack.length);
- }
- }
- let ret = '\n' + prefix + all;
- return ret;
- });
- let outputText = output.substring(1);
- return outputText;
- function getPrefix(prefixIndex) {
- let span = ' ';
- let output = [];
- for (let i = 0; i < prefixIndex; ++i) {
- output.push(span);
- }
- return output.join('');
- }
- }
- /*
- * 根据各自费用定额的文件结构,导出文件
- * 每个费用定额可能导出的结果文件都不同
- * 比如广东18需要将一个建设项目文件,多个单位工程文件打包成一个zip文件。重庆18就没这种要求
- * @param {Array}codes 工程编号数据
- * {Array}extractData 提取的数据
- * {Function}setCodeFunc 各自费用定额的导出前重设用户输入的工程编号方法
- * {Function}saveAsFunc 各自费用定额的导出方法
- * @return {void}
- * */
- async function exportFile(codes, extractData, setCodeFunc, saveAsFunc) {
- // 编号重置后将会被导出,需要将编号进行xml字符实体转换
- codes = getParsedData(codes);
- setCodeFunc(codes, extractData);
- // 获取文件数据
- let fileData = extractData.map(extractObj => {
- // 转换成xml字符串
- let xmlStr = _toXMLStr([extractObj.data]);
- // 加上xml声明
- xmlStr = `<?xml version="1.0" encoding="utf-8"?>${xmlStr}`;
- // 格式化
- xmlStr = _formatXml(xmlStr);
- let blob = new Blob([xmlStr], { type: 'text/plain;charset=utf-8' });
- return {
- blob: blob,
- exportKind: extractObj.exportKind,
- fileName: extractObj.fileName
- };
- });
- // 导出
- await saveAsFunc(fileData);
- }
- return {
- CONFIG,
- CACHE,
- UTIL,
- Element,
- extractExportData,
- exportFile
- };
- })();
|