Преглед изворни кода

新增项目工料机相关代码

caiaolin пре 8 година
родитељ
комит
a761276445

+ 89 - 0
modules/glj/controllers/glj_controller.js

@@ -0,0 +1,89 @@
+/**
+ * 工料机相关控制器
+ *
+ * @author CaiAoLin
+ * @date 2017/6/22
+ * @version
+ */
+import BaseController from "../../common/base/base_controller";
+import GLJListModel from "../models/glj_list_model";
+
+class GLJController extends BaseController {
+
+    /**
+     * 构造函数
+     *
+     * @return {void}
+     */
+    constructor() {
+        let parent = super();
+        parent.title = '工料机';
+    }
+
+    /**
+     * 工料机汇总页
+     *
+     * @param {object} request
+     * @param {object} response
+     * @return {void}
+     */
+    async index(request, response) {
+        let tenderId = request.query.tender;
+        tenderId = parseInt(tenderId);
+        try {
+            if (isNaN(tenderId) || tenderId <= 0) {
+                throw '标段id有误';
+            }
+            // 先获取对应标段的项目工料机数据
+            let gljListModel = new GLJListModel();
+            // 获取指定标段的单价文件  @todo 后续需要在标段属性中加入该标段绑定的标段id
+            let unitPriceTenderId = 1;
+            let gljList = await gljListModel.getListByTenderId(tenderId, unitPriceTenderId);
+
+            let renderData = {
+                gljList: JSON.stringify(gljList),
+                materialIdList: gljListModel.materialIdList
+            };
+            response.render('glj/html/glj_index', renderData);
+
+        } catch (error) {
+            response.status(404).send('404 Error');
+        }
+
+    }
+
+    /**
+     * 测试插入
+     *
+     * @param {object} request
+     * @param {object} response
+     * @return {void}
+     */
+    async test(request, response) {
+        // 从定额库获取的数据
+        let data = {
+            gli_repository_id: 1,
+            project_id: 1,
+            tender_id: 1,
+            code: '00010201',
+            name: '土石方综合工日',
+            specs: '',
+            unit: '工日',
+            type: 2,
+            type_of_work: 2
+        };
+        try {
+            let gljListModel = new GLJListModel();
+            let result = await gljListModel.addData(data);
+
+            console.log(result);
+        } catch (error) {
+            console.log(error);
+        }
+
+        response.end('success');
+    }
+
+}
+
+export default GLJController;

+ 0 - 8
modules/glj/db/unit_price_file_db.js

@@ -1,8 +0,0 @@
-/**
- * Created by jimiz on 2017/5/12.
- */
-var mongoose = require("mongoose");
-var dbm = require("../../../config/db/db_manager");
-var db = dbm.getCfgConnection("unitPriceFile");
-
-module.exports = db;

+ 0 - 8
modules/glj/db/user_glj_lib_db.js

@@ -1,8 +0,0 @@
-/**
- * Created by jimiz on 2017/5/12.
- */
-var mongoose = require("mongoose");
-var dbm = require("../../../config/db/db_manager");
-var db = dbm.getCfgConnection("userGLJLib");
-
-module.exports = db;

+ 54 - 0
modules/glj/models/counter_model.js

@@ -0,0 +1,54 @@
+/**
+ * ID计数器数据模型
+ *
+ * @author CaiAoLin
+ * @date 2017/6/23
+ * @version
+ */
+import BaseModel from "../../common/base/base_model";
+import CounterSchema from "./schemas/counter";
+
+class CounterModel extends BaseModel {
+
+
+    /**
+     * 构造函数
+     *
+     * @return {void}
+     */
+    constructor() {
+        let parent = super();
+        parent.model = CounterSchema;
+        parent.init();
+    }
+
+    /**
+     * 获取自增id
+     *
+     * @param {String} model
+     * @return {Number}
+     */
+    async getId(model = '') {
+        if (model === '') {
+            return 0;
+        }
+        let update = {$inc: {sequence_value: 1}};
+        let condition = {_id: model};
+        let options = {new: true};
+
+        // 先查找更新
+        let idData = await this.db.findAndModify(condition, update, options);
+        let idResult = idData === null || idData.sequence_value === undefined ? 0 : idData.sequence_value;
+
+        // 如果没有对应记录则新增
+        if (idResult === 0) {
+            let insertResult = await this.db.create({_id: model, sequence_value: 1});
+            idResult = Object.keys(insertResult).length > 0 ? 1 : 0;
+        }
+
+        return idResult;
+    }
+
+}
+
+export default CounterModel;

+ 0 - 99
modules/glj/models/glj_list.js

@@ -1,99 +0,0 @@
-/**
- * Created by jimiz on 2017/5/10.
- * 单价文件的GLJ列表,注意与项目GLJ区分
- */
-var mongoose = require("mongoose");
-var db = require("../db/unit_price_file_db");
-var Schema = mongoose.Schema;
-var deleteSchema = require('../../../public/models/delete_schema');
-var counter = require("../../../public/counter/counter.js");
-var consts = require('../../main/models/project_consts');
-var projectConsts = consts.projectConst;
-var commonConsts = consts.commonConst;
-
-var GLJListSchema = new Schema({
-    ID: Number,
-    fileID: Number,
-    code: String,
-    name: String,
-    specs: String,
-    unit: String,
-    type: Number,
-    adjustPrice: String,
-    rationPrice: String,
-    price: String, //Decimal
-    deleteInfo: deleteSchema
-});
-
-var GLJList = db.model("GLJList", GLJListSchema, "GLJList");
-
-var GLJListDAO = function(){};
-
-GLJListDAO.prototype.getData = function(fileID, callback){
-    var me = this;
-    GLJList.find({'$or': [{fileID: fileID, deleteInfo: null}, {fileID: fileID, 'deleteInfo.deleted': {$in: [null, false]}}]}, '-_id', function(err, datas){
-        if (!err) {
-            callback(0, projectConsts.GLJLIST, datas);
-        } else {
-            callback(1, '', null);
-        }
-    });
-};
-
-// 单价文件中的工料机不在这里新增,只能由add方法新增,删除需要在前端projectGLJ判断:1、是新工料机;2、没有定额引用,才可以删除
-GLJListDAO.prototype.save = function(fileId, datas, callback){
-    var functions = [];
-    var data;
-
-    // cb中返回doc,以便进行同步
-    function saveOne(doc) {
-        return function (cb) {
-            function updateCallback(err, data){
-                cb(err, doc);
-            }
-            switch (doc.updateType) {
-                case commonConsts.UT_UPDATE:
-                    ration.update({ID: doc.ID}, doc, updateCallback);
-                    break;
-                case commonConsts.UT_DELETE:
-                /* 假删除
-                 var item = new ration(doc);
-                 item.remove(cb);
-                 */
-            }
-        }
-    }
-    for (var i = 0; i < datas.length; i++){
-        data = datas[i];
-        functions.push(saveOne(data));
-    }
-
-    async.parallel(functions, callback);
-};
-
-GLJListDAO.prototype.add = function(fileID, count, callback){
-
-    function newCallback(err, lowID, highID){
-        if (!err) {
-            var datas = [];
-            for (var i = lowID; i <= highID; i++){
-                var GLJ = new GLJList;
-                GLJ.ID = i;
-                GLJ.fileID = fileID;
-                datas.push(GLJ);
-            }
-            callback(err, datas);
-
-        }
-        else{
-            callback(err, null);
-        }
-    }
-
-    counter.counterDAO.getIDAfterCount(COUNTER_MODULE_NAME.unitPriceGLJ, IDStep, function(err, highID){
-        var lowID = highID - IDStep + 1;
-        newCallback(err, lowID, highID);
-    });
-};
-
-module.exports = new GLJListDAO();

+ 132 - 0
modules/glj/models/glj_list_model.js

@@ -0,0 +1,132 @@
+/**
+ * 项目工料机列表数据模型
+ *
+ * @author CaiAoLin
+ * @date 2017/6/22
+ * @version
+ */
+import BaseModel from "../../common/base/base_model";
+import {default as GLJSchemas, collectionName as gljCollectionName} from "./schemas/glj";
+import CounterModel from "./counter_model";
+import UnitPriceModel from "./unit_price_model";
+
+class GLJListModel extends BaseModel {
+
+    /**
+     * 材料类型id
+     *
+     * @var {Array}
+     */
+    materialIdList = [5, 6, 7];
+
+    /**
+     * 构造函数
+     *
+     * @return {void}
+     */
+    constructor() {
+        let parent = super();
+        parent.model = GLJSchemas;
+        parent.init();
+    }
+
+    /**
+     * 设置场景
+     *
+     * @param {string} scene
+     * @return {void}
+     */
+    setScene(scene = '') {
+        switch (scene) {
+            // 新增数据的验证规则
+            case 'add':
+                this.model.schema.path('gli_repository_id').required(true);
+                this.model.schema.path('project_id').required(true);
+                this.model.schema.path('tender_id').required(true);
+                this.model.schema.path('unit').required(true);
+                this.model.schema.path('code').required(true);
+                this.model.schema.path('name').required(true);
+                this.model.schema.path('type').required(true);
+                this.model.schema.path('type_of_work').required(true);
+                break;
+        }
+    }
+
+    /**
+     * 根据标段对应工料机数据
+     *
+     * @param {Number} tenderId
+     * @param {Number} unitPriceTenderId
+     * @return {Promise}
+     */
+    async getListByTenderId(tenderId, unitPriceTenderId) {
+        let gljData = null;
+        try {
+            // 首先获取对应标段下所有的项目工料机数据
+            let condition = {tender_id: tenderId};
+            let fields = {_id: 0};
+            gljData = await this.db.find(condition, fields);
+
+            // 没有数据则直接返回空
+            if (gljData.length <= 0) {
+                throw '无数据';
+            }
+
+            // 获取标段设置的单价文件数据
+            let unitPriceModel = new UnitPriceModel();
+            let unitPriceList = await unitPriceModel.getDataByTenderId(unitPriceTenderId);
+
+            // 组合数据
+            this.combineUnitPrice(gljData, unitPriceList);
+
+        } catch (error) {
+            gljData = [];
+        }
+
+        return gljData;
+    }
+
+    /**
+     * 组合工料机数据和单价文件数据
+     *
+     * @param {object} gljList
+     * @param {object} unitPriceList
+     * @return {void}
+     */
+    combineUnitPrice(gljList, unitPriceList) {
+        // 循环组合数据
+        for(let glj of gljList) {
+            if (glj.code === undefined) {
+                continue;
+            }
+            glj.unit_price = unitPriceList[glj.code] !== undefined ? unitPriceList[glj.code] : null;
+            glj.adjust_price = glj.adjustment * glj.unit_price.base_price;
+        }
+    }
+
+    /**
+     * 新增工料机数据(定额工料机新增时调用)
+     *
+     * @param {object} data
+     * @return {Promise} 返回插入成功的数据
+     */
+    async addData(data) {
+        let result = false;
+        try {
+            if (Object.keys(data).length <= 0) {
+                throw '新增数据为空';
+            }
+            // 新增自增id
+            let counterModel = new CounterModel();
+            data.id = await counterModel.getId(gljCollectionName);
+            this.setScene('add');
+            result = await this.db.model.create(data);
+        } catch (error) {
+            result = false;
+        }
+
+        return result;
+    }
+}
+
+export default GLJListModel;

+ 70 - 0
modules/glj/models/glj_repository_model.js

@@ -0,0 +1,70 @@
+/**
+ * 工料机数据源模块
+ *
+ * @author CaiAoLin
+ * @date 2017/6/23
+ * @version
+ */
+import BaseModel from "../../common/base/base_model";
+import GLJRepositorySchema from "./schemas/glj_repository";
+
+class GLJRepositoryModel extends BaseModel {
+
+    /**
+     * 构造函数
+     *
+     * @return {void}
+     */
+    constructor() {
+        let parent = super();
+        parent.model = GLJRepositorySchema;
+        parent.init();
+    }
+
+    /**
+     * 新增数据
+     *
+     * @param {object} data
+     * @return {Promise} boolean
+     */
+    async add(data) {
+        let result = false;
+        try {
+            result = await this.db.create(data);
+        } catch (error) {
+            if (error.name !== null && error.name === 'ValidationError') {
+                // 这里是数据验证失败
+                console.log('数据验证失败!');
+            }
+            result = false;
+        }
+
+        return result;
+    }
+
+    /**
+     * 根据条件获取对应工料机数据
+     *
+     * @param {Object} condition
+     * @return {Promise} Array
+     */
+    async getDataByCondition(condition) {
+        let gljData = [];
+        try {
+            if (Object.keys(condition).length <= 0) {
+                throw '筛选条件有误';
+            }
+
+            gljData = await this.db.find(condition);
+
+        } catch (error) {
+            console.log(error);
+            gljData = [];
+        }
+
+        return gljData;
+    }
+
+}
+
+export default GLJRepositoryModel;

+ 22 - 0
modules/glj/models/schemas/counter.js

@@ -0,0 +1,22 @@
+/**
+ * 计数器数据结构
+ *
+ * @author CaiAoLin
+ * @date 2017/6/29
+ * @version
+ */
+import mongoose from "mongoose";
+
+let Schema = mongoose.Schema;
+let collectionName = 'counter';
+let modelSchema = {
+    // 模块名称
+    _id: String,
+    // 计数器
+    sequence_value: {
+        type: Number,
+        default: 1
+    },
+};
+
+export default mongoose.model(collectionName, new Schema(modelSchema, {versionKey: false}));

+ 77 - 0
modules/glj/models/schemas/glj.js

@@ -0,0 +1,77 @@
+/**
+ * 工料机数据模型
+ *
+ * @author CaiAoLin
+ * @date 2017/6/29
+ * @version
+ */
+import mongoose from "mongoose";
+
+let Schema = mongoose.Schema;
+let collectionName = 'glj_list';
+let modelSchema = {
+    // 自增id
+    id: Number,
+    // 工料机总库ID
+    glj_repository_id: Number,
+    // 项目ID
+    project_id: Number,
+    // 标段ID
+    tender_id: Number,
+    // 编码
+    code: String,
+    // 名称
+    name: String,
+    unit: String,
+    // 规格型号
+    specs: {
+        type: String,
+        default: ''
+    },
+    // 类型
+    type: Number,
+    // 人工工种
+    type_of_work: Number,
+    // 是否暂估 (0为否 1为是)
+    is_evaluate: {
+        type: Number,
+        default: 0
+    },
+    // 供货方式
+    supply: {
+        type: String,
+        default: ''
+    },
+    // 甲供数量
+    supply_quantity: {
+        type: Number,
+        default: 0
+    },
+    // 交货方式
+    delivery: {
+        type: String,
+        default: ''
+    },
+    // 送达地点
+    delivery_address: {
+        type: String,
+        default: ''
+    },
+    // 不调价
+    is_adjust_price: {
+        type: Number,
+        default: 0
+    },
+    // 调整系数
+    adjustment: {
+        type: Number,
+        default: 1
+    },
+    // 显示调整基价
+    adjust_price: String,
+    // 显示关联单价文件的字段
+    unit_price: Schema.Types.Mixed
+};
+let model = mongoose.model(collectionName, new Schema(modelSchema, {versionKey: false}));
+
+export { model as default, collectionName as collectionName} ;

+ 29 - 0
modules/glj/models/schemas/glj_repository.js

@@ -0,0 +1,29 @@
+/**
+ * 数据结构
+ *
+ * @author CaiAoLin
+ * @date 2017/6/28
+ * @version
+ */
+import mongoose from "mongoose";
+
+let Schema = mongoose.Schema;
+let collectionName = 'glj_repository';
+let modelSchema = {
+    // 自增id
+    id: Number,
+    // 定额id
+    ration_id: Number,
+    // 名称
+    name: String,
+    // 编号
+    code: String,
+    // 单位
+    unit: String,
+    // 定额单价
+    ration_price: String,
+    // 规格
+    standard: String
+};
+
+export default mongoose.model(collectionName, new Schema(modelSchema, {versionKey: false}));

+ 27 - 0
modules/glj/models/schemas/unit_price.js

@@ -0,0 +1,27 @@
+/**
+ * 单价文件数据结构
+ *
+ * @author CaiAoLin
+ * @date 2017/6/29
+ * @version
+ */
+import mongoose from "mongoose";
+
+let Schema = mongoose.Schema;
+let collectionName = 'unit_price';
+let modelSchema = {
+    // 自增ID
+    id: Number,
+    // 项目id
+    project_id: Number,
+    // 标段id
+    tender_id: Number,
+    // 基价单价
+    base_price: String,
+    // 市场单价
+    market_price: String,
+    // 编码
+    code: String
+};
+
+export default mongoose.model(collectionName, new Schema(modelSchema, {versionKey: false, collection: collectionName}));

+ 0 - 77
modules/glj/models/unit_price_file.js

@@ -1,77 +0,0 @@
-/**
- * Created by jimiz on 2017/5/12.
- */
-var mongoose = require("mongoose");
-var db = require("../db/unit_price_file_db");
-var Schema = mongoose.Schema;
-var deleteSchema = require('../../../public/models/delete_schema');
-var consts = require('../../main/models/project_consts');
-var projectConsts = consts.projectConst;
-var commonConsts = consts.commonConst;
-var GLJList = require('./glj_list');
-
-var unitPriceFileSchema = new Schema({
-    ID: Number,
-    name: String,
-    version: Number,
-    projects: Array,
-    deleteInfo: deleteSchema
-});
-
-var unitPriceFile = db.model("unitPriceFile", unitPriceFileSchema, "unitPriceFile");
-
-var unitPriceFileDAO = function(){};
-
-unitPriceFileDAO.prototype.getData = function(fileID, callback){
-    var data;
-    unitPriceFile.find({'$or': [{fileID: fileID, deleteInfo: null}, {fileID: fileID, 'deleteInfo.deleted': {$in: [null, false]}}]}, '-_id', function(err, datas){
-        if (!err) {
-            GLJList.getData(fileID, function(err, gljList){
-                data['properties'] = datas[0];
-                data['glj_list'] = gljList;
-                callback(0, projectConsts.UNITPRICEFILE, data);
-            });
-        } else {
-            callback(1, '', null);
-        }
-    });
-};
-
-unitPriceFileDAO.prototype.save = function(fileId, datas, callback){
-    function changed(err, changedDatas){
-        sync(fileId, changedDatas, callback);
-    }
-
-
-    GLJList.save(fileID, datas, changed);
-};
-
-unitPriceFileDAO.prototype.sync = function(fileID, datas, callback){
-    unitPriceFile.find({'$or': [{ID: fileID, deleteInfo: null}, {ID: fileID, 'deleteInfo.deleted': {$in: [null, false]}}]}, '-_id', function(err, datas){
-        if (!err) {
-            // to do
-
-            callback(0, projectConsts.UNITPRICEFILE, datas);
-        } else {
-            callback(1, '', null);
-        }
-    });
-};
-
-unitPriceFileDAO.prototype.add = function(fileID, count, callback){
-    GLJList.add(fileID, count, callback);
-};
-
-unitPriceFileDAO.prototype.newFile = function(data, callback){
-
-};
-
-unitPriceFileDAO.prototype.useFile = function(fileID, projectID, callback){
-
-};
-
-unitPriceFileDAO.prototype.unuseFile = function(fileID, projectID, callback){
-
-};
-
-module.exports = new unitPriceFileDAO();

+ 52 - 0
modules/glj/models/unit_price_model.js

@@ -0,0 +1,52 @@
+/**
+ * 单价文件业务模型
+ *
+ * @author CaiAoLin
+ * @date 2017/6/30
+ * @version
+ */
+import BaseModel from "../../common/base/base_model";
+import UnitPriceSchema from "./schemas/unit_price";
+
+class UnitPriceModel extends BaseModel {
+
+    /**
+     * 构造函数
+     *
+     * @return {void}
+     */
+    constructor() {
+        let parent = super();
+        parent.model = UnitPriceSchema;
+        parent.init();
+    }
+
+    /**
+     * 根据标段获取对应单价数据
+     *
+     * @param {Number} tenderId
+     * @return {Promise}
+     */
+    async getDataByTenderId(tenderId) {
+        tenderId = parseInt(tenderId);
+        if (isNaN(tenderId) || tenderId <= 0) {
+            return null;
+        }
+
+        let unitPriceList = await this.db.model.find({tender_id: tenderId});
+        if (unitPriceList.length <= 0) {
+            return null;
+        }
+
+        // 整理数据
+        let result = {};
+        for(let tmp of unitPriceList) {
+            result[tmp.code] = tmp;
+        }
+
+        return result;
+    }
+
+}
+
+export default UnitPriceModel;

+ 0 - 3
modules/glj/models/user_glj_lib.js

@@ -1,3 +0,0 @@
-/**
- * Created by jimiz on 2017/5/12.
- */

+ 18 - 0
modules/glj/routes/glj_router.js

@@ -0,0 +1,18 @@
+/**
+ * 登录相关路由
+ *
+ * @author CaiAoLin
+ * @date 2017/6/22
+ * @version
+ */
+import Express from "express";
+import GLJController from "../controllers/glj_controller";
+
+const router = Express.Router();
+let gljController = new GLJController();
+
+// action定义区域
+router.get('/', gljController.init, gljController.index);
+router.get('/test', gljController.init, gljController.test);
+
+module.exports = router;

+ 14 - 0
web/glj/html/footer.html

@@ -0,0 +1,14 @@
+<!-- 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="/web/building_saas/js/global.js"></script>
+<script src="/web/glj/js/socket.io.slim.js"></script>
+<script>GC.Spread.Sheets.LicenseKey = "559432293813965#A0y3iTOzEDOzkjMyMDN9UTNiojIklkI1pjIEJCLi4TPB9mM5AFNTd4cvZ7SaJUVy3CWKtWYXx4VVhjMpp7dYNGdx2ia9sEVlZGOTh7NRlTUwkWR9wEV4gmbjBDZ4ElR8N7cGdHVvEWVBtCOwIGW0ZmeYVWVr3mI0IyUiwCMzETN8kzNzYTM0IicfJye&Qf35VfiEzRwEkI0IyQiwiIwEjL6ByUKBCZhVmcwNlI0IiTis7W0ICZyBlIsIyNyMzM5ADI5ADNwcTMwIjI0ICdyNkIsIibj9SbvNmL4N7bjRnch56ciojIz5GRiwiI8+Y9sWY9QmZ0Jyp96uL9v6L0wap9biY9qiq95q197Wr9g+89iojIh94Wiqi";</script>
+
+</body>
+<script type="text/javascript">
+    autoFlashHeight();
+</script>
+
+</html>

+ 39 - 0
web/glj/html/glj_index.html

@@ -0,0 +1,39 @@
+<%include header.html %>
+<div class="main">
+    <div class="main-nav">
+        <ul class="nav flex-column">
+            <li><a href="zaojiashu.html">造价书</a></li>
+            <li><a href="gongliaoji.html" class="active">工料机</a></li>
+            <li><a href="baobiao.html">报表</a></li>
+            <li><a href="feilv.html">费率</a></li>
+        </ul>
+    </div>
+    <div class="content">
+        <div class="toolsbar px-1">
+            <div class="tools-btn btn-group align-top">
+                <a href="" class="btn btn-sm"><i class="fa fa-arrow-down" aria-hidden="true"></i>下移</a>
+                <a href="" class="btn btn-sm"><i class="fa fa-arrow-up" aria-hidden="true"></i>上移</a>
+                <a href="" class="btn btn-sm"><i class="fa fa-arrow-left" aria-hidden="true"></i></a>
+                <a href="" class="btn btn-sm"><i class="fa fa-arrow-right" aria-hidden="true"></i></a>
+                <a href="" class="btn btn-sm"><i class="fa fa-undo" aria-hidden="true"></i></a>
+            </div>
+        </div>
+        <div class="container-fluid">
+            <div class="row">
+                <div class="main-content col-lg-12 p-0">
+                    <div class="main-data-full" id="test">
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+<script type="text/javascript">
+    let jsonData = '<%- gljList %>';
+    let materialIdList = '<%- materialIdList %>';
+    if(materialIdList !== '') {
+        materialIdList = materialIdList.split(",");
+    }
+</script>
+<%include footer.html %>
+<script type="text/javascript" src="/web/glj/js/glj_index.js"></script>

+ 90 - 0
web/glj/html/header.html

@@ -0,0 +1,90 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title><%= title %>-Smartcost</title>
+    <link rel="stylesheet" href="/lib/bootstrap/css/bootstrap.min.css">
+    <link rel="stylesheet" href="/web/building_saas/css/main.css">
+    <link rel="stylesheet" href="/lib/font-awesome/font-awesome.min.css">
+    <link rel="stylesheet" href="/lib/spreadjs/sheets/css/gc.spread.sheets.excel2013white.10.0.1.css">
+    <script type="text/javascript" src="/public/web/sheet/sheet_common.js"></script>
+    <script type="text/javascript" src="/public/web/sheet/sheet_data_helper.js"></script>
+    <script src="/lib/spreadjs/sheets/gc.spread.sheets.all.10.0.1.min.js"></script>
+    <style type="text/css">
+        #chat-content {
+            border: 1px solid #000;
+            width: 500px;
+            height: 600px;
+        }
+        #notify {
+            display: none;
+        }
+    </style>
+</head>
+<body>
+<div class="header">
+    <div class="top-msg clearfix" id="notify">
+        <div class="alert alert-warning mb-0 py-0" role="alert">
+            <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+                <span aria-hidden="true">&times;</span>
+            </button>
+            <span id="message"><strong>注意!</strong> 这是一条消息通知 <a href="#">链接</a></span>
+        </div>
+    </div>
+    <nav class="navbar navbar-toggleable-lg navbar-light bg-faded p-0 justify-content-between">
+        <span class="header-logo px-2">Smartcost</span>
+        <div class="navbar-text"><a href="project-management.html">项目管理</a><i class="fa fa-angle-right fa-fw"></i>文件夹<i
+                class="fa fa-angle-right fa-fw"></i>建设项目<i class="fa fa-angle-right fa-fw"></i>单项工程<i
+                class="fa fa-angle-right fa-fw"></i>单位工程
+        </div>
+        <div class="float-lg-right navbar-text pt-0">
+            <div class="dropdown d-inline-block">
+                <button class="btn btn-link btn-sm dropdown-toggle" type="button" data-toggle="dropdown">陈特</button>
+                <div class="dropdown-menu dropdown-menu-right">
+                    <a class="dropdown-item" href="user-info.html" target="_blank">账号资料</a>
+                    <a class="dropdown-item" href="user-buy.html" target="_blank">产品购买</a>
+                    <a class="dropdown-item" href="user-set.html" target="_blank">偏好设置</a>
+                </div>
+            </div>
+            <span class="btn btn-link btn-sm new-msg">
+                  <i class="fa fa-envelope-o" aria-hidden="true"></i>&nbsp;2
+                </span>
+            <button class="btn btn-link btn-sm">注销</button>
+        </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="#" aria-haspopup="true" aria-expanded="false"><i class="fa fa-sliders"></i> 选项</a>
+            </li>
+            <li class="nav-item dropdown">
+                <a class="nav-link dropdown-toggle" href="#" data-toggle="dropdown" aria-haspopup="true"
+                   aria-expanded="false"><i class="fa fa-wrench"></i> 工具</a>
+                <div class="dropdown-menu">
+                    <a class="dropdown-item" href="#">定额库编辑器</a>
+                    <a class="dropdown-item" href="#">工料机库编辑器</a>
+                </div>
+            </li>
+            <li class="nav-item dropdown">
+                <a class="nav-link dropdown-toggle" href="#" data-toggle="dropdown" aria-haspopup="true"
+                   aria-expanded="false"><i class="fa fa-question-circle-o"></i> 帮助</a>
+                <div class="dropdown-menu">
+                    <a class="dropdown-item" href="#">帮助</a>
+                    <a class="dropdown-item" href="#">升级说明</a>
+                    <a class="dropdown-item" href="#">重庆市2008定额说明</a>
+                    <a class="dropdown-item" href="#">纵横官网</a>
+                    <a class="dropdown-item" href="#">动画教程</a>
+                    <a class="dropdown-item" href="#">联系客服</a>
+                    <a class="dropdown-item" href="#">关于</a>
+                </div>
+            </li>
+            <li class="nav-item">
+                <a class="nav-link" href="#" aria-haspopup="true" aria-expanded="false"><i class="fa fa-history"></i>
+                    历史记录</a>
+            </li>
+        </ul>
+        <form class="form-inline">
+            <input class="form-control form-control-sm mr-1" type="text" placeholder="告诉我你想做什么">
+        </form>
+    </nav>
+</div>

+ 172 - 0
web/glj/js/glj_index.js

@@ -0,0 +1,172 @@
+/**
+ * 聊天室相关
+ *
+ * @author CaiAoLin
+ * @date 2017/6/15
+ * @version
+ */
+$(document).ready(function () {
+    // excel
+    let header = [
+        {name: '编码', field: 'code', visible: true},
+        {name: '名称', field: 'name', visible: true},
+        {name: '规格型号', field: 'specs', visible: true},
+        {name: '单位', field: 'unit', visible: true},
+        {name: 'ID', field: 'id', visible: false},
+        {name: '类型', field: 'type', visible: false},
+        {name: '人工工种', field: 'type_of_work', visible: false},
+        {name: '总消耗量', field: '', visible: true},
+        {name: '基价单价', field: "unit_price.base_price", visible: true},
+        {name: '调整基价', field: 'adjust_price', visible: true},
+        {name: '市场单价', field: "unit_price.market_price", visible: true},
+        {name: '是否暂估', field: 'is_evaluate', visible: true, cellType: new GC.Spread.Sheets.CellTypes.CheckBox()},
+        {name: '供货方式', field: 'supply', visible: true},
+        {name: '甲供数量', field: 'supply_quantity', visible: true},
+        {name: '交货方式', field: 'delivery', visible: true},
+        {name: '送达地点', field: 'delivery_address', visible: true},
+        {name: '不调价', field: 'is_adjust_price', visible: true, cellType: new GC.Spread.Sheets.CellTypes.CheckBox()},
+    ];
+
+    let setting = {
+        header: []
+    };
+    for(let tmp of header) {
+        setting.header.push({headerName: tmp.name, headerWidth: 120});
+    }
+
+    let spread = sheetCommonObj.buildSheet(document.getElementById("test"), setting, 3);
+    spread.options.scrollbarShowMax = true;
+    spread.options.scrollbarMaxAlign = true;
+    spread.options.showHorizontalScrollbar = true;
+    let sheet = spread.getActiveSheet();
+
+    // 设置表单不可编辑
+    sheet.options.isProtected = true;
+
+    // 居中样式
+    let centerStyleSetting = {hAlign: 1};
+    sheet.setStyle(-1, 11, getStyle(centerStyleSetting), GC.Spread.Sheets.SheetArea.viewport);
+    sheet.setStyle(-1, 16, getStyle(centerStyleSetting), GC.Spread.Sheets.SheetArea.viewport);
+    sheet.setStyle(-1, 3, getStyle(centerStyleSetting), GC.Spread.Sheets.SheetArea.viewport);
+
+    // 向右对齐样式
+    let rightStyleSetting = {hAlign: GC.Spread.Sheets.HorizontalAlign.right};
+    sheet.setStyle(-1, 7, getStyle(rightStyleSetting), GC.Spread.Sheets.SheetArea.viewport);
+    sheet.setStyle(-1, 8, getStyle(rightStyleSetting), GC.Spread.Sheets.SheetArea.viewport);
+    sheet.setStyle(-1, 9, getStyle(rightStyleSetting), GC.Spread.Sheets.SheetArea.viewport);
+    sheet.setStyle(-1, 10, getStyle(rightStyleSetting), GC.Spread.Sheets.SheetArea.viewport);
+
+
+    // 设置可编辑列
+    sheet.getRange(-1, 10, -1, 1).locked(false);
+    sheet.getRange(-1, 11, -1, 1).locked(false);
+    sheet.getRange(-1, 16, -1, 1).locked(false);
+
+    // 设置json数据
+    let sourceData = JSON.parse(jsonData);
+    let rowCounter = 0;
+    for(let data of sourceData) {
+        let columnCounter = 0;
+        for(let columnInfo of header) {
+            // 设置是否显示
+            sheet.setColumnVisible(columnCounter, columnInfo.visible);
+
+            let dataString = columnInfo.field !== '' && columnInfo.field !== undefined ?
+                "data." + columnInfo.field : '';
+            let cellData = eval(dataString);
+
+            // 设置复选框
+            if (columnInfo.cellType !== undefined) {
+                let checkbox = new GC.Spread.Sheets.CellTypes.CheckBox();
+                sheet.setCellType(rowCounter, columnCounter, checkbox, GC.Spread.Sheets.SheetArea.viewport);
+            }
+
+            // 如果不为材料“是否暂估列”根据条件显示
+            if (columnInfo.field === 'is_evaluate' && materialIdList.indexOf(data.type + '') < 0) {
+                let string = new GC.Spread.Sheets.CellTypes.Text();
+                sheet.setCellType(rowCounter, columnCounter, string, GC.Spread.Sheets.SheetArea.viewport);
+                cellData = '';
+                // 并且锁定该单元格
+                sheet.getRange(rowCounter, columnCounter, 1, 1).locked(true);
+            }
+
+            sheet.setValue(rowCounter, columnCounter, cellData, GC.Spread.Sheets.SheetArea.viewport);
+            columnCounter++;
+        }
+        rowCounter++;
+    }
+
+/*
+    let socket = io('http://notify.smartcost.com.cn:3300');
+    socket.on('connect', function () {
+        socket.emit('join', project);
+        console.log('连接成功');
+    });
+
+    // 接受到改变
+    let changeInfo = [];
+    socket.on('dataChange', function(data) {
+        data = JSON.parse(data);
+        if (data.newValue === undefined) {
+            return false;
+        }
+        changeInfo.push(data);
+        $("#message").html('基价单位已被修改,<a href="javascript:void(0);" id="load-data">点击加载</a>');
+        $("#notify").slideDown('fast');
+        initiativeChange = false;
+    });
+
+    // 是否主动更改数据
+    let initiativeChange = false;
+    $("#message").on('click', '#load-data', function() {
+        $("#notify").slideUp('fast');
+        if (changeInfo.length > 0) {
+            for (let index in changeInfo) {
+                let cell = sheet.getCell(changeInfo[index].row, changeInfo[index].col, GC.Spread.Sheets.SheetArea.viewport);
+                cell.value(changeInfo[index].newValue);
+            }
+        }
+        changeInfo = [];
+    });
+
+    // 进入单元格后设置为主动设置数据
+    sheet.bind(GC.Spread.Sheets.Events.EditEnding, function (element, info) {
+        initiativeChange = true;
+    });
+
+    // 绑定事件
+    sheet.bind(GC.Spread.Sheets.Events.CellChanged, function (element, info) {
+        // 如果修改了数据且为主动修改,先存库再广播给其他页面
+        if (info.newValue !== undefined && info.oldValue !== undefined && initiativeChange) {
+            let id = sheet.getCell(info.row, 0).value();
+            $.ajax({
+                url: '/save',
+                type: 'post',
+                data: {priceValue: info.newValue, id: id},
+                error: function() {
+                    // @todo 替换为更好地错误提示
+                    alert('error');
+                },
+                beforeSend: function() {
+
+                },
+                success: function(response) {
+                    if (response.err === 0) {
+                        socket.emit('dataNotify', JSON.stringify(info));
+                    } else {
+                        // @todo 替换为更好地错误提示
+                        alert(response.msg);
+                    }
+                }
+            });
+        }
+    });
+*/
+});
+
+function getStyle(setting) {
+    let style = new GC.Spread.Sheets.Style();
+    style.locked = setting.readOnly === undefined ? true : setting.readOnly;
+    style.hAlign = setting.hAlign === undefined ? GC.Spread.Sheets.HorizontalAlign.center : setting.hAlign;
+    return style;
+}

Разлика између датотеке није приказан због своје велике величине
+ 3 - 0
web/glj/js/socket.io.slim.js