zhongzewei пре 7 година
родитељ
комит
d273a6b33b

+ 26 - 0
modules/all_models/std_billsGuidance_items.js

@@ -0,0 +1,26 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2018/5/29
+ * @version
+ */
+//清单指引条目
+const mongoose = require('mongoose');
+const Schema = mongoose.Schema;
+
+const stdBillsGuidanceItems = new Schema({
+    libID: String,
+    ID: String, //uuid
+    ParentID: String,
+    NextSiblingID: String,
+    billsID: String, //关联清单的ID
+    name: String,
+    type: Number, //0:工作内容 1:定额
+    rationID: {type: Number, default: null}, //定额类型时
+    deleted: {type: Boolean, default: false}
+}, {versionKey: false});
+
+mongoose.model('std_billsGuidance_items', stdBillsGuidanceItems, 'std_billsGuidance_items');

+ 27 - 0
modules/all_models/std_billsGuidance_lib.js

@@ -0,0 +1,27 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2018/5/29
+ * @version
+ */
+//清单指引库
+const mongoose = require('mongoose');
+const Schema = mongoose.Schema;
+
+const stdBillsGuidanceLib = new Schema({
+    ID: String, //uuid
+    compilationId: String,
+    compilationName: String,
+    billsLibId: Number,
+    billsLibName: String,
+    name: String,
+    creator: String,
+    createDate: String,
+    deleted: {type: Boolean, default: false},
+}, {versionKey: false});
+
+mongoose.model('std_billsGuidance_lib', stdBillsGuidanceLib, 'std_billsGuidance_lib');
+

+ 10 - 0
modules/ration_repository/controllers/ration_controller.js

@@ -9,6 +9,16 @@ var callback = function(req, res, err, message, data){
 };
 
 class RationController extends BaseController{
+    async getRationItemsByLib(req, res){
+        try{
+            let data = JSON.parse(req.body.data);
+            let rationItems = await rationItem.getRationItemsByLib(data.rationLibId);
+            callback(req, res, 0, '', rationItems);
+        }
+        catch(err){
+            callback(req, res, 1, err, null);
+        }
+    }
     getRationItemsBySection(req, res){
         let sectionId = req.body.sectionID;
         let rationRepId = req.body.rationRepId;

+ 10 - 0
modules/ration_repository/controllers/ration_repository_controller.js

@@ -18,6 +18,16 @@ const excel = require("node-xlsx");
 const rationItem = require("../models/ration_item");
 
 class RationRepositoryController extends baseController {
+    async getRationLibsByCompilation(req, res){
+        try{
+            let data = JSON.parse(req.body.data);
+            let rationLibs = await rationRepository.getRationLibsByCompilation(data.compilationId);
+            callback(req, res, 0, '', rationLibs);
+        }
+        catch(err){
+            callback(req, res, 1, err, null);
+        }
+    }
     async getCompilationList(req, res) {
         try {
             let compilationModel = new CompilationModel(), rst = [];

+ 4 - 0
modules/ration_repository/models/ration_item.js

@@ -14,6 +14,10 @@ import STDGLJListModel from '../../std_glj_lib/models/gljModel';
 
 var rationItemDAO = function(){};
 
+rationItemDAO.prototype.getRationItemsByLib = async function (rationRepId) {
+    return await rationItemModel.find({rationRepId: rationRepId, $or: [{isDeleted: null}, {isDeleted: false}]});
+};
+
 rationItemDAO.prototype.sortToNumber = function (datas) {
     for(let i = 0, len = datas.length; i < len; i++){
         let data = datas[i]._doc;

+ 4 - 0
modules/ration_repository/models/repository_map.js

@@ -27,6 +27,10 @@ function createNewLibModel(rationLibObj){
 
 var rationRepositoryDao = function(){};
 
+rationRepositoryDao.prototype.getRationLibsByCompilation = async function (compilationId) {
+    return await rationRepository.find({compilationId: compilationId, deleted: false});
+};
+
 rationRepositoryDao.prototype.updateGljLib = function (gljLibId, callback) {
     rationRepository.update({gljLib: gljLibId}, {$set: {gljLib: -1}}, {multi: true}, function (err) {
         if(err){

+ 2 - 0
modules/ration_repository/routes/ration_rep_routes.js

@@ -31,6 +31,7 @@ module.exports =  function (app) {
     app.get('/rationRepository/installation', viewsController.auth, viewsController.init, viewsController.redirectInstallation);
 
     apiRouter.post("/getCompilationList", rationRepositoryController.auth, rationRepositoryController.init, rationRepositoryController.getCompilationList);
+    apiRouter.post("/getRationLibsByCompilation", rationRepositoryController.auth, rationRepositoryController.init, rationRepositoryController.getRationLibsByCompilation);
 
     apiRouter.post("/getRationLib",rationRepositoryController.auth, rationRepositoryController.init, rationRepositoryController.getRationLib);
     apiRouter.post("/getRationDisplayNames",rationRepositoryController.auth, rationRepositoryController.init, rationRepositoryController.getDisPlayRationLibs);
@@ -51,6 +52,7 @@ module.exports =  function (app) {
     apiRouter.post("/updateAnnoSituation",rationChapterTreeController.auth, rationChapterTreeController.init, rationChapterTreeController.updateAnnoSituation);
 
     apiRouter.post("/getRationItems",rationController.auth, rationController.init, rationController.getRationItemsBySection);
+    apiRouter.post("/getRationItemsByLib",rationController.auth, rationController.init, rationController.getRationItemsByLib);
     apiRouter.post("/mixUpdateRationItems",rationController.auth, rationController.init, rationController.mixUpdateRationItems);
     apiRouter.post("/updateRationBasePrc",rationController.auth, rationController.init, rationController.updateRationBasePrc);
     apiRouter.post("/getRationGljIds",rationController.auth, rationController.init, rationController.getRationGljIds);

+ 103 - 0
modules/std_billsGuidance_lib/controllers/libController.js

@@ -0,0 +1,103 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2018/5/29
+ * @version
+ */
+import BaseController from '../../common/base/base_controller';
+import mongoose from 'mongoose';
+import CompilationModel from "../../users/models/compilation_model";
+import moment from 'moment';
+const uuidV1 = require('uuid/v1');
+const billsLibModel = mongoose.model('std_bills_lib_list');
+const billsGuideLibModel = mongoose.model('std_billsGuidance_lib');
+const billsGuideItemsModel = mongoose.model('std_billsGuidance_items');
+const stdBillsLibModel = mongoose.model('std_bills_lib_list');
+const stdBillsModel = mongoose.model('std_bills_lib_bills');
+const stdBillsJobsModel = mongoose.model('std_bills_lib_jobContent');
+const stdRationModel = mongoose.model('std_ration_lib_ration_items');
+const _ = require('lodash');
+const billsGuidanceFacade = require('../facade/facades');
+let callback = function (req, res, err, msg, data) {
+    res.json({error: err, message: msg, data: data});
+};
+
+class BillsGuideLibController extends BaseController{
+    //获取编办及编办清单库信息
+    async getComBillsLibInfo(req, res){
+        try{
+            let comBillsLibInfo = await billsGuidanceFacade.getComBillsLibInfo();
+            callback(req, res, 0, '', comBillsLibInfo);
+        }
+        catch(err) {
+            callback(req, res, 1, err, null);
+        }
+    }
+
+    async getBillsGuideLibs(req, res){
+        try{
+            let libs = await billsGuidanceFacade.getBillsGuideLibs({deleted: false});
+            callback(req, res, 0, '', libs);
+        }
+        catch(err){
+            callback(req, res, 1, '获取清单指引库数据错误', null);
+        }
+    }
+
+    async updateBillsGuideLib(req, res){
+        try{
+            let data = JSON.parse(req.body.data);
+            if(data.updateType === 'create'){
+                data.updateData.createDate = moment(Date.now()).format('YYYY-MM-DD HH:mm:ss');
+                data.updateData.creator = req.session.managerData.username;
+                await billsGuidanceFacade.initBillsGuideLib(data.updateData);
+            }
+            else{
+                await billsGuidanceFacade.updateBillsGuideLib(data);
+            }
+            callback(req, res, 0, '', data.updateData);
+        }
+        catch(err){
+            callback(req, res, 1, '更新失败', null);
+        }
+    }
+    //获取清单指引库和该库引用的清单
+    async getLibWithBills(req, res){
+        try{
+            let data = JSON.parse(req.body.data);
+            let rst = await billsGuidanceFacade.getLibWithBills(data.libID);
+            callback(req, res, 0, '', rst);
+        }
+        catch(err){
+            callback(req, res, 1, err, null);
+        }
+    }
+
+    async getItemsByBills(req, res){
+        try{
+            let data = JSON.parse(req.body.data);
+            let items = await billsGuidanceFacade.getItemsBybills(data.guidanceLibID, data.billsID);
+            callback(req, res, 0, '', items);
+        }
+        catch(err){
+            callback(req, res, 1, err, null);
+        }
+    }
+
+    async updateItems(req, res){
+        try{
+            let data = JSON.parse(req.body.data);
+            let updateDatas = data.updateDatas;
+            await billsGuidanceFacade.updateItems(updateDatas);
+            callback(req, res, 0, '', null);
+        }
+        catch(err){
+            callback(req, res, 1, err, null);
+        }
+    }
+}
+
+export default BillsGuideLibController;

+ 27 - 0
modules/std_billsGuidance_lib/controllers/viewController.js

@@ -0,0 +1,27 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2018/5/29
+ * @version
+ */
+import BaseController from "../../common/base/base_controller";
+
+class ViewsController extends BaseController{
+    redirectMain(req, res){
+        res.render('maintain/billsGuidance_lib/html/main.html',
+            {
+                userAccount: req.session.managerData.username
+            });
+    }
+    redirectGuidance(req, res){
+        res.render('maintain/billsGuidance_lib/html/zhiyin.html',
+            {
+                userAccount: req.session.managerData.username
+            });
+    }
+}
+
+export default ViewsController;

+ 233 - 0
modules/std_billsGuidance_lib/facade/facades.js

@@ -0,0 +1,233 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2018/6/1
+ * @version
+ */
+import mongoose from 'mongoose';
+import CompilationModel from "../../users/models/compilation_model";
+import moment from 'moment';
+const uuidV1 = require('uuid/v1');
+const billsLibModel = mongoose.model('std_bills_lib_list');
+const billsGuideLibModel = mongoose.model('std_billsGuidance_lib');
+const billsGuideItemsModel = mongoose.model('std_billsGuidance_items');
+const stdBillsLibModel = mongoose.model('std_bills_lib_list');
+const stdBillsModel = mongoose.model('std_bills_lib_bills');
+const stdBillsJobsModel = mongoose.model('std_bills_lib_jobContent');
+const stdRationModel = mongoose.model('std_ration_lib_ration_items');
+const _ = require('lodash');
+
+module.exports = {
+    getComBillsLibInfo,
+    getBillsGuideLibs,
+    initBillsGuideLib,
+    updateBillsGuideLib,
+    getLibWithBills,
+    getItemsBybills,
+    updateItems
+};
+
+async function getCompilationList() {
+    let compilationModel = new CompilationModel();
+    return await compilationModel.getCompilationList();
+}
+
+async function getComBillsLibInfo() {
+    let rst = [];
+    let compilationList = await getCompilationList();
+    if(compilationList.length <= 0){
+        throw '没有数据';
+    }
+    else{
+        for(let compilation of compilationList){
+            let billsLibs = await billsLibModel.find({compilationId: compilation._id, deleted: false}, '-_id billsLibId billsLibName');
+            rst.push({_id: compilation._id, name: compilation.name, billsLibs: billsLibs});
+        }
+        return rst;
+    }
+}
+
+async function getBillsGuideLibs(findData) {
+    return await billsGuideLibModel.find(findData);
+}
+
+//拷贝工作内容并转化为树结构,形成项目指引数据
+async function genGuidanceItems(guidanceLibId, billsLibId){
+    let bills = await stdBillsModel.find({billsLibId: billsLibId, deleted: false, 'jobs.0': {$exists: true}});
+    //设置工作内容数据
+    let jobIds = [];
+    let totalJobs = [];
+    for(let bill of bills){
+        for(let job of bill.jobs){
+            jobIds.push(job.id);
+        }
+    }
+    jobIds = Array.from(new Set(jobIds));
+    if(jobIds.length > 0){
+        totalJobs = await stdBillsJobsModel.find({deleted: false, id: {$in: jobIds}});
+    }
+    if(totalJobs.length > 0){
+        let jobIdIndex = {};//id索引
+        for(let job of totalJobs){
+            jobIdIndex[job.id] = job;
+        }
+        let insertArr = [];
+        for(let bill of bills){
+            //排序后根据serialNo转换成NextSiblingID,倒序
+            bill.jobs.sort(function (a, b) {
+                let rst = 0;
+                if(a.serialNo > b.serialNo){
+                    rst = -1;
+                }
+                else if(a.serialNo < b.serialNo){
+                    rst = 1;
+                }
+                return rst;
+            });
+            let jobNoIndex = {};//下标索引
+            for(let i = 0; i < bill.jobs.length; i++){
+                let newItem = {libID: guidanceLibId, ID: uuidV1(), ParentID: -1, NextSiblingID: jobNoIndex[i - 1] ? jobNoIndex[i - 1]['ID'] : -1,
+                    name: jobIdIndex[bill.jobs[i]['id']]['content'], type: 0, billsID: bill.ID};
+                jobNoIndex[i] = newItem;
+                insertArr.push({insertOne: {document: newItem}});
+            }
+        }
+        await billsGuideItemsModel.bulkWrite(insertArr);
+    }
+}
+
+async function initBillsGuideLib(updateData){
+    await billsGuideLibModel.create(updateData);
+    await genGuidanceItems(updateData.ID, updateData.billsLibId);
+}
+
+async function updateBillsGuideLib(data) {
+    await billsGuideLibModel.update(data.findData, {$set: data.updateData});
+    if(data.updateType === 'delete'){
+        //假删除所有条目
+        await billsGuideItemsModel.update({libID: data.findData.ID}, {$set: {deleted: true}}, {multi: true});
+    }
+}
+
+async function getLibWithBills(libID){
+    let guidanceLib = await getBillsGuideLibs({ID: libID, deleted: false});
+    if(guidanceLib.length === 0){
+        throw '不存在此指引库!';
+    }
+    let billsLib = await stdBillsLibModel.findOne({billsLibId: guidanceLib[0].billsLibId, deleted: false});
+    if(!billsLib){
+        throw '引用的清单规则库不存在!';
+    }
+    let bills = await stdBillsModel.find({billsLibId: billsLib.billsLibId, deleted: false}, '-_id code name ID NextSiblingID ParentID');
+    return {guidanceLib: guidanceLib[0], bills};
+}
+
+function getAttrs(field, datas){
+    let rst = [];
+    for(let data of datas){
+        if(data[field]){
+            rst.push(data[field]);
+        }
+    }
+    return rst;
+}
+
+//定额项目指所引用定额是否被删除
+function rationAllExist(rationItems, stdRationIdx) {
+    for(let item of rationItems){
+        if(!stdRationIdx[item.rationID]){
+            return false;
+        }
+    }
+    return true;
+}
+
+//将同层树结构转为顺序数组
+function chainToArr(nodes){
+    let rst = [];
+    let tempIdx = {};
+    let nodeIdx = {};
+    //建索引
+    for(let node of nodes){
+        tempIdx[node.ID] = {ID: node.ID, NextSiblingID: node.NextSiblingID, preSibling: null, nextSibling: null};
+        nodeIdx[node.ID] = node;
+    }
+    //建链
+    for(let i in tempIdx){
+        let temp = tempIdx[i];
+        if(temp.NextSiblingID != -1){
+            let next = tempIdx[temp.NextSiblingID];
+            temp.nextSibling = next;
+            next.preSibling = temp;
+        }
+    }
+    let firstNode = null;
+    for(let i in tempIdx){
+        if(!tempIdx[i].preSibling){
+            firstNode = tempIdx[i];
+            break;
+        }
+    }
+    //获得顺序队列
+    while(firstNode){
+        rst.push(nodeIdx[firstNode.ID]);
+        firstNode = firstNode.nextSibling;
+    }
+    return rst;
+}
+
+async function getItemsBybills(guidanceLibID, billsID){
+    const type = {job: 0, ration: 1};
+    let items = await billsGuideItemsModel.find({libID: guidanceLibID, billsID: billsID, deleted: false});
+    let rationItems = _.filter(items, {type: type.ration});
+    let rationIds = getAttrs('rationID', rationItems);
+    let stdRations = await stdRationModel.find({ID: {$in: rationIds}, $or: [{isDeleted: null}, {isDeleted: false}]});
+    let stdRationIndex = {};
+    for(let stdRation of stdRations){
+        stdRationIndex[stdRation.ID] = stdRation;
+    }
+    //判断定额完整性
+    if(!rationAllExist(rationItems, stdRationIndex)){
+        //建定额链, 排序后再清除不存在的定额,保证顺序正确性
+        rationItems = chainToArr(rationItems);
+        //清除已被删除的定额
+        let removeIds = [];
+        _.remove(rationItems, function (item) {
+            if(!stdRationIndex[item.rationID]){
+                removeIds.push(item.ID);
+                return true;
+            }
+            return false;
+        });
+        _.remove(items, function (item) {
+           return removeIds.includes(item.ID);
+        });
+        await billsGuideItemsModel.remove({ID: {$in: removeIds}});
+        //重组树结构
+        let bulkArr = [];
+        for(let i = 0, len = rationItems.length; i < len; i++){
+            rationItems[i].NextSiblingID = rationItems[i + 1] ? rationItems[i + 1].ID : -1;
+            bulkArr.push({updateOne: {filter: {ID: rationItems[i].ID}, update: {$set: {NextSiblingID: rationItems[i].NextSiblingID}}}});
+        }
+        await billsGuideItemsModel.bulkWrite(bulkArr);
+    }
+    return items;
+}
+
+async function updateItems(updateDatas) {
+    let bulkArr = [];
+    for(let updateData of updateDatas){
+        if(updateData.updateType === 'create'){
+            bulkArr.push({insertOne: {document: updateData.updateData}});
+        }
+        else{
+            bulkArr.push({updateOne: {filter: updateData.findData, update: {$set: updateData.updateData}}});
+        }
+    }
+    if(bulkArr.length > 0){
+        await billsGuideItemsModel.bulkWrite(bulkArr);
+    }
+}

+ 29 - 0
modules/std_billsGuidance_lib/routes/routes.js

@@ -0,0 +1,29 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2018/5/29
+ * @version
+ */
+import express from 'express';
+import BillsGuideLibController from '../controllers/libController';
+import ViewsController from '../controllers/viewController';
+const router = express.Router();
+const billsGuideLibController = new BillsGuideLibController();
+const viewsController = new ViewsController();
+
+module.exports = function (app) {
+  app.get('/billsGuidance/main', viewsController.auth, viewsController.init, viewsController.redirectMain);
+  app.get('/billsGuidance/guidance', viewsController.auth, viewsController.init, viewsController.redirectGuidance);
+  router.post('/getComBillsLibInfo', billsGuideLibController.auth, billsGuideLibController.init, billsGuideLibController.getComBillsLibInfo);
+  router.post('/getBillsGuideLibs', billsGuideLibController.auth, billsGuideLibController.init, billsGuideLibController.getBillsGuideLibs);
+  router.post('/updateBillsGuideLib', billsGuideLibController.auth, billsGuideLibController.init, billsGuideLibController.updateBillsGuideLib);
+  router.post('/getLibWithBills', billsGuideLibController.auth, billsGuideLibController.init, billsGuideLibController.getLibWithBills);
+  router.post('/getItemsByBills', billsGuideLibController.auth, billsGuideLibController.init, billsGuideLibController.getItemsByBills);
+  router.post('/updateItems', billsGuideLibController.auth, billsGuideLibController.init, billsGuideLibController.updateItems);
+
+
+  app.use('/billsGuidance/api', router);
+};

+ 41 - 0
public/web/tree_sheet/tree_sheet_controller.js

@@ -60,6 +60,47 @@ var TREE_SHEET_CONTROLLER = {
                     });
                 }
             }
+            return newNode;
+        };
+        controller.prototype.insertByIDS = function (ID, ParentID, NexSiblingID) {
+            var newNode = null, that = this,  sels = this.sheet.getSelections();
+            if (this.tree) {
+                if (this.tree.selected) {
+                    newNode = this.tree.insertByID(ID, ParentID, NexSiblingID);
+                } else {
+                    newNode = this.tree.insertByID(ID);
+                }
+                if (newNode) {
+                    TREE_SHEET_HELPER.massOperationSheet(this.sheet, function () {
+                        that.sheet.addRows(newNode.serialNo(), 1);
+                        TREE_SHEET_HELPER.refreshTreeNodeData(that.setting, that.sheet, [newNode], false);
+                        that.setTreeSelected(newNode);
+                        that.sheet.setSelection(newNode.serialNo(), sels[0].col, 1, 1);
+                        //that.sheet.showRow(newNode.serialNo(), GC.Spread.Sheets.VerticalPosition.center);
+                    });
+                }
+            }
+            return newNode;
+        };
+        controller.prototype.insertToChild = function (ID, ParentID, NextSiblingID) {
+            var newNode = null, that = this,  sels = this.sheet.getSelections();
+            if (this.tree) {
+                if (this.tree.selected) {
+                    newNode = this.tree.insertByID(ID, ParentID, NextSiblingID);
+                } else {
+                    newNode = this.tree.insertByID(ID);
+                }
+                if (newNode) {
+                    TREE_SHEET_HELPER.massOperationSheet(this.sheet, function () {
+                        that.sheet.addRows(newNode.serialNo(), 1);
+                        TREE_SHEET_HELPER.refreshTreeNodeData(that.setting, that.sheet, [newNode], false);
+                        that.setTreeSelected(newNode);
+                        that.sheet.setSelection(newNode.serialNo(), sels[0].col, 1, 1);
+                        //that.sheet.showRow(newNode.serialNo(), GC.Spread.Sheets.VerticalPosition.center);
+                    });
+                }
+            }
+            return newNode;
         };
         controller.prototype.delete = function () {
             var that = this, sels = this.sheet.getSelections();

+ 147 - 0
web/maintain/billsGuidance_lib/html/main.html

@@ -0,0 +1,147 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+    <meta http-equiv="x-ua-compatible" content="ie=edge">
+    <title>清单指引编辑器</title>
+    <link rel="stylesheet" href="/lib/bootstrap/css/bootstrap.min.css">
+    <link rel="stylesheet" href="/web/maintain/billsGuidance_lib/css/main.css">
+    <link rel="stylesheet" href="/lib/font-awesome/font-awesome.min.css">
+</head>
+
+<body>
+    <div class="header">
+        <nav class="navbar navbar-toggleable-lg navbar-light bg-faded p-0 ">
+            <span class="header-logo px-2">清单指引编辑器</span>
+            <div class="navbar-text"></div>
+        </nav>
+        <nav class="navbar navbar-toggleable-lg justify-content-between navbar-light p-0">
+          <ul class="nav navbar-nav px-1">
+              <li class="nav-item">
+                  <a class="nav-link" href="javacript:void(0);" aria-haspopup="true" aria-expanded="false" data-toggle="modal" data-target="#add">新建清单指引库</a>
+              </li>
+          </ul>
+        </nav>
+    </div>
+    <div class="main">
+        <div class="content">
+            <div class="container-fluid">
+                <div class="row">
+                  <div class="col-md-8">
+                    <div class="warp-p2 mt-3">
+                      <table class="table table-hover table-bordered">
+                        <thead><tr><th>清单指引名称</th><th>编办</th><th>清单规则</th><th width="160">添加时间</th><th width="90">操作</th></tr></thead>
+                        <tbody>
+                        </tbody>
+                      </table>
+                    </div>
+                  </div>
+                </div>
+            </div>
+        </div>
+    </div>
+    <!--弹出添加-->
+    <div class="modal fade" id="add" 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">
+                      <label>清单指引名称</label>
+                      <input id="createName" class="form-control" placeholder="输入清单指引名称" type="text">
+                    </div>
+                    <div class="form-group">
+                      <label>编办</label>
+                      <select id="comSels" class="form-control"><option>重庆2018</option></select>
+                    </div>
+                    <div class="form-group">
+                      <label>清单规则</label>
+                      <select id="billsLibSels" class="form-control"><option>重庆清单规则-2013</option></select>
+                    </div>
+                  </form>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                    <a href="javascript:void(0);" id="addY" class="btn btn-primary">新建</a>
+                </div>
+            </div>
+        </div>
+    </div>
+    <!--弹出编辑-->
+    <div class="modal fade" id="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">
+                  <form>
+                    <div class="form-group">
+                      <label>清单指引名称</label>
+                      <input id="edName" class="form-control" placeholder="输入清单指引名称" type="text" value="XXX清单指引">
+                    </div>
+                    <div class="form-group">
+                      <label>编办</label>
+                      <select id="edComSels" class="form-control" disabled><option>重庆2018</option></select>
+                    </div>
+                    <div class="form-group">
+                      <label>清单规则</label>
+                      <select id="edBillsLibSels" class="form-control" disabled><option>重庆清单规则-2013</option></select>
+                    </div>
+                  </form>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                    <a href="javascript:void(0);" id="editY" class="btn btn-primary">确定</a>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <!--弹出删除-->
+    <div class="modal fade" id="del" 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">
+                    <h5 class="text-danger">删除后无法恢复,确认是否删除?</h5>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                    <a id="delY" href="javascript:void(0);" class="btn btn-danger" data-dismiss="modal">删除</a>
+                </div>
+            </div>
+        </div>
+    </div>
+    <!-- JS. -->
+    <script src="/lib/jquery/jquery.min.js"></script>
+    <script src="/lib/tether/tether.min.js"></script>
+    <script src="/lib/bootstrap/bootstrap.min.js"></script>
+    <script src="/lib/lodash/lodash.js"></script>
+    <script src="/public/web/PerfectLoad.js"></script>
+    <script src="/web/maintain/billsGuidance_lib/js/global.js"></script>
+    <script src="/public/web/uuid.js"></script>
+    <script src="/public/web/common_ajax.js"></script>
+    <script src="/web/maintain/billsGuidance_lib/js/main.js"></script>
+
+</body>
+<script type="text/javascript">
+    autoFlashHeight();
+</script>
+
+</html>

Разлика између датотеке није приказан због своје велике величине
+ 89 - 0
web/maintain/billsGuidance_lib/html/zhiyin.html


+ 773 - 0
web/maintain/billsGuidance_lib/js/billsGuidance.js

@@ -0,0 +1,773 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2018/6/1
+ * @version
+ */
+
+const billsGuidance = (function () {
+    //自执行函数全局变量定义
+    const libID = getQueryString('libID');
+    const bills = {
+        dom: $('#billsSpread'),
+        workBook: null,
+        cache: [],
+        tree: null,
+        controller: null,
+        treeSetting: {
+            treeCol: 0,
+            emptyRows: 0,
+            headRows: 1,
+            headRowHeight: [40],
+            defaultRowHeight: 21,
+            cols: [{
+                width: 200,
+                readOnly: true,
+                head: {
+                    titleNames: ["项目编码"],
+                    spanCols: [1],
+                    spanRows: [1],
+                    vAlign: [1],
+                    hAlign: [1],
+                    font: ["Arial"]
+                },
+                data: {
+                    field: "code",
+                    vAlign: 1,
+                    hAlign: 0,
+                    font: "Arial"
+                }
+            }, {
+                width: 200,
+                readOnly: true,
+                head: {
+                    titleNames: ["项目名称"],
+                    spanCols: [1],
+                    spanRows: [1],
+                    vAlign: [1],
+                    hAlign: [1],
+                    font: ["Arial"]
+                },
+                data: {
+                    field: "name",
+                    vAlign: 1,
+                    hAlign: 0,
+                    font: "Arial"
+                }
+            }]
+        },
+        headers: [
+            {name: '项目编码', dataCode: 'code', width: 200, vAlign: 'center', hAlign: 'left', formatter: '@'},
+            {name: '项目名称', dataCode: 'name', width: 200, vAlign: 'center', hAlign: 'left', formatter: '@'}
+        ],
+        events: {
+            SelectionChanged: function (sender, info) {
+                billsInitSel(info.newSelections[0].row);
+            }
+        }
+    };
+    //项目指引类型
+    const itemType = {
+        job: 0,
+        ration: 1
+    };
+    const updateType = {
+        create: 'create',
+        update: 'update'
+    };
+    const guideItem = {
+        dom: $('#guideItemSpread'),
+        workBook: null,
+        tree: null,
+        controller: null,
+        treeSetting: {
+            treeCol: 0,
+            emptyRows: 0,
+            headRows: 1,
+            headRowHeight: [40],
+            defaultRowHeight: 21,
+            cols: [{
+                width: 400,
+                readOnly: false,
+                head: {
+                    titleNames: ["项目指引"],
+                    spanCols: [1],
+                    spanRows: [1],
+                    vAlign: [1],
+                    hAlign: [1],
+                    font: ["Arial"]
+                },
+                data: {
+                    field: "name",
+                    vAlign: 1,
+                    hAlign: 0,
+                    font: "Arial"
+                }
+            }]
+        },
+        headers: [
+            {name: '项目指引', dataCode: 'name', width: 400, vAlign: 'center', hAlign: 'left', formatter: '@'},
+        ],
+        events: {
+            SelectionChanged: function (sender, info) {
+                guideItemInitSel(info.newSelections[0].row)
+            },
+            EditEnded: function (sender, args) {
+                edit(args.sheet, [{row: args.row, col: args.col}]);
+            },
+            RangeChanged: function (sender, args) {
+                edit(args.sheet, args.changedCells);
+            }
+        }
+    };
+    const ration = {
+        dom: $('#rationSpread'),
+        workBook: null,
+        cache: [],
+        headers: [
+            {name: '选择', dataCode: 'select', width: 50, vAlign: 'center', hAlign: 'center'},
+            {name: '编码', dataCode: 'code', width: 110, vAlign: 'center', hAlign: 'left', formatter: '@'},
+            {name: '名称', dataCode: 'name', width: 250, vAlign: 'center', hAlign: 'left', formatter: '@'},
+            {name: '单位', dataCode: 'unit', width: 100, vAlign: 'center', hAlign: 'left', formatter: '@'}
+        ],
+        events: {
+            ButtonClicked: function (sender, args) {
+                if(args.sheet.isEditing()){
+                    args.sheet.endEdit(true);
+                }
+            },
+            CellDoubleClick: function (sender, args) {
+                if(ration.headers[args.col].dataCode === 'name'){
+                    let insertDatas = getInsertRations([args.row]);
+                    if(insertDatas.length > 0){
+                        insert(insertDatas);
+                    }
+                }
+            }
+        }
+    };
+    const options = {
+        workBook: {
+            tabStripVisible:  false,
+            allowContextMenu: false,
+            allowCopyPasteExcelStyle : false,
+            allowExtendPasteRange: false,
+            allowUserDragDrop : false,
+            allowUserDragFill: false,
+            scrollbarMaxAlign : true
+        },
+        sheet: {
+            protectionOptions: {allowResizeRows: true, allowResizeColumns: true},
+            clipBoardOptions: GC.Spread.Sheets.ClipboardPasteOptions.values
+        }
+    };
+
+    //渲染时方法,停止渲染
+    //@param {Object}sheet {Function}func @return {void}
+    function renderSheetFunc(sheet, func){
+        sheet.suspendEvent();
+        sheet.suspendPaint();
+        if(func){
+            func();
+        }
+        sheet.resumeEvent();
+        sheet.resumePaint();
+    }
+    //设置表选项
+    //@param {Object}workBook {Object}opts @return {void}
+    function setOptions (workBook, opts) {
+        for(let opt in opts.workBook){
+            workBook.options[opt] = opts.workBook[opt];
+        }
+        for(let opt in opts.sheet){
+            workBook.getActiveSheet().options[opt] = opts.sheet[opt];
+        }
+    }
+    //建表头
+    //@param {Object}sheet {Array}headers @return {void}
+    function buildHeader(sheet, headers) {
+        let fuc = function () {
+            sheet.setColumnCount(headers.length);
+            sheet.setRowHeight(0, 40, GC.Spread.Sheets.SheetArea.colHeader);
+            for(let i = 0, len = headers.length; i < len; i++){
+                sheet.setValue(0, i, headers[i].name, GC.Spread.Sheets.SheetArea.colHeader);
+                sheet.setColumnWidth(i, headers[i].width, GC.Spread.Sheets.SheetArea.colHeader);
+                if(headers[i].formatter){
+                    sheet.setFormatter(-1, i, headers[i].formatter);
+                }
+                sheet.getRange(-1, i, -1, 1).hAlign(GC.Spread.Sheets.HorizontalAlign[headers[i]['hAlign']]);
+                sheet.getRange(-1, i, -1, 1).vAlign(GC.Spread.Sheets.VerticalAlign[headers[i]['vAlign']]);
+            }
+        };
+        renderSheetFunc(sheet, fuc);
+    }
+    //表监听事件
+    //@param {Object}workBook @return {void}
+    function bindEvent(workBook, events) {
+        if(Object.keys(events).length === 0){
+            return;
+        }
+        const Events = GC.Spread.Sheets.Events;
+        let sheet = workBook.getActiveSheet();
+        for(let event in events){
+            workBook.bind(Events[event], events[event]);
+        }
+    }
+    //建表
+    //@param {Object}module @return {void}
+    function buildSheet(module) {
+        if(!module.workBook){
+            module.workBook = new GC.Spread.Sheets.Workbook(module.dom[0], {sheetCount: 1});
+            let sheet = module.workBook.getActiveSheet();
+            if(module === bills){
+                //默认初始可控制焦点在清单表中
+                module.workBook.focus();
+                sheet.options.isProtected = true;
+            }
+            if(module === ration){
+                sheet.options.isProtected = true;
+                sheet.getRange(-1, 0, -1, 1).locked(false);
+                sheet.getRange(-1, 1, -1, -1).locked(true);
+            }
+            setOptions(module.workBook, options);
+            buildHeader(module.workBook.getActiveSheet(), module.headers);
+            bindEvent(module.workBook, module.events);
+        }
+    }
+    //清空表数据
+    //@param {Object}sheet {Array}headers {Number}rowCount @return {void}
+    function cleanData(sheet, headers, rowCount){
+        renderSheetFunc(sheet, function () {
+            sheet.clear(-1, 0, -1, headers.length, GC.Spread.Sheets.SheetArea.viewport, GC.Spread.Sheets.StorageType.data);
+            if (rowCount > 0) {
+                sheet.setRowCount(rowCount);
+            }
+        });
+    }
+    //根据清单获取项目指引
+    //@param {String}guidanceLibID {Number}billsID {Function}callback @return {void}
+    function getItemsByBills(guidanceLibID, billsID, callback){
+        CommonAjax.post('/billsGuidance/api/getItemsByBills', {guidanceLibID: guidanceLibID, billsID: billsID}, function (rstData) {
+            if(callback){
+                callback(rstData);
+            }
+        });
+    }
+    //清单表焦点控制
+    //@param {Number}row @return {void}
+    function billsInitSel(row){
+        let guideSheet = guideItem.workBook.getActiveSheet();
+        cleanData(guideSheet, guideItem.headers, -1);
+        let node = bills.tree.items[row];
+        if(!node){
+            return;
+        }
+        bills.tree.selected = node;
+        if(!node.guidance.tree){
+            getItemsByBills(libID, node.data.ID, function (rstData) {
+                initTree(node.guidance, guideSheet, guideItem.treeSetting, rstData);
+                //项目指引初始焦点
+                guideItemInitSel(guideSheet.getActiveRowIndex() ? guideSheet.getActiveRowIndex() : 0);
+            });
+        }
+        else{
+            node.guidance.controller.showTreeData();
+            //项目指引初始焦点
+            guideItemInitSel(guideSheet.getActiveRowIndex() ? guideSheet.getActiveRowIndex() : 0);
+        }
+    }
+    //节点子项是否全是工作内容
+    //@param {Object}node @return {Boolean}
+    function allJobChildren(node){
+        for(let c of node.children){
+            if(c.data.type === itemType.ration){
+                return false;
+            }
+        }
+        return true;
+    }
+    //节点子项是否全是定额
+    //@param {Object}node @return {Boolean}
+    function allRationChildren(node){
+        for(let c of node.children){
+            if(c.data.type === itemType.job){
+                return false;
+            }
+        }
+        return true;
+    }
+    //刷新按钮有效性
+    //@param {Object}node @return {void}
+    function refreshBtn(node){
+        //全部设为无效
+        $('.tools-btn').children().addClass('disabled');
+        $('#insertRation').addClass('disabled');
+        //插入
+        if(bills.tree.selected && bills.tree.selected.guidance.tree){
+            $('#insert').removeClass('disabled');
+            if(node && node.data.type === itemType.ration){
+                $('#insert').addClass('disabled');
+            }
+        }
+        //删除
+        if(node){
+            $('#del').removeClass('disabled');
+        }
+        if(node && node.data.type === itemType.job){
+            //升级
+            if(node.parent){
+                $('#upLevel').removeClass('disabled');
+                if(node.nextSibling && node.children.length > 0 && !allJobChildren(node)){
+                    $('#upLevel').addClass('disabled');
+                }
+            }
+            //降级
+            if(node.preSibling){
+                $('#downLevel').removeClass('disabled');
+                if(node.preSibling.children.length > 0 && !allJobChildren(node.preSibling)){
+                    $('#downLevel').addClass('disabled');
+                }
+            }
+        }
+        //上移
+        if(node && node.preSibling){
+            $('#upMove').removeClass('disabled')
+        }
+        //下移
+        if(node && node.nextSibling){
+            $('#downMove').removeClass('disabled');
+        }
+        //插入定额
+        if(node && (node.children.length === 0 || allRationChildren(node))){
+            $('#insertRation').removeClass('disabled');
+        }
+    }
+    //项目指引表焦点控制
+    //@param {Number}row @return {void}
+    function guideItemInitSel(row){
+        let billsNode = bills.tree.selected;
+        let node = null;
+        if(billsNode && billsNode.guidance.tree){
+            node = billsNode.guidance.tree.items[row];
+            if(node){
+                billsNode.guidance.tree.selected = node;
+            }
+        }
+        refreshBtn(node);
+    }
+    //初始化当前库名
+    //@param {String} @return {void}
+    function initLibName(libName) {
+        $('#libName')[0].outerHTML = $('#libName')[0].outerHTML.replace("XXX清单指引", libName);
+    }
+    //初始化各工作表
+    //@param {Array}modules @return {void}
+    function initWorkBooks(modules){
+        for(let module of modules){
+            buildSheet(module);
+        }
+    }
+    //输出表数据(定额表)
+    //@param {Object}sheet {Array}headers {Array}datas @return {void}
+    function showData(sheet, headers, datas){
+        let fuc = function () {
+            sheet.setRowCount(datas.length);
+            //复选框
+            let checkBoxType = new GC.Spread.Sheets.CellTypes.CheckBox();
+            sheet.setCellType(-1, 0, checkBoxType);
+            for(let col = 0, cLen = headers.length; col < cLen; col++){
+                for(let row = 0, rLen = datas.length; row < rLen; row++){
+                    sheet.setValue(row, col, datas[row][headers[col]['dataCode']]);
+                }
+            }
+        };
+        renderSheetFunc(sheet, fuc);
+    }
+    //初始化定额条目
+    //@param {Number}rationLibId @return {void}
+    function initRationItems(rationLibId){
+        $.bootstrapLoading.start();
+        CommonAjax.post('/rationRepository/api/getRationItemsByLib', {rationLibId: rationLibId}, function (rstData) {
+            rstData.sort(function (a, b) {
+                let rst = 0;
+                if(a.code > b.code){
+                    rst = 1;
+                }
+                else if(a.code < b.code){
+                    rst = -1;
+                }
+                return rst;
+            });
+            ration.cache = rstData;
+            showData(ration.workBook.getActiveSheet(), ration.headers, rstData);
+            $.bootstrapLoading.end();
+        });
+    }
+    //初始化定额库选择
+    //@param {String}compilationId @return {void}
+    function initRationLibs(compilationId){
+        CommonAjax.post('/rationRepository/api/getRationLibsByCompilation', {compilationId: compilationId}, function (rstData) {
+            $('#rationLibSel').empty();
+            for(let rationLib of rstData){
+                let opt = `<option value="${rationLib.ID}">${rationLib.dispName}</option>`;
+                $('#rationLibSel').append(opt);
+            }
+            //初始选择
+            initRationItems(parseInt($('#rationLibSel').select().val()));
+            $('#rationLibSel').change(function () {
+                let rationLibId = parseInt($(this).select().val());
+                initRationItems(rationLibId);
+            })
+        });
+    }
+    //获取指引库信息及关联的清单
+    //@param {Number}libID {Function}callback @return {Object}
+    function getLibWithBills(libID, callback){
+        CommonAjax.post('/billsGuidance/api/getLibWithBills', {libID: libID}, function (rstData) {
+            initRationLibs(rstData.guidanceLib.compilationId);
+            bills.cache = rstData.bills;
+            initLibName(rstData.guidanceLib.name);
+            initTree(bills, bills.workBook.getActiveSheet(), bills.treeSetting, bills.cache);
+            //每一棵项目指引树挂在清单节点上
+            for(let node of bills.tree.items){
+                node.guidance = {tree: null, controller: null};
+            }
+            //默认初始节点
+            billsInitSel(0);
+            if(callback){
+                callback(rstData);
+            }
+        }, function (msg) {
+            window.location.href = '/billsGuidance/main';
+        });
+    }
+    //初始化并输出树
+    //@param {Object}module {Object}sheet {Object}treeSetting {Array}datas
+    function initTree(module, sheet, treeSetting, datas){
+        module.tree = idTree.createNew({id: 'ID', pid: 'ParentID', nid: 'NextSiblingID', rootId: -1, autoUpdate: true});
+        module.controller = TREE_SHEET_CONTROLLER.createNew(module.tree, sheet, treeSetting);
+        module.tree.loadDatas(datas);
+        module.controller.showTreeData();
+    }
+    //更新项目指引
+    //@param {Array}updateDatas {Function}callback @return {void}
+    function updateGuideItems(updateDatas, callback){
+        CommonAjax.post('/billsGuidance/api/updateItems', {updateDatas: updateDatas}, function (rstData) {
+            if(callback){
+                callback(rstData);
+            }
+        });
+    }
+    //项目指引编辑
+    //@param {Object}sheet {Array}cells
+    function edit(sheet, cells){
+        let updateDatas = [];
+        //同步节点数据
+        let syncDatas = [];
+        for(let cell of cells){
+            let text = sheet.getValue(cell.row, cell.col);
+            text = text ? text : '';
+            let node = bills.tree.selected.guidance.tree.items[cell.row];
+            if(node.data.name != text){
+                syncDatas.push({node: node, text: text});
+                updateDatas.push({updateType: updateType.update, findData: {ID: node.getID()}, updateData: {name: text}});
+            }
+        }
+        if(updateDatas.length > 0){
+            updateGuideItems(updateDatas, function () {
+                for(let syncData of syncDatas){
+                    syncData.node.data.name = syncData.text;
+                }
+            }, function () {
+                //失败恢复
+                renderSheetFunc(sheet, function () {
+                    for(let syncData of syncDatas){
+                        sheet.setValue(syncData.node.serialNo(), 0, syncData.node.data.name ? syncData.node.data.name : '');
+                    }
+                });
+            });
+        }
+    }
+    //项目指引插入,支持一次插入多条数据
+    //@param {Array}datas {Function}callback @return {void}
+    function insert(datas, callback = null){
+        $.bootstrapLoading.start();
+        let sheet = guideItem.workBook.getActiveSheet();
+        let controller = bills.tree.selected.guidance.controller;
+        let selected = bills.tree.selected.guidance.tree.selected;
+        let updateDatas = [];
+        //建立数组下标索引
+        let newDataIndex = {};
+        for(let i = 0; i < datas.length; i++){
+            let newNodeData = {
+                libID: libID, ID: uuid.v1(), ParentID: selected ? selected.getParentID() : -1, NextSiblingID: selected ? selected.getNextSiblingID() : -1,
+                billsID: bills.tree.selected.getID()
+            };
+            //定额类型插入当前工作内容焦点行,
+            if(selected && selected.data.type === itemType.job && datas[i].type === itemType.ration){
+                newNodeData.ParentID = selected.getID();
+                newNodeData.NextSiblingID = -1;
+            }
+            Object.assign(newNodeData, datas[i]);
+            newDataIndex[i] = newNodeData;
+        }
+        for(let i = 0; i < datas.length; i++){
+            //第一个节点
+            if(i === 0){
+                //非插入成子节点,更新选中节点NestSiblingID
+                if(selected && !(selected.data.type === itemType.job && datas[i].type === itemType.ration)){
+                    updateDatas.push({updateType: updateType.update, findData: {ID: selected.getID()}, updateData: {NextSiblingID: newDataIndex[i].ID}});
+                }
+            }
+            //非最后一个节点
+            if(i !== datas.length - 1){
+                newDataIndex[i].NextSiblingID = newDataIndex[i + 1].ID;
+            }
+            updateDatas.push({updateType: updateType.create, updateData: newDataIndex[i]});
+        }
+        updateGuideItems(updateDatas, function () {
+            for(let updateData of updateDatas){
+                if(updateData.updateType === updateType.create){
+                    let newNode = controller.insertByIDS(updateData.updateData.ID, updateData.updateData.ParentID, updateData.updateData.NextSiblingID);
+                    //同步data
+                    Object.assign(newNode.data, updateData.updateData);
+                    sheet.setValue(newNode.serialNo(), 0, newNode.data.name);
+                    refreshBtn(newNode);
+                }
+            }
+            if(callback){
+                callback();
+            }
+            $.bootstrapLoading.end();
+        });
+    }
+    //项目指引删除操作
+    //@return {void}
+    function del(){
+        $.bootstrapLoading.start();
+        let controller = bills.tree.selected.guidance.controller;
+        let selected = bills.tree.selected.guidance.tree.selected;
+        let updateDatas = [];
+        function getDelDatas(node){
+            updateDatas.push({updateType: updateType.update, findData: {ID: node.getID()}, updateData: {deleted: true}});
+            if(node.children.length > 0){
+                for(let c of node.children){
+                    getDelDatas(c);
+                }
+            }
+        }
+        getDelDatas(selected);
+        updateGuideItems(updateDatas, function () {
+            controller.delete();
+            refreshBtn(bills.tree.selected.guidance.tree.selected);
+            $.bootstrapLoading.end();
+        });
+    }
+    //项目指引升级
+    //@return {void}
+    function upLevel(){
+        $.bootstrapLoading.start();
+        let controller = bills.tree.selected.guidance.controller;
+        let selected = bills.tree.selected.guidance.tree.selected;
+        let updateDatas = [];
+        //更新父节点
+        updateDatas.push({updateType: updateType.update, findData: {ID: selected.getParentID()}, updateData: {NextSiblingID: selected.getID()}});
+        //更新选中节点
+        updateDatas.push({udpateType: updateType.update, findData: {ID: selected.getID()},
+            updateData: {ParentID: selected.parent.getParentID(), NextSiblingID: selected.parent.getNextSiblingID()}});
+        if(selected.nextSibling && selected.children.length > 0){
+            //更新选中节点最末子节点
+            let lastChild = selected.children[selected.children.length - 1];
+            updateDatas.push({updateType: updateType.update, findData: {ID: lastChild.getID()}, updateData: {NextSiblingID: selected.getNextSiblingID()}});
+        }
+        updateGuideItems(updateDatas, function () {
+            controller.upLevel();
+            refreshBtn(bills.tree.selected.guidance.tree.selected);
+            $.bootstrapLoading.end();
+        });
+    }
+    //项目指引降级
+    //@return {void}
+    function downLevel(){
+        $.bootstrapLoading.start();
+        let controller = bills.tree.selected.guidance.controller;
+        let selected = bills.tree.selected.guidance.tree.selected;
+        let updateDatas = [];
+        //更新前兄弟节点
+        updateDatas.push({updateType: updateType.update, findData: {ID: selected.preSibling.getID()}, updateData: {NextSiblingID: selected.getNextSiblingID()}});
+        //更新前兄弟节点最末子节点
+        if(selected.preSibling.children.length > 0){
+            let lastChild = selected.preSibling.children[selected.preSibling.children.length - 1];
+            updateDatas.push({updateType: updateType.update, findData: {ID: lastChild.getID()}, updateData: {NextSiblingID: selected.getID()}});
+        }
+        //更新选中节点
+        updateDatas.push({updateType: updateType.update, findData: {ID: selected.getID()}, updateData: {ParentID: selected.preSibling.getID(), NextSiblingID: -1}});
+        updateGuideItems(updateDatas, function () {
+            controller.downLevel();
+            refreshBtn(bills.tree.selected.guidance.tree.selected);
+            $.bootstrapLoading.end();
+        });
+    }
+    //项目指引上移
+    //@return {void}
+    function upMove(){
+        $.bootstrapLoading.start();
+        let controller = bills.tree.selected.guidance.controller;
+        let selected = bills.tree.selected.guidance.tree.selected;
+        let updateDatas = [];
+        //更新前节点
+        updateDatas.push({updateType: updateType.update, findData: {ID: selected.preSibling.getID()}, updateData: {NextSiblingID: selected.getNextSiblingID()}});
+        //更新前前节点
+        if(selected.preSibling.preSibling){
+            updateDatas.push({udpateType: updateType.update, findData: {ID: selected.preSibling.preSibling.getID()}, updateData: {NextSiblingID: selected.getID()}});
+        }
+        //更新选中节点
+        updateDatas.push({updateType: updateType.update, findData: {ID: selected.getID()}, updateData: {NextSiblingID: selected.preSibling.getID()}});
+        updateGuideItems(updateDatas, function () {
+            controller.upMove();
+            refreshBtn(bills.tree.selected.guidance.tree.selected);
+            $.bootstrapLoading.end();
+        });
+    }
+    //项目指引下移
+    //@return {void}
+    function downMove(){
+        $.bootstrapLoading.start();
+        let controller = bills.tree.selected.guidance.controller;
+        let selected = bills.tree.selected.guidance.tree.selected;
+        let updateDatas = [];
+        //更新下节点
+        updateDatas.push({updateType: updateType.update, findData: {ID: selected.getNextSiblingID()}, updateData: {NextSiblingID: selected.getID()}});
+        //更新前节点
+        if(selected.preSibling){
+            updateDatas.push({updateType: updateType.update, findData: {ID: selected.preSibling.getID()}, updateData: {NextSiblingID: selected.getNextSiblingID()}});
+        }
+        //更新选中节点
+        updateDatas.push({updateType: updateType.update, findData: {ID: selected.getID()}, updateData: {NextSiblingID: selected.nextSibling.getNextSiblingID()}});
+        updateGuideItems(updateDatas, function () {
+            controller.downMove();
+            refreshBtn(bills.tree.selected.guidance.tree.selected);
+            $.bootstrapLoading.end();
+        });
+    }
+    //获取定额类型的项目指引名称,通过定额转换
+    //@param {Object}ration @return {String}
+    function getRationItemName(ration){
+        let arr = [];
+        arr.push(ration.code ? ration.code : '');
+        arr.push(ration.name ? ration.name : '');
+        arr.push(ration.basePrice ? ration.basePrice : '');
+        let rst = arr.join(' ');
+        rst += `/${ration.unit ? ration.unit : ''}`;
+        return rst;
+    }
+    //获取选中的定额表行
+    //@return {Array}
+    function getCheckedRationRows(){
+        let rst = [];
+        let sheet = ration.workBook.getActiveSheet();
+        for(let i = 0; i < sheet.getRowCount(); i++){
+            let checked = sheet.getValue(i, 0);
+            if(checked){
+                rst.push(i);
+            }
+        }
+        return rst;
+    }
+    //清空选中定额表行
+    //@param {Array}rows @return {void}
+    function clearCheckedRation(rows) {
+        let sheet = ration.workBook.getActiveSheet();
+        renderSheetFunc(sheet, function () {
+            for(let row of rows){
+                sheet.setValue(row, 0, 0);
+            }
+        });
+    }
+    //获取要插入的定额数据
+    //@param {Array}rows @return {Array}
+    function getInsertRations(rows){
+        let rst = [];
+        //当前已存在定额
+        let curRationIems = [];
+        let selected = bills.tree.selected.guidance.tree.selected;
+        if(selected){
+            if(selected.data.type === itemType.job){
+                curRationIems = selected.children;
+            }
+            else {
+                curRationIems = selected.parent ? selected.parent.children : selected.tree.roots;
+            }
+        }
+        for(let row of rows){
+            let selRation = ration.cache[row];
+            if(selRation){
+                //添加的定额是否已存在,不重复添加
+                let isExist = false;
+                for(let curRation of curRationIems){
+                    if(curRation.data.rationID == selRation.ID){
+                        isExist = true;
+                        break;
+                    }
+                }
+                if(!isExist){
+                    rst.push({type: itemType.ration, name: getRationItemName(selRation), rationID: selRation.ID});
+                }
+            }
+        }
+        return rst;
+    }
+    //初始化个按钮点击
+    //@return {void}
+    function initBtn(){
+        $('#insert').click(function () {
+            insert([{type: itemType.job, name: ''}]);
+        });
+        $('#del').click(function () {
+            del();
+        });
+        $('#upLevel').click(function () {
+            upLevel();
+        });
+        $('#downLevel').click(function () {
+            downLevel();
+        });
+        $('#upMove').click(function () {
+            upMove();
+        });
+        $('#downMove').click(function () {
+            downMove();
+        });
+        $('#insertRation').click(function () {
+            let checkedRows = getCheckedRationRows();
+            let insertDatas = getInsertRations(checkedRows);
+            if(insertDatas.length > 0){
+                insert(insertDatas, function () {
+                    //清空选择
+                    clearCheckedRation(checkedRows);
+                });
+            }
+            else {
+                clearCheckedRation(checkedRows);
+            }
+        });
+    }
+    //初始化视图
+    //@param {void} @return {void}
+    function initViews(){
+        let modules = [bills, guideItem, ration];
+        initWorkBooks(modules);
+        getLibWithBills(libID);
+        initBtn();
+    }
+
+
+    return {initViews};
+})();
+
+$(document).ready(function () {
+    billsGuidance.initViews();
+});

+ 46 - 0
web/maintain/billsGuidance_lib/js/global.js

@@ -0,0 +1,46 @@
+/*全局自适应高度*/
+function autoFlashHeight(){
+    var headerHeight = $(".header").height();
+    var bottomContentHeight = $(".bottom-content").height();
+    var toolsBar = $(".toolsbar").height();
+    var toolsBarHeightQ = $(".tools-bar-height-q").height();
+    $(".content").height($(window).height()-headerHeight);
+    $(".main-side").height($(window).height()-headerHeight-2);
+    $(".fluid-content").height($(window).height()-headerHeight-1);
+    $(".side-content").height($(window).height()-headerHeight );
+    $(".poj-list").height($(window).height()-headerHeight);
+    $(".form-list").height($(window).height()-headerHeight-50 );
+    $(".main-data-top").height($(window).height()-headerHeight-toolsBar-bottomContentHeight-2);
+    $(".main-data").height($(window).height()-headerHeight-toolsBar);
+    $(".main-data-full").height($(window).height()-headerHeight);
+    $(".main-data-side-q").height($(window).height()-headerHeight-toolsBarHeightQ-2);
+
+};
+$(window).resize(autoFlashHeight);
+/*全局自适应高度结束*/
+$(function(){
+/*侧滑*/
+$(".open-sidebar").click(function(){
+    $(".slide-sidebar").animate({width:"800"}).addClass("open");
+});
+$("body").click(function(event){
+        var e = event || window.event; //浏览器兼容性
+        if(!$(event.target).is('a')) {
+            var elem = event.target || e.srcElement;
+            while (elem) { //循环判断至跟节点,防止点击的是div子元素
+                if (elem.className == "open-sidebar" || elem.className == 'slide-sidebar open') {
+                    return false;
+                }
+                elem = elem.parentNode;
+            }
+            $(".slide-sidebar").animate({width:"0"}).removeClass("open")// 关闭处理
+        }
+
+    });
+/*侧滑*/
+/*工具提示*/
+$('*[data-toggle=tooltip]').mouseover(function() {
+ $(this).tooltip('show');
+  });
+/*工具提示*/
+});

+ 208 - 0
web/maintain/billsGuidance_lib/js/main.js

@@ -0,0 +1,208 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2018/5/29
+ * @version
+ */
+
+const billsGuidanceMain = (function () {
+    const updateType = {create: 'create', update: 'update', delete: 'delete'};
+    let guidanceLibs = [];
+    let curLib = null;
+
+    //获取编办及编办下清单库
+    //@return {void}
+    function getComBillsLibInfo(){
+        CommonAjax.post('/billsGuidance/api/getComBillsLibInfo', {}, function (rstData) {
+            const comSels = $('#comSels');
+            const billsLibSels = $('#billsLibSels');
+            //设置编办及清单规则库选择
+            comSels.empty();
+            function setBillsLib(libs){
+                billsLibSels.empty();
+                for(let lib of libs){
+                    let libOpt = `<option value="${lib.billsLibId}">${lib.billsLibName}</option>`;
+                    billsLibSels.append(libOpt);
+                }
+            }
+            let comIndex = {};
+            for(let i = 0; i < rstData.length; i++){
+                let compilation = rstData[i];
+                comIndex[compilation._id] = compilation;
+                let comOpt = `<option value = "${compilation._id}">${compilation.name}</option>`;
+                comSels.append(comOpt);
+                //设置初始选择的清单规则库
+                if(i === 0){
+                    setBillsLib(compilation.billsLibs);
+                }
+            }
+            //变更编办选择
+            comSels.on('change', function () {
+                let curComId = $(this).select().val();
+                let curCom = comIndex[curComId];
+                setBillsLib(curCom.billsLibs);
+            });
+        });
+    }
+    //html新增库
+    //@param {Object}tbody {Object}lib @return {void}
+    function addLibToView(tbody, lib){
+        let tr = `<tr id="${lib.ID}">
+            <td><a href="/billsGuidance/guidance/?libID=${lib.ID}">${lib.name}</a>
+            <td>${lib.compilationName}</td><td>${lib.billsLibName}</td>
+            <td>${lib.createDate.split(' ')[0]}</td>
+            <td><a href="javascript:void(0);" data-toggle="modal" data-target="#edit" title="编辑"><i class="fa fa-pencil-square-o"></i></a>
+            <a href="javascript:void(0);" data-toggle="modal" data-target="#del" class="text-danger" title="删除"><i class="fa fa-remove"></i></a></td></tr>`;
+        tbody.append(tr);
+    }
+    //获取清单指引库
+    //@return {void}
+    function getLibs(){
+        CommonAjax.post('/billsGuidance/api/getBillsGuideLibs', {}, function (rstData) {
+            guidanceLibs = rstData;
+            const tbody = $('.main').find('tbody');
+            tbody.empty();
+            for(let lib of rstData){
+                addLibToView(tbody, lib);
+            }
+        });
+    }
+    //是否已存在此库
+    //@param {Object}findSet {Array}libs @return {Object}
+    function existLib(findSet, libs) {
+        for(let lib of libs){
+            if(lib[findSet.k] === findSet.v){
+                return lib;
+            }
+        }
+        return null;
+    }
+    //监听事件
+    //@return {void}
+    function eventListener(){
+        //新建库确认按钮事件
+        $('#addY').click(function () {
+            try{
+                let cName = $('#createName').val();
+                if(!cName || cName.trim() === ''){
+                    throw '请输入名称!';
+                }
+                if(existLib({k: 'name', v: cName}, guidanceLibs)){
+                    throw '已存在此库!';
+                }
+                let compilationId = $('#comSels').select().val();
+                let compilationName = $('#comSels').select().children('option:selected').text();
+                if(!compilationId){
+                    throw '请选择编办!';
+                }
+                let billsLibId = $('#billsLibSels').select().val();
+                let billsLibName = $('#billsLibSels').select().children('option:selected').text();
+                if(!billsLibId){
+                    throw '请选择清单规则库';
+                }
+                //新建
+                $.bootstrapLoading.start();
+                let createData = {ID: uuid.v1(), name: cName, compilationId: compilationId, compilationName: compilationName, billsLibId: parseInt(billsLibId), billsLibName:billsLibName};
+                let updateData = {updateType: updateType.create, updateData: createData};
+                CommonAjax.post('/billsGuidance/api/updateBillsGuideLib', updateData, function (rstData) {
+                    guidanceLibs.push(rstData);
+                    addLibToView($('.main').find('tbody'), rstData);
+                    $('#add').modal('hide');
+                    $.bootstrapLoading.end();
+                }, function () {
+                    $.bootstrapLoading.end();
+                });
+            }
+            catch(err){
+                alert(err);
+                $('#createName').focus();
+            }
+        });
+        //新建模态框
+        $('#add').on('hidden.bs.modal', function () {
+           $('#createName').val('');
+        });
+        $('#add').on('shown.bs.modal', function () {
+            $('#createName').focus();
+        });
+        //所有编辑按钮
+        $('.main').find('tbody').on('click', '[data-target="#edit"]', function () {
+            let tr = $(this).parent().parent();
+            let selLib = existLib({k: 'ID', v: tr.attr('id')}, guidanceLibs);
+            curLib = selLib;
+            $('#edName').val(curLib.name);
+            $('#edComSels').select().children('option:selected').text(curLib.compilationName);
+            $('#edBillsLibSels').select().children('option:selected').text(curLib.billsLibName);
+        });
+        //编辑确认
+        $('#editY').click(function(){
+            try{
+                let newName = $('#edName').val();
+                if(newName.trim() === curLib.name){
+                    $('#edit').modal('hide');
+                    return;
+                }
+                if(!newName || newName.trim() === ''){
+                    throw '名称不能为空!';
+                }
+                if(existLib({k: 'name', v: newName}, guidanceLibs)){
+                    throw '该库已存在!';
+                }
+                let updateData = {updateType: updateType.update, findData: {ID: curLib.ID}, updateData: {name: newName}};
+                CommonAjax.post('/billsGuidance/api/updateBillsGuideLib', updateData, function (rstData) {
+                    curLib.name = newName;
+                    $(`#${curLib.ID} td:first a`).text(newName);
+                    $('#edit').modal('hide');
+                });
+            }
+            catch(err){
+                alert(err);
+                $('#edName').focus();
+            }
+        });
+        //编辑模态框
+        $('#edit').on('shown.bs.modal', function () {
+            $('#edName').focus();
+        });
+        //所有删除按钮
+        $('.main').find('tbody').on('click', '[data-target="#del"]', function () {
+            let tr = $(this).parent().parent();
+            curLib = existLib({k: 'ID', v: tr.attr('id')}, guidanceLibs);
+        });
+        //删除确认
+        $('#delY').click(function () {
+            try{
+                if(!curLib){
+                    throw '不存在该库!';
+                }
+                $.bootstrapLoading.start();
+                let updateData = {updateType: updateType.delete, findData: {ID: curLib.ID}, updateData: {deleted: true}};
+                CommonAjax.post('/billsGuidance/api/updateBillsGuideLib', updateData, function (rstData) {
+                    $(`#${curLib.ID}`).remove();
+                    curLib = null;
+                    _.remove(guidanceLibs, function (lib) {
+                        return lib.ID === updateData.findData.ID;
+                    });
+                    $.bootstrapLoading.end();
+                }, function () {
+                    $.bootstrapLoading.end();
+                });
+            }
+            catch(err){
+                alert(err);
+            }
+        });
+
+    }
+
+    return {getComBillsLibInfo, getLibs, eventListener};
+})();
+
+$(document).ready(function () {
+    billsGuidanceMain.getComBillsLibInfo();
+    billsGuidanceMain.getLibs();
+    billsGuidanceMain.eventListener();
+});

+ 1 - 0
web/maintain/ration_repository/js/ration.js

@@ -192,6 +192,7 @@ let rationOprObj = {
                         callback: function(){},
                         items: {
                             "delete": {name: "删除", disabled: delDis, icon: "fa-remove", callback: function (key, opt) {
+                                me.rationsCodes.splice(me.rationsCodes.indexOf(ration.code.toString()), 1);
                                 me.mixDel = 1;
                                 me.mixUpdateRequest([], [], [ration.ID]);
                             }}