浏览代码

提交项目信息代码

olym 7 年之前
父节点
当前提交
c9294ba1b1

+ 2 - 0
app/base/base_controller.js

@@ -10,6 +10,7 @@
 const moment = require('moment');
 const messageType = require('../const/message_type');
 const Controller = require('egg').Controller;
+const menuList = require('../../config/menu');
 class BaseController extends Controller {
 
     /**
@@ -21,6 +22,7 @@ class BaseController extends Controller {
     constructor(ctx) {
         super(ctx);
         this.messageType = messageType;
+        ctx.menu = menuList[ctx.controllerName] === undefined ? {} : menuList[ctx.controllerName];
     }
 
     /**

+ 2 - 2
app/controller/login_controller.js

@@ -49,7 +49,7 @@ module.exports = app => {
                 // 判断是否已经有对应用户信息,没有则跳转初始化页面
                 const needBoot = await ctx.service.customer.isNeedBoot(ctx.request.body);
                 const url = needBoot ? '/boot' : '/dashboard';
-                console.log(url);
+
                 ctx.redirect(url);
             } catch (error) {
                 console.log(error);
@@ -73,4 +73,4 @@ module.exports = app => {
     }
 
     return LoginController;
-};
+};

+ 89 - 0
app/controller/project_controller.js

@@ -0,0 +1,89 @@
+'use strict';
+
+/**
+ * 项目相关控制器
+ *
+ * @author CaiAoLin
+ * @date 2017/11/29
+ * @version
+ */
+
+const officeList = require('../const/cld_office').list;
+module.exports = app => {
+
+    class ProjectController extends app.BaseController {
+
+        /**
+         * 项目信息页面
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        async info(ctx) {
+            try {
+                // 获取项目数据
+                const projectId = ctx.session.sessionUser.projectId;
+                const projectData = await ctx.service.project.getDataById(projectId);
+                if (projectData === null) {
+                    throw '没有对应的项目数据';
+                }
+
+                // 获取销售人员数据
+                const salesmanData = await ctx.service.manager.getDataById(projectData.manager_id);
+
+                // 数据规则
+                const rule = ctx.service.project.rule('saveInfo');
+                const frontRule = ctx.helper.validateConvert(rule);
+
+                const renderData = {
+                    projectData,
+                    salesmanData,
+                    officeList,
+                    rule: JSON.stringify(frontRule),
+                };
+                await this.layout('project/info.ejs', renderData);
+            } catch (error) {
+                console.log(error);
+                ctx.redirect('/dashboard');
+            }
+        }
+
+        /**
+         * 保存项目信息操作
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        async saveInfo(ctx) {
+            try {
+                // 获取项目数据
+                const projectId = ctx.session.sessionUser.projectId;
+                const projectData = await ctx.service.project.getDataById(projectId);
+                if (projectData === null) {
+                    throw '没有对应的项目数据';
+                }
+
+                const rule = ctx.service.project.rule('saveInfo');
+                ctx.validate(rule);
+
+                const updateData = {
+                    name: ctx.request.body.name,
+                };
+                const result = await ctx.service.project.update(updateData, { id: projectData.id });
+                if (!result) {
+                    throw '保存项目信息失败';
+                }
+
+                this.setMessage('保存成功', this.messageType.SUCCESS);
+            } catch (error) {
+                console.log(error);
+                this.setMessage(error, this.messageType.ERROR);
+            }
+
+            ctx.redirect(ctx.request.headers.referer);
+        }
+
+    }
+
+    return ProjectController;
+};

+ 0 - 33
app/extend/helper.js

@@ -155,37 +155,4 @@ module.exports = {
         return response.data;
     },
 
-    /**
-     * 转换面包屑导航数据
-     *
-     * @param {Object} breadCrumb - 面包屑数据
-     * @param {String} mode - 模式 append 为追加型模式 \ replace 为全部替换模式
-     * @return {String} - 转换为字符串数据
-     */
-    convertBreadCrumb(breadCrumb, mode = 'append') {
-        let result = '';
-        if (!breadCrumb instanceof Array || breadCrumb.length <= 0) {
-            return result;
-        }
-        if (mode === 'append') {
-            const tmpBreadCrumb = [];
-            tmpBreadCrumb.push({ name: this.ctx.topPermission.name });
-            tmpBreadCrumb.push.apply(tmpBreadCrumb, breadCrumb);
-            tmpBreadCrumb.push({ name: this.ctx.currentName });
-            breadCrumb = tmpBreadCrumb;
-        }
-        const tmpList = [];
-        for (const data of breadCrumb) {
-            if (data.name === undefined) {
-                continue;
-            }
-            const tmp = data.url === undefined || data.url === '' ?
-                data.name : '<a href="/' + data.url + '">' + data.name + '</a>';
-            tmpList.push(tmp);
-        }
-        result = tmpList.join(' / ');
-
-        return result;
-    },
-
 };

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

@@ -328,3 +328,45 @@ body {
   font-size:18px;
   color:#f90000
 }
+.toast{
+    position: absolute;
+    top: 0;
+    width: 65%;
+    left: 0;
+    right: 0;
+    margin: 0 auto;
+    opacity: 0.8;
+    box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
+    z-index: 999;
+    padding: 15px;
+    border-radius: 3px;
+    color: #ffffff;
+    display: none;
+}
+.toast .message{
+    padding-left: 50px;
+    display: inline-block;
+    font-size: 14px;
+}
+.toast i.icon{
+    font-size: 25px;
+    position: absolute;
+    left: 23px;
+    top: 13px;
+}
+.toast.success{
+    background: rgba(16, 196, 105, 0.8);
+    border: 2px solid #10c469
+}
+.toast.error{
+    background-color: rgba(255, 91, 91, 0.8);
+    border: 2px solid #ff5b5b;
+}
+.toast.warning {
+    background-color: rgba(249, 200, 81, 0.8);
+    border: 2px solid #f9c851;
+}
+.toast.info {
+    background-color: rgba(53, 184, 224, 0.8);
+    border: 2px solid #35b8e0;
+}

+ 73 - 0
app/public/js/component/input.js

@@ -0,0 +1,73 @@
+'use strict';
+
+/**
+ * vue自定义组件
+ *
+ * @author CaiAoLin
+ * @date 2017/11/27
+ * @version
+ */
+
+// 文本输入框
+Vue.component('input-text', {
+    props: ['label', 'id', 'name', 'value', 'required', 'placeholder', 'maxlength', 'readonly', 'password', 'disabled'],
+    template: '' +
+    '<div class="form-group" :class="{ required: required }">' +
+        '<label>{{ label }}</label>' +
+        '<input :type="[ password ? \'password\' : \'text\']" :id="id" :name="name" :value="value" :placeholder="placeholder" ' +
+            ':maxlength="maxlength" :readonly="readonly" :disabled="disabled" class="form-control"/>' +
+    '</div>'
+});
+
+// 长文本输入框
+Vue.component('input-textarea', {
+    props: ['label', 'id', 'name', 'value', 'required', 'placeholder', 'rows'],
+    template: '' +
+    '<div class="form-group row" :class="{ required: required }">' +
+        '<label class="col-sm-2 text-right">{{ label }}</label>' +
+        '<div class="col-lg-6">' +
+            '<textarea class="form-control" :id="id" :name="name" :rows="rows" :placeholder="placeholder">{{ value }}</textarea>' +
+        '</div>' +
+        '<div class="col-lg-4"></div>' +
+    '</div>'
+});
+
+// 单选框输入
+Vue.component('input-radio', {
+    props: ['label', 'id', 'name', 'value', 'required', 'items'],
+    template: '' +
+    '<div class="form-group row" :class="{ required: required }">' +
+        '<label class="col-sm-2 text-right">{{ label }}</label>' +
+        '<div class="col-lg-6">' +
+            '<label class="radio-inline" v-for="(item, index) of items">' +
+                '<input type="radio" :name="name" :value="item.value" :checked="item.value.toString() === value"> {{ item.text }} &nbsp;' +
+            '</label>' +
+        '</div>' +
+        '<div class="col-lg-4"></div>' +
+    '</div>'
+});
+
+// 下拉选择
+Vue.component('dropdown', {
+    props: ['id', 'value', 'name', 'options', 'placeholder', 'size'],
+    template: '' +
+    '<select class="form-control" :class="[ \'form-control-\' + size ]" :name="name" :id="id">' +
+        '<option value="">{{ placeholder }}</option>' +
+        '<option v-if="option !== null && option !== undefined && typeof option == \'string\'" v-for="(option, index) of options" :value="index" :selected="index.toString() === value">{{ option }}</option>' +
+        '<option v-if="option !== null && option !== undefined && option instanceof Object" v-for="(option, index) of options" :value="index" :selected="option.id.toString() === value">{{ option.name }}</option>' +
+    '</select>'
+});
+
+// 下拉框(Bootstrap组件)
+Vue.component('input-dropdown', {
+    props: ['label', 'id', 'name', 'value', 'required', 'options', 'placeholder', 'size'],
+    template: '' +
+    '<div class="form-group row" :class="{ required: required }">' +
+        '<label class="col-sm-2 col-form-label text-right">{{ label }}</label>' +
+        '<div class="col-lg-6">' +
+            '<dropdown :id="id" class="form-control" :name="name" :options="options" :placeholder="placeholder" ' +
+                ':value="value" :size="size"></dropdown>' +
+        '</div>' +
+        '<div class="col-lg-4"></div>' +
+    '</div>'
+});

+ 4 - 3
app/public/js/form_validate.js

@@ -11,14 +11,15 @@ $(document).ready(function() {
         messages: message === undefined ? {} : message,
         errorPlacement: function(error, element) {
             $(element).addClass('is-invalid');
-            $(element).parent().next("div.col-lg-4").append(error);
+            $(element).after(error);
         },
         errorClass: "invalid-feedback",
         errorElement: "div",
         highlight: false,
         success: function(element) {
-            $(element).parent().parent().find("input").removeClass('is-invalid');
-        }
+            $(element).prev('input').removeClass('is-invalid');
+            $(element).remove();
+        },
     });
 
 

+ 55 - 25
app/public/js/global.js

@@ -1,33 +1,33 @@
 /*全局自适应高度*/
-function autoFlashHeight(){
+function autoFlashHeight() {
     var headerHeight = $(".header").height();
     var toolsbarHeight = $(".toolsbar").height();
     var ftoolsbarHeight = $(".toolsbar-f").height();
     var bottomContentHeight = $(".bottom-content").height();
     var toolsBarHeightQ = $(".tools-bar-height-q").height();
     var toolsBarHeightD = $(".tools-bar-height-d").height();
-    $(".main-data-side-q").height($(window).height()-headerHeight-toolsbarHeight-toolsBarHeightQ-202);
-    $(".main-data-side-d").height($(window).height()-headerHeight-toolsbarHeight-toolsBarHeightD-202);
-    $(".main-data-top").height($(window).height()-headerHeight-toolsbarHeight-bottomContentHeight-1);
-    $(".main-data-full").height($(window).height()-headerHeight-toolsbarHeight-1);
-    $(".main-data-full-fl").height($(window).height()-headerHeight-toolsbarHeight-37);
-    $(".main-data-not").height($(window).height()-headerHeight-1);
-    $(".main-data-side-search").height($(window).height()-headerHeight-toolsbarHeight-64);
-    $(".side-content").height($(window).height()-headerHeight );
-    $(".poj-list").height($(window).height()-headerHeight-toolsbarHeight);
-    $(".form-view").height($(window).height()-headerHeight-ftoolsbarHeight);
-    $(".form-list").height($(window).height()-headerHeight-50 );
+    $(".main-data-side-q").height($(window).height() - headerHeight - toolsbarHeight - toolsBarHeightQ - 202);
+    $(".main-data-side-d").height($(window).height() - headerHeight - toolsbarHeight - toolsBarHeightD - 202);
+    $(".main-data-top").height($(window).height() - headerHeight - toolsbarHeight - bottomContentHeight - 1);
+    $(".main-data-full").height($(window).height() - headerHeight - toolsbarHeight - 1);
+    $(".main-data-full-fl").height($(window).height() - headerHeight - toolsbarHeight - 37);
+    $(".main-data-not").height($(window).height() - headerHeight - 1);
+    $(".main-data-side-search").height($(window).height() - headerHeight - toolsbarHeight - 64);
+    $(".side-content").height($(window).height() - headerHeight);
+    $(".poj-list").height($(window).height() - headerHeight - toolsbarHeight);
+    $(".form-view").height($(window).height() - headerHeight - ftoolsbarHeight);
+    $(".form-list").height($(window).height() - headerHeight - 50);
 };
 $(window).resize(autoFlashHeight);
 /*全局自适应高度结束*/
-$(function(){
-/*侧滑*/
-$(".open-sidebar").click(function(){
-    $(".slide-sidebar").animate({width:"800"}).addClass("open");
-});
-$("body").click(function(event){
+$(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')) {
+        if (!$(event.target).is('a')) {
             var elem = event.target || e.srcElement;
             while (elem) { //循环判断至跟节点,防止点击的是div子元素
                 if (elem.className == "open-sidebar" || elem.className == 'slide-sidebar open') {
@@ -35,13 +35,43 @@ $("body").click(function(event){
                 }
                 elem = elem.parentNode;
             }
-            $(".slide-sidebar").animate({width:"0"}).removeClass("open")// 关闭处理
+            $(".slide-sidebar").animate({width: "0"}).removeClass("open")// 关闭处理
         }
 
     });
-/*侧滑*/
-/*工具提示*/
-$(function () {
-  $('[data-toggle="tooltip"]').tooltip()
-});
+    /*侧滑*/
+    /*工具提示*/
+    $(function () {
+        $('[data-toggle="tooltip"]').tooltip()
+    });
+
+    // 数据提交
+    $("#submit-form").click(function() {
+        $("#save-form").submit();
+    });
+
 });
+
+/**
+ * 提示框
+ *
+ * @param string message
+ * @param string type
+ * @param string icon
+ * @return void
+ */
+function toast(message, type, icon)
+{
+    var toast = $(".toast");
+    toast.addClass(type);
+    toast.children('.message').html(message);
+    var iconClass = 'fa-' + icon;
+    toast.children('.icon').addClass(iconClass);
+    toast.fadeIn(500);
+
+    setTimeout(function() {
+        toast.fadeOut('fast');
+        toast.children('.message').text('');
+        toast.children('.icon').removeClass(iconClass);
+    }, 3000);
+}

文件差异内容过多而无法显示
+ 10517 - 0
app/public/js/vue/vue.js


文件差异内容过多而无法显示
+ 6 - 0
app/public/js/vue/vue.min.js


+ 4 - 0
app/router.js

@@ -17,4 +17,8 @@ module.exports = app => {
 
     // 控制面板相关
     app.get('/dashboard', sessionAuth, 'dashboardController.index');
+
+    // 项目相关
+    app.get('/project/info', sessionAuth, 'projectController.info');
+    app.post('/project/info', sessionAuth, 'projectController.saveInfo');
 };

+ 29 - 0
app/service/manager.js

@@ -0,0 +1,29 @@
+'use strict';
+
+/**
+ * 后台管理员数据模型
+ *
+ * @author CaiAoLin
+ * @date 2017/11/29
+ * @version
+ */
+
+module.exports = app => {
+
+    class Manager extends app.BaseService {
+
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'manager';
+        }
+    }
+
+    return Manager;
+};
+

+ 20 - 0
app/service/project.js

@@ -30,6 +30,26 @@ module.exports = app => {
         }
 
         /**
+         * 数据规则
+         *
+         * @param {String} scene - 场景
+         * @return {Object} - 返回数据规则
+         */
+        rule(scene) {
+            let rule = {};
+            switch (scene) {
+                case 'saveInfo':
+                    rule = {
+                        name: { type: 'string', required: true, min: 2 },
+                    };
+                    break;
+                default:
+                    break;
+            }
+            return rule;
+        }
+
+        /**
          * 根据项目code获取项目数据
          *
          * @param {String} code - 项目code

+ 3 - 1
app/service/project_account.js

@@ -63,7 +63,6 @@ module.exports = app => {
          */
         async accountLogin(data, loginType) {
             let result = false;
-            let needToBoot = false;
             try {
                 // 验证数据
                 const scene = loginType === 1 ? 'ssoLogin' : 'login';
@@ -71,12 +70,14 @@ module.exports = app => {
                 this.ctx.validate(rule, data);
 
                 let accountData = {};
+                let projectId = 0;
                 if (loginType === 2) {
                     // 查找项目数据
                     const projectData = await this.ctx.service.project.getProjectByCode(data.project.toString());
                     if (projectData === null) {
                         throw '不存在项目数据';
                     }
+                    projectId = projectData.id;
 
                     // 查找对应数据
                     accountData = await this.db.get(this.tableName, {
@@ -127,6 +128,7 @@ module.exports = app => {
                         loginTime: currentTime,
                         sessionToken,
                         loginType,
+                        projectId,
                     };
                 }
             } catch (error) {

+ 18 - 11
app/view/dashboard/index.ejs

@@ -1,12 +1,19 @@
-<div class="c-header mt-3">
-    <h4>需要你处理</h4>
-</div>
-<div class="c-body">
-    内容
-</div>
-<div class="c-header mt-4">
-    <h4>需要你关注</h4>
-</div>
-<div class="c-body">
-    内容
+<div class="panel-content">
+    <div class="panel-title fluid">
+        <div class="title-main"><h2>主页</h2></div>
+    </div>
+    <div class="content-wrap">
+        <div class="c-header mt-3">
+            <h4>需要你处理</h4>
+        </div>
+        <div class="c-body">
+            内容
+        </div>
+        <div class="c-header mt-4">
+            <h4>需要你关注</h4>
+        </div>
+        <div class="c-body">
+            内容
+        </div>
+    </div>
 </div>

+ 20 - 0
app/view/layout/body_header.ejs

@@ -0,0 +1,20 @@
+<div class="panel-sidebar">
+    <div class="panel-title">
+        <div class="title-bar">
+            <h2><%= ctx.menu.name === undefined ? '' : ctx.menu.name %></h2>
+        </div>
+    </div>
+    <div class="scrollbar-auto">
+        <div class="nav-box">
+            <% if (ctx.menu.children !== undefined) { %>
+            <ul class="nav-list list-unstyled">
+                <% for (const index in ctx.menu.children) { %>
+                <li <% if (ctx.actionName === index) { %>class="active"<% } %>>
+                    <a href="settings-poj.html"><span><%= ctx.menu.children[index].name %></span></a>
+                </li>
+                <% } %>
+            </ul>
+            <% } %>
+        </div>
+    </div>
+</div>

+ 42 - 27
app/view/layout/layout.ejs

@@ -5,28 +5,38 @@
     <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>
+    <title><%= ctx.menu.name === undefined ? '主页' : ctx.menu.name %>-计量支付</title>
     <link rel="stylesheet" href="/public/css/bootstrap/bootstrap.min.css">
     <link rel="stylesheet" href="/public/css/main.css">
     <link rel="stylesheet" href="/public/css/font-awesome/font-awesome.min.css">
+    <!-- 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/popper/popper.min.js"></script>
+    <script src="/public/js/bootstrap/bootstrap.min.js"></script>
+    <script src="/public/js/global.js"></script>
+    <script src="/public/js/vue/vue.js"></script>
+    <script src="/public/js/component/input.js"></script>
 </head>
 
 <body>
 <div class="header">
     <h1 class="logo"><a>主页-纵横变更管理系统</a></h1>
-    <!-- <div class="poj-name">
-      <span class="name">项目A</span>
-      <div class="btn-group">
-        <a class=" btn" data-toggle="dropdown" >
-          <span class="fa fa-caret-down" data-toggle="tooltip" data-placement="bottom" title="切换项目"></span>
-        </a>
-        <div class="dropdown-menu">
-         <a href="#" class="dropdown-item">项目B</a>
-         <a href="#" class="dropdown-item">项目C</a>
-         <a href="#" class="dropdown-item">项目D</a>
-       </div>
-     </div><a href="settings-poj.html" class="btn" data-toggle="tooltip" data-placement="bottom" title="项目设置"><i class="fa fa-cogs"></i></a>
-    </div> -->
+    <div class="poj-name">
+        <span class="name">项目A</span>
+        <div class="btn-group">
+            <a class=" btn" data-toggle="dropdown">
+                <span class="fa fa-caret-down" data-toggle="tooltip" data-placement="bottom" title="切换项目"></span>
+            </a>
+            <div class="dropdown-menu">
+                <a href="#" class="dropdown-item">项目B</a>
+                <a href="#" class="dropdown-item">项目C</a>
+                <a href="#" class="dropdown-item">项目D</a>
+            </div>
+        </div>
+        <a href="/project/info" class="btn" data-toggle="tooltip" data-placement="bottom" title="项目设置"><i
+                    class="fa fa-cogs"></i></a>
+    </div>
     <div class="header-box">
         <div class="header-nav"></div>
         <div class="header-user pull-right">
@@ -70,21 +80,26 @@
         </div>
     </div>
     <div class="main-panel">
-        <div class="panel-content">
-            <div class="panel-title fluid">
-                <div class="title-main"><h2>主页</h2></div>
-            </div>
-            <div class="content-wrap">
-                <%- content %>
-            </div>
-        </div>
+        <%- content %>
     </div>
 </div>
-<!-- JS. -->
-<script src="/public/js/jquery/jquery-3.2.1.min.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>
+<div class="toast">
+    <i class="icon fa"></i>
+    <span class="message"></span>
+</div>
+<script type="text/javascript">
+    let toastInfo = '<%- message %>';
+    try {
+        toastInfo = toastInfo !== '' && toastInfo !== 'null' ? JSON.parse(toastInfo) : '';
+    } catch (error) {
+        toastInfo = '';
+    }
+
+    if (toastInfo !== '') {
+        toast(toastInfo.message, toastInfo.type, toastInfo.icon);
+    }
+
+</script>
 </body>
 
 </html>

+ 56 - 0
app/view/project/info.ejs

@@ -0,0 +1,56 @@
+<% include ../layout/body_header.ejs %>
+<div class="panel-content">
+    <div class="panel-title">
+        <div class="title-main">
+            <h2><%= ctx.menu.children[ctx.actionName].name %>
+                <a href="javascript:void(0);" id="submit-form" class="btn btn-primary btn-sm pull-right">保存修改</a>
+            </h2>
+        </div>
+    </div>
+    <div class="content-wrap">
+        <div class="c-body">
+            <div class="row">
+                <div class="col-7">
+                    <form id="save-form" action="" method="post">
+                        <input-text value="<%= projectData.code %>" name="code" readonly="readonly" label="项目编号"></input-text>
+
+                        <input-text value="<%= projectData.name %>" name="name" label="项目名称"></input-text>
+
+                        <input-text value="<%= projectData.user_account %>" name="manager" readonly="readonly" label="管理员"></input-text>
+
+                        <div class="form-group">
+                            <label>销售负责人</label>
+                            <div class="card w-50">
+                                <div class="card-body">
+                                    <h4 class="card-title"><%= salesmanData.real_name %></h4>
+                                    <h6 class="card-subtitle mb-2 text-muted"><%= officeList[salesmanData.office] !== undefined ? officeList[salesmanData.office] : '' %></h6>
+                                </div>
+                                <ul class="list-group list-group-flush">
+                                    <li class="list-group-item" data-toggle="tooltip" data-placement="bottom" title="腾讯QQ"><i class="fa fa-qq"></i> 914630468</li>
+                                    <li class="list-group-item" data-toggle="tooltip" data-placement="bottom" title="手机号码"><i class="fa fa-tablet"></i> <%= salesmanData.telephone %></li>
+                                    <li class="list-group-item" data-toggle="tooltip" data-placement="bottom" title="固定电话"><i class="fa fa-phone"></i> 0756-3850891</li>
+                                </ul>
+                            </div>
+                        </div>
+                        
+                        <input-text value="<%= moment(projectData.create_time * 1000).format('YYYY-MM-DD HH:mm:ss') %>"
+                            label="创建时间" readonly="readonly" name="create_time"></input-text>
+                        <input type="hidden" name="_csrf" value="<%= ctx.csrf %>" />
+                    </form>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+<script type="text/javascript">
+    let rule = '<%- rule %>';
+    rule = JSON.parse(rule);
+
+    let message = {
+    };
+    new Vue({
+        el: '#save-form',
+    });
+</script>
+<script src="/public/js/form_validate.js"></script>
+<script src="/public/js/validate.extend.js"></script>

+ 31 - 0
config/menu.js

@@ -0,0 +1,31 @@
+'use strict';
+
+/**
+ * 前台菜单配置
+ *
+ * @author CaiAoLin
+ * @date 2017/11/29
+ * @version
+ */
+
+const menu = {
+    project: {
+        name: '项目设置',
+        children: {
+            info: {
+                name: '项目信息',
+                url: '',
+            },
+            accountSetting: {
+                name: '账号设置',
+                url: '',
+            },
+            approvalSetting: {
+                name: '审批设置',
+                url: '',
+            },
+        },
+    },
+};
+
+module.exports = menu;