零基础快速开发Vue图书管理系统—主体列表实现篇(四)
一、书籍编辑操作
服务端相关代码
const Router = require('@koa/router'); const mongoose = require('mongoose'); const { getBody } = require('../../helpers/utils') const BOOK_CONST = { IN: 'IN_COUNT', OUT: 'OUT_COUNT', } const Book = mongoose.model('Book'); const router = new Router({ prefix: '/book', }); router.post('/add', async(ctx) => { const { name, price, author, publishDate, classify, count } = getBody(ctx); const book = new Book({ name, price, author, publishDate, classify, count }); const res = await book.save(); ctx.body = { data: res, code: 1, msg: '添加成功' }; }); router.get('/list', async(ctx) => { const { page = 1, size = 10, keyword = '' } = ctx.query; //1 20 //2 20 //3 40 const query = {}; if (keyword) { query.name = keyword; } const list = await Book .find(query) //实现分页效果 .skip((page - 1) * size) .limit(size) .exec(); const total = await Book.countDocuments(); ctx.body = { data: { list, total, page, size, }, code: 1, msg: '获取列表成功' }; }); router.delete('/:id', async(ctx) => { const { id } = ctx.params; const delMsg = await Book.deleteOne({ _id: id, }); ctx.body = { data: delMsg, msg: '删除成功', code: 1, }; }); router.post('/update/count', async(ctx) => { const { id, type } = ctx.request.body; let { num, } = ctx.request.body; num = Number(num); const book = await Book.findOne({ _id: id, }).exec(); if (!book) { ctx.body = { code: 0, msg: '没有找到书籍' }; return; } //找到了书 if (type === BOOK_CONST.IN) { //入库操作 num = Math.abs(num); } else { //出库操作 num = -Math.abs(num); } book.count = book.count + num; if (book.count < 0) { ctx.body = { code: 0, msg: '剩下的量不足以出库' }; return; } const res = await book.save(); ctx.body = { data: res, code: 1, msg: '操作成功' }; }); router.post('/update', async(ctx) => { const { id, // name, // price, // author, // publishDate, // classify //剩余参数运算符 ...others } = ctx.request.body; const one = await Book.findOne({ _id: id, }).exec(); //没有找到书 if (!one) { ctx.body = { msg: '没有找到书籍', code: 0, } return; } const newQuery = {}; Object.entries(others).forEach(([key, value]) => { if (value) { newQuery[key] = value; } }); Object.assign(one, newQuery); const res = await one.save(); ctx.body = { data: res, code: 1, msg: '保存成功' }; }); module.exports = router;
客户端相关代码:
<template> <div> <a-modal title="添加书籍" :visible="props.show" @ok="submit" @cancel="close"> <a-form :label-col="{span:6}"> <a-form-item label="书名"> <a-input v-model:value="editForm.name" /> </a-form-item> <a-form-item label="价格"> <a-input-number v-model:value="editForm.price" :min="0" :max="9999999" /> </a-form-item> <a-form-item label="作者"> <a-input v-model:value="editForm.author" /> </a-form-item> <a-form-item label="出版日期"> <a-date-picker v-model:value="editForm.publishDate" /> </a-form-item> <a-form-item label="分类"> <a-input v-model:value="editForm.classify" /> </a-form-item> </a-form> </a-modal> </div> </template> <script src="./index.js"> </script> <style lang="scss" scoped> @import './index.scss' </style>
import { defineComponent, reactive, watch } from 'vue' import { book } from '@/service'; import { message } from 'ant-design-vue' import { result, clone } from '../../../helpers/utils/index'; import moment from 'moment'; export default defineComponent({ props: { show: Boolean, book: Object, }, setup(props, context) { const editForm = reactive({ name: '', price: 0, author: '', publishDate: 0, classify: '', }) const close = () => { context.emit('update:show', false); }; watch(() => props.book, (current) => { Object.assign(editForm, current); editForm.publishDate = moment(Number(editForm.publishDate)); }); const submit = async() => { const res = await book.update({ id: props.book._id, //…扩展运算符 name: editForm.name, price: editForm.price, author: editForm.author, publishDate: editForm.publishDate.valueOf(), classify: editForm.classify, }); result(res) .success(({ data, msg }) => { context.emit('update', data); message.success(msg); close(); }) } return { editForm, submit, props, close, } } })
二、书籍详情页面开发
<template> <div> <a-card> <space-between> <h2>书籍的名字</h2> <div> <a-button size="small" type="primary">编辑</a-button> <a-button size="small" type="danger">删除</a-button> </div> </space-between> <a-divider></a-divider> <div class="base-info"> <div class="items"> <div class="item"> <div class="title">价格</div> <div class="content">1</div> </div> <div class="item"> <div class="title">作者</div> <div class="content">2</div> </div> <div class="item"> <div class="title">分类</div> <div class="content">3</div> </div> </div> <div class="items"> <div class="item"> <div class="title">出版日期</div> <div class="content">4</div> </div> </div> </div> </a-card> <div class="log"> <a-card title="出入库日志"> <template #extra> <span> <a href="javascript:;">出库日志</a> </span> <span style="margin-left:12px"> <a href="javascript:;">入库日志</a> </span> </template> <div> <a-table bordered :pagination="false"></a-table> </div> <space-between style="margin-top:24px"> <div /> <a-pagination></a-pagination> </space-between> </a-card> </div> </div> </template> <script src="./index.js"> </script> <style lang="scss" scoped> @import './index.scss' </style>
三、书籍详情接口实现
四、库存日志相关内容实现
import { defineComponent, onMounted, ref } from 'vue'; import { useRoute, useRouter } from 'vue-router'; import { book, inventoryLog } from '@/service' import { result, formatTimestamp } from '@/helpers/utils'; import { CheckOutlined } from '@ant-design/icons-vue' import { message } from 'ant-design-vue' import Update from '@/views/Books/Update/index' const columns = [{ title: '数量', dataIndex: 'num', }, { title: '操作时间', slots: { customRender: 'createdAt' } } ] export default defineComponent({ components: { Update, CheckOutlined }, setup() { const route = useRoute(); const router = useRouter(); const showUpdateModal = ref(false); const { id } = route.params; const detailInfo = ref({}); const log = ref([]); const logTotal = ref(0); const logCurPage = ref(1); const curLogType = ref('IN_COUNT') const getDetail = async() => { const res = await book.detail(id); result(res) .success(({ data }) => { detailInfo.value = data; }) }; //获取出库入库日志 const getInventoryLog = async() => { const res = await inventoryLog.list( curLogType.value, logCurPage.value, 10); result(res) .success(({ data: { list, total } }) => { log.value = list; logTotal.value = total; }) }; onMounted(() => { getDetail(); getInventoryLog(); }); const remove = async() => { const res = await book.remove(id); result(res) .success(({ msg }) => { message.success(msg); router.replace('/books') }); }; //更新操作 const update = (book) => { Object.assign(detailInfo.value, book) }; //日志分页切换的时候 const setLogPage = (page) => { logCurPage.value = page; getInventoryLog(); }; //筛选日志 const logFilter = (type) => { curLogType.value = type; getInventoryLog(); }; return { d: detailInfo, formatTimestamp, remove, showUpdateModal, update, log, logTotal, setLogPage, columns, logFilter, curLogType, logCurPage } } });
<template> <div> <a-card> <space-between> <h2>{{d.name}}</h2> <div> <a-button size="small" type="primary" @click="showUpdateModal=true">编辑</a-button> <a-button size="small" type="danger" @click="remove">删除</a-button> </div> </space-between> <a-divider /> <div class="base-info"> <div class="items"> <div class="item"> <div class="title">价格</div> <div class="content">{{d.price}}</div> </div> <div class="item"> <div class="title">作者</div> <div class="content">{{d.author}}</div> </div> <div class="item"> <div class="title">分类</div> <div class="content">{{d.classify}}</div> </div> </div> <div class="items"> <div class="item"> <div class="title">出版日期</div> <div class="content">{{formatTimestamp(d.publishDate)}}</div> </div> </div> </div> </a-card> <div class="log"> <a-card title="出入库日志"> <template #extra> <span> <a href="javascript:;" @click="logFilter('IN_COUNT')"> <CheckOutlined v-if="curLogType==='IN_COUNT'" /> 入库日志</a> </span> <span style="margin-left:12px"> <a href="javascript:;" @click="logFilter('OUT_COUNT')"> <CheckOutlined v-if="curLogType==='OUT_COUNT'" /> 出库日志</a> </span> </template> <div> <a-table :data-source="log" :columns="columns" bordered :pagination="false"> <template #createdAt="{record}"> {{ formatTimestamp(record.meta.createdAt) }} </template> </a-table> </div> <space-between style="margin-top:24px"> <div /> <a-pagination v-model:current="logCurPage" :total="logTotal" :page-size="10" @change="setLogPage"> </a-pagination> </space-between> </a-card> </div> <update v-model:show="showUpdateModal" :book="d" @update="update" /> </div> </template> <script src="./index.js"> </script> <style lang="scss" scoped> @import './index.scss' </style>
五、书籍相关内容的优化
给列表增加排序功能