|
@@ -23,6 +23,8 @@ const compilationModel = mongoose.model('compilation');
|
|
|
const billMaterialModel = mongoose.model('std_billsGuidance_materials');
|
|
|
const gljModel = mongoose.model('std_glj_lib_gljList');
|
|
|
const gljLibModel = mongoose.model('std_glj_lib_map');
|
|
|
+const billClassModel = mongoose.model('billClass');
|
|
|
+const idTree = require('../../../public/id_tree').getTree();
|
|
|
const _ = require('lodash');
|
|
|
const zhLibID = 'cf851660-3534-11ec-9641-2da8021b8e4e';
|
|
|
const cqLibID = '90c51220-a740-11e8-a354-ab5db7d42428';
|
|
@@ -37,6 +39,7 @@ module.exports = {
|
|
|
updateItems,
|
|
|
getBillMaterials,
|
|
|
editBillMaterials,
|
|
|
+ generateClassData,
|
|
|
testItems
|
|
|
};
|
|
|
|
|
@@ -443,6 +446,100 @@ async function editBillMaterials(libID, billID, gljCodes, compilationID) {
|
|
|
return gljList.map(glj => ({ gljID: glj.ID, code: glj.code, name: glj.name, specs: glj.specs }));
|
|
|
}
|
|
|
|
|
|
+ // 是否为工序行
|
|
|
+ function isProcessNode(node) {
|
|
|
+ return node && node.depth() % 2 === 0 && node.data.type === 0
|
|
|
+}
|
|
|
+
|
|
|
+// 是否是选项行
|
|
|
+function isOptionNode(node) {
|
|
|
+ return node && node.depth() % 2 === 1 && node.data.type === 0
|
|
|
+}
|
|
|
+
|
|
|
+// 从指引节点,获取分类特征数据
|
|
|
+function getItemCharacterData(nodes, prefix) {
|
|
|
+ const processNodes = nodes.filter(node => isProcessNode(node) && node.data.required);
|
|
|
+ const classGroups = []; // 同层必填选项的数组(二维数组)
|
|
|
+ processNodes.forEach(processNode => {
|
|
|
+ const classItems = [];
|
|
|
+ const optionNodes = processNode.children.filter(node => isOptionNode(node));
|
|
|
+ optionNodes.forEach(optionNode => {
|
|
|
+ if (!optionNode.children
|
|
|
+ || !optionNode.children.length
|
|
|
+ || (optionNode.children[0].data && optionNode.children[0].data.rationID)
|
|
|
+ || !optionNode.children.some(node => isProcessNode(node) && node.data.required)) {
|
|
|
+ classItems.push(optionNode.data.name);
|
|
|
+ } else {
|
|
|
+ classItems.push(...getItemCharacterData(optionNode.children, optionNode.data.name));
|
|
|
+ }
|
|
|
+ });
|
|
|
+ classGroups.push(classItems);
|
|
|
+ });
|
|
|
+ // 拼接上一文本
|
|
|
+ if (classGroups[0] && classGroups[0].length) {
|
|
|
+ classGroups[0] = classGroups[0].map(name => prefix ? `${prefix}@${name}` : name);
|
|
|
+ }
|
|
|
+ // 二维数组内容排列组合
|
|
|
+ while (classGroups.length > 1) {
|
|
|
+ const prevClassItems = classGroups[0];
|
|
|
+ const nextClassItems = classGroups[1];
|
|
|
+ const mergedClassItems = [];
|
|
|
+ for (let i = 0; i < prevClassItems.length; i++) {
|
|
|
+ for (let j = 0; j < nextClassItems.length; j++) {
|
|
|
+ mergedClassItems.push(`${prevClassItems[i]}@${nextClassItems[j]}`);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ classGroups.splice(0, 2, mergedClassItems);
|
|
|
+ }
|
|
|
+ return classGroups[0] || [];
|
|
|
+}
|
|
|
+
|
|
|
+// 生成清单分类
|
|
|
+async function generateClassData(libID) {
|
|
|
+ const lib = await billsGuideLibModel.findOne({ ID: libID }).lean();
|
|
|
+ if (!lib) {
|
|
|
+ throw new Error('无有效精灵库');
|
|
|
+ }
|
|
|
+ const guidanceItems = await billsGuideItemsModel.find({ libID }, '-_id').lean();
|
|
|
+ // 清单ID - 指引数据映射
|
|
|
+ const guidanceMap = {};
|
|
|
+ guidanceItems.forEach(item => {
|
|
|
+ (guidanceMap[item.billsID] || (guidanceMap[item.billsID] = [])).push(item);
|
|
|
+ });
|
|
|
+ const bills = await stdBillsModel.find({ billsLibId: lib.billsLibId }, '-_id ID ParentID NextSiblingID name code').lean();
|
|
|
+ const billTree = idTree.createNew({id: 'ID', pid: 'ParentID', nid: 'NextSiblingID', rootId: -1, autoUpdate: true});
|
|
|
+ billTree.loadDatas(bills);
|
|
|
+ // 叶子清单
|
|
|
+ const leaves = billTree.items.filter(node => !node.children || !node.children.length);
|
|
|
+ // 获取分类数据
|
|
|
+ let classNum = 1;
|
|
|
+ const billClassData = [];
|
|
|
+ leaves.forEach(billNode => {
|
|
|
+ const guidanceItems = guidanceMap[billNode.data.ID];
|
|
|
+ if (!guidanceItems || !guidanceItems.length) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const guidanceTree = idTree.createNew({id: 'ID', pid: 'ParentID', nid: 'NextSiblingID', rootId: -1, autoUpdate: true});
|
|
|
+ guidanceTree.loadDatas(guidanceItems);
|
|
|
+ const itemCharacterData = getItemCharacterData(guidanceTree.roots);
|
|
|
+ itemCharacterData.forEach(itemCharacter => {
|
|
|
+ billClassData.push({
|
|
|
+ itemCharacter,
|
|
|
+ class: classNum++,
|
|
|
+ classCode: `${billNode.data.code}@${itemCharacter}`,
|
|
|
+ compilationID: lib.compilationId,
|
|
|
+ name: billNode.data.name,
|
|
|
+ code: billNode.data.code,
|
|
|
+ });
|
|
|
+ });
|
|
|
+ });
|
|
|
+ // 清空旧的分类数据
|
|
|
+ await billClassModel.deleteMany({ compilationID: lib.compilationId });
|
|
|
+ if (billClassData.length) {
|
|
|
+ await billClassModel.insertMany(billClassData);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
async function testItems(libID) {
|
|
|
let items = await billsGuideItemsModel.find({libID: libID});
|
|
|
//删除垃圾数据
|