Mercedes-admin后台实训项目

项目介绍

本项目为奔驰汽车的 CRM 中的销售机会信息管理。奔驰汽车和 4A 广告公司合作做出各类精良的落地页并在各个社交、媒体平台中进行投放。需要一套承接这类落地页收集回来的用户信息,并进行跟踪、统计、反馈的管理系统。通过数据反馈出,哪个落地页有效,哪个渠道获客最多,哪个销售转化最强。

项目主要

使用 Node.js 的 Express 框架完成用户数据的增删改查、及角色的设置。收集落地页提交的用户信息,管理员进行分配给销售,销售对客户进行跟踪。项目主要包含以下几个模块:

  1. 前台
  2. 落地页
  3. 后台
  4. 后台登录
  5. 用户管理 1. 用户列表 2. 用户新增 3. 用户修改
  6. 线索管理 1. 线索列表 2. 线索跟踪

第一天任务实践笔记

任务一: 环境搭建 主要通过 express-generator 快速搭建 Web 服务框架。

任务二:数据库设计 主要通过产品原型设计出数据库表结构。

任务三:使用knex 增删改查数据库


环境搭建

环境搭建在桌面打开终端使用express Mercedes-admin的指令生产项目配置模版引擎

**nunjucks**是Mozilla开发的一个纯JavaScript编写的模板引擎,既可以用在Node环境下,又可以运行在浏览器端。

安装 $ npm install nunjucks

app.js中引入替换掉原有的模版引擎

// 引入 nunjucks
var nunjucks = require('nunjucks');

...

// 视图模版设置
// 1. 设置视图模版后缀修改为 tpl 文件
// 2. 添加 nunjucks 在 express 中的自动配置
// 3. 注释 设置 views 代码,在 nunjucks 自动配置中有设置
// app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'tpl');
nunjucks.configure('views', {
  autoescape: true,
  express: app,
  watch: true
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

Layout.tpl模版

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>{{title}}</title>
    {% block css %}
    {% endblock %}
</head>
<body>
    {% block content %}
    {% endblock %}

    {% block js %}
    {% endblock %}
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

如何使用

{% extends './layout.tpl' %} //继承layout 模版

{% block css %} //在对应的区域写上内容
<link rel="stylesheet" href="/stylesheets/style.css">
{% endblock %}

{% block content %}
<h1>{{title}}</h1>
<p>Welcome to {{title}} with nunjucks!</p>

{% endblock %}
1
2
3
4
5
6
7
8
9
10
11

运行项目npm start 地址:http://localhost:3000/

数据库的搭建

我使用的是sequelpro

打开软件connect进入制表

Name:127.0.0.1
Host:127.0.0.1
Username:root
password:
DataBase:optional
Port:3306
1
2
3
4
5
6

点击Choose Database >> 选择 Add Database 创建Mercedes-admin

建立三张表分别为clue,clue_log,user

User:放置用户管理主要销售和管理人员的信息进行增删改查

Clue_log:销售记录主要为销售更具分配的销售线索进行定期跟踪和记录,记录下每天和用户接触的内容、反馈和必要点

Clue:销售线索主要为落地页提交进来的用户信息,管理员更具销售信息分配给各个销售,销售标记销售线索的状态和备注信息

# ************************************************************
# Sequel Pro SQL dump
# Version 4541
#
# http://www.sequelpro.com/
# https://github.com/sequelpro/sequelpro
#
# Host: 127.0.0.1 (MySQL 5.7.25)
# Database: Mercedes-admin
# Generation Time: 2019-07-20 04:06:54 +0000
# ************************************************************


/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;


# Dump of table clue
# ------------------------------------------------------------

DROP TABLE IF EXISTS `clue`;

CREATE TABLE `clue` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `phone` int(255) DEFAULT NULL,
  `name` text,
  `utm` text,
  `created_time` timestamp NULL DEFAULT NULL,
  `statis` int(11) DEFAULT NULL,
  `remark` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

LOCK TABLES `clue` WRITE;
/*!40000 ALTER TABLE `clue` DISABLE KEYS */;

INSERT INTO `clue` (`id`, `phone`, `name`, `utm`, `created_time`, `statis`, `remark`)
VALUES
	(1,12,'12','','2019-07-19 15:42:16',NULL,NULL);

/*!40000 ALTER TABLE `clue` ENABLE KEYS */;
UNLOCK TABLES;


# Dump of table clue_log
# ------------------------------------------------------------

DROP TABLE IF EXISTS `clue_log`;

CREATE TABLE `clue_log` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `clue_id` int(11) DEFAULT NULL,
  `content` text,
  `created_time` timestamp NULL DEFAULT NULL,
  `is_deleted` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


# Dump of table user
# ------------------------------------------------------------

DROP TABLE IF EXISTS `user`;

CREATE TABLE `user` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` text,
  `phone` int(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  `role` text,
  `create_time` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

LOCK TABLES `user` WRITE;
/*!40000 ALTER TABLE `user` DISABLE KEYS */;

INSERT INTO `user` (`id`, `name`, `phone`, `password`, `role`, `create_time`)
VALUES
	(12,'鹅厂大牛',12345678,'12345678','2','2019-07-18 17:45:19'),
	(13,'123',123,'123','1','2019-07-18 17:45:19'),
	(14,'123',12,'323123','2','2019-07-18 21:59:06'),
	(15,'管理',1234,'12312312312','1','2019-07-19 10:54:07');

/*!40000 ALTER TABLE `user` ENABLE KEYS */;
UNLOCK TABLES;



/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101

Knex的使用

Knex可以在Node.JS和浏览器中用作SQL查询构建器,Knex的主要目标环境是Node.js,您需要安装knex库,然后安装相应的数据库

npm install knex --save
npm install mysql
1
2

初始化

knex模块本身就是一个函数,它接受Knex的配置对象,接受一些参数。该client参数是必需的,用于确定将与库一起使用的客户端适配器

根目录下新建config.js

const configs = {
    mysql: {
      host: '127.0.0.1',
      port: '3306',
      user: 'root',
      password: '',
      database: 'Mercedes-admin'
    }
  }
  
  module.exports = configs
1
2
3
4
5
6
7
8
9
10
11

新建model/knex.js

// 引用配置文件
const configs = require('../config');
// 把配置文件中的信息,设置在初始化配置中
module.exports = require('knex')({
  client: 'mysql',
  connection: {
    host: configs.mysql.host,
    port: configs.mysql.port,
    user: configs.mysql.user,
    password: configs.mysql.password,
    database: configs.mysql.database
  }
})
1
2
3
4
5
6
7
8
9
10
11
12
13

第二天任务实践笔记

任务四:模版配置 主要通过 Nunjucks 和 router 配置生成各个页面及访问路径。

任务五:页面样式 主要通过 HTML 、CSS 完成所有页面的结构与样式。

任务六:用户管理 主要通过 knex.js 连接 MySQL 实现用户数据的增删改查。


模版配置

修改routes下原有的user.js文件为api.js,同时需要在app.js中把原有的导入和使用修改

var apiRouter = require('./routes/api');
....
app.use('/api', apiRouter);
1
2
3

Index.js主要放置页面路由

以下列举格式

roter.get('/页面地址',fucntion(req,res,next){
	res.render('admin/user')
})
1
2
3

配置页面样式结构

新建以下页面文件

view
	-admin
		-login.tpl
		-user.tpl
		-clue.tpl
		-clue_log.tpl
		-user_created.tpl
		-user_edit.tpl
	-index.tpl
	-layout.tpl
	-error.tpl
	-admin_layout.tpl
1
2
3
4
5
6
7
8
9
10
11
12

配置好的页面 https://github.com/ragnar-document/Mercedes-admin/tree/master/views

页面的数据通过routes/index.js发送

 res.render('admin/user.tpl',res.locals)
1

方法render(view, model)接受两个参数第一个放置视图,model放置数据,在JavaScript中,它就是一个简单的Object。render函数返回一个字符串,就是模板的输出。

用户管理

在models文件中放置knex文件在第一天配置数据库时顺便先给配置上了

文件结构

models
	- knex.js
	- base.js		//配置查询器
	- user.js		//定义用户模型并基础基础模型/定义参数默认值
	-	clue.js
	-	log.js
1
2
3
4
5
6

Base对数据库查询方法进行封装

//使用knex
const knex = require('./knex.js');

//构造类函数
class Base {
  constructor(props){ //接收一个函数props
    this.table = props; //设置表
  }
}

all(){
  return knex(this.table).select();
  //创建select查询,获取查询的可选列数组,如果在构建查询时没有指定列,则默认为*。select调用的响应将使用从数据库中选择的对象数组解析。
}

select(params){
  return knex(this.table).select().where(params);
  //接收params的数据查询数据库中对应的数据
}

insert(params){
  return knex(this.table).insert(params);
  //创建一个插入查询,将要插入到行中的属性的哈希值或插入数组作为单个插入命令执行。
}

update(id,params){
  return knex(this.table).where('id','=',id).update(params);
  //查询是否是对应id内容是就更新
  //创建更新查询,根据其他查询约束更新属性哈希值或键/值对。如果传递返回的数组,例如['id','title'],则它会解析promise /使用包含指定列的所有更新行的数组来完成回调。
}

delete(id){
  return knex(this.table).where('id','=',id).del()
  //此方法根据查询中指定的其他条件删除一行或多行。
}

count(){
  return knex(this.table).where(params).conunt('id as sum')
  //输出
  //select count(`id`) as `sum` from `this.table`
}


module.exports = Base 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

基础格式

// 引用基础模型
const Base = require('./base.js');

// 定义用户模型并基础基础模型
class User extends Base {
  // 定义参数默认值为 users 表
  constructor(props = 'user') {
    super(props);
  }
}

module.exports = new User()
1
2
3
4
5
6
7
8
9
10
11
12

第三天任务实践笔记

任务七:登录与退出 主要通过 cookie 实现用户登录状态的管理。

任务八:线索记录 主要通过落地页发送的用户数据在线索管理列表中展示。


登录与退出

新建加密文件utils/authCode.js用于cookie的加密和解密注意不要吧算法文件上传

/**
 * 加密解密
 */

const crypto = require('crypto');
const key = Buffer.from('jikexueyuan#$123', 'utf8');
const iv = Buffer.from('FnJL7EDzjqWjcaY9', 'utf8');

const authcode = function (str, operation){
  //没有就解密有就加密
    operation ? operation : 'DECODE';
    if (operation == 'DECODE') {
        let src = '';
        let cipher = crypto.createDecipheriv('aes-128-cbc', key, iv);
        src += cipher.update(str, 'hex', 'utf8');
        src += cipher.final('utf8');
        return src;
    }else {
        let sign = '';
        let cipher = crypto.createCipheriv('aes-128-cbc', key, iv);
        sign += cipher.update(str, 'utf8', 'hex');
        sign += cipher.final('hex');
        return sign;
    }
}

module.exports = authcode;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

在api.js需要调用登陆权限的方法和页面渲染规则判断输入的用户和密码是否与数据一致

通过调用models层的user.js使用查找数据对比数据是否一致

通过调用加密算法判断是否加密或解密

新建/controllers/auth.js

const User = require('./../models/user.js');
const authCodeFunc = require('./../utils/authCod.js');

const authController = {
  login: async function(req,res,next){
    let phone = req.body.phone;
    let password = req.body.password;
    
    if(!phone || !password){
      alert('请填写完整信息');
      return
    } 
    
  	try{
     const users = await User.select({phoen,password}) ;
     const user = users[0];
     if(user){
       //组合加密
       let auth_Code = phone +'\t' + password +'\t' + user.id + '\t' + user.role;
       auth_Code = authCodeFunc(auth_Code,'ENCODE');
       //加密繁殖在cookie中
       res.cookie('ac',auth_Code, { maxAge: 24* 60 * 60 * 1000, httpOnly: true });
       res.json({
         code:200,
         message:'登陆成功'
       })
     }else{
       res.json({
         code:0,
         
         message:'没有该用户'
       })
     }
    }catch(err){
      res.json({
        code:0,
        message:'系统问题'
      })
    } 
  },
  // 渲染登录页面的模版
  renderLogin:async function(req,res,next){
    // 如果用户已经登录,重定向到用户管理页面
    if(res.locals.isLogin){
      res.redirect('/admin/clue')
      return
    }
    res.render('admin/login')
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

需要在routes/api.js中引入Login方法

var authController = require('./../controllers/auth.js');

...
router.post('/login' , authController.login);
1
2
3
4

在routes/index.js中引入渲染的方法

var authController = require('./../controllers/auth.js');

...
router.get('/admin/login', authController.renderLogin);
1
2
3
4

为Login页也写上js脚本发送ajax请求

const PAGE = {
  init:funciton(){
  	this.bind();
	},
  bind:funciton(){
    $('#userSumbit').bind('click',this.handleSumbit);
  },
  handleSumbit:funciton(){
    let phone = $('#userPhone').val();
    let password = $('#userPassword').val();
    
    if(!phone || !paswword){alert('缺少参数‘)return}
		$.ajax({
    	url:'api/login',
			data:{phone,password},
      type:'POST',
      beforeSend:function(){
        //禁止节点
        $("#userSubmit").attr("disabled",true);
      },
      success:function(){
        if(data.code === 200){
          alert('登录成功!')
          location.href = '/admin/user'
        }else{
          alert(data.message)
        }
      },
      error:function(error){
        console.log(error)
      },
      complete:function(){
       $("#userSubmit").attr("disabled",false);
      }
		})
  }
}
PAGE.init();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

新建过滤中间件,filters/index.js,filters/loginFilter.js,filters/initFilter.js。filters/index.js 为主文件分别引用 filters/loginFilter.js 及 filters/initFilter.js,分别用于设置用户信息和全局信息。

文件参考:https://github.com/ragnar-document/Mercedes-admin/tree/master/filters

在启动文件 app.js 中引用文件中引用 filters ,要在定义路由之前定义。

var filters = require('./filters/index')

...

filters(app);
app.use('/', indexRouter);
app.use('/api', apiRouter);
1
2
3
4
5
6
7

新建用户中间件,并设置判断是否登录的方法

Middleware/auth.js

const authMiddleware = {
  mustLogin: function(req,res,next){
    if(!res.locals.isLogin){
      res.redirect('/admin/login')
      return
    }
    next();
  }
}

module.exports = authMiddleware;
1
2
3
4
5
6
7
8
9
10
11

在用户管理页面相关路由中引入

线索记录

实现过程需要重数据库拿到数据进行渲染所有需要先创建models层的clue继承base的方法,在controller

建立展示页面的逻辑,然后在api和index添加controller中创建的方法

创建clue的model

const Base = require('./knex');

class Clue extends Base {
  constructor(props = 'clue'){
    super(props)
  }
}

module.exports = new Clue()
1
2
3
4
5
6
7
8
9

创建线索 controller ,并完善其添加和线索列表页面展示的逻辑

const Clue = require('./../models/clue.js');
const { formatTime } = require('./../utils/date.js');

const userController = {
  insert: async function(req,res,next){
  	let phone = req.body.phone;
    let name = req.body.name;
    let utm = req.body.utm;
    let created_time = new Date();
    if(!name||!phone){
      res.json({
        code:0,
        message:'缺少参数'
      })
    }
    
    try{
      const clues = await Clue.insert({
        phone,name,utm,created_time
      });
      res.json({
        code:200,
        data:clues
      })
    }catch(e){
			console.log(e);
      res.json({
        code:0,
        message:'内部问题'
      })
    }
	},
  show:async function(req,res,next){
    try{
      const clues = await Clue.all();
      res.locals.clues = clues.map((data)=>{	//渲染模版需要的数据
        data.created_time_display = formatTime(data.created_time);
        return data
      })
     res.render('admin/clue.tpl',res.locals)//渲染clue页
    }catch(e){
      res.locals.error = e;
      res.render('error',res.locals);
    }
  }
}

module.exports = new Clue();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

/views/index.tpl 中引入**/public/javascripts/index.js**

https://github.com/ragnar-document/Mercedes-admin/blob/master/public/javascripts/index.js

配置线索列表模版

https://github.com/ragnar-document/Mercedes-admin/blob/master/views/admin/clue.tpl

第四天任务实践笔记

任务九:线索跟踪 主要通过对应的线索信息进行编辑和提交记录信息。

任务十:销售展示 主要通过权限的区分为管理员与销售展示不同的内容。


线索跟踪

在线索列表页中每一条记录都有跟踪按钮对信息进行记录和更改,点击时跳到对应id编辑页,在clue_log中获取到页面ID通过knex查询表对应ID的用户信息对页面作出渲染。信息编辑通过获取更改的数据判断是否有修改值通过ajax请求put到数据表中添加信息则是通过post

 log: async function(req,res,next) {
    try{
      //获取页面id
      const id = req.params.id;
      const clues = await Clue.select({ id })
      //获取表中信息
      const logs = await ClueLog.select({ clue_id : id})
      //获取管理员列表
      const users = await User.select({ role: 2 })
      //保存到res.locals
      res.locals.users = users.map(data => {
        return {
          id: data.id,
          name: data.name
        }
      });
      //把获取到的数据存入locals中
      res.locals.clue = clues[0]
      res.locals.clue.created_time_display = formatTime(res.locals.clue.created_time);
      res.locals.logs = logs.map((data)=>{
        data.created_time_display = formatTime(data.created_time);
        return data
      });
      //渲染到页面中
      res.render('admin/clue_log.tpl',res.locals)
    }catch(e){
      res.locals.error = e;
      res.render('error',res.locals);
    }
  }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

获取页面ID >> 通过id获取表中信息 >> 把获得的信息存入locals中 >> 发送渲染到页面

把页面渲染出来后接着就做页面逻辑

通过点击按键获取修改的内容接着判断是否缺少参数如何通过ajax发送请求

 $.ajax({
    url: '/api/clue/' + id,
    data: { remark, status, user_id }, //发送修改的数据
    type: 'PUT',	//通过put请求
    beforeSend: function() {	//点击完关上按钮
      $("#clueSubmit").attr("disabled",true);
    },
    success: function(data) { //成功后的反应
      if(data.code === 200){
        alert('编辑成功!')
      }else{
        alert(data.message)
      }
    },
    error: function(err) {	//失败后的反应
      console.log(err)
    },
    complete: function() {	//响应结束后打开按钮
      $("#clueSubmit").attr("disabled",false);
    }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

同样添加数据也是相似的使用post请求发送数据,添加成功后使用 location.reload();刷新页面

接下来是在api.js中请求数据库

获取请求体中的数据判断是否获取到值,通过trycatch捕获成功和失败的值返回一个状态码

update: async function(req,res,next) {
    let status = req.body.status;    
    let remark = req.body.remark;
    let id = req.params.id;
    let user_id = req.body.user_id;
    if(!status || !remark){
      res.json({ code: 0, message: '缺少必要参数' });
      return
    }

    try{
      const clue = await Clue.update( id ,{ 
        status,user_id,remark
      });
      res.json({ 
        code: 200, 
        data: clue
      })
    }catch(e){
      console.log(e)
      res.json({ 
        code: 0,
        message: '内部错误'
      })
    }
  },
    
  addLog:async function(req,res,next){
    let content = req.body.content;
    let created_time = new Date();
    let clue_id = req.params.id;

    
    if (!content) {
      res.json({
        code:0,
        message:'缺少参数'
      })
    }

    try {
      const clue = await ClueLog.insert({
        content,created_time,clue_id
      });
      res.json({
        code:200,
        data:clue
      })  
    } catch (error) {
      console.log(error);
      res.json({code:0,message:'内部错误'})
    }
  },
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

销售展示

由于销售和线索是分开两张表所以需要连表查询

加入 -.join(table, first, [operator], second)
1

连接构建器可用于指定表之间的连接,第一个参数是连接表,后三个参数分别是第一个连接列,连接操作符和第二个连接列。

实例

knex('users')
  .join('contacts', 'users.id', '=', 'contacts.user_id')
  .select('users.id', 'contacts.phone')
1
2
3

models/Clue.js

class Clue extends Base{
  constructor(props = 'clue'){
    super(props);
  }
  
  //声明一个方法同时接收参数
  joinUser(params={}){
    return knex('clue').join('user','clue.user_id','=','user_id')
    .select(
      'clue.id',
      'clue.name',
      'clue.phone',
      'clue.utm',
      'clue.status',
      'clue.created_time',
      {'sales_name':'user.name'},
    ).where(params)
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

Routes/index.js

连接好表以后需要到渲染页面的index文件中使用clue中的方法进行取值

 show: async function(req,res,next){
    try{
      // const clues = await Clue.all();
      const role = res.locals.userInfo.role;
      const user_id = res.locals.userInfo.id;
      // console.log(role,user_id);
      let params = {};
      //判断是否是管理人员如果是就传入到params中
      if (role == 2) {
        params.user_id = user_id
      }
      
      //通过获取到的用户id传入到model层进行查询取值
      const clues = await Clue.joinUser(params);
      console.log(clues)
      //map循环取到的值返回一个新数组存入res.locals中
      
      res.locals.clues = clues.map((data)=>{
        data.created_time_display = formatTime(data.created_time);
        // console.log(data)
        return data
      });
      res.render('admin/clue.tpl',res.locals)
    }catch(e){
      res.locals.error = e;
      res.render('error',res.locals);
    }
  },
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

结束总结

数据库类型需要设置好否则无法插入值会报错,使用knex连接数据使用通过base文件设置公共样式文件,因为未做分离所以代码看上去显得非常臃肿不美观难以维护,在下次修改对应用层controller进行分离。一般问题都处在传值上面出问题

常用代码片段

  $.ajax({
      url:'/地址',
      data: { 传入数据 },
      type: 'POST,PUT,DELETE,GET....等',
      beforeSend: function() {
      $("#logSubmit").attr("disabled",true);
      },
      success: function(data) {
      if(data.code === 200){
          alert('添加成功!')
          //添加后重新加载网页
          location.reload();
      }else{
          alert(data.message)
      }
      },
      error: function(err) {
  	    console.log(err)
      },
      complete: function() {
      $("#logSubmit").attr("disabled",false);
      }
  })
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

组件分离管理

按照分类我们需要把卸载router/index和api中的方法抽离到一个专门的文件controllers文件中进行调用使用

因为方法中都使用到model层的查询方法所以需要注意调用,把登陆管理的放在中间件文件单独存放