瀏覽代碼

提交新增标段时初始化项目节数据

olym 7 年之前
父節點
當前提交
ba2b27c3a1

+ 3 - 0
app/base/base_controller.js

@@ -22,7 +22,10 @@ class BaseController extends Controller {
     constructor(ctx) {
         super(ctx);
         this.messageType = messageType;
+        // 当前菜单
         ctx.menu = menuList[ctx.controllerName] === undefined ? {} : menuList[ctx.controllerName];
+        // 菜单列表
+        ctx.menuList = menuList;
     }
 
     /**

+ 1 - 0
app/base/base_service.js

@@ -22,6 +22,7 @@ class BaseService extends Service {
         super(ctx);
         this.db = this.app.mysql;
         this.cache = this.app.redis;
+        this.transaction = null;
         this.sqlBuilder = null;
     }
 

+ 70 - 0
app/controller/ledger_controller.js

@@ -0,0 +1,70 @@
+'use strict';
+
+/**
+ * 台账相关控制器
+ *
+ * @author CaiAoLin
+ * @date 2017/11/30
+ * @version
+ */
+
+module.exports = app => {
+
+    class LedgerController extends app.BaseController {
+
+        /**
+         * 台账列表
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        async index(ctx) {
+            const rule = ctx.service.tender.rule('add');
+            const frontRule = ctx.helper.validateConvert(rule);
+            let tender = ctx.request.query.tender;
+            tender = parseInt(tender);
+            tender = isNaN(tender) ? 0 : tender;
+
+            // 获取标段数据
+            const tenderList = await ctx.service.tender.getList();
+            // 如果没有指定标段则默认载入第一个
+            if (tenderList.length > 0 && tender <= 0) {
+                tender = tenderList[0].id;
+            }
+
+            // 获取标段项目节点
+            const tenderNode = await ctx.service.tenderNode.getDataByTenderId(tender);
+
+            const renderData = {
+                tenderList,
+                rule: JSON.stringify(frontRule),
+                currentTender: tender,
+            };
+            await this.layout('ledger/index.ejs', renderData);
+        }
+
+        /**
+         * 添加标段操作
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        async addTender(ctx) {
+            try {
+                const rule = ctx.service.tender.rule('add');
+                ctx.validate(rule);
+
+                const result = ctx.service.tender.add(ctx.request.body);
+                if (!result) {
+                    throw '新增标段失败';
+                }
+            } catch (error) {
+                this.setMessage(error.toString(), this.messageType.ERROR);
+            }
+
+            ctx.redirect(ctx.request.headers.referer);
+        }
+    }
+
+    return LedgerController;
+};

+ 5 - 0
app/public/css/main.css

@@ -369,4 +369,9 @@ body {
 .toast.info {
     background-color: rgba(53, 184, 224, 0.8);
     border: 2px solid #35b8e0;
+}
+label.required::after {
+    color: red;
+    content: "*";
+    margin-left: 4px;
 }

+ 1 - 1
app/public/js/form_validate.js

@@ -23,7 +23,7 @@ $(document).ready(function() {
     });
 
 
-    $("button").click(function() {
+    $("button[type='submit']").click(function() {
         $("form").valid();
     });
 });

+ 6 - 0
app/router.js

@@ -4,6 +4,8 @@ module.exports = app => {
 
     // session验证中间件
     const sessionAuth = app.middlewares.sessionAuth();
+    // 创建时间自动填充中间件
+    const datetimeFill = app.middlewares.datetimeFill();
 
     // 登入登出相关
     app.get('/login', 'loginController.index');
@@ -21,4 +23,8 @@ module.exports = app => {
     // 项目相关
     app.get('/project/info', sessionAuth, 'projectController.info');
     app.post('/project/info', sessionAuth, 'projectController.saveInfo');
+
+    // 台账管理相关
+    app.get('/ledger', sessionAuth, 'ledgerController.index');
+    app.post('/ledger/tender/add', sessionAuth, datetimeFill, 'ledgerController.addTender');
 };

+ 120 - 0
app/service/tender.js

@@ -0,0 +1,120 @@
+'use strict';
+
+/**
+ * 标段数据模型
+ *
+ * @author CaiAoLin
+ * @date 2017/11/30
+ * @version
+ */
+
+module.exports = app => {
+
+    class Tender extends app.BaseService {
+
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'tender';
+            this.status = {
+                INIT: 1,
+            };
+        }
+
+        /**
+         * 数据规则
+         *
+         * @param {String} scene - 场景
+         * @return {Object} - 返回数据规则
+         */
+        rule(scene) {
+            let rule = {};
+            switch (scene) {
+                case 'add':
+                    rule = {
+                        name: { type: 'string', required: true, min: 2 },
+                    };
+                    break;
+                default:
+                    break;
+            }
+
+            return rule;
+        }
+
+        /**
+         * 获取标段列表
+         *
+         * @return {Array} - 返回标段数据
+         */
+        async getList() {
+            // 获取当前用户信息
+            const sessionUser = this.ctx.session.sessionUser;
+            this.initSqlBuilder();
+            this.sqlBuilder.setAndWhere('project_id', {
+                value: sessionUser.projectId,
+                operate: '=',
+            });
+            this.sqlBuilder.setAndWhere('user_id', {
+                value: sessionUser.accountId,
+                operate: '=',
+            });
+            this.sqlBuilder.limit = 10;
+            this.sqlBuilder.columns = ['id', 'name', 'status'];
+            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
+
+            return await this.db.query(sql, sqlParam);
+        }
+
+        /**
+         * 新增标段
+         *
+         * @param {Object} postData - 表单post过来的数据
+         * @return {Boolean} - 返回新增结果
+         */
+        async add(postData) {
+            let result = false;
+            this.transaction = await this.db.beginTransaction();
+            try {
+                // 获取当前用户信息
+                const sessionUser = this.ctx.session.sessionUser;
+                const insertData = {
+                    name: postData.name,
+                    status: this.status.INIT,
+                    project_id: sessionUser.projectId,
+                    user_id: sessionUser.accountId,
+                    create_time: postData.create_time,
+                };
+                const operate = await this.transaction.insert(this.tableName, insertData);
+                result = operate.insertId > 0;
+                if (!result) {
+                    throw '新增标段数据失败';
+                }
+
+                // 获取标段项目节点模板
+                const tenderNodeTemplateData = await this.ctx.service.tenderNodeTemplate.getData();
+                // 复制模板数据到标段数据表
+                this.ctx.service.tenderNode.transaction = this.transaction;
+                const copyResult = await this.ctx.service.tenderNode.add(tenderNodeTemplateData, operate.insertId);
+
+                if (!copyResult) {
+                    throw '新增标段项目节点失败';
+                }
+                this.transaction.commit();
+            } catch (error) {
+                result = false;
+                this.transaction.rollback();
+            }
+
+            return result;
+        }
+
+    }
+
+    return Tender;
+};

+ 99 - 0
app/service/tender_node.js

@@ -0,0 +1,99 @@
+'use strict';
+
+/**
+ * 标段项目节数据模型
+ *
+ * @author CaiAoLin
+ * @date 2017/12/1
+ * @version
+ */
+
+module.exports = app => {
+
+    class TenderNode extends app.BaseService {
+
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'tender_node';
+        }
+
+        /**
+         * 新增数据
+         *
+         * @param {Object} data - 新增的数据(可批量)
+         * @param {Number} tenderId - 标段id
+         * @return {Boolean} - 返回新增的结果
+         */
+        async add(data, tenderId) {
+            let result = false;
+            try {
+                if (tenderId <= 0) {
+                    throw '标段id错误';
+                }
+                if (data instanceof Array) {
+                    // 数组则为批量插入
+                    if (data.length <= 0) {
+                        throw '插入数据为空';
+                    }
+                    // 整理数据
+                    const insertData = [];
+                    for (const tmp of data) {
+                        tmp.template_id = tmp.id;
+                        tmp.template_pid = tmp.pid;
+                        tmp.tender_id = tenderId;
+                        delete tmp.id;
+                        delete tmp.pid;
+                        insertData.push(tmp);
+                    }
+                    const operate = await this.transaction.insert(this.tableName, insertData);
+                    result = operate.affectedRows > 0;
+                } else {
+                    // 对象则单个插入
+                }
+            } catch (error) {
+                result = false;
+            }
+
+            return result;
+        }
+
+        /**
+         * 根据层级获取数据
+         *
+         * @param {Number} tenderId - 标段id
+         * @param {Boolean} showAll - 是否显示全部
+         * @return {Array} - 返回数据
+         */
+        async getDataByTenderId(tenderId, showAll = false) {
+            if (tenderId <= 0) {
+                return [];
+            }
+            const showLevel = !showAll ? 2 : -1;
+            this.initSqlBuilder();
+            this.sqlBuilder.setAndWhere('tender_id', {
+                value: tenderId,
+                operate: '=',
+            });
+
+            if (showLevel > 0) {
+                this.sqlBuilder.setAndWhere('level', {
+                    value: showLevel,
+                    operate: '<=',
+                });
+            }
+
+            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
+            const data = await this.db.query(sql, sqlParam);
+
+            return data;
+        }
+    }
+
+    return TenderNode;
+};

+ 53 - 0
app/service/tender_node_template.js

@@ -0,0 +1,53 @@
+'use strict';
+
+/**
+ * 标段项目模板数据模型
+ *
+ * @author CaiAoLin
+ * @date 2017/12/1
+ * @version
+ */
+
+module.exports = app => {
+
+    class TenderNodeTemplate extends app.BaseService {
+
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'tender_node_template';
+        }
+
+        /**
+         * 获取模板数据
+         *
+         * @param {Boolean} isCache - 是否使用缓存
+         * @return {Array} - 返回模板数据
+         */
+        async getData(isCache = true) {
+            const cacheKey = 'tenderTPL';
+            const data = await this.cache.get(cacheKey);
+
+            if (data !== null && !isCache) {
+                return JSON.parse(data);
+            }
+
+            // 获取所有数据
+            const templateData = await this.db.select(this.tableName);
+            if (templateData.length <= 0) {
+                return [];
+            }
+
+            this.cache.set(cacheKey, JSON.stringify(templateData), 'EX', app.config.cacheTime);
+
+            return templateData;
+        }
+    }
+
+    return TenderNodeTemplate;
+};

+ 3 - 16
app/view/layout/layout.ejs

@@ -12,6 +12,7 @@
     <!-- JS. -->
     <script src="/public/js/jquery/jquery-3.2.1.min.js"></script>
     <script src="/public/js/jquery/jquery.validate.js"></script>
+    <script src="/public/js/messages_zh.js"></script>
     <script src="/public/js/popper/popper.min.js"></script>
     <script src="/public/js/bootstrap/bootstrap.min.js"></script>
     <script src="/public/js/global.js"></script>
@@ -63,22 +64,7 @@
     </div>
 </div>
 <div class="main">
-    <div class="main-nav">
-        <div class="nav-top">
-            <ul class="nav nav-pills flex-column nav-fill bg-nav">
-                <li class="nav-item active"><a href="dashboard.html" data-toggle="tooltip" data-placement="right"
-                                               title="主页"><i class="fa fa-dashboard"></i></a></li>
-                <li class="nav-item"><a href="taizhang.html" data-toggle="tooltip" data-placement="right"
-                                        title="台帐管理"><i class="fa fa-list-alt"></i></a></li>
-                <li class="nav-item"><a href="jiliang.html" data-toggle="tooltip" data-placement="right" title="计量管理"><i
-                                class="fa fa-calendar-check-o"></i></a></li>
-                <li class="nav-item"><a href="biangeng.html" data-toggle="tooltip" data-placement="right"
-                                        title="变更管理"><i class="fa fa-retweet"></i></a></li>
-                <li class="nav-item"><a href="hetong.html" data-toggle="tooltip" data-placement="right" title="合同管理"><i
-                                class="fa fa-handshake-o"></i></a></li>
-            </ul>
-        </div>
-    </div>
+    <% include ./menu.ejs %>
     <div class="main-panel">
         <%- content %>
     </div>
@@ -87,6 +73,7 @@
     <i class="icon fa"></i>
     <span class="message"></span>
 </div>
+<% include ./modal.ejs %>
 <script type="text/javascript">
     let toastInfo = '<%- message %>';
     try {

+ 19 - 0
app/view/layout/menu.ejs

@@ -0,0 +1,19 @@
+<div class="main-nav">
+    <div class="nav-top">
+        <ul class="nav nav-pills flex-column nav-fill bg-nav">
+            <li class="nav-item <% if(ctx.controllerName === 'dashboard') { %>active<% } %>">
+                <a href="/dashboard" data-toggle="tooltip" data-placement="right" title="主页">
+                    <i class="fa fa-dashboard"></i>
+                </a>
+            </li>
+            <% for (const index in ctx.menuList) { %>
+            <% if (ctx.menuList[index].display === undefined || !ctx.menuList[index].display) { continue } %>
+            <li class="nav-item <% if(ctx.controllerName === index) { %>active<% } %>">
+                <a href="<%= ctx.menuList[index].url %>" data-toggle="tooltip" data-placement="right" title="<%= ctx.menuList[index].name %>">
+                    <i class="fa <%= ctx.menuList[index].icon %>"></i>
+                </a>
+            </li>
+            <% } %>
+        </ul>
+    </div>
+</div>

+ 23 - 0
app/view/layout/modal.ejs

@@ -0,0 +1,23 @@
+<!--弹出添加帐号-->
+<div class="modal fade" id="add-bd" data-backdrop="static">
+    <div class="modal-dialog" role="document">
+        <form method="post" action="/ledger/tender/add">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <h5 class="modal-title">添加新标段</h5>
+                </div>
+                <div class="modal-body">
+                    <div class="form-group">
+                        <label class="required">标段名称</label>
+                        <input class="form-control" placeholder="输入标段名称" type="text" name="name" id="tender-name"/>
+                    </div>
+                </div>
+                <div class="modal-footer">
+                    <input type="hidden" name="_csrf" value="<%= ctx.csrf %>"/>
+                    <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
+                    <button type="submit" class="btn btn-primary">确定添加</button>
+                </div>
+            </div>
+        </form>
+    </div>
+</div>

+ 105 - 0
app/view/ledger/index.ejs

@@ -0,0 +1,105 @@
+<div class="panel-sidebar">
+    <div class="panel-title">
+        <div class="title-bar d-flex justify-content-between">
+            <h2>标段列表</h2>
+            <div class="mr-3">
+                <a href="#add-bd" data-toggle="modal" data-target="#add-bd" class="btn btn-sm btn-outline-primary">添加</a>
+            </div>
+        </div>
+    </div>
+    <div class="scrollbar-auto">
+        <div class="nav-box">
+            <ul class="nav-list list-unstyled">
+                <% tenderList.forEach(function(tender) {%>
+                <li <% if (currentTender === tender.id) { %>class="active"<% } %>><a href="/ledger?tender=<%= tender.id %>"><span><%= tender.name %></span></a></li>
+                <% }) %>
+            </ul>
+        </div>
+    </div>
+</div>
+<div class="panel-content">
+    <div class="panel-title">
+        <div class="title-main">
+            <h2>WWUJ-2 台帐
+                <a href="#" class="btn btn-primary btn-sm pull-right">上报审批</a>
+                <a href="#" class="btn btn-outline-secondary btn-sm pull-right disabled">已报审</a>
+                <a href="#" class="btn btn-outline-danger btn-sm pull-right">删除标段</a></h2>
+        </div>
+    </div>
+    <div class="content-wrap row">
+        <div class="c-header p-0 col-12 d-flex justify-content-between">
+            <!--工具-->
+            <div>
+                <div class="form-check">
+                    <label class="form-check-label">
+                        <input type="checkbox" class="form-check-input">
+                        查看审批过程
+                    </label>
+                </div>
+            </div>
+            <!--标准清单-->
+            <ul class="nav nav-tabs">
+                <li class="nav-item">
+                    <a class="nav-link active" data-toggle="tab" href="#xiangmujie" role="tab">项目节</a>
+                </li>
+                <li class="nav-item">
+                    <a class="nav-link" data-toggle="tab" href="#qingdan" role="tab">工程量清单</a>
+                </li>
+            </ul>
+        </div>
+        <div class="c-body col-8">
+            <table class="table table-bordered">
+                <tr>
+                    <th></th>
+                    <th>项目节编号</th>
+                    <th>清单编号</th>
+                    <th>名称</th>
+                    <th>单位</th>
+                    <th>单价</th>
+                    <th>施工图原设计</th>
+                    <th>图(册)号</th>
+                    <th>备注</th>
+                </tr>
+            </table>
+        </div>
+        <div class="c-body col-4">
+            <div class="tab-content">
+                <div id="xiangmujie" class="tab-pane active">
+                    <select class="form-control form-control-sm">
+                        <option>0号计量台帐部位参考(项目节)</option>
+                    </select>
+                    <table class="table table-bordered">
+                        <tr>
+                            <th></th>
+                            <th>项目节编号</th>
+                            <th>名称</th>
+                            <th>单位</th>
+                        </tr>
+                    </table>
+                </div>
+                <div id="qingdan" class="tab-pane">
+                    <select class="form-control form-control-sm">
+                        <option>0号计量台帐部位参考(项目节)</option>
+                    </select>
+                    <table class="table table-bordered">
+                        <tr>
+                            <th></th>
+                            <th>清单编号</th>
+                            <th>名称</th>
+                            <th>单位</th>
+                        </tr>
+                    </table>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+<script type="text/javascript">
+    let rule = '<%- rule %>';
+    rule = JSON.parse(rule);
+
+    let message = {
+    };
+</script>
+<script src="/public/js/form_validate.js"></script>
+<script src="/public/js/validate.extend.js"></script>

+ 30 - 0
config/menu.js

@@ -11,6 +11,8 @@
 const menu = {
     project: {
         name: '项目设置',
+        icon: null,
+        display: false,
         children: {
             info: {
                 name: '项目信息',
@@ -26,6 +28,34 @@ const menu = {
             },
         },
     },
+    ledger: {
+        name: '台帐管理',
+        icon: 'fa-list-alt',
+        display: true,
+        children: null,
+        url: '/ledger',
+    },
+    measure: {
+        name: '计量管理',
+        icon: 'fa-calendar-check-o',
+        display: true,
+        children: null,
+        url: '/measure',
+    },
+    change: {
+        name: '变更管理',
+        icon: 'fa-retweet',
+        display: true,
+        children: null,
+        url: '/change',
+    },
+    contract: {
+        name: '合同管理',
+        icon: 'fa-handshake-o',
+        display: true,
+        children: null,
+        url: '/contract',
+    },
 };
 
 module.exports = menu;