فهرست منبع

新增栏目与菜单

nihao 5 سال پیش
والد
کامیت
1f1ee2a070
8فایلهای تغییر یافته به همراه441 افزوده شده و 0 حذف شده
  1. 75 0
      app/controller/.column.js
  2. 75 0
      app/controller/.menu.js
  3. 16 0
      app/controller/column.js
  4. 16 0
      app/controller/menu.js
  5. 41 0
      app/model/column.js
  6. 33 0
      app/model/menu.js
  7. 95 0
      app/service/column.js
  8. 90 0
      app/service/menu.js

+ 75 - 0
app/controller/.column.js

@@ -0,0 +1,75 @@
+module.exports = {
+  // 添加栏目
+  "create": {
+    "parameters": {
+      "query": ["!site"],
+    },
+    "requestBody": ["!moudle", "!name", "picurl", "description", "sort", "inMenu", "showModes", "isAudit", "issuer"],
+  },
+  // 修改栏目
+  "update": {
+    "parameters": {
+      "query": ["!id"],
+    },
+    "requestBody": ["moudle", "name", "picurl", "description", "sort", "inMenu", "showModes", "isAudit", "issuer"],
+    // "options": {
+    //   "projection": "+name",
+    // },
+  },
+  // 获取栏目详情
+  "fetch": {
+    "parameters": {
+      "query": ["!id"],
+    },
+    // "options": {
+    //   "projection": "+content",
+    // },
+  },
+  // 删除栏目
+  "delete": {
+    "parameters": {
+      "query": ["!id"],
+    },
+  },
+  // 恢复栏目
+  "restore": {
+    "parameters": {
+      "query": ["!id"],
+    },
+  },
+  // 后台查询栏目列表
+  "query": {
+    "parameters": {
+      "query": ["!site"],
+    },
+    "service": "query",
+    "options": {
+      "query": ["skip", "limit"],
+      "sort": ["meta.createdAt"],
+      "desc": true,
+      "count": true,
+      "projection": {
+        "attachment": 0
+      }
+    }
+  },
+  // 前台加载栏目列表
+  "list": {
+    "parameters": {
+      "query": ["!site"],
+      "options": {
+        "meta.state": 0, // 只显示未删除数据
+      },
+    },
+    "service": "query",
+    "options": {
+      "query": ["skip", "limit"],
+      "sort": ["top", "meta.createdAt"],
+      "desc": true,
+      "count": true,
+      "projection": {
+        "attachment": 0
+      }
+    }
+  },
+};

+ 75 - 0
app/controller/.menu.js

@@ -0,0 +1,75 @@
+module.exports = {
+  // 添加菜单
+  "create": {
+    "parameters": {
+      "query": ["!site"],
+    },
+    "requestBody": ["!parentId", "!name", "picurl", "sort", "description", "isShow", "issuer"],
+  },
+  // 修改菜单
+  "update": {
+    "parameters": {
+      "query": ["!id"],
+    },
+    "requestBody": ["!parentId", "!name", "picurl", "sort", "description", "isShow", "issuer"],
+    // "options": {
+    //   "projection": "+name",
+    // },
+  },
+  // 获取菜单详情
+  "fetch": {
+    "parameters": {
+      "query": ["!id"],
+    },
+    // "options": {
+    //   "projection": "+content",
+    // },
+  },
+  // 删除菜单
+  "delete": {
+    "parameters": {
+      "query": ["!id"],
+    },
+  },
+  // 恢复菜单
+  "restore": {
+    "parameters": {
+      "query": ["!id"],
+    },
+  },
+  // 后台查询菜单列表
+  "query": {
+    "parameters": {
+      "query": ["!site"],
+    },
+    "service": "query",
+    "options": {
+      "query": ["skip", "limit"],
+      "sort": ["meta.createdAt"],
+      "desc": true,
+      "count": true,
+      "projection": {
+        "attachment": 0
+      }
+    }
+  },
+  // 前台加载菜单列表
+  "list": {
+    "parameters": {
+      "query": ["!site"],
+      "options": {
+        "meta.state": 0, // 只显示未删除数据
+      },
+    },
+    "service": "query",
+    "options": {
+      "query": ["skip", "limit"],
+      "sort": ["top", "meta.createdAt"],
+      "desc": true,
+      "count": true,
+      "projection": {
+        "attachment": 0
+      }
+    }
+  },
+};

+ 16 - 0
app/controller/column.js

@@ -0,0 +1,16 @@
+'use strict';
+
+const _ = require('lodash');
+const meta = require('./.column.js');
+const Controller = require('egg').Controller;
+const { CrudController } = require('naf-framework-mongoose/lib/controller');
+
+class ColumnController extends Controller {
+  constructor(ctx) {
+    super(ctx);
+    this.service = this.ctx.service.column;
+  }
+
+}
+
+module.exports = CrudController(ColumnController, meta);

+ 16 - 0
app/controller/menu.js

@@ -0,0 +1,16 @@
+'use strict';
+
+const _ = require('lodash');
+const meta = require('./.menu.js');
+const Controller = require('egg').Controller;
+const { CrudController } = require('naf-framework-mongoose/lib/controller');
+
+class MenuController extends Controller {
+  constructor(ctx) {
+    super(ctx);
+    this.service = this.ctx.service.menu;
+  }
+
+}
+
+module.exports = CrudController(MenuController, meta);

+ 41 - 0
app/model/column.js

@@ -0,0 +1,41 @@
+/**
+ * 栏目信息
+ */
+'use strict';
+const Schema = require('mongoose').Schema;
+const metaPlugin = require('naf-framework-mongoose/lib/model/meta-plugin');
+
+// // 附件信息
+// const Attachment = new Schema({
+//   name: { type: String, maxLength: 128 },
+//   uri: { type: String, maxLength: 128 },
+// }, { _id: false });
+
+// 栏目信息
+const SchemaDefine = {
+  site: { type: String, required: true, maxLength: 64 }, // 归属站点
+  moudle: { type: String, required: true, maxLength: 20 }, // 栏目模块
+  name: { type: String, required: true, maxLength: 100 }, // 栏目名称
+  picurl: { type: String, required: false, maxLength: 256 }, // 栏目图片URL
+  description: { type: String, required: false, maxLength: 256 }, // 栏目描述
+  inMenu: { type: String, required: false, maxLength: 5 }, // 是否在菜单中显示
+  showModes: { type: String, required: false, maxLength: 5 }, // 展现方式
+  isAudit: { type: String, required: false, maxLength: 5 }, // 是否需要审核
+  sort: [{ type: Number, maxLength: 5 }], // 排序
+  issuer: String, // 栏目单位
+  meta: {
+    createdBy: String, // 创建用户
+    updatedBy: String, // 修改用户
+  },
+  remark: { type: String, maxLength: 500 }, // 备注
+};
+const schema = new Schema(SchemaDefine, { 'multi-tenancy': true, toJSON: { virtuals: true } });
+schema.plugin(metaPlugin);
+schema.index({ column: 1 });
+schema.index({ 'meta.state': 1 });
+schema.index({ 'meta.createdAt': -1 });
+schema.index({ 'meta.createdAt': -1, top: -1, 'meta.state': 1 });
+module.exports = app => {
+  const { mongoose } = app;
+  return mongoose.model('ColumnInfo', schema, 'cms_column');
+};

+ 33 - 0
app/model/menu.js

@@ -0,0 +1,33 @@
+/**
+ * 栏目信息
+ */
+'use strict';
+const Schema = require('mongoose').Schema;
+const metaPlugin = require('naf-framework-mongoose/lib/model/meta-plugin');
+
+// 栏目信息
+const SchemaDefine = {
+  site: { type: String, required: true, maxLength: 64 }, // 归属站点
+  parentId: { type: String, required: true, maxLength: 64 }, // 父级ID
+  name: { type: String, required: true, maxLength: 100 }, // 菜单名称
+  picurl: { type: String, required: false, maxLength: 256 }, // 栏目图片URL
+  sort: [{ type: Number, maxLength: 5 }], // 排序
+  description: { type: String, required: false, maxLength: 256 }, // 栏目描述
+  isShow: { type: String, required: false, maxLength: 5 }, // 是否需要审核
+  issuer: String, // 栏目单位
+  meta: {
+    createdBy: String, // 创建用户
+    updatedBy: String, // 修改用户
+  },
+  remark: { type: String, maxLength: 500 }, // 备注
+};
+const schema = new Schema(SchemaDefine, { 'multi-tenancy': true, toJSON: { virtuals: true } });
+schema.plugin(metaPlugin);
+schema.index({ column: 1 });
+schema.index({ 'meta.state': 1 });
+schema.index({ 'meta.createdAt': -1 });
+schema.index({ 'meta.createdAt': -1, top: -1, 'meta.state': 1 });
+module.exports = app => {
+  const { mongoose } = app;
+  return mongoose.model('MenuInfo', schema, 'cms_menu');
+};

+ 95 - 0
app/service/column.js

@@ -0,0 +1,95 @@
+'use strict';
+
+const assert = require('assert');
+const _ = require('lodash');
+const { BusinessError, ErrorCode } = require('naf-core').Error;
+const { isNullOrUndefined, trimData } = require('naf-core').Util;
+const { CrudService } = require('naf-framework-mongoose/lib/service');
+
+class ColumnService extends CrudService {
+  constructor(ctx) {
+    super(ctx);
+    this.model = this.ctx.model.column;
+  }
+
+  async create({ site }, { moudle, name, picurl, description, inMenu, showModes, isAudit, sort, issuer }) {
+    // 检查数据
+    assert(_.isString(site), 'site不能为空');
+    assert(_.isString(moudle), 'moudle不能为空');
+    assert(_.isString(name), 'name不能为空');
+    assert(!picurl || _.isString(picurl), 'picurl必须为字符串');
+    assert(!description || _.isString(description), 'description必须为字符串');
+    assert(!inMenu || _.isString(inMenu), 'inMenu必须为字符串');
+    assert(!showModes || _.isString(showModes), 'showModes必须为字符串');
+    assert(!isAudit || _.isString(isAudit), 'isAudit必须为字符串');
+    assert(_.isUndefined(sort) || _.isNumber(sort), 'top必须为数字');
+    assert(!issuer || _.isString(issuer), 'issuer必须为字符串');
+
+    // TODO: 检查用户信息
+    const userid = this.ctx.userid;
+    if (!_.isString(userid)) throw new BusinessError(ErrorCode.NOT_LOGIN);
+
+    // TODO:保存数据
+    const data = {
+      moudle, name, picurl, description, inMenu, showModes, isAudit, sort, issuer,
+      meta: { createdBy: userid },
+    };
+
+    const res = await this.model.create(data);
+    return res;
+  }
+
+  async update({ id }, payload) {
+    // 检查数据
+    const { moudle, name, picurl, description, inMenu, showModes, isAudit, sort, issuer } = payload;
+    assert(id, 'id不能为空');
+    // assert(_.isString(site), 'site不能为空');
+    assert(_.isString(moudle), 'moudle不能为空');
+    assert(_.isString(name), 'name不能为空');
+    assert(!picurl || _.isString(picurl), 'picurl必须为字符串');
+    assert(!description || _.isString(description), 'description必须为字符串');
+    assert(!inMenu || _.isString(inMenu), 'inMenu必须为字符串');
+    assert(!showModes || _.isString(showModes), 'showModes必须为字符串');
+    assert(!isAudit || _.isString(isAudit), 'isAudit必须为字符串');
+    assert(_.isUndefined(sort) || _.isNumber(sort), 'top必须为数字');
+    assert(!issuer || _.isString(issuer), 'issuer必须为字符串');
+
+    // TODO: 检查用户信息
+    const userid = this.ctx.userid;
+    if (!_.isString(userid)) throw new BusinessError(ErrorCode.NOT_LOGIN);
+
+    // TODO:检查数据是否存在
+    const doc = await this.model.findById(id).exec();
+    if (isNullOrUndefined(doc)) {
+      throw new BusinessError(ErrorCode.DATA_NOT_EXIST);
+    }
+
+    // TODO:保存数据
+    const data = trimData(payload);
+    await this.model.findByIdAndUpdate(doc.id, { ...data, 'meta.updatedBy': userid }, { new: true }).exec();
+    const res = this.model.findById(id, '+name').exec();
+    return res;
+  }
+
+  async status({ id, state }) {
+
+    // TODO: 检查数据状态
+    const doc = await this.model.findById(id).exec();
+    if (!doc) {
+      throw new BusinessError(ErrorCode.DATA_NOT_EXIST);
+    }
+
+    doc.meta.state = state;
+    return await doc.save();
+  }
+
+  async delete({ id }) {
+    return await this.status({ id, state: 1 });
+  }
+
+  async restore({ id }) {
+    return await this.status({ id, state: 0 });
+  }
+}
+
+module.exports = ColumnService;

+ 90 - 0
app/service/menu.js

@@ -0,0 +1,90 @@
+'use strict';
+
+const assert = require('assert');
+const _ = require('lodash');
+const { BusinessError, ErrorCode } = require('naf-core').Error;
+const { isNullOrUndefined, trimData } = require('naf-core').Util;
+const { CrudService } = require('naf-framework-mongoose/lib/service');
+
+class MenuService extends CrudService {
+  constructor(ctx) {
+    super(ctx);
+    this.model = this.ctx.model.menu;
+  }
+
+  async create({ site }, { parentId, name, picurl, sort, description, isShow,  issuer }) {
+    // 检查数据
+    assert(_.isString(site), 'site不能为空');
+    assert(_.isString(parentId), 'parentId不能为空');
+    assert(_.isString(name), 'name不能为空');
+    assert(!picurl || _.isString(picurl), 'picurl必须为字符串');
+    assert(!description || _.isString(description), 'description必须为字符串');
+    assert(_.isUndefined(sort) || _.isNumber(sort), 'top必须为数字');
+    assert(!isShow || _.isString(isShow), 'isShow必须为字符串');
+    assert(!issuer || _.isString(issuer), 'issuer必须为字符串');
+
+    // TODO: 检查用户信息
+    const userid = this.ctx.userid;
+    if (!_.isString(userid)) throw new BusinessError(ErrorCode.NOT_LOGIN);
+
+    // TODO:保存数据
+    const data = {
+      parentId, name, picurl, sort, description, isShow, issuer,
+      meta: { createdBy: userid },
+    };
+
+    const res = await this.model.create(data);
+    return res;
+  }
+
+  async update({ id }, payload) {
+    // 检查数据
+    const { parentId, name, picurl, sort, description, isShow, issuer } = payload;
+    assert(id, 'id不能为空');
+    assert(_.isString(parentId), 'parentId不能为空');
+    assert(_.isString(name), 'name不能为空');
+    assert(!picurl || _.isString(picurl), 'picurl必须为字符串');
+    assert(!description || _.isString(description), 'description必须为字符串');
+    assert(_.isUndefined(sort) || _.isNumber(sort), 'top必须为数字');
+    assert(!isShow || _.isString(isShow), 'isShow必须为字符串');
+    assert(!issuer || _.isString(issuer), 'issuer必须为字符串');
+
+    // TODO: 检查用户信息
+    const userid = this.ctx.userid;
+    if (!_.isString(userid)) throw new BusinessError(ErrorCode.NOT_LOGIN);
+
+    // TODO:检查数据是否存在
+    const doc = await this.model.findById(id).exec();
+    if (isNullOrUndefined(doc)) {
+      throw new BusinessError(ErrorCode.DATA_NOT_EXIST);
+    }
+
+    // TODO:保存数据
+    const data = trimData(payload);
+    await this.model.findByIdAndUpdate(doc.id, { ...data, 'meta.updatedBy': userid }, { new: true }).exec();
+    const res = this.model.findById(id, '+name').exec();
+    return res;
+  }
+
+  async status({ id, state }) {
+
+    // TODO: 检查数据状态
+    const doc = await this.model.findById(id).exec();
+    if (!doc) {
+      throw new BusinessError(ErrorCode.DATA_NOT_EXIST);
+    }
+
+    doc.meta.state = state;
+    return await doc.save();
+  }
+
+  async delete({ id }) {
+    return await this.status({ id, state: 1 });
+  }
+
+  async restore({ id }) {
+    return await this.status({ id, state: 0 });
+  }
+}
+
+module.exports = MenuService;