Przeglądaj źródła

Merge branch 'master' of http://192.168.1.41:3000/SmartCost/YangHuOperation

Tony Kang 2 tygodni temu
rodzic
commit
ede70b5482
36 zmienionych plików z 1133 dodań i 256 usunięć
  1. 7 0
      lib/localforage/localforage.min.js
  2. 7 2
      modules/all_models/stdGlj_glj.js
  3. 14 6
      modules/all_models/stdGlj_gljClass.js
  4. 3 1
      modules/all_models/std_price_info_items.js
  5. 24 17
      modules/all_models/tpl_tree_node.js
  6. 9 0
      modules/bills_lib/controllers/bills_lib_controllers.js
  7. 3 0
      modules/bills_lib/controllers/bills_permissionController.js
  8. 21 3
      modules/bills_lib/models/bills_lib_interfaces.js
  9. 1 0
      modules/bills_lib/routes/bills_lib_routes.js
  10. 23 0
      modules/common/const/bills_fixed.js
  11. 11 0
      modules/price_info_lib/controllers/index.js
  12. 47 0
      modules/price_info_lib/facade/index.js
  13. 1 0
      modules/price_info_lib/routes/index.js
  14. 0 1
      modules/ration_repository/controllers/repository_views_controller.js
  15. 6 6
      modules/ration_repository/models/ration_item.js
  16. 5 23
      modules/reports/controllers/rpt_tpl_controller.js
  17. 1 1
      modules/std_glj_lib/controllers/viewsController.js
  18. 2 2
      modules/std_glj_lib/models/gljModel.js
  19. 1 0
      package.json
  20. 133 106
      public/web/id_tree.js
  21. 24 0
      public/web/lock_util.js
  22. 22 2
      public/web/tree_sheet/tree_sheet_controller.js
  23. 25 0
      web/maintain/bills_lib/css/main.css
  24. 99 1
      web/maintain/bills_lib/html/qingdan.html
  25. 12 12
      web/maintain/bills_lib/scripts/bills_lib_ajax.js
  26. 299 46
      web/maintain/bills_lib/scripts/db_controller.js
  27. 30 0
      web/maintain/price_info_lib/html/edit.html
  28. 2 1
      web/maintain/price_info_lib/js/index.js
  29. 63 5
      web/maintain/price_info_lib/js/priceArea.js
  30. 2 1
      web/maintain/price_info_lib/js/priceClass.js
  31. 105 3
      web/maintain/price_info_lib/js/priceItem.js
  32. 2 0
      web/maintain/report/html/rpt_tpl_dtl_info.html
  33. 31 3
      web/maintain/report/js/rpt_tpl_main.js
  34. 29 1
      web/maintain/std_glj_lib/html/gongliao.html
  35. 68 13
      web/maintain/std_glj_lib/js/glj.js
  36. 1 0
      web/maintain/std_glj_lib/js/gljClassTree.js

Plik diff jest za duży
+ 7 - 0
lib/localforage/localforage.min.js


+ 7 - 2
modules/all_models/stdGlj_glj.js

@@ -33,6 +33,7 @@ const std_glj = new Schema(
       default: {},
     },
     gljClass: Number,
+    classSeq: Number,
     gljType: Number,
     shortName: String,
     unit: String,
@@ -47,5 +48,9 @@ const std_glj = new Schema(
   { versionKey: false }
 );
 
-mongoose.model('std_glj_lib_gljList', std_glj, 'std_glj_lib_gljList');
-mongoose.model('std_glj_lib_gljList_backup', std_glj, 'std_glj_lib_gljList_backup');
+mongoose.model("std_glj_lib_gljList", std_glj, "std_glj_lib_gljList");
+mongoose.model(
+  "std_glj_lib_gljList_backup",
+  std_glj,
+  "std_glj_lib_gljList_backup"
+);

+ 14 - 6
modules/all_models/stdGlj_gljClass.js

@@ -2,16 +2,24 @@
  * Created by Zhong on 2018/3/22.
  */
 /*标准工料机分类树*/
-const mongoose = require('mongoose');
+const mongoose = require("mongoose");
 const Schema = mongoose.Schema;
-const std_gljClass = new Schema({
+const std_gljClass = new Schema(
+  {
     repositoryId: Number,
     ID: Number,
     ParentID: Number,
     NextSiblingID: Number,
     Name: String,
-    deleted: Boolean
-}, { versionKey: false });
+    deleted: Boolean,
+    classSeq: Number,
+  },
+  { versionKey: false }
+);
 
-mongoose.model('std_glj_lib_gljClass', std_gljClass, 'std_glj_lib_gljClass');
-mongoose.model('std_glj_lib_gljClass_backup', std_gljClass, 'std_glj_lib_gljClass_backup');
+mongoose.model("std_glj_lib_gljClass", std_gljClass, "std_glj_lib_gljClass");
+mongoose.model(
+  "std_glj_lib_gljClass_backup",
+  std_gljClass,
+  "std_glj_lib_gljClass_backup"
+);

+ 3 - 1
modules/all_models/std_price_info_items.js

@@ -83,6 +83,8 @@ const priceInfoItems = new Schema({
         default: []
     }
 }, { versionKey: false });
-priceInfoItems.index({ areaID:1,period:1});
+priceInfoItems.index({ areaID: 1, period: 1 });
+priceInfoItems.index({ ID: 1 });
+priceInfoItems.index({ libID: 1 });
 
 mongoose.model('std_price_info_items', priceInfoItems, 'std_price_info_items');

+ 24 - 17
modules/all_models/tpl_tree_node.js

@@ -19,27 +19,34 @@ let Schema = mongoose.Schema;
 // });
 
 let TplNodeSchema = new Schema({
-    nodeType: Number,   //节点类型:树节点(枝) 或 模板节点(叶), 统一结构
-    ID: Number,         //template节点ID,只有在nodeType是模板节点有效
-    refId: Number,      //引用报表模板id (引用 collection: rpt_templates)
-    name: String,       //显示名称
-    released: Boolean,  //是否已发布
-    items: []           //子节点
+  nodeType: Number, //节点类型:树节点(枝) 或 模板节点(叶), 统一结构
+  ID: Number, //template节点ID,只有在nodeType是模板节点有效
+  refId: Number, //引用报表模板id (引用 collection: rpt_templates)
+  name: String, //显示名称
+  released: Boolean, //是否已发布
+  items: [], //子节点
 });
 
 let RptTplTreeSchema = new Schema({
-    compilationId: String,      //编办的ObjectId
-    // engineerId: Number,         //工程专业Id(参考 /modules/common/const/engineering.js)
-    userId: String,             //用户名的object_id串
-    properties: [],             //这是一个预留的属性,假定未来还会有不同的划分细节(如:招标/投标/清单 ... etc)
-    name: String,               //显示名称
-    released: Boolean,          //是否已发布
-    isDeleted: Boolean,         //删除标记
-    flags: Schema.Types.Mixed,  //额外标记集合(这些标记可能会影响到前端显示,如‘计税方式’等)
-    items: []                   //TplNodeSchema entity
+  compilationId: String, //编办的ObjectId
+  // engineerId: Number,         //工程专业Id(参考 /modules/common/const/engineering.js)
+  userId: String, //用户名的object_id串
+  properties: [], //这是一个预留的属性,假定未来还会有不同的划分细节(如:招标/投标/清单 ... etc)
+  name: String, //显示名称
+  released: Boolean, //是否已发布
+  isDeleted: Boolean, //删除标记
+  flags: Schema.Types.Mixed, //额外标记集合(这些标记可能会影响到前端显示,如‘计税方式’等)
+  UUID: String,
+  items: [], //TplNodeSchema entity
 });
-RptTplTreeSchema.statics.findAndModify = function (query, sort, doc, options, callback) {
-    return this.collection.findAndModify(query, sort, doc, options, callback);
+RptTplTreeSchema.statics.findAndModify = function (
+  query,
+  sort,
+  doc,
+  options,
+  callback
+) {
+  return this.collection.findAndModify(query, sort, doc, options, callback);
 };
 
 mongoose.model("rpt_tpl_tree", RptTplTreeSchema, "rpt_tpl_tree");

+ 9 - 0
modules/bills_lib/controllers/bills_lib_controllers.js

@@ -168,6 +168,15 @@ module.exports = {
             callback(req, res, err, message, datas);
         });
     },
+    transferRecharge: async function (req, res) {
+        try {
+            let data = JSON.parse(req.body.data);
+            await billsLibDao.transferRecharge(data.billsLibId);
+            callback(req, res, 0, 'success', null);
+        } catch (error) {
+            callback(req, res, 1, error.message, null);
+        }
+    },
     getJobContent: function (req, res) {
         let data = JSON.parse(req.body.data);
         billsLibDao.getJobContent(data, function (err, message, jobs) {

+ 3 - 0
modules/bills_lib/controllers/bills_permissionController.js

@@ -69,6 +69,9 @@ class billsPermContr extends baseController {
     isUsed(req, res) {
         billsController.isUsed(req, res);
     }
+    transferRecharge(req, res) {
+        billsController.transferRecharge(req, res);
+    }
     /*
      * 导入标准清单(确定节点结构:深度数组)
      * */

+ 21 - 3
modules/bills_lib/models/bills_lib_interfaces.js

@@ -13,7 +13,8 @@ let moment = require("moment");
 let billsGuidanceLib = mongoose.model("std_billsGuidance_lib");
 const engLibModel = mongoose.model("engineering_lib");
 let uuid = require("uuid");
-let billsLibDao = function () {};
+let _ = require("lodash");
+let billsLibDao = function () { };
 
 billsLibDao.prototype.copyLib = async function (userName, libName, fromLibId) {
   const libData = await this.createStdBillsLibSync(userName, libName);
@@ -396,13 +397,13 @@ billsLibDao.prototype.createBills = function (cbillsData, callback) {
   let newBills = [];
   for (let bill of insertBills) {
     newBills.push({
-      ...bill,
       code: "",
       name: "",
       unit: "",
       ruleText: "",
       Expression: "",
       recharge: "",
+      ...bill,
       deleted: false,
     });
   }
@@ -2570,6 +2571,23 @@ billsLibDao.prototype.isUsed = function (data, callback) {
   }
 };
 
+// 计算规则转移补注
+billsLibDao.prototype.transferRecharge = async function (billsLibId) {
+  const bills = await Bills.find({ billsLibId }).lean('-_id ID recharge ruleText');
+  const bulks = [];
+  bills.forEach(bill => {
+    if (bill.ruleText) {
+      bulks.push({ updateOne: { filter: { ID: bill.ID }, update: { $set: { recharge: `<p>${bill.ruleText}</p>`, ruleText: '' } } } });
+    }
+  });
+  const chunks = _.chunk(bulks, 1000);
+  for (const chunk of chunks) {
+    if (chunk.length) {
+      await Bills.bulkWrite(chunk);
+    }
+  }
+};
+
 //--------------JobContent------------------
 
 billsLibDao.prototype.getJobContent = function (gJobData, callback) {
@@ -4815,7 +4833,7 @@ billsLibDao.prototype.importBills = async function (billsLibId, sheetData) {
       recharge: "",
     };
     let jobData =
-        typeof rowData[4] !== "undefined" ? getDivideData(rowData[4]) : [],
+      typeof rowData[4] !== "undefined" ? getDivideData(rowData[4]) : [],
       itemData =
         typeof rowData[5] !== "undefined" ? getDivideData(rowData[5]) : [];
     bills.jobData = jobData;

+ 1 - 0
modules/bills_lib/routes/bills_lib_routes.js

@@ -60,6 +60,7 @@ module.exports = function (app) {
     billsRouter.post('/pasteRel', billsContr.auth, billsContr.init, billsContr.pasteRel);
     billsRouter.post("/deleteBills", billsContr.auth, billsContr.init, billsContr.deleteBills);
     billsRouter.post("/isUsed", billsContr.auth, billsContr.init, billsContr.isUsed);
+    billsRouter.post("/transferRecharge", billsContr.auth, billsContr.init, billsContr.transferRecharge);
 
     billsRouter.post("/getJobContent", jobsContr.auth, jobsContr.init, jobsContr.getJobContent);
     billsRouter.post("/createJobContent", jobsContr.auth, jobsContr.init, jobsContr.createJobContent);

+ 23 - 0
modules/common/const/bills_fixed.js

@@ -228,6 +228,22 @@ if (process.env.NODE_ENV.indexOf('hw') !== -1) {
         ADD_REQ_LAND: 198,
         // 国有土地
         NATIONAL_LAND: 199,
+        // 竣(交)工验收试验检测费
+        COMPLETION_DETECTION: 200,
+        // 预可、工可编制费
+        PRE_PERMIT_COMPILATION: 201,
+        // 水土保持评估费
+        SOLID_WATER_ASSESSMENT: 202,
+        // 地质灾害危险性评价费
+        GEO_DISASTER_RISK: 203,
+        // 节能评估费
+        ENERGY_CONSERVATION: 204,
+        // 社会稳定风险评估费
+        SOCIAL_STABILITY: 205,
+        // 建设项目其他费设置
+        CONSTRUCTION_OTHER_SETTING: 206
+
+
     };
 }
 
@@ -301,6 +317,13 @@ const fixedFlagList = [
     { name: '招标费用', value: fixedFlag.INVITATION },
     { name: '补征地', value: fixedFlag.ADD_REQ_LAND },
     { name: '国有土地', value: fixedFlag.NATIONAL_LAND },
+    { name: '竣(交)工验收试验检测费', value: fixedFlag.COMPLETION_DETECTION },
+    { name: '预可、工可编制费', value: fixedFlag.PRE_PERMIT_COMPILATION },
+    { name: '水土保持评估费', value: fixedFlag.SOLID_WATER_ASSESSMENT },
+    { name: '地质灾害危险性评价费', value: fixedFlag.GEO_DISASTER_RISK },
+    { name: '节能评估费', value: fixedFlag.ENERGY_CONSERVATION },
+    { name: '社会稳定风险评估费', value: fixedFlag.SOCIAL_STABILITY },
+    { name: '建设项目其他费设置', value: fixedFlag.CONSTRUCTION_OTHER_SETTING },
 ];
 
 export { fixedFlag as default, fixedFlagList as List };

+ 11 - 0
modules/price_info_lib/controllers/index.js

@@ -303,6 +303,17 @@ class PriceInfoController extends BaseController {
         }
     }
 
+    async batchUpdate(req, res) {
+        try {
+            const { priceItem, prop, val } = JSON.parse(req.body.data);
+            await facade.batchUpdate(priceItem, prop, val);
+            res.json({ error: 0, message: 'batchUpdate success' });
+        } catch (err) {
+            console.log(err);
+            res.json({ error: 1, message: err.toString() });
+        }
+    }
+
     // 匹配总表
     async matchSummary(req, res) {
         try {

+ 47 - 0
modules/price_info_lib/facade/index.js

@@ -763,6 +763,52 @@ async function exportInfoPriceByCompilation(compilationID) {
 }
 
 
+// 批量修改同省份下所有相同材料(编号、名称、规格、单位)
+async function batchUpdate(priceItem, prop, val) {
+    const date1 = Date.now();
+    const areas = await priceInfoAreaModel.find({ compilationID: priceItem.compilationID }, '-_id ID name').lean();
+    const area = areas.find(item => item.ID === priceItem.areaID);
+    if (!area || !area.name) {
+        throw new Error('找不到对应地区');
+    }
+    const province = area.name.split('-')[0];
+    const reg = new RegExp(`^${province}`)
+    const sameProvinceAreas = areas.filter(item => reg.test(item.name));
+    console.log(`sameProvinceAreas`);
+    console.log(sameProvinceAreas);
+    if (!sameProvinceAreas.length) {
+        return;
+    }
+    console.log('1', date1);
+    const date2 = Date.now();
+    const areaIDs = sameProvinceAreas.map(item => item.ID);
+    // 根据编号初筛
+    const priceItems = await priceInfoItemModel.find({ libID: priceItem.libID, code: priceItem.code || '' }, '-_id ID areaID code name specs unit').lean();
+    const date3 = Date.now();
+    console.log('2', date3 - date2);
+    // 批量修改相同材料
+    // const bulks = [];
+    const getKey = (item) => {
+        return `${item.code || ''}@${item.name || ''}@${item.specs || ''}@${item.unit || ''}`;
+    }
+    const key = getKey(priceItem);
+    const updateIDs = [];
+    priceItems.forEach(item => {
+        if (areaIDs.includes(item.areaID) && getKey(item) === key) {
+            updateIDs.push(item.ID);
+            // bulks.push({ updateOne: { filter: { ID: item.ID }, update: { $set: { [prop]: val } } } });
+        }
+    });
+    if (updateIDs.length) {
+        await priceInfoItemModel.updateMany({ ID: { $in: updateIDs } }, { $set: { [prop]: val } });
+    }
+    const date4 = Date.now();
+    console.log('3', date4 - date3);
+
+
+}
+
+
 module.exports = {
     getLibs,
     createLib,
@@ -788,4 +834,5 @@ module.exports = {
     exportInfoPriceByLib,
     exportInfoPriceByCompilation,
     getAllLibs,
+    batchUpdate,
 }

+ 1 - 0
modules/price_info_lib/routes/index.js

@@ -31,6 +31,7 @@ module.exports = function (app) {
     router.get("/exportInfoPriceByLib", priceInfoController.auth, priceInfoController.init, priceInfoController.exportInfoPriceByLib);
     router.get("/exportInfoPriceByCompilation", priceInfoController.auth, priceInfoController.init, priceInfoController.exportInfoPriceByCompilation);
     router.post("/getAllLibs", priceInfoController.auth, priceInfoController.init, priceInfoController.getAllLibs);
+    router.post("/batchUpdate", priceInfoController.auth, priceInfoController.init, priceInfoController.batchUpdate);
 
     app.use("/priceInfo", router);
 };

+ 0 - 1
modules/ration_repository/controllers/repository_views_controller.js

@@ -30,7 +30,6 @@ class ViewsController extends BaseController {
         } else {
             compilationList[0].active = 'active'
         }
-        // await rationDao.copyLib(173, 214, 7, 7)
         res.render('maintain/ration_repository/main.html',
             {
                 rationLibs: rationLibs,

+ 6 - 6
modules/ration_repository/models/ration_item.js

@@ -42,7 +42,7 @@ async function getIDMapping(counterName, data) {
 
 // 拷贝分类树
 async function copyClassData(sourceLibID, targetLibID) {
-    const sourceClassData = await stdRationSectionBackupModel.find({ rationRepId: sourceLibID }, '-_id').lean();
+    const sourceClassData = await stdRationSectionModel.find({ rationRepId: sourceLibID }, '-_id').lean();
     const IDMapping = await getIDMapping(counter.moduleName.rationTree, sourceClassData);
     const insertData = sourceClassData.map(item => ({
         ...item,
@@ -59,7 +59,7 @@ async function copyClassData(sourceLibID, targetLibID) {
 
 // 拷贝子目换算
 async function copyCoeData(sourceLibID, targetLibID) {
-    const sourceCoeData = await stdCoeBackupModel.find({ libID: sourceLibID }, '-_id').lean();
+    const sourceCoeData = await stdCoeModel.find({ libID: sourceLibID }, '-_id').lean();
     const IDMapping = await getIDMapping(counter.moduleName.coeList, sourceCoeData);
     const insertData = sourceCoeData.map(item => ({
         ...item,
@@ -75,11 +75,11 @@ async function copyCoeData(sourceLibID, targetLibID) {
 
 // 拷贝定额库
 rationItemDAO.prototype.copyLib = async function (sourceLibID, targetLibID, sourceGLJLibID, targetGLJLibID) {
-    const sourceRationData = await rationItemBackupModel.find({ rationRepId: sourceLibID }, '-_id').lean();
+    const sourceRationData = await rationItemModel.find({ rationRepId: sourceLibID }, '-_id').lean();
     const rationIDMapping = await getIDMapping(counter.moduleName.rations, sourceRationData);
     const classIDMapping = await copyClassData(sourceLibID, targetLibID);
     const coeIDMapping = await copyCoeData(sourceLibID, targetLibID);
-    const sourceGLJData = await stdGLJItemModelBackup.find({ repositoryId: sourceGLJLibID }, '-_id code ID').lean();
+    const sourceGLJData = await stdGLJItemModel.find({ repositoryId: sourceGLJLibID }, '-_id code ID').lean();
     const sourceGLJCodeMapping = {};
     sourceGLJData.forEach(glj => sourceGLJCodeMapping[glj.code] = glj.ID);
     const targetGLJData = await stdGLJItemModel.find({ repositoryId: targetGLJLibID }, '-_id code ID').lean();
@@ -115,7 +115,7 @@ rationItemDAO.prototype.copyLib = async function (sourceLibID, targetLibID, sour
 }
 
 rationItemDAO.prototype.handleGLJCode = async function (rationLibID, gljLibID) {
-    const rations = await _rationItemModelBackup.find({ rationRepId: rationLibID }, 'ID rationGljList').lean();
+    const rations = await rationItemModel.find({ rationRepId: rationLibID }, 'ID rationGljList').lean();
     const gljs = await stdGLJItemModel.find({ repositoryId: gljLibID }, 'ID code').lean();
     const gljMap = {};
     gljs.forEach(glj => gljMap[glj.ID] = glj.code);
@@ -134,7 +134,7 @@ rationItemDAO.prototype.handleGLJCode = async function (rationLibID, gljLibID) {
         }
     });
     if (bulks.length) {
-        await _rationItemModelBackup.bulkWrite(bulks);
+        await rationItemModel.bulkWrite(bulks);
     }
 }
 

+ 5 - 23
modules/reports/controllers/rpt_tpl_controller.js

@@ -485,31 +485,13 @@ let mExport = {
       });
   },
   // 导出所有的报表数据
-  getAllBackupData: async function (req, res) {
+  async getAllBackupData(req, res) {
     try {
       const filePath = "./public/highWay_reportBackup.zip";
-      let rptTemplate = [];
-      let rptTplTree = [];
-      let rptConfig = [];
-      let rptField = [];
-      await new Promise(async function (resolve) {
-        rptTemplate = await RptTplModel.find({}, "-_id");
-        resolve();
-      });
-
-      await new Promise(async function (resolve) {
-        rptTplTree = await TreeNodeModel.find({}, "-_id");
-        resolve();
-      });
-      await new Promise(async function (resolve) {
-        rptConfig = await rpt_cfg_mdl.find({}, "-_id");
-        resolve();
-      });
-      await new Promise(async function (resolve) {
-        rptField = await Rpt_Map_Fld_Mdl.find({}, "-_id");
-        resolve();
-      });
-
+      const rptConfig = await rpt_cfg_mdl.find({}, "-_id");
+      const rptTemplate = await RptTplModel.find({}, "-_id");
+      const rptTplTree = await TreeNodeModel.find({}, "-_id");
+      const rptField = await Rpt_Map_Fld_Mdl.find({}, "-_id");
       var zip = new JSZip();
       zip.file(
         "报表模板备份.json",

+ 1 - 1
modules/std_glj_lib/controllers/viewsController.js

@@ -33,7 +33,7 @@ class ViewsController extends BaseController {
             let absoluteUrl = compilation.overWriteUrl ? req.app.locals.rootDir + compilation.overWriteUrl : req.app.locals.rootDir;
             overWriteUrl = fs.existsSync(absoluteUrl) && fs.statSync(absoluteUrl).isFile() ? compilation.overWriteUrl : null;
         }
-        // await gljDao.copyLib(7,24); //UAT 部颁2018 -> 部颁2018计价标准
+        // await gljDao.copyLib(37, 58); //UAT 部颁2018 -> 部颁2018计价标准
         // await gljDao.copyLib(7,25); //PROD 部颁2018 -> 部颁2018计价标准
         // await gljDao.copyLib(7,26); //PROD 部颁2018 -> 河南养护工料机库2022
 

+ 2 - 2
modules/std_glj_lib/models/gljModel.js

@@ -95,7 +95,7 @@ class GljDao extends OprDao {
     }
 
     async copyClassData(sourceLibID, targetLibID) {
-        const sourceClassData = await gljClassModelBackup.find({ repositoryId: sourceLibID }, '-_id').lean();
+        const sourceClassData = await gljClassModel.find({ repositoryId: sourceLibID }, '-_id').lean();
         const insertData = sourceClassData.map(item => ({
             ...item,
             repositoryId: targetLibID
@@ -106,7 +106,7 @@ class GljDao extends OprDao {
     }
 
     async copyGLJData(sourceLibID, targetLibID) {
-        const sourceGLJData = await gljModelBackup.find({ repositoryId: sourceLibID }, '-_id').lean();
+        const sourceGLJData = await gljModel.find({ repositoryId: sourceLibID }, '-_id').lean();
         const IDMapping = {};
         const countData = await counter.counterDAO.getIDAfterCount(counter.moduleName.GLJ, sourceGLJData.length);
         const countIdx = countData.sequence_value - (sourceGLJData.length - 1);

+ 1 - 0
package.json

@@ -51,6 +51,7 @@
     "prod_server2": "SET NODE_ENV=prod_s2&& D:/GitHome/ConstructionOperation/node_modules/.bin/babel-node operation.js",
     "prod_sc_server": "SET NODE_ENV=prod_sc&& babel-node operation.js",
     "local2prod_hw_server": "SET NODE_ENV=local2prod_hw&& babel-node operation.js",
+    "local2prod_yh_server": "SET NODE_ENV=prod_s&& babel-node operation.js",
     "qa_hw_server": "SET NODE_ENV=qa_hw&& babel-node operation.js",
     "uat_hw_server": "SET NODE_ENV=uat_hw&& babel-node operation.js",
     "prod_hw_server": "SET NODE_ENV=prod_hw&& babel-node operation.js"

+ 133 - 106
public/web/id_tree.js

@@ -122,12 +122,12 @@ var idTree = {
             },
             addUpdateDataForParent: function (datas, nodes, pid) {
                 nodes.forEach(function (node) {
-                    datas.push({type: 'update', data: node.tree.getDataTemplate(node.getID(), pid, node.getNextSiblingID())});
+                    datas.push({ type: 'update', data: node.tree.getDataTemplate(node.getID(), pid, node.getNextSiblingID()) });
                 });
             },
             addUpdateDataForNextSibling: function (datas, node, nid) {
                 if (node) {
-                    datas.push({type: 'update', data: node.tree.getDataTemplate(node.getID(), node.getParentID(), nid)});
+                    datas.push({ type: 'update', data: node.tree.getDataTemplate(node.getID(), node.getParentID(), nid) });
                 }
             }
         };
@@ -222,14 +222,14 @@ var idTree = {
 
 
         // 获取节点所有后代节点
-        Node.prototype.getPosterity = function() {
+        Node.prototype.getPosterity = function () {
             let posterity = [];
             getNodes(this.children);
             return posterity;
             function getNodes(nodes) {
                 for (let node of nodes) {
                     posterity.push(node);
-                    if (node.children.length > 0){
+                    if (node.children.length > 0) {
                         getNodes(node.children);
                     }
                 }
@@ -237,12 +237,12 @@ var idTree = {
         };
 
         // 担心链有问题,preSibling不靠谱的话,按照显示顺序算preSibling
-        Node.prototype.prevNode = function() {
+        Node.prototype.prevNode = function () {
             const parent = this.parent || this.tree.roots;
             if (!parent) {
                 return null;
             }
-            const children = parent === this.tree.roots ? this.tree.roots :  parent.children;
+            const children = parent === this.tree.roots ? this.tree.roots : parent.children;
             const index = children.indexOf(this);
             return children[index - 1] || null;
         }
@@ -297,12 +297,12 @@ var idTree = {
                     tools.addUpdateDataForNextSibling(data, this.preSibling, this.tree.setting.rootId);
                 }
                 tools.addUpdateDataForNextSibling(data, this.parent, this.getID());
-                data.push({type: 'update', data: this.tree.getDataTemplate(this.getID(), this.parent.getParentID(), this.parent.getNextSiblingID())});
+                data.push({ type: 'update', data: this.tree.getDataTemplate(this.getID(), this.parent.getParentID(), this.parent.getNextSiblingID()) });
             }
             return data;
         };
         Node.prototype.upLevel = function () {
-            var result = {success: false, updateDatas: []};
+            var result = { success: false, updateDatas: [] };
             var iIndex = this.parent.children.indexOf(this), orgParent = this.parent, newNextSibling = this.parent.nextSibling;
             if (this.canUpLevel) {
                 // NextSiblings become child
@@ -329,7 +329,7 @@ var idTree = {
                     tools.addUpdateDataForNextSibling(data, this.preSibling.lastChild(), this.getID());
                 }
                 tools.addUpdateDataForNextSibling(data, this.preSibling, this.getNextSiblingID());
-                data.push({type: 'update', data: this.tree.getDataTemplate(this.getID(), this.preSibling.getID(), this.tree.setting.rootId)});
+                data.push({ type: 'update', data: this.tree.getDataTemplate(this.getID(), this.preSibling.getID(), this.tree.setting.rootId) });
             }
             return data;
         };
@@ -533,7 +533,7 @@ var idTree = {
         Tree.prototype.insert = function (parentID, nextSiblingID) {
             var newID = this.newNodeID(), node = null, data = {};
             var parent = parentID == -1 ? null : this.nodes[this.prefix + parentID];
-            var nextSibling = nextSiblingID == -1 ? null: this.nodes[this.prefix + nextSiblingID];
+            var nextSibling = nextSiblingID == -1 ? null : this.nodes[this.prefix + nextSiblingID];
             if (newID !== -1) {
                 data = {};
                 data[this.setting.id] = newID;
@@ -551,24 +551,24 @@ var idTree = {
             }
             return node;
         };
-        Tree.prototype.m_insert = function (datas,parentID, nextSiblingID) {
-           // var newID = this.newNodeID(), node = null, data = {};
+        Tree.prototype.m_insert = function (datas, parentID, nextSiblingID) {
+            // var newID = this.newNodeID(), node = null, data = {};
             var parent = parentID == -1 ? null : this.nodes[this.prefix + parentID];
-            var nextSibling = nextSiblingID == -1 ? null: this.nodes[this.prefix + nextSiblingID];
-            let preInsertNode = null,nodes = [];
-            for(let d of datas){
-                let node = new Node(this,d.data);
-                if(preInsertNode == null){
+            var nextSibling = nextSiblingID == -1 ? null : this.nodes[this.prefix + nextSiblingID];
+            let preInsertNode = null, nodes = [];
+            for (let d of datas) {
+                let node = new Node(this, d.data);
+                if (preInsertNode == null) {
                     if (nextSibling) {
                         tools.addNodes(this, parent, [node], nextSibling.siblingIndex());
                     } else {
                         tools.addNodes(this, parent, [node]);
                     }
-                }else {
+                } else {
                     tools.addNodes(this, parent, [node], preInsertNode.siblingIndex());
                 }
                 this.nodes[this.prefix + d.data.ID] = node;
-                if(preInsertNode) node.setNextSibling(preInsertNode);
+                if (preInsertNode) node.setNextSibling(preInsertNode);
                 preInsertNode = node;
                 nodes.push(node);
             }
@@ -581,7 +581,7 @@ var idTree = {
         Tree.prototype.insertByID = function (newID, parentID, nextSiblingID) {
             var node = null, data = {};
             var parent = parentID == -1 ? null : this.nodes[this.prefix + parentID];
-            var nextSibling = nextSiblingID == -1 ? null: this.nodes[this.prefix + nextSiblingID];
+            var nextSibling = nextSiblingID == -1 ? null : this.nodes[this.prefix + nextSiblingID];
             if (newID) {
                 data = {};
                 data[this.setting.id] = newID;
@@ -602,9 +602,9 @@ var idTree = {
             var data = [];
             var newID = this.newNodeID();
             var parent = parentID == -1 ? null : this.nodes[this.prefix + parentID];
-            var nextSibling = nextSiblingID == -1 ? null: this.nodes[this.prefix + nextSiblingID];
+            var nextSibling = nextSiblingID == -1 ? null : this.nodes[this.prefix + nextSiblingID];
             if (newID !== -1) {
-                data.push({type: 'new', data: this.getDataTemplate(newID, parent ? parent.getID() : this.setting.rootId, nextSibling ? nextSibling.getID() : this.setting.rootId)});
+                data.push({ type: 'new', data: this.getDataTemplate(newID, parent ? parent.getID() : this.setting.rootId, nextSibling ? nextSibling.getID() : this.setting.rootId) });
 
                 if (nextSibling && nextSibling.preSibling) {
                     tools.addUpdateDataForNextSibling(data, nextSibling.preSibling, newID);
@@ -617,17 +617,17 @@ var idTree = {
             return data;
         };
         //插入多行
-        Tree.prototype.getInsertDatas = function (rowCount,parentID, nextSiblingID) {
-            let data = [],preInsertID = null,lastID;
+        Tree.prototype.getInsertDatas = function (rowCount, parentID, nextSiblingID) {
+            let data = [], preInsertID = null, lastID;
             let parent = parentID == -1 ? null : this.nodes[this.prefix + parentID];
-            let nextSibling = nextSiblingID == -1 ? null: this.nodes[this.prefix + nextSiblingID];
-            for(let i=0;i<rowCount ;i++){//先插入的在最后,后插的在最前
+            let nextSibling = nextSiblingID == -1 ? null : this.nodes[this.prefix + nextSiblingID];
+            for (let i = 0; i < rowCount; i++) {//先插入的在最后,后插的在最前
                 let newID = this.newNodeID();
-                if(newID !== -1){
-                    if(preInsertID == null){//说明是第一个插入的
-                        data.push({type: 'new', data: this.getDataTemplate(newID, parent ? parent.getID() : this.setting.rootId, nextSibling ? nextSibling.getID() : this.setting.rootId)});
-                    }else {//其它的下一节点ID取上一个插入的节点
-                        data.push({type: 'new', data: this.getDataTemplate(newID, parent ? parent.getID() : this.setting.rootId, preInsertID)});
+                if (newID !== -1) {
+                    if (preInsertID == null) {//说明是第一个插入的
+                        data.push({ type: 'new', data: this.getDataTemplate(newID, parent ? parent.getID() : this.setting.rootId, nextSibling ? nextSibling.getID() : this.setting.rootId) });
+                    } else {//其它的下一节点ID取上一个插入的节点
+                        data.push({ type: 'new', data: this.getDataTemplate(newID, parent ? parent.getID() : this.setting.rootId, preInsertID) });
                     }
                     this.maxNodeID(newID);
                     preInsertID = newID;
@@ -656,25 +656,34 @@ var idTree = {
                 } else {
                     tools.addNodes(this, parent, [node]);
                 }
-                this.nodes[this.prefix +  data[this.setting.id]] = node;
+                this.nodes[this.prefix + data[this.setting.id]] = node;
                 tools.sortTreeItems(this);
-                this.maxNodeID( data[this.setting.id]);
+                this.maxNodeID(data[this.setting.id]);
                 return node;
             }
         };
+        // 插入离散节点
+        Tree.prototype.insertByDatas = function (datas) {
+            const nodes = [];
+            datas.forEach(item => {
+                const node = this.insertByData(item, item.ParentID, item.NextSiblingID);
+                nodes.push(node);
+            });
+            return nodes;
+        };
         //批量新增节点到节点后项,节点已有树结构数据
         Tree.prototype.insertDatasTo = function (preData, datas) {
             let rst = [];
-            for(let data of datas){
+            for (let data of datas) {
                 this.nodes[this.prefix + data.ID] = new Node(this, data.ID);
                 this.nodes[this.prefix + data.ID]['data'] = data;
                 rst.push(this.nodes[this.prefix + data.ID]);
             }
-            for(let data of datas){
+            for (let data of datas) {
                 let node = this.nodes[this.prefix + data.ID];
                 let parent = data.ParentID == -1 ? null : this.nodes[this.prefix + data.ParentID];
                 node.parent = parent;
-                if(!parent){
+                if (!parent) {
                     this.roots.push(node);
                 }
                 else {
@@ -682,14 +691,14 @@ var idTree = {
                 }
                 let next = data.NextSiblingID == -1 ? null : this.nodes[this.prefix + data.NextSiblingID];
                 node.nextSibling = next;
-                if(next){
+                if (next) {
                     next.preSibling = node;
                 }
             }
             let preNode = this.nodes[this.prefix + preData.ID];
-            if(preNode){
+            if (preNode) {
                 preNode.nextSibling = this.nodes[this.prefix + preData.NextSiblingID] ? this.nodes[this.prefix + preData.NextSiblingID] : null;
-                if(preNode.nextSibling){
+                if (preNode.nextSibling) {
                     preNode.nextSibling.preSibling = preNode;
                 }
             }
@@ -700,7 +709,7 @@ var idTree = {
         };
         Tree.prototype.delete = function (node) {
             var success = false, that = this;
-            if(node) success = that.m_delete([node]);
+            if (node) success = that.m_delete([node]);
             return success;
         };
         Tree.prototype.m_delete = function (nodes) {
@@ -711,7 +720,7 @@ var idTree = {
                     deleteIdIndex(node.children);
                 })
             };
-            for(let n of nodes){
+            for (let n of nodes) {
                 deleteIdIndex([n]);
                 if (n.preSibling) {
                     n.preSibling.setNextSibling(n.nextSibling);
@@ -734,76 +743,76 @@ var idTree = {
             let o_next = o_parent.nextSibling;//父节点的下一节点
             let o_pre = nodes[0].preSibling;
             let o_children = o_parent.children;//旧的所有兄弟节点
-            let children = o_parent.parent?o_parent.parent.children:this.roots;//新的兄弟节点
+            let children = o_parent.parent ? o_parent.parent.children : this.roots;//新的兄弟节点
             let last;
             let lastNext;//最后一个选中节点后面的所有兄弟节点变成最后一个节点的子节点
-            for(let i = 0; i<nodes.length;i++){
+            for (let i = 0; i < nodes.length; i++) {
                 let index = children.indexOf(o_parent) + 1;
-                children.splice(index + i,0,nodes[i]);//往新的父节点的子节点插入节点
+                children.splice(index + i, 0, nodes[i]);//往新的父节点的子节点插入节点
                 o_children.splice(nodes[i].siblingIndex(), 1);//旧的数组删除节点
-                if(i == 0){//第一个节点变成原来父节点的下一节点
+                if (i == 0) {//第一个节点变成原来父节点的下一节点
                     o_parent.setNextSibling(nodes[i]);
-                    if(o_pre) o_pre.setNextSibling(null); //第一个选中节点的前一节点的下一节点设置为空
+                    if (o_pre) o_pre.setNextSibling(null); //第一个选中节点的前一节点的下一节点设置为空
                 }
                 nodes[i].setParent(o_parent.parent);
                 last = nodes[i];
                 lastNext = last.nextSibling;
             }
             last.setNextSibling(o_next);//最后一个选中的节点的下一个节点设置为原父节点的下一节点
-            if(lastNext){
+            if (lastNext) {
                 let t_index = o_children.indexOf(lastNext);
-                for(let j = t_index;j <o_children.length;j++ ){//剩下的添加为最后一个选中节点的子节点
+                for (let j = t_index; j < o_children.length; j++) {//剩下的添加为最后一个选中节点的子节点
                     last.addChild(o_children[j]);
                 }
-                if(o_children.length > t_index)  o_children.splice(t_index, o_children.length - t_index);//从原先的children中移除
+                if (o_children.length > t_index) o_children.splice(t_index, o_children.length - t_index);//从原先的children中移除
             }
-            if (o_parent.parent&& !o_parent.parent.expanded)  o_parent.parent.setExpanded(true);
+            if (o_parent.parent && !o_parent.parent.expanded) o_parent.parent.setExpanded(true);
             tools.sortTreeItems(this);
             return true;
         };
         Tree.prototype.getUpLevelDatas = function (nodes) {
             //getParentID
-            let o_parentID =  nodes[0].getParentID();
+            let o_parentID = nodes[0].getParentID();
             let o_children = nodes[0].parent.children;//旧的所有兄弟节点
             let o_pre = nodes[0].preSibling;
             let new_parentID = nodes[0].parent.getParentID();
             let o_nextID = nodes[0].parent.getNextSiblingID();
-            let dataMap = {},updateDatas=[],lastID,lastNext;
-            for(let i = 0; i<nodes.length;i++){
-                if(i == 0){
-                    dataMap[o_parentID] = {"ID":o_parentID,"NextSiblingID":nodes[i].getID()};
-                    if(o_pre) dataMap[o_pre.getID()] = {"ID":o_pre.getID(),"NextSiblingID":-1}; //nodes[i].preSibling.setNextSibling(null);
+            let dataMap = {}, updateDatas = [], lastID, lastNext;
+            for (let i = 0; i < nodes.length; i++) {
+                if (i == 0) {
+                    dataMap[o_parentID] = { "ID": o_parentID, "NextSiblingID": nodes[i].getID() };
+                    if (o_pre) dataMap[o_pre.getID()] = { "ID": o_pre.getID(), "NextSiblingID": -1 }; //nodes[i].preSibling.setNextSibling(null);
                 }
-                dataMap[nodes[i].getID()] = {"ID":nodes[i].getID(),"ParentID":new_parentID};
+                dataMap[nodes[i].getID()] = { "ID": nodes[i].getID(), "ParentID": new_parentID };
                 lastID = nodes[i].getID();
                 lastNext = nodes[i].nextSibling;
             }
-            if(dataMap[lastID] !== undefined){
+            if (dataMap[lastID] !== undefined) {
                 dataMap[lastID].NextSiblingID = o_nextID;
             }
-            if(lastNext){
+            if (lastNext) {
                 let t_index = o_children.indexOf(lastNext);
-                for(let j = t_index;j <o_children.length;j++ ){//剩下的添加为最后一个选中节点的子节点
-                    dataMap[o_children[j].getID()] = {"ID":o_children[j].getID(),"ParentID":lastID};
+                for (let j = t_index; j < o_children.length; j++) {//剩下的添加为最后一个选中节点的子节点
+                    dataMap[o_children[j].getID()] = { "ID": o_children[j].getID(), "ParentID": lastID };
                 }
             }
-            for(let key in dataMap){
-                updateDatas.push({type: 'update', data:dataMap[key]});
+            for (let key in dataMap) {
+                updateDatas.push({ type: 'update', data: dataMap[key] });
             }
             return updateDatas;
         };
         Tree.prototype.m_downLevel = function (nodes) {
-            let pre = nodes[0].preSibling ; //第一个节点的前一节点,即会成为新的父节点
-            let next ;//最后一个节点的后一节点,会成为pre 的下一个节点
-            let last ;//选中的最后一个节点,nextSibling要设置为0
-            for( let n of nodes){
+            let pre = nodes[0].preSibling; //第一个节点的前一节点,即会成为新的父节点
+            let next;//最后一个节点的后一节点,会成为pre 的下一个节点
+            let last;//选中的最后一个节点,nextSibling要设置为0
+            for (let n of nodes) {
                 next = n.nextSibling;
                 last = n;
-                let  children = n.parent?n.parent.children:this.roots;
+                let children = n.parent ? n.parent.children : this.roots;
                 children.splice(n.siblingIndex(), 1);
                 pre.addChild(n);
             }
-            if (!pre.expanded)  pre.setExpanded(true);
+            if (!pre.expanded) pre.setExpanded(true);
             pre.setNextSibling(next);
             last.nextSibling = null;
             tools.sortTreeItems(this);
@@ -811,25 +820,25 @@ var idTree = {
         };
 
         Tree.prototype.getDownLevelDatas = function (nodes) {
-            let dataMap = {},updateDatas=[],nextID,last;//注释同m_downLevel 方法
+            let dataMap = {}, updateDatas = [], nextID, last;//注释同m_downLevel 方法
             let newParent = nodes[0].preSibling;//{"type":"update","data":{"ID":3,"ParentID":-1,"NextSiblingID":5}}
-            let newPre = newParent.children && newParent.children.length > 0 ? newParent.children[newParent.children.length -1]:null;
-            if(newPre){ //如果新的父节点有子节点,则把新的父节点的最后一个子节点的下一节点的值改成第一个选中节点的ID
-                dataMap[newPre.getID()] = {"ID":newPre.getID(),"NextSiblingID":nodes[0].getID()}
+            let newPre = newParent.children && newParent.children.length > 0 ? newParent.children[newParent.children.length - 1] : null;
+            if (newPre) { //如果新的父节点有子节点,则把新的父节点的最后一个子节点的下一节点的值改成第一个选中节点的ID
+                dataMap[newPre.getID()] = { "ID": newPre.getID(), "NextSiblingID": nodes[0].getID() }
             }
-            for(let n of nodes){
+            for (let n of nodes) {
                 nextID = n.getNextSiblingID();
                 last = n;
-                dataMap[n.getID()] = {"ID":n.getID(),"ParentID":newParent.getID()}//修改父ID;
+                dataMap[n.getID()] = { "ID": n.getID(), "ParentID": newParent.getID() }//修改父ID;
             }
-            dataMap[newParent.getID()] = {"ID":newParent.getID(),"NextSiblingID":nextID}//设置新的父节点的下一个节点ID;
-            if(dataMap[last.getID()]!==undefined){//把最后一个节点的下一个节点ID变成-1
+            dataMap[newParent.getID()] = { "ID": newParent.getID(), "NextSiblingID": nextID }//设置新的父节点的下一个节点ID;
+            if (dataMap[last.getID()] !== undefined) {//把最后一个节点的下一个节点ID变成-1
                 dataMap[last.getID()].NextSiblingID = -1
-            }else {
-                dataMap[last.getID()] = {"ID":last.getID(),"NextSiblingID":-1};
+            } else {
+                dataMap[last.getID()] = { "ID": last.getID(), "NextSiblingID": -1 };
             }
-            for(let key in dataMap){
-                updateDatas.push({type: 'update', data:dataMap[key]});
+            for (let key in dataMap) {
+                updateDatas.push({ type: 'update', data: dataMap[key] });
             }
             return updateDatas;
         };
@@ -840,7 +849,7 @@ var idTree = {
                 nodes.forEach(function (node) {
                     var delData = {};
                     delData[node.tree.setting.id] = node.getID();
-                    datas.push({type: 'delete', data: delData});
+                    datas.push({ type: 'delete', data: delData });
                     addUpdateDataForDelete(datas, node.children);
                 })
             };
@@ -852,32 +861,32 @@ var idTree = {
             }
             return data;
         };
-        Tree.prototype.getDeleteDatas = function (deleteMap,deleteNodes){//批量删除
+        Tree.prototype.getDeleteDatas = function (deleteMap, deleteNodes) {//批量删除
             let datas = [];
-            addDeleteDatas(datas,deleteNodes);
-            for(let d of deleteNodes){
-                addPreUpdateData(datas,deleteMap,d.preSibling,d.nextSibling);
-            }
-           function addPreUpdateData(updateDatas,map,preSibling,nextSibling) {
-               if(preSibling && (map[preSibling.getID()] == undefined || map[preSibling.getID()] == null)){
-                   if(nextSibling){
-                      if(map[nextSibling.getID()]){//如果下一个节点也是要删除的,则再往下顺延
-                          addPreUpdateData(updateDatas,map,preSibling,nextSibling.nextSibling);
-                      }else {
-                          updateDatas.push({type: 'update', data: preSibling.tree.getDataTemplate(preSibling.getID(), preSibling.getParentID(),nextSibling.getID())});
-                      }
-                   }else {
-                       updateDatas.push({type: 'update', data: preSibling.tree.getDataTemplate(preSibling.getID(), preSibling.getParentID(),-1)});
-                   }
-               }
-           }
-
-            function addDeleteDatas(dataArray,nodes) {
-                for(let n of nodes){
+            addDeleteDatas(datas, deleteNodes);
+            for (let d of deleteNodes) {
+                addPreUpdateData(datas, deleteMap, d.preSibling, d.nextSibling);
+            }
+            function addPreUpdateData(updateDatas, map, preSibling, nextSibling) {
+                if (preSibling && (map[preSibling.getID()] == undefined || map[preSibling.getID()] == null)) {
+                    if (nextSibling) {
+                        if (map[nextSibling.getID()]) {//如果下一个节点也是要删除的,则再往下顺延
+                            addPreUpdateData(updateDatas, map, preSibling, nextSibling.nextSibling);
+                        } else {
+                            updateDatas.push({ type: 'update', data: preSibling.tree.getDataTemplate(preSibling.getID(), preSibling.getParentID(), nextSibling.getID()) });
+                        }
+                    } else {
+                        updateDatas.push({ type: 'update', data: preSibling.tree.getDataTemplate(preSibling.getID(), preSibling.getParentID(), -1) });
+                    }
+                }
+            }
+
+            function addDeleteDatas(dataArray, nodes) {
+                for (let n of nodes) {
                     let delData = {};
                     delData[n.tree.setting.id] = n.getID();
-                    dataArray.push({type: 'delete', data: delData});
-                    addDeleteDatas(dataArray,n.children);
+                    dataArray.push({ type: 'delete', data: delData });
+                    addDeleteDatas(dataArray, n.children);
                 }
             }
             return datas;
@@ -899,7 +908,25 @@ var idTree = {
             this.event[eventName] = eventFun;
         };
 
+        Tree.prototype.resetID = function (items, IDFunc) {
+            const IDMap = {};
+            items.forEach(item => {
+                IDMap[item.ID] = IDFunc();
+            });
+            items.forEach(item => {
+                if (IDMap[item.ID]) {
+                    item.ID = IDMap[item.ID];
+                }
+                if (IDMap[item.ParentID]) {
+                    item.ParentID = IDMap[item.ParentID];
+                }
+                if (IDMap[item.NextSiblingID]) {
+                    item.NextSiblingID = IDMap[item.NextSiblingID];
+                }
+            });
+        };
+
         return new Tree(setting);
     },
-    updateType: {update: 'update', new: 'new', delete: 'delete'}
+    updateType: { update: 'update', new: 'new', delete: 'delete' }
 };

+ 24 - 0
public/web/lock_util.js

@@ -70,6 +70,29 @@ const lockUtil = (() => {
             }
         });
     }
+
+    function unLockSpreads(spreads) {
+        spreads.forEach(spread => {
+            spread.unbind(GC.Spread.Sheets.Events.ButtonClicked);
+            const sheetCount = spread.getSheetCount();
+            for (let i = 0; i < sheetCount; i++) {
+                const sheet = spread.getSheet(i);
+                sheet.suspendPaint();
+                sheet.suspendEvent();
+                sheet.options.isProtected = false;
+                const rowCount = sheet.getRowCount();
+                const colCount = sheet.getColumnCount();
+                for (let row = 0; row < rowCount; row++) {
+                    for (let col = 0; col < colCount; col++) {
+                        sheet.getCell(row, col).locked(false);
+                    }
+                }
+                sheet.resumePaint();
+                sheet.resumeEvent();
+            }
+        });
+    }
+
     function lockURL(locked, $url) {
         const originURL = $url.prop('href');
         const originLocked = !locked;
@@ -108,6 +131,7 @@ const lockUtil = (() => {
         getLocked,
         lockTools,
         lockSpreads,
+        unLockSpreads,
         lockURL,
         displayLock,
         handleLockClick,

+ 22 - 2
public/web/tree_sheet/tree_sheet_controller.js

@@ -91,6 +91,24 @@ var TREE_SHEET_CONTROLLER = {
             return nodes;
         };
 
+        controller.prototype.insertByDatas = function (datas) {
+            let nodes = [], that = this, sels = this.sheet.getSelections();
+            if (this.tree) {
+                nodes = this.tree.insertByDatas(datas);
+            }
+            let length = nodes.length;
+            if (nodes.length > 0) {
+                TREE_SHEET_HELPER.massOperationSheet(this.sheet, function () {
+                    that.sheet.addRows(nodes[0].serialNo(), length);
+                    TREE_SHEET_HELPER.refreshTreeNodeData(that.setting, that.sheet, nodes, false);
+                    that.setTreeSelected(nodes[0]);
+                    that.sheet.setSelection(nodes[0].serialNo(), sels[0].col, 1, 1);
+                    //that.sheet.showRow(newNode.serialNo(), GC.Spread.Sheets.VerticalPosition.center);
+                });
+            }
+            return nodes;
+        };
+
 
         controller.prototype.insertByID = function (ID) {
             var newNode = null, that = this, sels = this.sheet.getSelections();
@@ -173,8 +191,9 @@ var TREE_SHEET_CONTROLLER = {
                             rowCount = rowCount + node.posterityCount() + 1;
                         }
                         that.sheet.deleteRows(sels[0].row, rowCount);
-                        that.setTreeSelected(that.tree.items[sels[0].row]);
-                        that.sheet.setSelection(sels[0].row, sels[0].col, 1, sels[0].colCount);
+                        const locateRow = that.tree.items.length <= sels[0].row ? that.tree.items.length - 1 : sels[0].row;
+                        that.setTreeSelected(that.tree.items[locateRow]);
+                        that.sheet.setSelection(locateRow, sels[0].col, 1, sels[0].colCount);
                     });
                 }
             }
@@ -281,6 +300,7 @@ var TREE_SHEET_CONTROLLER = {
                 this.event.beforeTreeSelectedChange(this.tree.selected);
             }
             this.tree.selected = node;
+            console.log(node);
             if (this.event.refreshBaseActn) {
                 this.event.refreshBaseActn(this.tree);
             }

+ 25 - 0
web/maintain/bills_lib/css/main.css

@@ -281,4 +281,29 @@ body {
     pointer-events: none;
     opacity: .65;
     color:#666;
+}
+
+
+.search-container {
+  position: relative;
+  display: inline-block;
+}
+
+.icon-input {
+  padding: 2px 16px 2px 6px; /* 右侧留出32px图标空间 */
+  width: 160px;
+}
+
+.search-icon {
+  position: absolute;
+  right: 12px;
+  top: 50%;
+  transform: translateY(-50%);
+  color: #666;
+  pointer-events: none; /* 防止图标阻挡输入框点击 */
+}
+.next-btn{
+    height: 30px;
+    padding: 6px;
+    font-size: 14px;
 }

+ 99 - 1
web/maintain/bills_lib/html/qingdan.html

@@ -9,6 +9,7 @@
     <link rel="stylesheet" href="/lib/bootstrap/css/bootstrap.min.css">
     <link rel="stylesheet" href="/web/maintain/bills_lib/css/main.css">
     <link rel="stylesheet" href="/lib/font-awesome/font-awesome.min.css">
+    <link rel="stylesheet" href="/lib/jquery-contextmenu/jquery.contextMenu.css">
     <!--spread-->
     <link rel="stylesheet" href="/lib/spreadjs/sheets/css/gc.spread.sheets.sc.css">
     <link rel="stylesheet" href="/lib/codemirror/codemirror.css">
@@ -71,6 +72,17 @@
                           <li class="nav-item">
                               <a class="nav-link text-primary lock-btn-control" doing="false" fcsOnBills="true" canMove="false" id="downMove" href="javascript: void(0);"><i class="fa fa-arrow-down" aria-hidden="true"></i>下移</a>
                           </li>
+                          <li class="nav-item">
+                            <div class="search-container">
+                                <input type="text" placeholder="输入后按回车查找..." id="searchInput" class="icon-input">
+                                <i class="fa fa-search search-icon"></i>
+                            </div> 
+                        </li>
+                        <li class="nav-item" id="searchResult" style="display: none;">
+                            搜索结果:<span id="searchCount">0</span>  
+                            <a class="btn btn-primary next-btn" doing="false" canMove="false" id="search-pre" href="javascript: void(0);">上一个</a> 
+                            <a class="btn btn-primary next-btn" doing="false" canMove="false" id="search-next" href="javascript: void(0);">下一个</a> 
+                        </li>
                       </ul>
                   </div>
                 </nav>
@@ -350,16 +362,21 @@
     <%include ../../../common/html/uploadImg.html %>
     <!-- JS. -->
     <script src = "/lib/spreadjs/sheets/gc.spread.sheets.all.11.1.2.min.js"></script>
+    <script src = "/lib/localforage/localforage.min.js"></script>
+    <script src="/public/common_util.js"></script>
     <script>GC.Spread.Sheets.LicenseKey =  '<%- LicenseKey %>';</script>
     <script src="/public/web/uuid.js"></script>
     <script src="/lib/jquery/jquery.min.js"></script>
     <script src="/lib/tether/tether.min.js"></script>
+    <script src="/lib/jquery-contextmenu/jquery.contextMenu.min.js"></script>
+    <script src="/lib/jquery-contextmenu/jquery.ui.position.js"></script>
     <script src="/lib/bootstrap/bootstrap.min.js"></script>
     <script src="/web/maintain/bills_lib/scripts/global.js"></script>
     <script src="/public/web/PerfectLoad.js"></script>
     <script src="/public/web/common_ajax.js"></script>
     <script src="/public/web/lock_util.js"></script>
     <script src="/public/web/sheet/sheet_common.js"></script>
+    <script type="text/javascript" src="/public/web/sheet/sheet_data_helper.js"></script>
     <script src="/web/maintain/bills_lib/scripts/set_sheets.js"></script>
     <script src="/web/maintain/bills_lib/scripts/bills_lib_ajax.js"></script>
     <!--idTree-->
@@ -471,6 +488,7 @@
         });
 
 
+
         $('#insert_row').on('keypress', function(e) {
             // 检查是否按下的是 Enter 键(keyCode 13 或 which 13)
             if (e.which === 13 || e.keyCode === 13) {
@@ -482,6 +500,83 @@
             dbController.delete(controller, btnDelete, totalJobs, totalItems);
             $('#delAlert').modal('hide');
         });
+
+        function isMatch(bill,searchInput){
+            searchInput = searchInput.toLowerCase().trim()
+            const billName = bill.data.name? bill.data.name.toLowerCase():''; 
+            const code = bill.data.code? bill.data.code.toLowerCase():''; 
+            return billName.includes(searchInput) || code.includes(searchInput);
+        }
+
+
+        function locateBill(bill){
+            if(bill){
+                controller.setTreeSelected(bill);
+                controller.sheet.setSelection(bill.serialNo(), 1, 1, 1); 
+                controller.sheet.showRow(bill.serialNo(), GC.Spread.Sheets.VerticalPosition.center);
+            }
+        }
+
+        $('#searchInput').on('keypress', function(e) {
+            // 检查是否按下的是 Enter 键(keyCode 13 或 which 13)
+            if (e.which === 13 || e.keyCode === 13) {
+                const searchValue = $(this).val().toLowerCase().trim();
+                if(searchValue){
+                    const controller = dbController.controller;
+                    let select = null;
+                    let count =0
+                    for(const bill of controller.tree.items){
+                       if(isMatch(bill,searchValue)){
+                          if(select===null) select=bill   
+                          count++;                    
+                        }
+                    }
+                    locateBill(select);   
+                    $('#searchCount').text(count); 
+                    $('#searchResult').show();     
+                }else{
+                    $('#searchResult').hide();
+                }    
+            }
+        });
+
+
+        $('#search-next').click(function(){
+            const searchValue = $('#searchInput').val().toLowerCase().trim();
+            if(searchValue){
+                const controller = dbController.controller;
+                const selected = controller.tree.selected;
+                if(selected){
+                    const index = controller.tree.items.indexOf(selected)+1;
+                    if(index>=controller.tree.items.length) return ;
+                    for(let i=index ;i<controller.tree.items.length;i++){
+                        if(isMatch(controller.tree.items[i],searchValue)){
+                            locateBill(controller.tree.items[i]);
+                            break;
+                        }
+                    }
+                } 
+            } 
+        });
+
+        $('#search-pre').click(function(){
+            const searchValue = $('#searchInput').val().toLowerCase().trim();
+            if(searchValue){
+                const controller = dbController.controller;
+                const selected = controller.tree.selected;
+                if(selected){
+                    const index = controller.tree.items.indexOf(selected)-1;
+                    if(index<0) return ;
+                    for(let i=index ;i>=0;i--){
+                        if(isMatch(controller.tree.items[i],searchValue)){
+                            locateBill(controller.tree.items[i]);
+                            break;
+                        }
+                    }
+                } 
+            } 
+        });
+
         btnDelete.click(function(){
             if(btnDelete.attr('doing') === 'false' && btnDelete.attr('fcsOnBills') === 'true'){
                 $('#delAlert').modal('show');
@@ -615,6 +710,7 @@
         let nameList = BillsFixedFlagList.map((data) => data.name);
         let comboCol = setting.cols.findIndex((data) => data.data.field === 'fixedFlag');
         setCombo(billsSheet, comboCol, nameList);
+        onContextmenuOpr(billsSpread, controller);
     }
 
     function switchFcs(controller, billsSheet, billsSpread, jobsSheet, designsSheet, itemsSheet){
@@ -981,10 +1077,12 @@
 
     function bindPasteBills(controller, sheet, setting){
         sheet.bind(GC.Spread.Sheets.Events.ClipboardPasting, function (sender, args) {
+            debugger;
             sheetBillsDatas = tools.getsheetDatas(sheet, 'bills', controller);
             let maxCol = args.cellRange.col + args.cellRange.colCount - 1;
+            let maxRow = args.cellRange.row + args.cellRange.rowCount - 1;
             //复制的列数超过正确的列数,不可复制
-            if(maxCol >= billsLibSetting.cols.length){
+            if(maxCol >= billsLibSetting.cols.length || maxRow >= controller.tree.items.length){
                 args.cancel = true;
             }
         });

+ 12 - 12
web/maintain/bills_lib/scripts/bills_lib_ajax.js

@@ -15,7 +15,7 @@ var mainAjax = {
           $option.val(result.data[i]._id);
           $("#compilationSels").append($option); //
         }
-        $("#compilationSels").on("change", function () {});
+        $("#compilationSels").on("change", function () { });
       },
     });
   },
@@ -189,7 +189,7 @@ var billsAjax = {
         if (!result.error) {
           $(".navbar-text").append(
             "<a href='stdBillsmain'>清单规则</a><i class='fa fa-angle-right fa-fw'></i>" +
-              result.data[0].billsLibName
+            result.data[0].billsLibName
           );
         }
       },
@@ -394,7 +394,7 @@ var billsAjax = {
         }),
       },
       dataType: "json",
-      success: function (result) {},
+      success: function (result) { },
     });
   },
   updateSectionInfo: function (data, callback) {
@@ -424,7 +424,7 @@ var billsAjax = {
         }),
       },
       dataType: "json",
-      success: function (result) {},
+      success: function (result) { },
     });
   },
   updateSerialNo: function (billsLibId, billsId, updateArr, field, callback) {
@@ -527,7 +527,7 @@ var billsAjax = {
         }),
       },
       dataType: "json",
-      success: function (result) {},
+      success: function (result) { },
     });
   },
   pasteRel: function (
@@ -627,7 +627,7 @@ var jobsAjax = {
         }),
       },
       dataType: "json",
-      success: function (result) {},
+      success: function (result) { },
     });
   },
   deleteJobContent: function (lastOperator, billsLibId, ids) {
@@ -642,7 +642,7 @@ var jobsAjax = {
         }),
       },
       dataType: "json",
-      success: function (result) {},
+      success: function (result) { },
     });
   },
   pasteJobs: function (lastOperator, billsLibId, pasteDatas, callback) {
@@ -782,7 +782,7 @@ var designsAjax = {
         }),
       },
       dataType: "json",
-      success: function (result) {},
+      success: function (result) { },
     });
   },
   deleteDesignContent: function (lastOperator, billsLibId, ids) {
@@ -797,7 +797,7 @@ var designsAjax = {
         }),
       },
       dataType: "json",
-      success: function (result) {},
+      success: function (result) { },
     });
   },
   pasteDesigns: function (lastOperator, billsLibId, pasteDatas, callback) {
@@ -941,7 +941,7 @@ var itemsAjax = {
         }),
       },
       dataType: "json",
-      success: function (result) {},
+      success: function (result) { },
     });
   },
   updateValue: function (
@@ -966,7 +966,7 @@ var itemsAjax = {
         }),
       },
       dataType: "json",
-      success: function (reslut) {},
+      success: function (reslut) { },
     });
   },
   deleteItemCharacter: function (lastOperator, billsLibId, ids) {
@@ -981,7 +981,7 @@ var itemsAjax = {
         }),
       },
       dataType: "json",
-      success: function (result) {},
+      success: function (result) { },
     });
   },
   pasteItems: function (lastOperator, billsLibId, pasteDatas, callback) {

+ 299 - 46
web/maintain/bills_lib/scripts/db_controller.js

@@ -47,6 +47,296 @@ function getNewBIlls(controller, rowCount, billsLibId) {
   return { insertBills, updatePreData };
 }
 
+// 创建清单
+const createBills = (controller, btn, insertBills, updatePreData, isInsertByDatas) => {
+  billsAjax.createBills(
+    userAccount,
+    billsLibId,
+    updatePreData,
+    insertBills,
+    function () {
+      if (updatePreData) {
+        const node = controller.tree.findNode(updatePreData.ID);
+        if (node) {
+          Object.assign(node.data, updatePreData);
+        }
+      }
+      // 显示的时候,类别和固定ID转换为名称显示
+      const kindMap = {};
+      billKindComboList.forEach(item => {
+        kindMap[item.value] = item.name;
+      });
+      const flagMap = {};
+      BillsFixedFlagList.forEach(item => {
+        flagMap[item.value] = item.name;
+      });
+      insertBills.forEach(bill => {
+        if (bill.kind) {
+          bill.kind = kindMap[bill.kind] || '';
+        }
+        if (bill.fixedFlag) {
+          bill.fixedFlag = flagMap[bill.fixedFlag] || '';
+        }
+      })
+      const treeData = insertBills.map((item) => ({
+        type: "new",
+        data: item,
+      }));
+      const newNodes = isInsertByDatas ? controller.insertByDatas(insertBills) : controller.m_insert(treeData);
+      newNodes.forEach(n => {
+        n.jobs = [];
+        n.items = [];
+        n.designs = [];
+        controller.sheet.setTag(
+          n.serialNo(),
+          0,
+          n.getID()
+        );
+      });
+      sheetBillsDatas = tools.getsheetDatas(
+        controller.sheet,
+        "bills",
+        controller
+      );
+      if (btn) {
+        tools.btnAction(btn);
+        btn.attr("doing", "false");
+      }
+      controller.sheet.getParent().focus(true);
+    }
+  );
+}
+
+// 获取需要复制的节点(与第一个节点同层的所有节点,包括后代)
+const getCopyNodes = (controller) => {
+  const { tree, sheet } = controller;
+  const selection = sheet.getSelections()[0];
+  const nodes = [];
+  const firstNode = tree.items[selection.row];
+  if (!firstNode) {
+    return [];
+  }
+  const firstNodeDepth = firstNode.depth();
+  for (let i = 0; i < selection.rowCount; i++) {
+    const row = selection.row + i;
+    const node = tree.items[row];
+    if (node && node.depth() === firstNodeDepth) {
+      nodes.push(node);
+    }
+  }
+  const rst = [];
+  nodes.forEach(node => {
+    const allNodes = [node, ...node.getPosterity()];
+    allNodes.forEach(n => {
+      if (!rst.includes(n)) {
+        rst.push(n);
+      }
+    })
+  });
+  return rst;
+}
+
+// 复制整块
+const copyBlock = async (controller) => {
+  try {
+    $.bootstrapLoading.start();
+    const nodes = getCopyNodes(controller);
+    const bills = [];
+    nodes.forEach(node => {
+      const bill = {};
+      Object.keys(node.data).forEach(key => {
+        if (typeof node.data[key] !== 'object') {
+          bill[key] = node.data[key];
+          bill.ID = node.getID();
+          bill.ParentID = node.getParentID();
+          bill.NexSiblingID = node.getNextSiblingID();
+        }
+      });
+      bills.push(bill);
+    });
+    await localforage.setItem('billsBlock', bills);
+    console.log(bills);
+  } catch (error) {
+    alert(error.message);
+  }
+  $.bootstrapLoading.end();
+}
+
+// 设置节点的前三层信息
+const setPasteSectionInfo = (tree, bills) => {
+  const IDMap = {};
+  tree.items.forEach(item => {
+    IDMap[item.getID()] = { ID: item.getID(), ParentID: item.getParentID(), NexSiblingID: item.getNextSiblingID() }; // 树操作后可能有缓存问题,data里的ID还没变
+  });
+  bills.forEach(bill => {
+    IDMap[bill.ID] = bill;
+  });
+  const getThreeParentIDs = (bill) => {
+    const parentIDs = [];
+    let cur = bill;
+    for (let i = 0; i < 3; i++) {
+      const parent = IDMap[cur.ParentID];
+      if (parent) {
+        parentIDs.push(parent.ID);
+        cur = parent;
+      } else {
+        break;
+      }
+    }
+    return parentIDs.reverse();
+  };
+  bills.forEach(bill => {
+    const parentIDs = getThreeParentIDs(bill);
+    const sectionInfo = { first: parentIDs[0] || null, second: parentIDs[1] || null, third: parentIDs[2] || null };
+    bill.sectionInfo = sectionInfo;
+  });
+}
+
+// 获取粘贴整块数据
+const getPasteData = async (controller) => {
+  const bills = await localforage.getItem('billsBlock');
+  if (!bills || !bills.length) {
+    throw new Error('请先复制整块!');
+  }
+  const { tree } = controller;
+  const selected = tree.selected;
+  if (!selected) {
+    throw new Error('请选中节点!');
+  }
+  tree.resetID(bills, uuid.v1);
+  // 粘贴到选中节点的最末子项
+  let updatePreData = null;
+  const lastChild = selected.lastChild();
+  const firstBill = bills[0];
+  if (lastChild) {
+    updatePreData = { ID: lastChild.getID(), NextSiblingID: firstBill.ID };
+  }
+  let lastRoot = firstBill;
+  const kindMap = {};
+  billKindComboList.forEach(item => {
+    kindMap[item.name] = item.value;
+  });
+  const flagMap = {};
+  BillsFixedFlagList.forEach(item => {
+    flagMap[item.name] = item.value;
+  });
+  const firstParentID = firstBill.ParentID;
+  bills.forEach(bill => {
+    bill.billsLibId = billsLibId;
+    bill.jobs = [];
+    bill.items = [];
+    bill.designs = [];
+    if (bill.kind) {
+      bill.kind = kindMap[bill.kind] || undefined;
+    }
+    if (bill.fixedFlag) {
+      bill.fixedFlag = flagMap[bill.fixedFlag] || undefined;
+    }
+    if (bill.ParentID === firstParentID) {
+      bill.ParentID = selected.getID();
+      lastRoot = bill;
+    }
+  });
+  if (lastRoot) {
+    lastRoot.NexSiblingID = -1;
+  }
+  setPasteSectionInfo(tree, bills);
+  return { insertBills: bills, updatePreData };
+}
+
+// 粘贴整块
+const pasteBlock = async (controller) => {
+  try {
+    $.bootstrapLoading.end();
+    const { insertBills, updatePreData } = await getPasteData(controller);
+    if (insertBills.length) {
+      createBills(controller, undefined, insertBills, updatePreData, true);
+    }
+    controller.event.refreshBaseActn(controller.tree);
+  } catch (error) {
+    alert(error.message);
+  }
+  $.bootstrapLoading.end();
+}
+
+// 计算规则转移补注
+const transferRecharge = async () => {
+  try {
+    $.bootstrapLoading.end();
+    await ajaxPost('/stdBillsEditor/transferRecharge', { billsLibId });
+    window.location.reload();
+  } catch (error) {
+    alert(error.message);
+  }
+  $.bootstrapLoading.end();
+}
+
+// 右键
+const onContextmenuOpr = (workBook, controller) => {
+  //右键菜单
+  $.contextMenu({
+    selector: "#spreadBills",
+    build: function ($triggerElement, e) {
+      //控制允许右键菜单在哪个位置出现
+      let target = SheetDataHelper.safeRightClickSelection(
+        $triggerElement,
+        e,
+        workBook
+      );
+      let bill = controller.tree.items[target.row] || null;
+      controller.setTreeSelected(bill);
+      if (target.hitTestType === 3) {
+        return {
+          callback: function () { },
+          items: {
+            copyBlock: {
+              name: "复制整块",
+              disabled: function () {
+                const inValidCell =
+                  !commonUtil.isDef(target.row) ||
+                  !commonUtil.isDef(target.col);
+                const inValidData = target.row >= controller.tree.items.length;
+                return locked || inValidCell || inValidData;
+              },
+              icon: "fa-copy",
+              callback: function (key, opt) {
+                copyBlock(controller);
+              },
+            },
+            pasteBlock: {
+              name: "粘贴整块",
+              disabled: function () {
+                const inValidCell =
+                  !commonUtil.isDef(target.row) ||
+                  !commonUtil.isDef(target.col);
+                const inValidData = target.row >= controller.tree.items.length;
+                return locked || inValidCell || inValidData;
+              },
+              icon: "fa-paste",
+              callback: function (key, opt) {
+                pasteBlock(controller);
+              },
+            },
+            handleRecharge: {
+              name: "计算规则转移补注",
+              disabled: function () {
+                return locked;
+              },
+              icon: "fa-exchange",
+              callback: function (key, opt) {
+                transferRecharge();
+              },
+            },
+          },
+        };
+      } else {
+        return false;
+      }
+    },
+  });
+};
+
+
 var dbController = {
   controller: null,
   currentEditData: null,
@@ -58,44 +348,7 @@ var dbController = {
       rowCount,
       billsLibId
     );
-    billsAjax.createBills(
-      userAccount,
-      billsLibId,
-      updatePreData,
-      insertBills,
-      function () {
-        if (updatePreData) {
-          const node = controller.tree.findNode(updatePreData.ID);
-          if (node) {
-            Object.assign(node.data, updatePreData);
-          }
-        }
-
-        const treeData = insertBills.map((item) => ({
-          type: "new",
-          data: item,
-        }));
-        const newNodes = controller.m_insert(treeData);
-        newNodes.forEach(n => {
-          n.jobs = [];
-          n.items = [];
-          console.log(n.serialNo(), n.getID());
-          controller.sheet.setTag(
-            n.serialNo(),
-            0,
-            n.getID()
-          );
-        });
-        sheetBillsDatas = tools.getsheetDatas(
-          controller.sheet,
-          "bills",
-          controller
-        );
-        tools.btnAction(btn);
-        btn.attr("doing", "false");
-        controller.sheet.getParent().focus(true);
-      }
-    );
+    createBills(controller, btn, insertBills, updatePreData);
   },
 
   upLevel: function (controller, btn) {
@@ -179,8 +432,8 @@ var dbController = {
         );
 
         billsAjax.upLevel(userAccount, billsLibId, updateData, function () {
-          //tools.btnAction(btn);
-          //btn.attr('doing', 'false');
+          tools.btnAction(btn);
+          btn.attr('doing', 'false');
           for (let upLevelNode of selNodes) {
             controller.setTreeSelected(upLevelNode);
             controller.upLevel();
@@ -196,8 +449,8 @@ var dbController = {
             billsAjax.updateSectionInfo(
               tools.getUpdateSectionData(toUpSectionNodes),
               function () {
-                tools.btnAction(btn);
-                btn.attr("doing", "false");
+                /* tools.btnAction(btn);
+                btn.attr("doing", "false"); */
               }
             );
           }
@@ -253,8 +506,8 @@ var dbController = {
         );
 
         billsAjax.downLevel(userAccount, billsLibId, updateData, function () {
-          //tools.btnAction(btn);
-          //btn.attr('doing', 'false');
+          tools.btnAction(btn);
+          btn.attr('doing', 'false');
           for (let downNode of selNodes) {
             controller.setTreeSelected(downNode);
             controller.downLevel();
@@ -270,8 +523,8 @@ var dbController = {
             billsAjax.updateSectionInfo(
               tools.getUpdateSectionData(toUpSectionNodes),
               function () {
-                tools.btnAction(btn);
-                btn.attr("doing", "false");
+                /* tools.btnAction(btn);
+                btn.attr("doing", "false"); */
               }
             );
           }

+ 30 - 0
web/maintain/price_info_lib/html/edit.html

@@ -118,6 +118,36 @@
             </div>
         </div>
     </div>
+
+    <div class="modal fade" id="batch-edit" data-backdrop="static" style="display: none;" aria-hidden="true">
+        <div class="modal-dialog" role="document">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <h5 class="modal-title">批量修改</h5>
+                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                        <span aria-hidden="true">×</span>
+                    </button>
+                </div>
+                <div class="modal-body">
+                    <div id="edit-item" style="margin-bottom: 1rem;"></div>
+                    <form>
+                        <div class="form-group row" style="margin-left: 0px;">
+                            <label class="col-auto col-form-label" id="edit-label" style="line-height: 26px;">名称</label>
+                            <div class="col">
+                                <input id="edit-text" class="form-control" placeholder="请输入内容" type="text" value="">
+                            </div>
+                        </div>
+                    </form>
+                    <div style="color: red;">*批量修改同一省份下相同材料</div>
+                </div>
+                <div class="modal-footer">
+                    <a id="batch-edit-confirm" href="javascript: void(0);" class="btn btn-primary">确定</a>
+                    <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                </div>
+            </div>
+        </div>
+    </div>
+    
     <!-- JS. -->
     <script src="/lib/jquery/jquery.min.js"></script>
     <script src="/lib/jquery-contextmenu/jquery.contextMenu.min.js"></script>

+ 2 - 1
web/maintain/price_info_lib/js/index.js

@@ -1,7 +1,8 @@
 $(document).ready(() => {
     console.log('进入信息价');
     $('[data-toggle="tooltip"]').tooltip();
-    AREA_BOOK.handleSelectionChanged(0);
+    // AREA_BOOK.handleSelectionChanged(0);
+    AREA_BOOK.init();
     const $range = $(document.body);
     lockUtil.lockTools($range, locked);
 });

+ 63 - 5
web/maintain/price_info_lib/js/priceArea.js

@@ -1,5 +1,7 @@
 // 地区表
 const AREA_BOOK = (() => {
+  // 地区表格锁
+  let areaLocked = true;
   const cache = areaList;
   const setting = {
     header: [
@@ -9,7 +11,7 @@ const AREA_BOOK = (() => {
   };
   // 初始化表格
   const workBook = initSheet($('#area-spread')[0], setting);
-  lockUtil.lockSpreads([workBook], locked);
+  lockUtil.lockSpreads([workBook], locked || areaLocked);
   workBook.options.allowExtendPasteRange = false;
   workBook.options.allowUserDragDrop = false;
   workBook.options.allowUserDragFill = false;
@@ -55,13 +57,35 @@ const AREA_BOOK = (() => {
       });
     }
   }
-  sheet.bind(GC.Spread.Sheets.Events.ValueChanged, function (e, info) {
+
+  const bindEdit = () => {
+    sheet.bind(GC.Spread.Sheets.Events.ValueChanged, function (e, info) {
+      const changedCells = [{ row: info.row, col: info.col }];
+      handleEdit(changedCells);
+    });
+    sheet.bind(GC.Spread.Sheets.Events.RangeChanged, function (e, info) {
+      handleEdit(info.changedCells);
+    });
+  };
+
+  bindEdit();
+
+  /* sheet.bind(GC.Spread.Sheets.Events.ValueChanged, function (e, info) {
     const changedCells = [{ row: info.row, col: info.col }];
     handleEdit(changedCells);
   });
   sheet.bind(GC.Spread.Sheets.Events.RangeChanged, function (e, info) {
     handleEdit(info.changedCells);
-  });
+  }); */
+
+  const setCurAreaStorage = (curLibID, curAreaID) => {
+    window.localStorage.setItem(`priceArea:${curLibID}`, curAreaID);
+  };
+
+  const geCurAreaStorage = (curLibID) => {
+    const curAreaID = window.localStorage.getItem(`priceArea:${curLibID}`);
+    return curAreaID;
+  };
 
   const curArea = { ID: null, name: '' };
   // 焦点变更处理
@@ -73,10 +97,25 @@ const AREA_BOOK = (() => {
     const areaItem = cache[row];
     curArea.ID = areaItem && areaItem.ID || null;
     curArea.name = areaItem && areaItem.name || '';
+    setCurAreaStorage(libID, curArea.ID);
     CLASS_BOOK.initData(libID, curArea.ID);
   }
   sheet.bind(GC.Spread.Sheets.Events.SelectionChanged, debounceSelectionChanged);
 
+  // 第一次进来初始化显示
+  const init = () => {
+    const curAreaID = geCurAreaStorage(libID);
+    if (!curAreaID) {
+      handleSelectionChanged(0);
+      return;
+    }
+    let row = cache.findIndex(item => item.ID === curAreaID);
+    row = row >= 0 ? row : 0;
+    handleSelectionChanged(row);
+    sheet.setActiveCell(row, 1);
+    sheet.showCell(row, 0, GC.Spread.Sheets.VerticalPosition.center);
+  }
+
   // 新增
   async function insert() {
     const data = {
@@ -139,11 +178,27 @@ const AREA_BOOK = (() => {
           }
           return {
             items: {
+              lock: {
+                name: areaLocked ? '解锁' : '锁定',
+                icon: areaLocked ? "fa-unlock" : 'fa-lock',
+                disabled: function () {
+                  return locked;
+                },
+                callback: function (key, opt) {
+                  areaLocked = !areaLocked;
+                  if (locked || areaLocked) {
+                    lockUtil.lockSpreads([workBook], locked || areaLocked);
+                  } else {
+                    lockUtil.unLockSpreads([workBook]);
+                    bindEdit();
+                  }
+                }
+              },
               insert: {
                 name: '新增',
                 icon: "fa-arrow-left",
                 disabled: function () {
-                  return locked;
+                  return locked || areaLocked;
                 },
                 callback: function (key, opt) {
                   insert();
@@ -153,7 +208,7 @@ const AREA_BOOK = (() => {
                 name: '删除',
                 icon: "fa-arrow-left",
                 disabled: function () {
-                  return locked || !cache[target.row];
+                  return locked || areaLocked || !cache[target.row];
                 },
                 callback: function (key, opt) {
                   del();
@@ -171,9 +226,12 @@ const AREA_BOOK = (() => {
   buildContextMenu();
 
   return {
+    init,
     handleSelectionChanged,
     curArea,
     cache,
+    setCurAreaStorage,
+    geCurAreaStorage
   }
 
 })();

+ 2 - 1
web/maintain/price_info_lib/js/priceClass.js

@@ -416,7 +416,7 @@ const CLASS_BOOK = (() => {
   }
 
   // 焦点变更处理
-  const curClass = { ID: null };
+  const curClass = { ID: null, IDList: [] };
   function handleSelectionChanged(row) {
     curRow = row;
     const classNode = tree.items[row] || null;
@@ -429,6 +429,7 @@ const CLASS_BOOK = (() => {
       const children = classNode.getPosterity();
       children.forEach(child => classIDList.push(child.data.ID));
     }
+    curClass.classIDList = [];
     PRICE_BOOK.initData(classIDList);
   }
   const debounceSelectionChanged = _.debounce(function (e, info) {

+ 105 - 3
web/maintain/price_info_lib/js/priceItem.js

@@ -40,7 +40,8 @@ const PRICE_BOOK = (() => {
     $.bootstrapLoading.start();
     try {
       cache = await ajaxPost('/priceInfo/getPriceData', { classIDList }, 1000 * 60 * 10);
-      cache = _.sortBy(cache, 'classCode');
+      // cache = _.sortBy(cache, 'classCode');
+      // cache = _.sortBy(cache, 'code');
       showData(sheet, cache, setting.header, 5);
       const row = sheet.getActiveRowIndex();
       const keywordList = cache[row] && cache[row].keywordList || [];
@@ -118,11 +119,16 @@ const PRICE_BOOK = (() => {
     const changedCells = [{ row: info.row }];
     handleEdit(changedCells);
   });
-  sheet.bind(GC.Spread.Sheets.Events.SelectionChanged, function (e, info) {
-    const row = info.newSelections && info.newSelections[0] ? info.newSelections[0].row : 0;
+
+  const handleSelectionChange = (row) => {
     // 显示关键字数据
     const keywordList = cache[row] && cache[row].keywordList || [];
     KEYWORD_BOOK.showKeywordData(keywordList);
+  }
+
+  sheet.bind(GC.Spread.Sheets.Events.SelectionChanged, function (e, info) {
+    const row = info.newSelections && info.newSelections[0] ? info.newSelections[0].row : 0;
+    handleSelectionChange(row);
   });
   sheet.bind(GC.Spread.Sheets.Events.RangeChanged, function (e, info) {
     const changedRows = [];
@@ -169,10 +175,97 @@ const PRICE_BOOK = (() => {
     showData(sheet, cache, setting.header);
   }
 
+  const getKey = (item) => {
+    return `${item.code || ''}@${item.name || ''}@${item.specs || ''}@${item.unit || ''}`;
+  }
+
+  // 批量修改
+  const batchEdit = async () => {
+    try {
+      $.bootstrapLoading.start();
+      const row = sheet.getActiveRowIndex();
+      const col = sheet.getActiveColumnIndex();
+      const colHeader = setting.header[col];
+      const priceItem = cache[row];
+      if (!priceItem || !colHeader) {
+        return;
+      }
+      const prop = colHeader.dataCode;
+      const val = $('#edit-text').val();
+      if (['noTaxPrice', 'taxPrice'].includes(prop) && (!val || isNaN(val))) {
+        throw new Error('请输入数值');
+      }
+      await ajaxPost('/priceInfo/batchUpdate', { priceItem, prop, val });
+      const key = getKey(priceItem);
+      cache.forEach(item => {
+        if (key === getKey(item)) {
+          item[prop] = val;
+        }
+      });
+      showData(sheet, cache, setting.header, 5);
+      $('#batch-edit').modal('hide');
+    } catch (error) {
+      alert(error.message);
+    }
+    $.bootstrapLoading.end();
+  }
+
+  // 右键功能
+  function buildContextMenu() {
+    $.contextMenu({
+      selector: '#price-spread',
+      build: function ($triggerElement, e) {
+        // 控制允许右键菜单在哪个位置出现
+        const offset = $('#price-spread').offset();
+        const x = e.pageX - offset.left;
+        const y = e.pageY - offset.top;
+        const target = sheet.hitTest(x, y);
+        if (target.hitTestType === 3) { // 在表格内
+          const sel = sheet.getSelections()[0];
+          if (sel && sel.rowCount === 1 && typeof target.row !== 'undefined') {
+            const orgRow = sheet.getActiveRowIndex();
+            sheet.setActiveCell(target.row, target.col);
+            if (orgRow !== target.row) {
+              handleSelectionChange(target.row);
+            }
+          }
+          return {
+            items: {
+              batchUpdate: {
+                name: '批量修改',
+                icon: "fa-edit",
+                disabled: function () {
+                  return locked || !cache[target.row];
+                },
+                callback: function (key, opt) {
+                  const colHeader = setting.header[target.col];
+                  const item = cache[target.row];
+                  if (item) {
+                    const info = `材料:${item.code || ''} ${item.name || ''} ${item.specs || ''} ${item.unit}`;
+                    $('#edit-item').text(info);
+                    $('#edit-label').text(colHeader.headerName);
+                    $('#edit-text').attr('placeholder', `请输入${colHeader.headerName}`);
+                    $('#edit-text').val(item[colHeader.dataCode] || '');
+                    $('#batch-edit').modal('show');
+                  }
+                }
+              },
+            }
+          };
+        }
+        else {
+          return false;
+        }
+      }
+    });
+  }
+  buildContextMenu();
+
   return {
     clear,
     initData,
     showRepeatData,
+    batchEdit,
   }
 })();
 
@@ -181,4 +274,13 @@ $(document).ready(() => {
   $('#check-repeat').click(() => {
     PRICE_BOOK.showRepeatData();
   });
+
+  // 批量修改
+  $('#batch-edit-confirm').click(() => {
+    PRICE_BOOK.batchEdit();
+  });
+
+  $('#batch-edit').on('shown.bs.modal', function () {
+    $('#edit-text').focus();
+  });
 });

+ 2 - 0
web/maintain/report/html/rpt_tpl_dtl_info.html

@@ -136,6 +136,8 @@
                         <option value="complexConstructMultiple">各阶段项目对比(3个建设项目,多对多对多)</option>
                         <option value="complexSelfConstructMultiple">各阶段项目对比(当前建设项目对本阶段对其他阶段)</option>
                         <option value="businessSummary">多个业务汇总</option>
+                        <option value="changeProjectSummary">变更业务对比汇总</option>
+                        <option value="changeProjectGljSummary">变更业务工料机对比汇总</option>
                     </select>
                     <label class="form-check-label" id="outputDesignDataBar" style="display: none;">
                         <input onchange="zTreeOprObj.onChangeFlag('outputDesignData', this)"  id="outputDesignData" type="checkbox">输出设计清单

+ 31 - 3
web/maintain/report/js/rpt_tpl_main.js

@@ -26,7 +26,6 @@ const valuationSelectorMap = {
   valuationSelector_changeBudget: "变更预算",
   valuationSelector_settlement: "结算",
 };
-
 let rptTplObj = {
   iniPage: function () {
     zTreeOprObj.getCompilationList();
@@ -190,6 +189,7 @@ let zTreeOprObj = {
         isDeleted: topNode.isDeleted,
         items: me.private_build_items(topNode.items, excludeNode),
         name: topNode.name,
+        UUID: topNode.UUID,
       };
     }
     return rst;
@@ -209,6 +209,7 @@ let zTreeOprObj = {
         released: isReleased,
         items: me.private_build_items(subNode.items, null),
         name: subNode.name,
+        UUID: subNode.UUID,
       };
       if (subNode.hasOwnProperty("flags")) {
         rst.flags = subNode.flags;
@@ -217,6 +218,17 @@ let zTreeOprObj = {
     return rst;
   },
 
+  generateRandomString() {
+    const charset =
+      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+    let randomString = "";
+    for (let i = 0; i < 10; i++) {
+      const randomIndex = Math.floor(Math.random() * charset.length);
+      randomString += charset[randomIndex];
+    }
+    return randomString;
+  },
+
   private_build_items: function (items, excludeNode) {
     let me = this,
       itemRst = null;
@@ -234,11 +246,14 @@ let zTreeOprObj = {
           ir.name = item.name;
           ir.ID = item.ID;
           ir.released = isReleased;
+          ir.UUID =
+            item.UUID ||
+            `${new Date().getTime()}_${this.generateRandomString()}`;
           if (item.hasOwnProperty("flags")) {
             ir.flags = item.flags;
           }
           // 同类表(associateRefIds)处理
-          if (item.hasOwnProperty('associateRefIds')) {
+          if (item.hasOwnProperty("associateRefIds")) {
             ir.associateRefIds = item.associateRefIds;
           }
           ir.items = me.private_build_items(item.items);
@@ -253,7 +268,12 @@ let zTreeOprObj = {
     let me = zTreeOprObj,
       sObj = $("#" + treeNode.tId + IDMark_Span);
 
-    if (treeNode.editNameFlag || $("#addBtn_" + treeNode.tId).length > 0 || treeNode.nodeType === RT.NodeType.TEMPLATE) return;
+    if (
+      treeNode.editNameFlag ||
+      $("#addBtn_" + treeNode.tId).length > 0 ||
+      treeNode.nodeType === RT.NodeType.TEMPLATE
+    )
+      return;
     if (treeNode.level === 0) {
       let addStr =
         "<span class='button star' id='addBtn_" +
@@ -499,6 +519,10 @@ let zTreeOprObj = {
     let me = zTreeOprObj;
     zTreeOprObj.treeObj.checkNode(treeNodes[0], false, false);
     treeNodes[0].released = false;
+    // 拷贝后的uuid重复的问题
+    if (isCopy) {
+      treeNodes[0].UUID = `${new Date().getTime()}_${me.generateRandomString()}`;
+    }
     let targetTopNode = me.getParentNodeByNodeLevel(
       targetNode,
       NODE_LEVEL_COMPILATION_NEW
@@ -1279,6 +1303,10 @@ let zTreeOprObj = {
                   $("#element_sumLv_flags")[0].selectedIndex = 15;
                 else if (sumLvType === "businessSummary")
                   $("#element_sumLv_flags")[0].selectedIndex = 16;
+                else if (sumLvType === "changeProjectSummary")
+                  $("#element_sumLv_flags")[0].selectedIndex = 17;
+                else if (sumLvType === "changeProjectGljSummary")
+                  $("#element_sumLv_flags")[0].selectedIndex = 18;
                 else {
                   $("#element_sumLv_flags")[0].selectedIndex = 0;
                 }

+ 29 - 1
web/maintain/std_glj_lib/html/gongliao.html

@@ -257,6 +257,34 @@
         </div>
     </div>
 
+    <div class="modal fade" id="edit-code" data-backdrop="static" style="display: none;" aria-hidden="true">
+        <div class="modal-dialog" role="document">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <h5 class="modal-title">修改编号</h5>
+                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                        <span aria-hidden="true">×</span>
+                    </button>
+                </div>
+                <div class="modal-body">
+
+                    <form>
+                        <div class="form-group row" style="margin-left: 0px;">
+                            <label class="col-auto col-form-label" id="edit-label" style="line-height: 26px;">编号</label>
+                            <div class="col">
+                                <input id="edit-code-text" class="form-control" placeholder="请输入编号" type="text" value="">
+                            </div>
+                        </div>
+                    </form>
+                </div>
+                <div class="modal-footer">
+                    <a id="edit-code-confirm" href="javascript: void(0);" class="btn btn-primary">确定</a>
+                    <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                </div>
+            </div>
+        </div>
+    </div>
+
     <!-- JS. -->
     <script src="/lib/jquery/jquery.min.js"></script>
     <script src="/lib/jquery-contextmenu/jquery.contextMenu.min.js"></script>
@@ -393,4 +421,4 @@
     autoFlashHeight();
 </script>
 
-</html>
+</html>

+ 68 - 13
web/maintain/std_glj_lib/js/glj.js

@@ -56,6 +56,7 @@ let repositoryGljObj = {
   treeObj: null,
   workBook: null,
   gljCurTypeId: -1,
+  gljCurClassSeq: 0,
   currentRepositoryId: -1,
   currentCache: null,
   parentNodeIds: {},
@@ -474,7 +475,7 @@ let repositoryGljObj = {
             me.rationLibs = result.data[0].rationLibs;
             $(".navbar-text").append(
               "<a href='/stdGljRepository/main'>人材机库</a><i class='fa fa-angle-right fa-fw'></i>" +
-                result.data[0].dispName
+              result.data[0].dispName
             );
             pageOprObj.gljLibName = result.data[0].dispName;
           }
@@ -493,7 +494,6 @@ let repositoryGljObj = {
       cache: false,
       timeout: 20000,
       success: function (result, textStatus, status) {
-        debugger;
         if (status.status == 200) {
           zTreeHelper.createTree(result.data, gljSetting, "repositoryTree", me);
           zTreeHelper.createTree(
@@ -504,6 +504,7 @@ let repositoryGljObj = {
           );
           if (result.data && result.data.length > 0) {
             me.gljCurTypeId = result.data[0].ID;
+            me.gljCurClassSeq = result.data[0].classSeq;
           } else {
             //重新创建库?
             gljTypeTreeOprObj.addRootNode();
@@ -848,6 +849,7 @@ let repositoryGljObj = {
     if (row < me.currentCache.length) {
       //标记当前工料机
       me.currentGlj = me.currentCache[row];
+      console.log(me.currentGlj);
       if (allowComponent.includes(me.currentCache[row].gljType)) {
         //展示数据
         if (me.currentGlj.component.length > 0) {
@@ -1247,6 +1249,7 @@ let repositoryGljObj = {
     }
     if (!me.parentNodeIds["_pNodeId_" + me.gljCurTypeId]) {
       rObj.gljClass = me.gljCurTypeId;
+      rObj.classSeq = me.gljCurClassSeq;
     }
     if (updateArr.length > 0 || addArr.length > 0) {
       me.currentEditingGlj = null;
@@ -1432,6 +1435,33 @@ let repositoryGljObj = {
         false
       );
   },
+  editCode: async function () {
+    const sheet = this.workBook.getSheet(0);
+    const row = sheet.getActiveRowIndex();
+    const glj = this.currentCache[row];
+    if (!glj) {
+      alert('请选中工料机!');
+      $('#edit-code').modal('hide');
+      return;
+    }
+    const newCode = $('#edit-code-text').val();
+    if (!newCode) {
+      alert('编号不可为空!');
+      $('#edit-code-text').focus();
+      return;
+    }
+    if (this.gljList.some(item => item.ID !== glj.ID && item.code === newCode)) {
+      alert('编号已存在!');
+      $('#edit-code-text').focus();
+      return;
+    }
+    if (newCode === glj.code) {
+      $('#edit-code').modal('hide');
+      return;
+    }
+    this.mixUpdateRequest([{ ...glj, code: newCode }], [], []);
+    $('#edit-code').modal('hide');
+  },
   onContextmenuOpr: function () {
     let me = repositoryGljObj;
     $.contextMenu({
@@ -1466,8 +1496,23 @@ let repositoryGljObj = {
             sheet.setActiveCell(target.row, target.col);
           }
           return {
-            callback: function () {},
+            callback: function () { },
             items: {
+              edit: {
+                name: "修改编号",
+                disabled: function () {
+                  return (
+                    locked || !(me.currentCache && me.currentCache[target.row])
+                  );
+                },
+                icon: "fa-edit",
+                callback: function (key, opt) {
+                  if (me.currentCache[target.row]) {
+                    $('#edit-code').modal('show');
+                    $('#edit-code-text').val(me.currentCache[target.row].code || '');
+                  }
+                },
+              },
               delete: {
                 name: "删除",
                 disabled: function () {
@@ -1811,8 +1856,8 @@ let repositoryGljObj = {
     if (!priceProperties || priceProperties.length === 0) {
       pasteObj.basePrice =
         !isNaN(parseFloat(pasteObj.basePrice)) &&
-        pasteObj.basePrice &&
-        typeof pasteObj.basePrice !== "undefined"
+          pasteObj.basePrice &&
+          typeof pasteObj.basePrice !== "undefined"
           ? parseFloat(pasteObj.basePrice)
           : 0;
     } else {
@@ -1837,6 +1882,7 @@ let repositoryGljObj = {
     //pasteObj.basePrice = !isNaN(parseFloat(pasteObj.basePrice)) && (pasteObj.basePrice && typeof pasteObj.basePrice !== 'undefined') ? parseFloat(pasteObj.basePrice) : 0;
     if (!me.parentNodeIds["_pNodeId_" + me.gljCurTypeId]) {
       pasteObj.gljClass = me.gljCurTypeId;
+      pasteObj.classSeq = me.gljCurClassSeq;
     }
     return true;
   },
@@ -1930,7 +1976,7 @@ let repositoryGljObj = {
         info.cellRange.colCount >= 5 &&
         info.cellRange.colCount <= me.setting.header.length &&
         info.cellRange.col + info.cellRange.colCount - 1 >=
-          me.colMapping.fieldToCol["gljType"]
+        me.colMapping.fieldToCol["gljType"]
       ) {
         for (let i = 0; i < items.length; i++) {
           if (me.isValidObj(items[i])) {
@@ -2317,7 +2363,7 @@ let gljTypeTreeOprObj = {
           pNode.isParent = false;
         }
       },
-      error: function () {},
+      error: function () { },
     });
     return true;
   },
@@ -2355,7 +2401,7 @@ let gljTypeTreeOprObj = {
         success: function (result, textStatus, status) {
           console.log(status + " : " + result);
         },
-        error: function () {},
+        error: function () { },
       });
     }
   },
@@ -2426,10 +2472,10 @@ let gljTypeTreeOprObj = {
         btn.bind("click", function () {
           treeNode.doing = true;
           let rawNode = {
-              ParentID: treeNode.ID,
-              NextSiblingID: -1,
-              Name: "新增子节点",
-            },
+            ParentID: treeNode.ID,
+            NextSiblingID: -1,
+            Name: "新增子节点",
+          },
             lastNodeId = -1;
           if (treeNode.items.length > 0) {
             lastNodeId = treeNode.items[treeNode.items.length - 1].ID;
@@ -2532,7 +2578,7 @@ $(document).ready(function () {
     },
     function () {
       let resizeRate =
-          (SlideResize.resizeWidth * 100) / $("#midContent").width(),
+        (SlideResize.resizeWidth * 100) / $("#midContent").width(),
         sheetRate = 100 - resizeRate;
       $("#slideResizeLeft").css("width", `${resizeRate}%`);
       $("#GLJListSheet").css("width", `${sheetRate}%`);
@@ -2569,4 +2615,13 @@ $(document).ready(function () {
     repositoryGljObj.mixUpdateRequest(updateArr, [], []);
     $("#moveTo").modal("hide");
   });
+
+  // 修改编号弹窗
+  $('#edit-code').on('shown.bs.modal', function () {
+    $('#edit-code-text').focus();
+  });
+
+  $('#edit-code-confirm').click(async () => {
+    await repositoryGljObj.editCode();
+  });
 });

+ 1 - 0
web/maintain/std_glj_lib/js/gljClassTree.js

@@ -730,6 +730,7 @@ let gljClassTreeObj = {
     }
     let gljTypeId = node.data.ID;
     re.gljCurTypeId = node.data.ID;
+    re.gljCurClassSeq = node.data.classSeq;
     re.addGljObj = null;
     sheetCommonObj.cleanSheet(that.workBook.getSheet(0), that.setting, 10);
     if (re.parentNodeIds["_pNodeId_" + gljTypeId]) {