ref
查詢另外一表中的數據npm i -S moment
//分別切換到/server
、/client
目錄下安裝/users
的路由和處理邏輯拷一份,改更名// 新建文件:server/control/approves.js const moment = require('moment'); const approveModel = require('../model/approve'); const userModel = require('../model/user'); async function list(ctx) { // 【一般作法,由多的一方過濾單一的一方】 // 文檔:http://www.mongoosejs.net/docs/populate.html#refs-to-children try { const approves = await approveModel.find({ author: ctx.state.auth.id }); ctx.body = { code: '200', data: approves, msg: '查詢成功' }; } catch (err) { ctx.body = { code: '403', data: { error: err }, msg: '查詢失敗' } } } async function get(ctx){ const { id } = ctx.params; try { const approve = await approveModel.findOne({ _id: id }); if(approve) { ctx.body = { code: '200', data: approve, msg: '成功' } } else { ctx.body = { code: '403', data: null, msg: '找不到數據建立人' } } } catch (err) { ctx.body = { code: '404', data: { _id: id }, msg: '獲取失敗,請覈對數據id' } } } async function create(ctx) { const { id: loginerId } = ctx.state.auth; const payload = ctx.request.body; const curtime = moment().format('x'); try { const newApprove = await new approveModel({ ...payload, status: false, author: loginerId, modifier: loginerId, createtime: curtime, latesttime: curtime, }).save(); ctx.body = { code: '200', data: newApprove, msg: '新建成功' } } catch (err) { ctx.body = { code: '403', data: null, msg: '新建失敗' } } } async function update(ctx){ const payload = ctx.request.body; const { id } = ctx.params; const curtime = moment().format('x'); try { await approveModel.updateOne( { _id: id }, { ...payload, latesttime: curtime } ).exec(); ctx.body= { code: '200', data: { _id: id }, msg: '更新成功' } } catch (err) { ctx.body = { code: '404', data: payload, msg: '更新失敗,請覈對數據id' } } } async function drop(ctx){ const { id } = ctx.params; await approveModel.findOneAndRemove({ _id: id }) ctx.body = { code: '200', data: null, msg: '刪除成功' } } module.exports = { list, get, create, update, drop }
路由攔截css
checkLoginer
// 更新文件:server/router/approves.js const Router = require('@koa/router'); const approveModel = require('../model/approve'); const controls = require('../control/approves'); const routerUtils = require('../utils/router'); const { list, get, create, update, drop } = controls; const router = new Router({ prefix: '/approves' }); async function checkLoginer (ctx, next) { const { id } = ctx.params; const approve = await approveModel.findOne({ _id: id }); if (approve.author != ctx.state.auth.id) { ctx.body = { code: '403', data: null, msg: '當前用戶不是建立者' } } else { await next() } } const routes = [ { path: '/', method: 'GET', handle: list }, { path: '/', method: 'POST', handle: create }, { path: '/:id', method: 'GET', handle: get }, { path: '/:id', method: 'PATCH', payload: {}, handle: update, middlewares: [ checkLoginer ] }, { path: '/:id', method: 'DELETE', handle: drop, middlewares: [ checkLoginer ] } ] routerUtils.register.call(router, routes); module.exports = router;
// 更新文件:server/router/index.js const userRouter = require('./users'); const assetsRouter = require('./assets'); const approvesRouter = require('./approves'); module.exports = [ userRouter.routes(), userRouter.allowedMethods(), approvesRouter.routes(), approvesRouter.allowedMethods(), assetsRouter.routes(), assetsRouter.allowedMethods() ];
// 更新文件:client/src/views/approve-panel/index.vue <template\> <div class\="approve-module"\> <div class\="btns-wrap"\> <el-button type\="primary" @click\="handleApprove('increase')"\>新建</el-button\> </div\> <el-table :data\="table.tableBody" border @selection-change\="handleSelectionChange" style\="width: 100%"\> <template v-for\="header in table.tableHeader"\> <el-table-column v-if\="header.key === 'selection'" :key\="header.key" v-bind\="Object.assign({}, header.options, header.layout)" \> </el-table-column\> <el-table-column v-else :key\="header.key" :label\="header.metas.label" v-bind\="Object.assign({}, header.options, header.layout)"\> <template slot-scope\="scope"\> <span v-if\="header.metas.type === 'text'"\>{{scope.row\[header.key\]}}</span\> <el-button-group v-else-if\="header.metas.type === 'button'"\> <template v-for\="btn in header.metas.value"\> <el-button :class\="\`btn-${btn.key}\`" @click\="handleApprove(btn.key, scope.row)" v-if\="btn.attributes.visible" size\="small" type\="text" :key\="btn.key" v-bind\="btn.attributes"\>{{btn.label}}</el-button\> </template\> </el-button-group\> <span v-else\>{{header.metas.formatter(scope.row\[header.key\])}}</span\> </template\> </el-table-column\> </template\> </el-table\> <el-dialog :title\="dialogForm.title" :visible.sync\="dialogForm.visible"\> <el-form :inline\="false" :ref\="dialogForm.formRef" :model\="dialogForm.form" :rules\="dialogForm.rules"\> <el-form-item label\="名稱" prop\="name"\> <el-input v-model\="dialogForm.form.name"\></el-input\> </el-form-item\> <el-form-item label\="分類" prop\="category"\> <el-select v-model\="dialogForm.form.category" placeholder\="請選擇分類"\> <el-option label\="年假" value\="1"\></el-option\> <el-option label\="病假" value\="2"\></el-option\> </el-select\> </el-form-item\> <el-form-item label\="描述" prop\="description"\> <el-input type\="textarea" v-model\="dialogForm.form.description"\></el-input\> </el-form-item\> </el-form\> <div slot\="footer" class\="dialog-footer"\> <el-button @click\="cancelOperate"\>取 消</el-button\> <el-button type\="primary" @click\="submitForm"\>確 定</el-button\> </div\> </el-dialog\> </div\> </template\> <script\> import moment from 'moment' import http from '@/utils/http' export default { INITFORMDATA: { name: '', category: '', description: '', status: false, latesttime: 0, createtime: 0, author: {}, }, methods: { async init () { const res \= await http.get('/approves') if (res.code \=== '200') { this.$set(this.table, 'tableBody', res.data) } }, handleSelectionChange (val) { console.log(val) }, handleClick (row) { console.log(row) }, handleApprove (type, initData) { this\[\`${type}Handle\`\](initData) }, cancelOperate () { this.dialogForm \= Object.assign( {}, this.dialogForm, { visible: false, formRef: '', form: this.$options.INITFORMDATA } ) }, increaseHandle (initData \= {}) { this.dialogForm \= Object.assign( this.dialogForm, { visible: true, title: '新建', formRef: 'increaseForm' } ) }, editHandle (initData \= {}) { this.dialogForm \= Object.assign( this.dialogForm, { visible: true, title: '編輯', formRef: 'editForm', form: { ...initData } } ) }, dropHandle (initData \= {}) { this.$confirm('此操做將永久刪除該數據, 是否繼續?', '提示', { confirmButtonText: '肯定', cancelButtonText: '取消', type: 'warning' }).then(async () \=> { const res \= await http.delete(\`/approves/${initData.\_id}\`) if (res.code \=== '200') { this.$message({ type: 'success', message: '刪除成功!' }) this.init() } else { throw(new Error('發生錯誤')) } }).catch((err) \=> { this.$message({ type: 'info', message: err.message || '已取消刪除' }); }); }, async submitForm () { try { const valid \= this.$refs\[this.dialogForm.formRef\].validate() if (this.dialogForm.formRef \=== 'increaseForm') { const res \= await http.post( '/approves', { ...this.dialogForm.form } ) if (res.code \=== '200') { this.$message({ type: 'success', message: '新建成功' }) } else { this.$message({ type: 'error', message: res.msg }) } } else { const { \_id, name, category, description, status} \= this.dialogForm.form const res \= await http.patch( \`/approves/${\_id}\`, { name, category, description, status } ) if (res.code \=== '200') { this.$message({ type: 'success', message: '更新成功' }) } else { this.$message({ type: 'error', message: res.msg }) } } this.cancelOperate() this.init() } catch (err) { console.log(err) } } }, data () { return { table: { tableHeader: \[ { key: 'selection', metas: { }, options: { type: 'selection' }, layout: { } }, { key: 'name', metas: { label: '名稱', type: 'text' }, options: { 'show-overflow-tooltip': true }, layout: { width: 200 } }, { key: 'category', metas: { label: '類別', type: 'text' }, layout: { width: 60 } }, { key: 'description', metas: { label: '描述', type: 'text' }, options: { 'show-overflow-tooltip': true }, layout: { } }, { key: 'author', metas: { label: '建立人', type: 'object', formatter (val) { return val.alias || val.account } }, layout: { width: 80 } }, { key: 'createtime', metas: { label: '建立時間', type: 'timestamp', formatter (val) { return moment(val).format('YYYY-MM-DD hh:mm') } }, layout: { width: 150 } }, { key: 'latesttime', metas: { label: '更新時間', type: 'timestamp', formatter (val) { return moment(val).format('YYYY-MM-DD HH:mm') } }, layout: { width: 150 } }, { key: 'operate', metas: { label: '操做', type: 'button', value: \[ { key: 'edit', label: '編輯', attributes: { visible: true, disabled: false } }, { key: 'drop', label: '刪除', attributes: { visible: true, disabled: false } } \] }, layout: { fixed: 'right', width: 100 } } \], tableBody: \[\] }, dialogForm: { visible: false, title: '', formRef: '', form: { name: '', category: '', description: '', status: false }, rules: { name: \[ { required: true, message: '請輸入名稱', trigger: 'blur' } \], category: \[ { required: true, message: '請選擇分類', trigger: 'change' } \], description: \[\] } } } }, async created () { this.init() } } </script\> <style lang\="scss" scoped\> @import '~@/stylesheets/layout.scss'; @import './index.scss'; </style\>
// 新建文件:client/src/views/approve-panel/index.scss .approve-module { .btns-wrap { margin-bottom: 20px; @include flex($content: flex-end); } /deep/ { .btn-drop { margin-left: 16px; } } }
展現效果:
html
這裏「建立人」是具體的用戶名,上傳和存儲的時候都是用戶ID,如何經過用戶ID查找用戶具體信息:前端
// 更新文件:server/control/approves.js ... async function list (ctx) { ... try { const approves = await approveModel.find({ author: ctx.state.auth.id }).populate('author'); ctx.body = { code: '200', data: approves, msg: '查詢成功' }; } ... } ... async function get (ctx) { const { id } = ctx.params; try { const approve = await approveModel.findOne({ _id: id }).populate({ path: 'author', select: '+avatar +alias +telephone +email +department +job +role +_id +__v' }).exec(); ... }
populate
與server/model/approve.js
文件中的author: { type: Schema.Types.ObjectId, ref: 'User', required: true },
對應使用,可查出用戶信息。
測試結果:[動態太大,傳不上來]
vue
發現,描述沒有顯示出來,這是由於description
沒有被查出,修改server/control/approves.js
中list
部分代碼.populate('author').select('+description');
npm
一對多關係app