后端处理

基础流程

  1. $ npx be_app -e 快速构建项目骨架
  2. $ yarn 安装依赖包
  3. 修改 package.json
{"name": "be-app","version": "0.0.0","private": true,"scripts": {"start": "nodemon ./bin/www" //修改定位},"dependencies": {"cookie-parser": "~1.4.4","debug": "~2.6.9","ejs": "~2.6.1","express": "~4.16.1","http-errors": "~1.6.3","morgan": "~1.9.1"}
}
  1. routes 文件夹下面创建路由文件 例如 shop.js
var express = require("express");
var router = express.Router();router.route("/shop").post((req, res, next) => {res.send("zhanghaoyu");
});
module.exports = router;
  1. 在 app.js 中进行引入
var createError = require("http-errors");
var express = require("express");
var path = require("path");
var cookieParser = require("cookie-parser");
var logger = require("morgan");var indexRouter = require("./routes/index");
var usersRouter = require("./routes/users");
var shopRouter = require("./routes/shop"); //修改定位var app = express();// view engine setup
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "ejs");app.use(logger("dev"));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, "public")));app.use("/", indexRouter);
app.use("/users", usersRouter);
app.use("/", shopRouter); // 修改定位// catch 404 and forward to error handler
app.use(function(req, res, next) {next(createError(404));
});// error handler
app.use(function(err, req, res, next) {// set locals, only providing error in developmentres.locals.message = err.message;res.locals.error = req.app.get("env") === "development" ? err : {};// render the error pageres.status(err.status || 500);res.render("error");
});module.exports = app;
  1. 打开 Insomnia 软件,进行 post 请求测试
  2. 测试成功后进行下一流程

数据保存请求流程

  1. 在 insomnia 进行请求数据模拟
  2. req 中包含文件、图片等,需要运用 multer 插件

    Multer 是一个 node.js 中间件,用于处理 multipart/form-data 类型的表单数据,它主要用于上传文件。它是写在 busboy 之上非常高效。
    注意: Multer 不会处理任何非 multipart/form-data 类型的表单数据。

  3. 下载与安装
    1. $ yarn multer
    2. 在 需要使用的 shop.js 中引入使用
const express = require("express");const router = express.Router();const path = require("path");
const multer = require("multer");
const upload = multer({ dest: "uploads/" });router.route("/shop").post(upload.any(), (req, res, next) => {res.send("zhanghaoyu");
});
module.exports = router;
  1. upload.any() 接受一切上传的文件。文件数组将保存在 req.files。
const express = require('express');const router = express.Router();const path = require('path');
const multer = require('multer')
const upload = multer({ dest: 'uploads/' }); //数据保存地址router.route('/shop').post(upload.any(), (req, res, next) => {// 接受一切上传的文件。文件数组将保存在 req.files。res.send('zhanghaoyu')})
module.exports = router;
  1. 修改数据保存地址,通过multer的磁盘存储引擎将前端发来的文件保存在后端

磁盘存储引擎 (DiskStorage)
磁盘存储引擎可以让你控制文件的存储。

//案例说明
var storage = multer.diskStorage({destination: function (req, file, cb) {cb(null, '/tmp/my-uploads')},filename: function (req, file, cb) {cb(null, file.fieldname + '-' + Date.now())}
})var upload = multer({ storage: storage })
//shop.js
const express = require('express');const router = express.Router();const path = require('path');
//Multer 是一个 node.js 中间件,用于处理 multipart/form-data 类型的表单数据,它主要用于上传文件。
const multer = require('multer')//磁盘存储引擎 (DiskStorage)
const storage = multer.diskStorage({destination: function(req, file, cb) {cb(null, '/tmp/my-uploads')},filename: function(req, file, cb) {cb(null, file.fieldname + '-' + Date.now())}
})const upload = multer({ storage: storage }); //数据保存地址router.route('/shop').post(upload.any(), (req, res, next) => {// 接受一切上传的文件。文件数组将保存在 req.files。res.send('zhanghaoyu')})
module.exports = router;
  1. 设置文件保存地址,并进行文件数据命名
const express = require('express');const router = express.Router();const path = require('path');
//Multer 是一个 node.js 中间件,用于处理 multipart/form-data 类型的表单数据,它主要用于上传文件。
const multer = require('multer')//磁盘存储引擎 (DiskStorage)
const storage = multer.diskStorage({destination: function(req, file, cb) { //设置文件保存地址cb(null, path.join(__dirname, '../public/upload'))},filename: function(req, file, cb) { //文件数据命名// console.log("张浩雨: cb", cb)// console.log("张浩雨: req", req)console.log("张浩雨: file", file)const fileType = file.originalname.split('.').pop();cb(null, file.fieldname + '-' + Date.now() + '.' + fileType)}
})const upload = multer({ storage: storage }); //数据保存地址router.route('/shop').post(upload.any(), (req, res, next) => {// 接受一切上传的文件。文件数组将保存在 req.files。res.send('zhanghaoyu')})
module.exports = router;
  1. 需注意const storage = multer.diskStorage每保存一个文件、图片等 都将执行一次
const express = require('express');const router = express.Router();const path = require('path');
//Multer 是一个 node.js 中间件,用于处理 multipart/form-data 类型的表单数据,它主要用于上传文件。
const multer = require('multer')const imgObj = {};
//磁盘存储引擎 (DiskStorage)const storage = multer.diskStorage({destination: function(req, file, cb) { //设置文件保存地址cb(null, path.join(__dirname, '../public/upload'))},filename: function(req, file, cb) { //文件数据命名// console.log("张浩雨: cb", cb)// console.log("张浩雨: req", req)console.log("张浩雨: file", file)const fileType = file.originalname.split('.').pop(); //获取图片类型const fileName = file.fieldname + '-' + Date.now() + '.' + fileType; //拼接图片名称imgObj[file.fieldname] = fileName;cb(null, fileName)}
})
const upload = multer({ storage: storage }); //数据保存地址router.route('/shop').post(upload.any(), (req, res, next) => {// 接受一切上传的文件。文件数组将保存在 req.files。console.log("张浩雨: imgObj", imgObj)res.send('zhanghaoyu')})
module.exports = router;
  1. 将imgObj 合并到 req.body 中
const express = require('express');const router = express.Router();const path = require('path');
//Multer 是一个 node.js 中间件,用于处理 multipart/form-data 类型的表单数据,它主要用于上传文件。
const multer = require('multer')const imgObj = {};
//磁盘存储引擎 (DiskStorage)const storage = multer.diskStorage({destination: function(req, file, cb) { //设置文件保存地址cb(null, path.join(__dirname, '../public/upload'))},filename: function(req, file, cb) { //文件数据命名// console.log("张浩雨: cb", cb)// console.log("张浩雨: req", req)console.log("张浩雨: file", file)// file 只有一个值, 需要数据拼接// file { fieldname: 'shop_file',//     originalname: '生命周期master.jpg',//     encoding: '7bit',//     mimetype: 'image/jpeg' // }const fileType = file.originalname.split('.').pop(); //获取图片类型const fileName = file.fieldname + '-' + Date.now() + '.' + fileType; //拼接图片名称imgObj[file.fieldname] = fileName; //对imgObj 进行数据绑定// imgObj { shop_file: 'shop_file-1570772574597.jpg',//     shop_file_1: 'shop_file_1-1570772574602.jpg' // }req.fieldname = imgObj; //将imgObj 绑定到req 上面cb(null, fileName)}
})
const upload = multer({ storage: storage }); //数据保存地址router.route('/shop').post(upload.any(), (req, res, next) => {// 接受一切上传的文件。文件数组将保存在 req.files。console.log("张浩雨: imgObj", imgObj);// imgObj { shop_file: 'shop_file-1570772574597.jpg',//     shop_file_1: 'shop_file_1-1570772574602.jpg' // }Object.assign(req.body, req.fieldname); //合并数据console.log("张浩雨: req.body", req.body);// req.body [Object: null prototype] {//     shop_name: 'zhanghaoyu',//     shop_goods: '‘memeda’',//     shop_file: 'shop_file-1570772923436.jpg',//     shop_file_1: 'shop_file_1-1570772923440.jpg'//  }res.send('zhanghaoyu')})
module.exports = router;
  1. 接下来 在mongodb 中 进行数据库添加流程

数据库添加数据

  1. 引入db库,添加数据操作
/* index开头就表明了这个文件、文件夹的作用好处: index可以省略
*/const mongoose = require("mongoose");
const connect = require("./connect");// mongoose使用流程如下// 1. 链接数据库
connect.init();//2.创建schema骨架,定义字段
const {userSchema,shopSchema
} = require("./schema");//3.创建模型 Module// const userModel = mongoose.model( 集合名称【复数】,对应的骨架 )
const userModule = mongoose.model("users", userSchema); //一定要将集合名称写为复数
const shopModule = mongoose.model("shops", shopSchema); //一定要将集合名称写为复数const db = {shop: {add(data) {return new Promise((resolve, reject) => {// '通过数据库的查询来完成判断'// 商铺是否有重复注册 // 1. 查询数据库,将数据库中已有的店铺查询出来// 2. 然后在查询出来的店铺数据中查找是否有 前端当前注册的店铺信息   通过shop_id来判断shopModule.find({}, (error, docs) => {// console.log( docs )// 数组,数组中放着我们所有的存储的数据if (error) console.log("张浩雨: add -> error", error)const shop = new shopModule(data);const flag = docs.some(item => item.shop_id === data.shop_id);if (flag) {resolve({info: '店铺已注册',status: 0})} else {shop.save(error => {if (err) {resolve({info: '店铺注册失败',status: 2})} else {resolve({info: '店铺注册成功',status: 1})}})}});});},dele() {},modify() {},query() {}}
};
userSchema
module.exports = db;
  1. 在shop.js 中 引入并使用

需注意res.render({})基于前面的db.shop.add(data)异步操作,所以采用async-await 将异步处理为同步


const express = require('express');const router = express.Router();const path = require('path');
//Multer 是一个 node.js 中间件,用于处理 multipart/form-data 类型的表单数据,它主要用于上传文件。
const multer = require('multer');
const db = require('../db');const imgObj = {};
//磁盘存储引擎 (DiskStorage)const storage = multer.diskStorage({ //每保存一个文件、图片等 都将执行一次destination: function(req, file, cb) { //设置文件保存地址cb(null, path.join(__dirname, '../public/upload'))},filename: function(req, file, cb) { //文件数据命名// console.log("张浩雨: cb", cb)// console.log("张浩雨: req", req)// console.log("张浩雨: file", file)// file 只有一个值, 需要数据拼接// file { fieldname: 'shop_file',//     originalname: '生命周期master.jpg',//     encoding: '7bit',//     mimetype: 'image/jpeg' // }const fileType = file.originalname.split('.').pop(); //获取图片类型const fileName = file.fieldname + '-' + Date.now() + '.' + fileType; //拼接图片名称imgObj[file.fieldname] = fileName; //对imgObj 进行数据绑定// imgObj { shop_file: 'shop_file-1570772574597.jpg',//     shop_file_1: 'shop_file_1-1570772574602.jpg' // }req.fieldname = imgObj; //将imgObj 绑定到req 上面cb(null, fileName)}
})
const upload = multer({ storage: storage }); //数据保存地址router.route('/shop').post(upload.any(), async(req, res, next) => {// upload.any()接受一切上传的文件。文件数组将保存在 req.files。// console.log("张浩雨: imgObj", imgObj);// imgObj { shop_file: 'shop_file-1570772574597.jpg',//     shop_file_1: 'shop_file_1-1570772574602.jpg' // }Object.assign(req.body, req.fieldname); //合并数据console.log("张浩雨: req.body", req.body);// req.body [Object: null prototype] {//     shop_name: 'zhanghaoyu',//     shop_goods: '‘memeda’',//     shop_file: 'shop_file-1570772923436.jpg',//     shop_file_1: 'shop_file_1-1570772923440.jpg'//  }const result = await db.shop.add(data);res.render('shop', {data: JSON.stringify({info: result.info,status: result.status})})res.send('zhanghaoyu---shop--add');})
module.exports = router;
  1. 进入前端与 后端的联通流程


前端与后端的数据联通

    • <form>标签添加enctype="multipart/form-data"属性。
  1. 在form下 的所有的表单元素添加 name属性(因为提交不能没有name名称)
  2. 再进行ajax 请求数据

注意: 在 shop.ejs文件中的内容为<%- data %>

<template><article><el-row type="flex"><el-col :span="12" :offset="4"><el-form:model="shop"enctype="multipart/form-data":rules="rules"ref="shop"label-width="100px"id="shop_form"><el-form-item label="店铺名称" prop="name"><el-input v-model="shop.name" name="shop_name"></el-input></el-form-item><el-form-item label="店铺执照" prop="id"><el-input v-model="shop.id" placeholder="id" name="shop_id"></el-input></el-form-item><el-form-item label="店铺地址" prop="address"><el-autocompletev-model="state":fetch-suggestions="querySearchAsync"placeholder="请输入内容"@select="handleSelect"name="shop_address"></el-autocomplete></el-form-item><el-form-item label="联系电话" required><el-input v-model="shop.phone" name="shop_phone"></el-input></el-form-item><el-form-item label="店铺简介"><el-input v-model="shop.info" name="shop_info"></el-input></el-form-item><el-form-item label="店铺标语"><el-input v-model="shop.slogan" name="shop_slogan"></el-input></el-form-item><el-form-item label="店铺分类"><div class="block"><el-cascaderv-model="shop.category":options="options":props="{ expandTrigger: 'hover' }"@change="handleChange"clearablename="shop_categorys"></el-cascader></div></el-form-item><el-form-item label="店铺特典" prop="delivery"><div class="features" v-for="item in features" :key="item.id"><span>{{ item.text }}</span>&nbsp;&nbsp;<el-switch v-model="item.flag"></el-switch></div></el-form-item><el-form-item label="配送费" prop="deli_cost"><el-input-numbername="shop_deli_cost"v-model="shop.deli_cost"@change="handleChange":min="1":max="100"label="描述文字"></el-input-number></el-form-item><el-form-item label="起送价" prop="min_cost"><el-input-numberv-model="shop.min_cost"@change="handleChange2":min="1":max="10000"label="描述文字"name="shop_min_cost"></el-input-number></el-form-item><el-form-item label="营业时间" id="hold_time"><el-row type="flex" :gutter="20"><el-col :span="10"><el-time-selectplaceholder="起始时间"v-model="shop.start_time":picker-options="{start: '09:30',step: '00:15',end: '18:30'}"name="shop_start_time"></el-time-select></el-col><el-col :span="10"><el-time-selectplaceholder="结束时间"v-model="shop.end_time":picker-options="{start: '08:30',step: '00:15',end: '23:30',minTime: shop.start_time}"name="shop_end_time"></el-time-select></el-col></el-row></el-form-item><el-form-item label="上传店铺头像"><el-uploadclass="avatar-uploader"action="https://jsonplaceholder.typicode.com/posts/":show-file-list="true":on-success="handleAvatarSuccess"name="shop_url"><img v-if="shop_url" :src="shop_url" class="avatar" /><i v-else class="el-icon-plus avatar-uploader-icon"></i></el-upload></el-form-item><el-form-item label="上传营业执照"><el-uploadclass="avatar-uploader"action="https://jsonplaceholder.typicode.com/posts/":show-file-list="true":on-success="handleAvatarSuccess2"name="id_url"><img v-if="id_url" :src="id_url" class="avatar" /><i v-else class="el-icon-plus avatar-uploader-icon"></i></el-upload></el-form-item><el-form-item label="上传营业许可证"><el-uploadclass="avatar-uploader"action="https://jsonplaceholder.typicode.com/posts/":show-file-list="true":on-success="handleAvatarSuccess3"name="allow_url"><img v-if="allow_url" :src="allow_url" class="avatar" /><i v-else class="el-icon-plus avatar-uploader-icon"></i></el-upload></el-form-item><el-form-item label="优惠活动"></el-form-item><el-form-item><el-button type="primary" @click="submitForm('shop')">立即创建</el-button></el-form-item></el-form></el-col></el-row></article>
</template><script>
import api from '@/api';
export default {data() {return {shop: {name: "",id: "",date1: "",phone: "",date2: "",delivery: false,type: [],resource: "",desc: "",info: "",slogan: "",category: "",deli_cost: 1,min_cost: 1,start_time: "",end_time: ""},deli_cost: 1,features: [{id: 1,text: "品牌保证",flag: false},{id: 2,text: "蜂鸟专送",flag: false},{id: 3,text: "新开店铺",flag: false},{id: 4,text: "外卖保",flag: false},{id: 5,text: "准时达",flag: false},{id: 6,text: "开发票",flag: false}],rules: {name: [{ required: true, message: "请输入店铺名称", trigger: "blur" },{ min: 5, max: 15, message: "长度在 5 到 15 个字符", trigger: "blur" }],id: [{ required: true, message: "请填写店铺执照", trigger: "change" }],phone: [{ required: true,message:"请填写phone",trigger:"blur"}],type: [{type: "array",required: true,message: "请至少选择一个活动性质",trigger: "change"}],resource: [{ required: true, message: "请选择活动资源", trigger: "change" }],desc: [{ required: true, message: "请填写活动形式", trigger: "blur" }]},shop_url: "",id_url: "",allow_url: "",restaurants: [],state: "",timeout: null,value: [],options: [{value: "zhinan",label: "指南",children: [{value: "shejiyuanze",label: "设计原则",children: [{value: "yizhi",label: "一致"},{value: "fankui",label: "反馈"},{value: "xiaolv",label: "效率"},{value: "kekong",label: "可控"}]},{value: "daohang",label: "导航",children: [{value: "cexiangdaohang",label: "侧向导航"},{value: "dingbudaohang",label: "顶部导航"}]}]},{value: "zujian",label: "组件",children: [{value: "basic",label: "Basic",children: [{value: "layout",label: "Layout 布局"},{value: "color",label: "Color 色彩"},{value: "typography",label: "Typography 字体"},{value: "icon",label: "Icon 图标"},{value: "button",label: "Button 按钮"}]},{value: "form",label: "Form",children: [{value: "radio",label: "Radio 单选框"},{value: "checkbox",label: "Checkbox 多选框"},{value: "input",label: "Input 输入框"},{value: "input-number",label: "InputNumber 计数器"},{value: "select",label: "Select 选择器"},{value: "cascader",label: "Cascader 级联选择器"},{value: "switch",label: "Switch 开关"},{value: "slider",label: "Slider 滑块"},{value: "time-picker",label: "TimePicker 时间选择器"},{value: "date-picker",label: "DatePicker 日期选择器"},{value: "datetime-picker",label: "DateTimePicker 日期时间选择器"},{value: "upload",label: "Upload 上传"},{value: "rate",label: "Rate 评分"},{value: "form",label: "Form 表单"}]},{value: "data",label: "Data",children: [{value: "table",label: "Table 表格"},{value: "tag",label: "Tag 标签"},{value: "progress",label: "Progress 进度条"},{value: "tree",label: "Tree 树形控件"},{value: "pagination",label: "Pagination 分页"},{value: "badge",label: "Badge 标记"}]},{value: "notice",label: "Notice",children: [{value: "alert",label: "Alert 警告"},{value: "loading",label: "Loading 加载"},{value: "message",label: "Message 消息提示"},{value: "message-box",label: "MessageBox 弹框"},{value: "notification",label: "Notification 通知"}]},{value: "navigation",label: "Navigation",children: [{value: "menu",label: "NavMenu 导航菜单"},{value: "tabs",label: "Tabs 标签页"},{value: "breadcrumb",label: "Breadcrumb 面包屑"},{value: "dropdown",label: "Dropdown 下拉菜单"},{value: "steps",label: "Steps 步骤条"}]},{value: "others",label: "Others",children: [{value: "dialog",label: "Dialog 对话框"},{value: "tooltip",label: "Tooltip 文字提示"},{value: "popover",label: "Popover 弹出框"},{value: "card",label: "Card 卡片"},{value: "carousel",label: "Carousel 走马灯"},{value: "collapse",label: "Collapse 折叠面板"}]}]},{value: "ziyuan",label: "资源",children: [{value: "axure",label: "Axure Components"},{value: "sketch",label: "Sketch Templates"},{value: "jiaohu",label: "组件交互文档"}]}]};},methods: {submitForm(formName) {let _this = this;let form = new FormData($("#shop_form")[0]);let features = this.features.filter(item=> item.flag)form .append('shop_category',this.shop.category);  //添加店铺分类form .append('shop_features',features);  //添加商品特性this.$refs['shop'].validate(valid => {if (valid) {_this.$message.success("submit!");$.ajax({url: api.shop,type: "POST",cache: false, //不必须data: form,processData: false, //必须contentType: false, //必须success: function(data) {// data= JSON.parse(data)console.log("张浩雨: submitForm -> data", data)console.log("张浩雨: submitForm -> data", data.status)if(data.status== 1){_this.$message.success("submit!  again");}},// complete:function (data) {//   console.log(data)// }});console.log("张浩雨: submitForm -> form", form)} else {_this.$message.error("error submit!!");return false;}});},resetForm(formName) {this.$refs[formName].resetFields();},loadAll() {return [{ value: "三全鲜食(北新泾店)", address: "长宁区新渔路144号" },{value: "Hot honey 首尔炸鸡(仙霞路)",address: "上海市长宁区淞虹路661号"},{value: "新旺角茶餐厅",address: "上海市普陀区真北路988号创邑金沙谷6号楼113"},{ value: "泷千家(天山西路店)", address: "天山西路438号" },{value: "胖仙女纸杯蛋糕(上海凌空店)",address: "上海市长宁区金钟路968号1幢18号楼一层商铺18-101"},{ value: "贡茶", address: "上海市长宁区金钟路633号" },{value: "豪大大香鸡排超级奶爸",address: "上海市嘉定区曹安公路曹安路1685号"},{value: "茶芝兰(奶茶,手抓饼)",address: "上海市普陀区同普路1435号"},{ value: "十二泷町", address: "上海市北翟路1444弄81号B幢-107" },{ value: "星移浓缩咖啡", address: "上海市嘉定区新郁路817号" },{ value: "阿姨奶茶/豪大大", address: "嘉定区曹安路1611号" },{ value: "新麦甜四季甜品炸鸡", address: "嘉定区曹安公路2383弄55号" },{value: "Monica摩托主题咖啡店",address: "嘉定区江桥镇曹安公路2409号1F,2383弄62号1F"},{value: "浮生若茶(凌空soho店)",address: "上海长宁区金钟路968号9号楼地下一层"},{ value: "NONO JUICE  鲜榨果汁", address: "上海市长宁区天山西路119号" },{ value: "CoCo都可(北新泾店)", address: "上海市长宁区仙霞西路" },{value: "快乐柠檬(神州智慧店)",address: "上海市长宁区天山西路567号1层R117号店铺"},{value: "Merci Paul cafe",address: "上海市普陀区光复西路丹巴路28弄6号楼819"},{value: "猫山王(西郊百联店)",address: "上海市长宁区仙霞西路88号第一层G05-F01-1-306"},{ value: "枪会山", address: "上海市普陀区棕榈路" },{ value: "纵食", address: "元丰天山花园(东门) 双流路267号" },{ value: "钱记", address: "上海市长宁区天山西路" },{ value: "壹杯加", address: "上海市长宁区通协路" },{value: "唦哇嘀咖",address: "上海市长宁区新泾镇金钟路999号2幢(B幢)第01层第1-02A单元"},{ value: "爱茜茜里(西郊百联)", address: "长宁区仙霞西路88号1305室" },{value: "爱茜茜里(近铁广场)",address:"上海市普陀区真北路818号近铁城市广场北区地下二楼N-B2-O2-C商铺"},{value: "鲜果榨汁(金沙江路和美广店)",address: "普陀区金沙江路2239号金沙和美广场B1-10-6"},{value: "开心丽果(缤谷店)",address: "上海市长宁区威宁路天山路341号"},{ value: "超级鸡车(丰庄路店)", address: "上海市嘉定区丰庄路240号" },{ value: "妙生活果园(北新泾店)", address: "长宁区新渔路144号" },{ value: "香宜度麻辣香锅", address: "长宁区淞虹路148号" },{value: "凡仔汉堡(老真北路店)",address: "上海市普陀区老真北路160号"},{ value: "港式小铺", address: "上海市长宁区金钟路968号15楼15-105室" },{ value: "蜀香源麻辣香锅(剑河路店)", address: "剑河路443-1" },{ value: "北京饺子馆", address: "长宁区北新泾街道天山西路490-1号" },{value: "饭典*新简餐(凌空SOHO店)",address: "上海市长宁区金钟路968号9号楼地下一层9-83室"},{value: "焦耳·川式快餐(金钟路店)",address: "上海市金钟路633号地下一层甲部"},{ value: "动力鸡车", address: "长宁区仙霞西路299弄3号101B" },{ value: "浏阳蒸菜", address: "天山西路430号" },{ value: "四海游龙(天山西路店)", address: "上海市长宁区天山西路" },{value: "樱花食堂(凌空店)",address: "上海市长宁区金钟路968号15楼15-105室"},{ value: "壹分米客家传统调制米粉(天山店)", address: "天山西路428号" },{value: "福荣祥烧腊(平溪路店)",address: "上海市长宁区协和路福泉路255弄57-73号"},{value: "速记黄焖鸡米饭",address: "上海市长宁区北新泾街道金钟路180号1层01号摊位"},{ value: "红辣椒麻辣烫", address: "上海市长宁区天山西路492号" },{value: "(小杨生煎)西郊百联餐厅",address: "长宁区仙霞西路88号百联2楼"},{ value: "阳阳麻辣烫", address: "天山西路389号" },{value: "南拳妈妈龙虾盖浇饭",address: "普陀区金沙江路1699号鑫乐惠美食广场A13"}];},querySearchAsync(queryString, cb) {var restaurants = this.restaurants;var results = queryString? restaurants.filter(this.createStateFilter(queryString)): restaurants;clearTimeout(this.timeout);this.timeout = setTimeout(() => {cb(results);}, 3000 * Math.random());},createStateFilter(queryString) {return state => {return (state.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0);};},handleSelect(item) {console.log(item);},handleChange(value) {console.log(value);},handleChange2(value) {console.log(value);},handleChange(value) {console.log(value);},handleAvatarSuccess(res, file) {this.shop_url = URL.createObjectURL(file.raw);},handleAvatarSuccess2(res, file) {this.id_url = URL.createObjectURL(file.raw);},handleAvatarSuccess3(res, file) {this.allow_url = URL.createObjectURL(file.raw);}},mounted() {this.restaurants = this.loadAll();}
};
</script><style>
.features {float: left;padding: 1px 10px;
}
.el-input-number .el-input__inner {padding: 3px 10px;text-align: left;
}
.el-input-number .el-input-number__increase {right: -3px;top: 4px;
}
.el-input-number /deep/ .el-input-number__decrease {left: 105px;top: 4px;
}
#hold_time {width: 500px;
}
.el-date-editor.el-input {width: auto;
}
.avatar-uploader .el-upload {border: 1px dashed #d9d9d9;border-radius: 6px;cursor: pointer;position: relative;overflow: hidden;
}
.avatar-uploader .el-upload:hover {border-color: #409eff;
}
.avatar-uploader-icon {font-size: 28px;color: #8c939d;width: 178px;height: 178px;line-height: 178px;text-align: center;
}
.avatar {width: 178px;height: 178px;display: block;
}
.el-form-item__label {text-align-last: left;
}
</style>
  1. 对返回的数据 按照data.status 的状态码进行 判断处理,若店铺未注册,则跳转business_list 页面
<template><article><el-row type="flex"><el-col :span="12" :offset="4"><el-form:model="shop"enctype="multipart/form-data":rules="rules"ref="shop"label-width="100px"id="shop_form"><el-form-item label="店铺名称" prop="name"><el-input v-model="shop.name" name="shop_name"></el-input></el-form-item><el-form-item label="店铺执照" prop="id"><el-input v-model="shop.id" placeholder="id" name="shop_id"></el-input></el-form-item><el-form-item label="店铺地址" prop="address"><el-autocompletev-model="state":fetch-suggestions="querySearchAsync"placeholder="请输入内容"@select="handleSelect"name="shop_address"></el-autocomplete></el-form-item><el-form-item label="联系电话" required><el-input v-model="shop.phone" name="shop_phone"></el-input></el-form-item><el-form-item label="店铺简介"><el-input v-model="shop.info" name="shop_info"></el-input></el-form-item><el-form-item label="店铺标语"><el-input v-model="shop.slogan" name="shop_slogan"></el-input></el-form-item><el-form-item label="店铺分类"><div class="block"><el-cascaderv-model="shop.category":options="options":props="{ expandTrigger: 'hover' }"@change="handleChange"clearablename="shop_categorys"></el-cascader></div></el-form-item><el-form-item label="店铺特典" prop="delivery"><div class="features" v-for="item in features" :key="item.id"><span>{{ item.text }}</span>&nbsp;&nbsp;<el-switch v-model="item.flag"></el-switch></div></el-form-item><el-form-item label="配送费" prop="deli_cost"><el-input-numbername="shop_deli_cost"v-model="shop.deli_cost"@change="handleChange":min="1":max="100"label="描述文字"></el-input-number></el-form-item><el-form-item label="起送价" prop="min_cost"><el-input-numberv-model="shop.min_cost"@change="handleChange2":min="1":max="10000"label="描述文字"name="shop_min_cost"></el-input-number></el-form-item><el-form-item label="营业时间" id="hold_time"><el-row type="flex" :gutter="20"><el-col :span="10"><el-time-selectplaceholder="起始时间"v-model="shop.start_time":picker-options="{start: '09:30',step: '00:15',end: '18:30'}"name="shop_start_time"></el-time-select></el-col><el-col :span="10"><el-time-selectplaceholder="结束时间"v-model="shop.end_time":picker-options="{start: '08:30',step: '00:15',end: '23:30',minTime: shop.start_time}"name="shop_end_time"></el-time-select></el-col></el-row></el-form-item><el-form-item label="上传店铺头像"><el-uploadclass="avatar-uploader"action="https://jsonplaceholder.typicode.com/posts/":show-file-list="true":on-success="handleAvatarSuccess"name="shop_url"><img v-if="shop_url" :src="shop_url" class="avatar" /><i v-else class="el-icon-plus avatar-uploader-icon"></i></el-upload></el-form-item><el-form-item label="上传营业执照"><el-uploadclass="avatar-uploader"action="https://jsonplaceholder.typicode.com/posts/":show-file-list="true":on-success="handleAvatarSuccess2"name="id_url"><img v-if="id_url" :src="id_url" class="avatar" /><i v-else class="el-icon-plus avatar-uploader-icon"></i></el-upload></el-form-item><el-form-item label="上传营业许可证"><el-uploadclass="avatar-uploader"action="https://jsonplaceholder.typicode.com/posts/":show-file-list="true":on-success="handleAvatarSuccess3"name="allow_url"><img v-if="allow_url" :src="allow_url" class="avatar" /><i v-else class="el-icon-plus avatar-uploader-icon"></i></el-upload></el-form-item><el-form-item label="优惠活动"></el-form-item><el-form-item><el-button type="primary" @click="submitForm('shop')">立即创建</el-button></el-form-item></el-form></el-col></el-row></article>
</template><script>
import api from "@/api";
export default {data() {return {shop: {name: "",id: "",date1: "",phone: "",date2: "",delivery: false,type: [],resource: "",desc: "",info: "",slogan: "",category: "",deli_cost: 1,min_cost: 1,start_time: "",end_time: ""},deli_cost: 1,features: [{id: 1,text: "品牌保证",flag: false},{id: 2,text: "蜂鸟专送",flag: false},{id: 3,text: "新开店铺",flag: false},{id: 4,text: "外卖保",flag: false},{id: 5,text: "准时达",flag: false},{id: 6,text: "开发票",flag: false}],rules: {name: [{ required: true, message: "请输入店铺名称", trigger: "blur" },{ min: 5, max: 15, message: "长度在 5 到 15 个字符", trigger: "blur" }],id: [{ required: true, message: "请填写店铺执照", trigger: "change" }],phone: [{ required: true, message: "请填写phone", trigger: "blur" }],type: [{type: "array",required: true,message: "请至少选择一个活动性质",trigger: "change"}],resource: [{ required: true, message: "请选择活动资源", trigger: "change" }],desc: [{ required: true, message: "请填写活动形式", trigger: "blur" }]},shop_url: "",id_url: "",allow_url: "",restaurants: [],state: "",timeout: null,value: [],options: [{value: "zhinan",label: "指南",children: [{value: "shejiyuanze",label: "设计原则",children: [{value: "yizhi",label: "一致"},{value: "fankui",label: "反馈"},{value: "xiaolv",label: "效率"},{value: "kekong",label: "可控"}]},{value: "daohang",label: "导航",children: [{value: "cexiangdaohang",label: "侧向导航"},{value: "dingbudaohang",label: "顶部导航"}]}]},{value: "zujian",label: "组件",children: [{value: "basic",label: "Basic",children: [{value: "layout",label: "Layout 布局"},{value: "color",label: "Color 色彩"},{value: "typography",label: "Typography 字体"},{value: "icon",label: "Icon 图标"},{value: "button",label: "Button 按钮"}]},{value: "form",label: "Form",children: [{value: "radio",label: "Radio 单选框"},{value: "checkbox",label: "Checkbox 多选框"},{value: "input",label: "Input 输入框"},{value: "input-number",label: "InputNumber 计数器"},{value: "select",label: "Select 选择器"},{value: "cascader",label: "Cascader 级联选择器"},{value: "switch",label: "Switch 开关"},{value: "slider",label: "Slider 滑块"},{value: "time-picker",label: "TimePicker 时间选择器"},{value: "date-picker",label: "DatePicker 日期选择器"},{value: "datetime-picker",label: "DateTimePicker 日期时间选择器"},{value: "upload",label: "Upload 上传"},{value: "rate",label: "Rate 评分"},{value: "form",label: "Form 表单"}]},{value: "data",label: "Data",children: [{value: "table",label: "Table 表格"},{value: "tag",label: "Tag 标签"},{value: "progress",label: "Progress 进度条"},{value: "tree",label: "Tree 树形控件"},{value: "pagination",label: "Pagination 分页"},{value: "badge",label: "Badge 标记"}]},{value: "notice",label: "Notice",children: [{value: "alert",label: "Alert 警告"},{value: "loading",label: "Loading 加载"},{value: "message",label: "Message 消息提示"},{value: "message-box",label: "MessageBox 弹框"},{value: "notification",label: "Notification 通知"}]},{value: "navigation",label: "Navigation",children: [{value: "menu",label: "NavMenu 导航菜单"},{value: "tabs",label: "Tabs 标签页"},{value: "breadcrumb",label: "Breadcrumb 面包屑"},{value: "dropdown",label: "Dropdown 下拉菜单"},{value: "steps",label: "Steps 步骤条"}]},{value: "others",label: "Others",children: [{value: "dialog",label: "Dialog 对话框"},{value: "tooltip",label: "Tooltip 文字提示"},{value: "popover",label: "Popover 弹出框"},{value: "card",label: "Card 卡片"},{value: "carousel",label: "Carousel 走马灯"},{value: "collapse",label: "Collapse 折叠面板"}]}]},{value: "ziyuan",label: "资源",children: [{value: "axure",label: "Axure Components"},{value: "sketch",label: "Sketch Templates"},{value: "jiaohu",label: "组件交互文档"}]}]};},methods: {submitForm(formName) {let _this = this;let form = new FormData($("#shop_form")[0]);let features = this.features.filter(item => item.flag);form.append("shop_category", this.shop.category); //添加店铺分类form.append("shop_features", features); //添加商品特性this.$refs["shop"].validate(valid => {if (valid) {$.ajax({url: api.shop,type: "POST",cache: false, //不必须data: form,processData: false, //必须contentType: false, //必须success: function(data) {data = JSON.parse(data);console.log("张浩雨: submitForm -> data", data); //这里有数据类型错误switch (data.status) {case 1:_this.$message.success("正在跳转店铺列表页面...");setTimeout(function() {_this.$router.push("/business_list");}, 3000);break;case 2:_this.$alert("此店铺已存在,请确认后重新添加", "重复添加", {confirmButtonText: "确定"});break;default:// 0表示添加失败_this.$alert("服务器或是操作有误,请您重新添加", "添加失败", {confirmButtonText: "确定"});break;}}// complete:function (data) {//   console.log(data)// }});console.log("张浩雨: submitForm -> form", form);} else {_this.$message.error("error submit!!");return false;}});},resetForm(formName) {this.$refs[formName].resetFields();},loadAll() {return [{ value: "三全鲜食(北新泾店)", address: "长宁区新渔路144号" },{value: "Hot honey 首尔炸鸡(仙霞路)",address: "上海市长宁区淞虹路661号"},{value: "新旺角茶餐厅",address: "上海市普陀区真北路988号创邑金沙谷6号楼113"},{ value: "泷千家(天山西路店)", address: "天山西路438号" },{value: "胖仙女纸杯蛋糕(上海凌空店)",address: "上海市长宁区金钟路968号1幢18号楼一层商铺18-101"},{ value: "贡茶", address: "上海市长宁区金钟路633号" },{value: "豪大大香鸡排超级奶爸",address: "上海市嘉定区曹安公路曹安路1685号"},{value: "茶芝兰(奶茶,手抓饼)",address: "上海市普陀区同普路1435号"},{ value: "十二泷町", address: "上海市北翟路1444弄81号B幢-107" },{ value: "星移浓缩咖啡", address: "上海市嘉定区新郁路817号" },{ value: "阿姨奶茶/豪大大", address: "嘉定区曹安路1611号" },{ value: "新麦甜四季甜品炸鸡", address: "嘉定区曹安公路2383弄55号" },{value: "Monica摩托主题咖啡店",address: "嘉定区江桥镇曹安公路2409号1F,2383弄62号1F"},{value: "浮生若茶(凌空soho店)",address: "上海长宁区金钟路968号9号楼地下一层"},{ value: "NONO JUICE  鲜榨果汁", address: "上海市长宁区天山西路119号" },{ value: "CoCo都可(北新泾店)", address: "上海市长宁区仙霞西路" },{value: "快乐柠檬(神州智慧店)",address: "上海市长宁区天山西路567号1层R117号店铺"},{value: "Merci Paul cafe",address: "上海市普陀区光复西路丹巴路28弄6号楼819"},{value: "猫山王(西郊百联店)",address: "上海市长宁区仙霞西路88号第一层G05-F01-1-306"},{ value: "枪会山", address: "上海市普陀区棕榈路" },{ value: "纵食", address: "元丰天山花园(东门) 双流路267号" },{ value: "钱记", address: "上海市长宁区天山西路" },{ value: "壹杯加", address: "上海市长宁区通协路" },{value: "唦哇嘀咖",address: "上海市长宁区新泾镇金钟路999号2幢(B幢)第01层第1-02A单元"},{ value: "爱茜茜里(西郊百联)", address: "长宁区仙霞西路88号1305室" },{value: "爱茜茜里(近铁广场)",address:"上海市普陀区真北路818号近铁城市广场北区地下二楼N-B2-O2-C商铺"},{value: "鲜果榨汁(金沙江路和美广店)",address: "普陀区金沙江路2239号金沙和美广场B1-10-6"},{value: "开心丽果(缤谷店)",address: "上海市长宁区威宁路天山路341号"},{ value: "超级鸡车(丰庄路店)", address: "上海市嘉定区丰庄路240号" },{ value: "妙生活果园(北新泾店)", address: "长宁区新渔路144号" },{ value: "香宜度麻辣香锅", address: "长宁区淞虹路148号" },{value: "凡仔汉堡(老真北路店)",address: "上海市普陀区老真北路160号"},{ value: "港式小铺", address: "上海市长宁区金钟路968号15楼15-105室" },{ value: "蜀香源麻辣香锅(剑河路店)", address: "剑河路443-1" },{ value: "北京饺子馆", address: "长宁区北新泾街道天山西路490-1号" },{value: "饭典*新简餐(凌空SOHO店)",address: "上海市长宁区金钟路968号9号楼地下一层9-83室"},{value: "焦耳·川式快餐(金钟路店)",address: "上海市金钟路633号地下一层甲部"},{ value: "动力鸡车", address: "长宁区仙霞西路299弄3号101B" },{ value: "浏阳蒸菜", address: "天山西路430号" },{ value: "四海游龙(天山西路店)", address: "上海市长宁区天山西路" },{value: "樱花食堂(凌空店)",address: "上海市长宁区金钟路968号15楼15-105室"},{ value: "壹分米客家传统调制米粉(天山店)", address: "天山西路428号" },{value: "福荣祥烧腊(平溪路店)",address: "上海市长宁区协和路福泉路255弄57-73号"},{value: "速记黄焖鸡米饭",address: "上海市长宁区北新泾街道金钟路180号1层01号摊位"},{ value: "红辣椒麻辣烫", address: "上海市长宁区天山西路492号" },{value: "(小杨生煎)西郊百联餐厅",address: "长宁区仙霞西路88号百联2楼"},{ value: "阳阳麻辣烫", address: "天山西路389号" },{value: "南拳妈妈龙虾盖浇饭",address: "普陀区金沙江路1699号鑫乐惠美食广场A13"}];},querySearchAsync(queryString, cb) {var restaurants = this.restaurants;var results = queryString? restaurants.filter(this.createStateFilter(queryString)): restaurants;clearTimeout(this.timeout);this.timeout = setTimeout(() => {cb(results);}, 3000 * Math.random());},createStateFilter(queryString) {return state => {return (state.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0);};},handleSelect(item) {console.log(item);},handleChange(value) {console.log(value);},handleChange2(value) {console.log(value);},handleChange(value) {console.log(value);},handleAvatarSuccess(res, file) {this.shop_url = URL.createObjectURL(file.raw);},handleAvatarSuccess2(res, file) {this.id_url = URL.createObjectURL(file.raw);},handleAvatarSuccess3(res, file) {this.allow_url = URL.createObjectURL(file.raw);}},mounted() {this.restaurants = this.loadAll();}
};
</script><style>
.features {float: left;padding: 1px 10px;
}
.el-input-number .el-input__inner {padding: 3px 10px;text-align: left;
}
.el-input-number .el-input-number__increase {right: -3px;top: 4px;
}
.el-input-number /deep/ .el-input-number__decrease {left: 105px;top: 4px;
}
#hold_time {width: 500px;
}
.el-date-editor.el-input {width: auto;
}
.avatar-uploader .el-upload {border: 1px dashed #d9d9d9;border-radius: 6px;cursor: pointer;position: relative;overflow: hidden;
}
.avatar-uploader .el-upload:hover {border-color: #409eff;
}
.avatar-uploader-icon {font-size: 28px;color: #8c939d;width: 178px;height: 178px;line-height: 178px;text-align: center;
}
.avatar {width: 178px;height: 178px;display: block;
}
.el-form-item__label {text-align-last: left;
}
</style>
  1. 在business_list 页面进行处理

在business_list 页面进行数据处理

  1. 在页面加载时,执行mounted 钩子的内容,开始走vuex
<template><el-table :data="business_list" style="width: 100%"><el-table-column type="expand"><template slot-scope="props"><el-form label-position="left" inline class="demo-table-expand"><el-form-item label="店铺名称"><span>{{ props.row.shop_name }}</span></el-form-item><el-form-item label="店铺执照id"><span>{{ props.row.shop_id }}</span></el-form-item><el-form-item label="店铺地址"><span>{{ props.row.shop_address }}</span></el-form-item><el-form-item label="联系电话"><span>{{ props.row.shop_phone }}</span></el-form-item><el-form-item label="店铺简介"><span>{{ props.row.shop_info }}</span></el-form-item><el-form-item label="店铺标语"><span>{{ props.row.shop_slogan }}</span></el-form-item><el-form-item label="店铺分类"><span>{{ props.row.shop_category }}</span></el-form-item><el-form-item label="店铺特点"><span v-for="item in JSON.parse(props.row.shop_feature) " :key="item.id"><span v-if="item.flag" style="color:red;padding:2px 5px;">{{ item.text}}</span></span></el-form-item><el-form-item label="配送费"><span>{{ props.row.shop_deli_cost }}</span></el-form-item><el-form-item label="起送价"><span>{{ props.row.shop_min_cost }}</span></el-form-item><el-form-item label="营业时间"><span>早: {{ props.row.shop_start_time }}</span><span>晚: {{ props.row.shop_end_time }}</span></el-form-item><el-form-item label="店铺logo"><img :src=" imgUrl + props.row.shop_url" class="shop_img" alt /></el-form-item><el-form-item label="店铺营业许可证"><img :src=" imgUrl + props.row.id_url" class="shop_img" alt /></el-form-item><el-form-item label="店铺餐饮许可证"><img :src=" imgUrl + props.row.allow_url" class="shop_img" alt /></el-form-item></el-form></template></el-table-column><el-table-column label="店铺名称" prop="shop_name"></el-table-column><el-table-column label="店铺地址" prop="shop_address"></el-table-column><el-table-column label="店铺简介" prop="shop_info"></el-table-column><el-table-column fixed="right" label="操作" width="150" ><template slot-scope="scope"><el-button @click="handleModify(scope.row._id)" type="warning" round plain size="small">修改</el-button><el-button type="success" plain round size="small" @click="delBusinessList(scope.row['_id'])">删除</el-button></template></el-table-column></el-table>
</template><script>
import ENV from "@/api/config";
import { mapState, mapActions } from "vuex";
export default {data() {return {imgUrl: ""};},computed: {...mapState({business_list: state => state.business_list.business_list})},methods: {...mapActions(["getBusinessList","delBusinessList"]),handleModify(row) {console.log(row);},},mounted() {//内存中的模板已挂载到页面中console.log('mounted')this.getBusinessList();this.imgUrl = ENV.DEV.BACK_END_URL + "/upload/";}
};
</script><style>
.demo-table-expand {font-size: 0;
}
.demo-table-expand label {width: 90px;color: #99a9bf;
}
.demo-table-expand .el-form-item {margin-right: 0;margin-bottom: 0;width: 50%;
}
.shop_img {width: 60px;height: 60px;
}
.el-table /deep/ .cell{text-align: center;
}
</style>
  1. 想后端发送请求
import request from '@/utils/request.js';
import api from '@/api';const GET_BUSIESS_LIST = 'GET_BUSIESS_LIST';
const DEL_BUSIESS_LIST = 'DEL_BUSIESS_LIST';const store = {state: {business_list: null},actions: {async getBusinessList({ commit }) {const result = await request({method: 'get',url: api.shop});const action = {type: GET_BUSIESS_LIST,payload: result}console.log("张浩雨: getBusinessList -> result", result)commit(action)},async delBusinessList({ commit }, _id) {console.log("张浩雨: delBusinessList -> _id", _id)const result = await request({url: api.shop,method: 'delete',params: {_id}});console.log("张浩雨: delBusinessList -> result", result)const action = {type: DEL_BUSIESS_LIST,payload: result}commit(action)},},mutations: {[GET_BUSIESS_LIST](state, action) {state.business_list = action.payload.data.data.reverse()},[DEL_BUSIESS_LIST](state, action) {// console.log("张浩雨: action", action)let data = action.payload.data.dataif (data) {data.reverse()}state.business_list = data// console.log("张浩雨: data", data)},}
};export default store;
  1. 在后端进行请求接口处理
const express = require('express');const router = express.Router();const path = require('path');
//Multer 是一个 node.js 中间件,用于处理 multipart/form-data 类型的表单数据,它主要用于上传文件。
const multer = require('multer');
const db = require('../db');const imgObj = {};//磁盘存储引擎 (DiskStorage)
const storage = multer.diskStorage({ //每保存一个文件、图片等 都将执行一次destination: function(req, file, cb) { //设置文件保存地址cb(null, path.join(__dirname, '../public/upload'))},filename: function(req, file, cb) { //文件数据命名// console.log("张浩雨: cb", cb)// console.log("张浩雨: req", req)console.log("张浩雨: file", file)// file 只有一个值, 需要数据拼接// file { fieldname: 'shop_file',//     originalname: '生命周期master.jpg',//     encoding: '7bit',//     mimetype: 'image/jpeg' // }const fileType = file.originalname.split('.').pop(); //获取图片类型const fileName = file.fieldname + '' + Date.now() + '.' + fileType; //拼接图片名称imgObj[file.fieldname] = fileName; //对imgObj 进行数据绑定// imgObj { shop_file: 'shop_file-1570772574597.jpg',//     shop_file_1: 'shop_file_1-1570772574602.jpg' // }req.fieldname = imgObj; //将imgObj 绑定到req 上面cb(null, fileName)}
})
const upload = multer({ storage: storage }); //数据保存地址router.route('/shop').post(upload.any(), async(req, res, next) => {// upload.any()接受一切上传的文件。文件数组将保存在 req.files。// console.log("张浩雨: imgObj", imgObj);// imgObj { shop_file: 'shop_file-1570772574597.jpg',//     shop_file_1: 'shop_file_1-1570772574602.jpg' // }Object.assign(req.body, req.fieldname); //合并数据console.log("张浩雨: req.fieldname", req.fieldname)// res.setCharacterEncoding("utf-8");// res.setHeaders('Content-Type', 'applicationn/json,charset=utf8')console.log("张浩雨: req.body", req.body);// req.body [Object: null prototype] {//     shop_name: 'zhanghaoyu',//     shop_goods: '‘memeda’',//     shop_file: 'shop_file-1570772923436.jpg',//     shop_file_1: 'shop_file_1-1570772923440.jpg'//  }const result = await db.shop.add(req.body);// console.log("张浩雨: req.body", req.body)// 需注意res.render({})  基于前面的db.shop.add(data)异步操作,所以采用async-await 将异步处理为同步res.render('shop', {data: JSON.stringify({"info": result.info,"status": result.status})})// res.send('post') //写完 render 函数  res.send()会报错, }).get(async(req, res, next) => {const result = await db.shop.query();res.render('shop', {data: JSON.stringify({"info": result.info,"status": result.status,"data": result.data})})// console.log('getgetget')}).delete(async(req, res, next) => {// console.log("张浩雨: req.query", req.query._id)const result = await db.shop.del(req.query);res.render('shop', {data: JSON.stringify({"info": result.info,"status": result.status,"data": result.info})})// console.log('getgetget')})
module.exports = router;
  1. 操作mongo数据库
/* index开头就表明了这个文件、文件夹的作用好处: index可以省略
*/const mongoose = require("mongoose");
const connect = require("./connect");// mongoose使用流程如下// 1. 链接数据库
connect.init();//2.创建schema骨架,定义字段
const {userSchema,shopSchema
} = require("./schema");//3.创建模型 Module// const userModel = mongoose.model( 集合名称【复数】,对应的骨架 )
const userModule = mongoose.model("users", userSchema); //一定要将集合名称写为复数
const shopModule = mongoose.model("shops", shopSchema); //一定要将集合名称写为复数const db = {user: {add(data) {return new Promise((resolve, reject) => {// '通过数据库的查询来完成判断'userModule.find({}, (error, docs) => {// console.log( docs )// 数组,数组中放着我们所有的存储的数据const user = new userModule(data);if (docs.length) { //当数据库中有数据时if (docs.some(item => item.username === data.username)) { //当在数据库中匹配到收到的数据时,说明用户名重复了resolve({info: '用户名已重复',status: 0})} else { //此时可以存储用户信息user.save(err => {if (err) {resolve({info: err,status: 1})} else {resolve({info: '用户注册成功',status: 2})}})}} else { //当数据库中没有数据时,直接存储user.save(err => {if (err) {resolve({info: err,status: 1})} else {resolve({"info": '用户注册成功',status: 2})}})}});});},del(data) {return new Promise((resolve, reject) => {userModule.find({}, (err, docs) => {if (docs.length) {//集合有数据docs.map(item => {if (item.username === data.username) {userModule.findById(item.id, (error, doc) => {doc.remove((error) => {if (error) {resolve({"info": '删除失败了',"status": 0})} else {resolve({"info": '删除成功',"status": 1})}})})}})}})})},modify(data) {return new Promise((resolve, reject) => {userModule.find({}, (err, docs) => {if (docs.length) {docs.map(item => {if (item.username === data.username) {userModule.findById(item._id, (err, doc) => {doc.password = data.newPassworddoc.save(error => {if (error) {resolve({info: '修改失败了',status: 0})} else {resolve({info: '密码修改成功',status: 1})}})})return}})}})});},query(data) {return new Promise((resolve, reject) => {userModule.find({}, (err, docs) => {if (docs.length) { //若数据库有数据if (docs.some(item => item.username === data.username && item.password === data.password)) { //用户账号和密码都匹配时resolve({info: '登陆成功',status: 1});} else { //用户账号或密码错误if (docs.some(item => item.username === data.username)) {resolve({info: '用户名或是密码错误',status: 3})} else {// 证明数据库中没有这个用户名resolve({info: '账号没有注册',status: 2})}}} else { //数据库为空时// user集合是空的,提示用户去注册resolve({info: '你是第一个用户,您还没有注册,请先注册',status: 0})}})});}},shop: {add(data) {return new Promise((resolve, reject) => {// '通过数据库的查询来完成判断'// 商铺是否有重复注册 // 1. 查询数据库,将数据库中已有的店铺查询出来// 2. 然后在查询出来的店铺数据中查找是否有 前端当前注册的店铺信息   通过shop_id来判断shopModule.find({}, (error, docs) => {console.log(docs) // 数组,数组中放着我们所有的存储的数据if (error) console.log("张浩雨: add -> error", error)let flag = docs.some(item => item.shop_id === data.shop_id);// console.log("张浩雨: add -> flag", flag)if (flag) {resolve({"info": '店铺已注册',"status": 0})} else {const shop = new shopModule(data);shop.save(error => {if (error) {resolve({"info": '店铺注册失败',"status": 2})} else {resolve({"info": '店铺注册成功',"status": 1})}})}});// reject({//     info: 'reject',//     status: '500'// })});},del(_id) {return new Promise((resolve, reject) => {shopModule.findById(_id, (err, doc) => {if (err) resolve({info: '服务器错误',status: 2})console.log("张浩雨: del -> doc", doc)doc.remove(err => {if (err) {resolve({info: '未找到对应的店铺',status: 0})} else {shopModule.find({}, (err, docu) => {// console.log("张浩雨: del -> docu", docu)resolve({info: docu,status: 1,name: 'zhanghaoyu',// data: docu})})console.log('店铺删除成功!!!')}})})})},modify() {},query() {return new Promise((resolve, reject) => {shopModule.find({}, (err, doc) => {console.log("张浩雨: query -> doc", doc)if (err) {resolve({info: '服务器出错啦',status: 0})} else {resolve({info: '数据请求成功',status: 1,data: doc})}})})}}
};module.exports = db;
  1. 在前端的vuex store.js 中处理请求到的数据 并赋值更新数据
import request from '@/utils/request.js';
import api from '@/api';const GET_BUSIESS_LIST = 'GET_BUSIESS_LIST';
const DEL_BUSIESS_LIST = 'DEL_BUSIESS_LIST';const store = {state: {business_list: null},actions: {async getBusinessList({ commit }) {const result = await request({method: 'get',url: api.shop});const action = {type: GET_BUSIESS_LIST,payload: result}console.log("张浩雨: getBusinessList -> result", result)commit(action)},async delBusinessList({ commit }, _id) {console.log("张浩雨: delBusinessList -> _id", _id)const result = await request({url: api.shop,method: 'delete',params: {_id}});console.log("张浩雨: delBusinessList -> result", result)const action = {type: DEL_BUSIESS_LIST,payload: result}commit(action)},},mutations: {[GET_BUSIESS_LIST](state, action) {state.business_list = action.payload.data.data.reverse()},[DEL_BUSIESS_LIST](state, action) {// console.log("张浩雨: action", action)let data = action.payload.data.dataif (data) {data.reverse()}state.business_list = data// console.log("张浩雨: data", data)},}
};export default store;
  1. 接下来走修改操作流程

后端处理数据保存请求流程multer+ajax 数据库添加数据 前端与后端的数据联通 在business_list 页面进行数据处理 @stage3---week3--day4相关推荐

  1. mfc创建excel如何另存为_mfc表格数据保存为excel文件-VC (MFC)如何从对话框写数据到Excel...

    我现在把Excel表格嵌入到MFC单文档界面,然后对嵌... 1.首先,打开媒介工具"记事本",将word文件里需要导入的数据,复制粘贴到记事本当中,然后保存成为txt文件,本例中 ...

  2. oracle dul误删数据,案例:Oracle dul数据挖掘 没有数据库备份非常规恢复truncate删除的数据表...

    Oracle数据库在没有备份情况下在对表中的某数据表进行truncate删除后,通过oracle dul进行非常规恢复 1.准备oracle dul测试环境SQL> select count(* ...

  3. tcga数据下载_给你tcga数据库过万病人的原始测序数据你可以做什么

    最近有两年前的学生过来寻求合作,让我想想给我tcga数据库过万病人的原始测序数据,我可以做什么方法学的创新.我想把这个问题抛给粉丝: 假设给你tcga数据库过万病人的原始测序数据你可以做什么??? 大 ...

  4. uniapp ajax数据库查询,uniapp小程序登录、数据请求方式

    index页面 手动授权按钮 exportdefault{ data() {return{ imgInfo:"",//头像 nickName:""//昵称 } ...

  5. 前后端分离项目,请求头中包含Authorizaton:XX,但是后端getHeader(Authorizaton) 获取不到

    前端请求头 后台校验 结果是 request = null: 原因是因为,在发起跨域请求时,会发送事先发送一个OPTIONS请求,可以在浏览器的NETWORK中看到发起了两个名字一样的请求. 第一个请 ...

  6. 前后端分离模式下前端与后端数据交互

    下面举的例子就是使用jQuery Ajax和Python Flask进行前后端交互时,前端提交表单数据到后端,后端返回JSON数据给前端. 前端GET提交表单数据: # GET请求var data = ...

  7. MVC框架中的前端与后端数据传递及实例

    一.MVC框架 MVC代表Model.View.Controller,即模型.视图.控制器.其中: View(视图):就是人机交互界面,可以给用户显示业务逻辑数据,同时也可以 接收用户输入的数据. M ...

  8. python的前端和后端_python前端和后端数据交互,tornado框架入门,初学小试牛刀!...

    Python前端和后端是如何交互的,怎么用tornado框架快速搭建前端和后端数据交互? 前端与后端的数据交互,最常用的就是GET.POST,比较常用的用法是:提交表单数据到后端,后端返回json 前 ...

  9. 一文搞懂前台,后台,中台,前端,后端,管理端,业务端,技术中台,业务中台,数据中台,物联网中台到底是什么?

    1. 前台/前端 前台 (Frontend):是指用户直接面对的系统界面部分,包括用户界面设计.页面交互逻辑.数据呈现和用户操作等,主要职责是与用户打交道,用友好的交互方式把闭门造车的后台功能暴露出来 ...

最新文章

  1. SSM框架整合(Spring+SpringMVC+MyBatis)
  2. 区块链中的“智能合约”有何应用?
  3. 领扣-191 位1的个数 Number of 1 Bits MD
  4. Java基础:Java异常处理
  5. Linux新建yaml文件,yaml文件创建pod和deployment
  6. 云原生生态周报 Vol. 15 | K8s 安全审计报告发布
  7. 2020 idea 查看内存消耗_idea内存如何设置
  8. java sqlite 创建_关于Java:创建3个由sqlite数据库填充的微调器
  9. java-log入门【目的把日志写入socket】
  10. 查看linux系统软件各种版本环境
  11. LINUX下载编译nasm
  12. 安装和卸载IE浏览器
  13. 计算机组成原理串行加法器延迟时间,2021考研408计算机组成原理:串行加法器和并行加法器...
  14. 【Python实战】 ---- 批量图片压缩
  15. 引擎开发-图形渲染器开发
  16. 微型计算机不是ecu,ECU升级是什么意思?
  17. 为什么创造 Charj 语言?从十年以后的编程说起
  18. 高清电脑桌面壁纸的网站--高图网(GAOPIC)
  19. TypeError: Cannot read property 'xxxx' of undefined报错的情况分析
  20. 前端白屏问题_首页白屏的引发的思考(一)

热门文章

  1. equals变量是前面还是后面
  2. python字典排序sort_Python字典排序
  3. 另辟蹊径,阿里从业务切入移动安全
  4. 怎么区分SSL证书的级别呢
  5. “捷径系统”推出人脸识别健身房系统,60天卖出100套
  6. 图像像素转换 8-bit 16-bit 32-bit游戏效果
  7. 无锡移动4G覆盖面积超700平方公里 新资费下月启动
  8. PM,RD,FE,UE,UI,QA,OP,DBA,BRD,MRD,PRD,FSD
  9. 世界那么大,终于克服语言障碍走出国门了
  10. Jetson Agx Xavier 安装cuda10.2和cudnn,pytorch,pycharm, unet