新增电子书表单及编辑功能

新增电子书表单

主要是对admin-book.vue进行修改。

  • 点击编辑按钮,弹出对话框,这里使用Antd的Modal组件
<template>
  <a-layout>
    <a-layout-content
        :style="{ background: '#fff', padding: '24px', margin: 0, minHeight: '280px' }"
    >
      <a-table :columns="columns" 
        :dataSource="ebooks"
        :row-key="record=>record.id"
        :pagination="pagination"
        :loading="loading"
        @change="handleTableChange">
        <template #cover="{text:cover}">
          <img v-if="cover" :src="cover" alt="avatar">
        </template>
        <template #action="{text,record}">
          <a-space>
            <a-button type="primary" @click="handleEdit">编辑</a-button>
            <a-button type="danger">删除</a-button>
          </a-space>
        </template>
      </a-table>
    </a-layout-content>

  </a-layout>

  <a-modal
    title="电子书表单"
    v-model:visible="visible"
    :confirm-loading="confirmLoading"
    @ok="handleOk"
  >
    <p>{{ modalText }}</p>
  </a-modal>

</template>


<script lang="ts">

import { defineComponent,ref,onMounted} from 'vue';
import axios from "axios";
export default defineComponent({
  name:"AdminEbook",
  setup() {
    const ebooks = ref();
    const pagination = ref({
      current:1,
      pageSize:4,
      total:0
    });
    const loading = ref(false);
    const columns = [
      {
        title:"封面",
        dataIndex:"cover",
        key:"cover",
        slots:{customRender:'cover'}
      },
      {
        title:"名称",
        key:"name",
        dataIndex:"name"
      },
      {
        title:"分类一",
        key:"category1Id",
        dataIndex:"category1Id"
      },
      {
        title:"分类二",
        key:"category2Id",
        dataIndex:"category2Id"
      },
      {
        title:"文档数",
        key:"docCount",
        dataIndex:"docCount"
      },
      {
        title:"阅读数",
        key:"viewCount",
        dataIndex:"viewCount"
      },
      {
        title:"点赞数",
        key:"vouteCount",
        dataIndex:"voteCount"
      },
      {
        title:"操作",
        key:"action",
        dataIndex:"action",
        slots:{customRender:'action'}

      }
    ];

    const visible = ref(false);
    const modalText = ref('test');
    const confirmLoading = ref(false);

    const handleQuery = (params:any) => {
      loading.value = true;
      axios.get("/ebook/list",{params:params}).then(response => {
        loading.value = false;
        const data = response.data.content;
        ebooks.value = data.list;
        
        pagination.value.total = data.total;
        pagination.value.current = params.page;
      })
    };

    const handleTableChange = (pagination:any) => {
      handleQuery({
        page:pagination.current,
        size:pagination.pageSize
      });
    }

    const handleEdit = (record:any) => {
      visible.value = true;
    }

    const handleOk = () => {
      modalText.value = 'The modal will be closed after two seconds';
      confirmLoading.value = true;
      setTimeout(() => {
        visible.value = false;
        confirmLoading.value = false;
      }, 2000);
    };
    
    onMounted(() => {
      handleQuery({
        page:1,
        size:pagination.value.pageSize
      });
    })

    return {
      columns,
      ebooks,
      loading,
      pagination,
      handleTableChange,
      visible,
      modalText,
      confirmLoading,
      handleEdit,
      handleOk
    }
  }
})
</script>


<style scoped>
img{
  width: 48px;
  height: 48px;
}
</style>

在这里插入图片描述

  • 弹出的对话框,框中内容是表单,所以使用Antd的Form组件
<template>
  <a-layout>
    <a-layout-content
        :style="{ background: '#fff', padding: '24px', margin: 0, minHeight: '280px' }"
    >
      <a-table :columns="columns" 
        :dataSource="ebooks"
        :row-key="record=>record.id"
        :pagination="pagination"
        :loading="loading"
        @change="handleTableChange">
        <template #cover="{text:cover}">
          <img v-if="cover" :src="cover" alt="avatar">
        </template>
        <template #action="{text,record}">
          <a-space>
            <a-button type="primary" @click="handleEdit(record)">编辑</a-button>
            <a-button type="danger">删除</a-button>
          </a-space>
        </template>
      </a-table>
    </a-layout-content>

  </a-layout>

  <a-modal
    title="电子书表单"
    v-model:visible="visible"
    :confirm-loading="confirmLoading"
    @ok="handleOk"
  >
    <a-form :model="ebook" :label-col="{span:4}" :wrapper-col="{span:16}">
      <a-form-item label="封面">
        <a-input v-model:value="ebook.cover" />
      </a-form-item>
      <a-form-item label="名称">
        <a-input v-model:value="ebook.name" />
      </a-form-item>
      <a-form-item label="分类一">
        <a-input v-model:value="ebook.category1Id" />
      </a-form-item>  
      <a-form-item label="分类二">
        <a-input v-model:value="ebook.category2Id" />
      </a-form-item>     
      <a-form-item label="描述">
        <a-input v-model:value="ebook.description" />
      </a-form-item>      
    </a-form>
  </a-modal>

</template>


<script lang="ts">

import { defineComponent,ref,onMounted} from 'vue';
import axios from "axios";
export default defineComponent({
  name:"AdminEbook",
  setup() {
    const ebooks = ref();
    const pagination = ref({
      current:1,
      pageSize:4,
      total:0
    });
    const loading = ref(false);
    const columns = [
      {
        title:"封面",
        dataIndex:"cover",
        key:"cover",
        slots:{customRender:'cover'}
      },
      {
        title:"名称",
        key:"name",
        dataIndex:"name"
      },
      {
        title:"分类一",
        key:"category1Id",
        dataIndex:"category1Id"
      },
      {
        title:"分类二",
        key:"category2Id",
        dataIndex:"category2Id"
      },
      {
        title:"文档数",
        key:"docCount",
        dataIndex:"docCount"
      },
      {
        title:"阅读数",
        key:"viewCount",
        dataIndex:"viewCount"
      },
      {
        title:"点赞数",
        key:"vouteCount",
        dataIndex:"voteCount"
      },
      {
        title:"操作",
        key:"action",
        dataIndex:"action",
        slots:{customRender:'action'}

      }
    ];

    const visible = ref(false);
    const modalText = ref('test');
    const confirmLoading = ref(false);
    const ebook= ref({});

    const handleQuery = (params:any) => {
      loading.value = true;
      axios.get("/ebook/list",{params:params}).then(response => {
        loading.value = false;
        const data = response.data.content;
        ebooks.value = data.list;
        
        pagination.value.total = data.total;
        pagination.value.current = params.page;
      })
    };

    const handleTableChange = (pagination:any) => {
      handleQuery({
        page:pagination.current,
        size:pagination.pageSize
      });
    }

    const handleEdit = (record:any) => {
      visible.value = true;
      ebook.value = record;
    }

    const handleOk = () => {
      modalText.value = 'The modal will be closed after two seconds';
      confirmLoading.value = true;
      setTimeout(() => {
        visible.value = false;
        confirmLoading.value = false;
      }, 2000);
    };
    
    onMounted(() => {
      handleQuery({
        page:1,
        size:pagination.value.pageSize
      });
    })

    return {
      columns,
      ebooks,
      loading,
      pagination,
      handleTableChange,
      visible,
      modalText,
      confirmLoading,
      handleEdit,
      handleOk,
      ebook
    }
  }
})
</script>


<style scoped>
img{
  width: 48px;
  height: 48px;
}
</style>

在这里插入图片描述

完成电子书编辑功能
新增并测试后端接口

修改电子书属性后,点击OK按钮,保存,对此,需要新增后端接口。

  • com.jepcc.test.req包下新增类EbookSaveReq
package com.jepcc.test.req;

public class EbookSaveReq {
    private Long id;

    private String name;

    private Long category1Id;

    private Long category2Id;

    private String description;

    private String cover;

    private Integer docCount;

    private Integer viewCount;

    private Integer voteCount;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Long getCategory1Id() {
        return category1Id;
    }

    public void setCategory1Id(Long category1Id) {
        this.category1Id = category1Id;
    }

    public Long getCategory2Id() {
        return category2Id;
    }

    public void setCategory2Id(Long category2Id) {
        this.category2Id = category2Id;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getCover() {
        return cover;
    }

    public void setCover(String cover) {
        this.cover = cover;
    }

    public Integer getDocCount() {
        return docCount;
    }

    public void setDocCount(Integer docCount) {
        this.docCount = docCount;
    }

    public Integer getViewCount() {
        return viewCount;
    }

    public void setViewCount(Integer viewCount) {
        this.viewCount = viewCount;
    }

    public Integer getVoteCount() {
        return voteCount;
    }

    public void setVoteCount(Integer voteCount) {
        this.voteCount = voteCount;
    }
}
  • com.jepcc.test.service.EbookService中添加保存方法
package com.jepcc.test.service;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.jepcc.test.mapper.EbookMapper;
import com.jepcc.test.model.Ebook;
import com.jepcc.test.model.EbookExample;
import com.jepcc.test.req.EbookReq;
import com.jepcc.test.req.EbookSaveReq;
import com.jepcc.test.resp.EbookResp;
import com.jepcc.test.resp.PageResp;
import com.jepcc.test.util.CopyUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.util.List;


@Service
public class EbookService {
    private static final Logger LOG = LoggerFactory.getLogger(EbookService.class);
    @Autowired
    private EbookMapper ebookMapper;
    public PageResp<EbookResp> list(EbookReq req){

        EbookExample ebookExample = new EbookExample();
        EbookExample.Criteria criteria = ebookExample.or();
        if(!ObjectUtils.isEmpty(req.getName())){
            criteria.andNameLike("%"+req.getName()+"%");
        }

        PageHelper.startPage(req.getPage(),req.getSize());
        List<Ebook> ebookList = ebookMapper.selectByExample(ebookExample);

        PageInfo<Ebook> pageinfo = new PageInfo<>(ebookList);
//        LOG.info("总条数:{}",pageinfo.getTotal());
//        LOG.info("总页数,{}",pageinfo.getPages());
        List<EbookResp> list = CopyUtil.copyList(ebookList,EbookResp.class);
        PageResp<EbookResp> pageResp = new PageResp<>();
        pageResp.setTotal(pageinfo.getTotal());
        pageResp.setList(list);

        return pageResp;
    }

    public void save(EbookSaveReq req){
        Ebook ebook = CopyUtil.copy(req,Ebook.class);
        if(!ObjectUtils.isEmpty(ebook.getId())){
            ebookMapper.updateByPrimaryKey(ebook);
        }
    }
}

在这里插入图片描述

  • com.jepcc.test.controller.EbookController新增保存方法
package com.jepcc.test.controller;

import com.alibaba.fastjson.JSONObject;
import com.jepcc.test.req.EbookReq;
import com.jepcc.test.req.EbookSaveReq;
import com.jepcc.test.resp.CommonResp;
import com.jepcc.test.resp.EbookResp;
import com.jepcc.test.resp.PageResp;
import com.jepcc.test.service.EbookService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/ebook")
public class EbookController {
    private static final Logger LOG = LoggerFactory.getLogger(EbookController.class);
    @Autowired
    private EbookService ebookService;


    @GetMapping("/list")
    public CommonResp list(EbookReq req){
        CommonResp resp = new CommonResp();
        PageResp<EbookResp> list = ebookService.list(req);
        resp.setContent(list);
        return resp;
    }

    @PostMapping("/save")
    public CommonResp save(@RequestBody EbookSaveReq req){
        LOG.info("----------------------------------------");
        LOG.info("req:{}", JSONObject.toJSONString(req));
        LOG.info("----------------------------------------");
        CommonResp resp = new CommonResp();
        ebookService.save(req);
        return resp;
    }
}

在这里插入图片描述

  • 接口测试
POST http://localhost:8088/ebook/save
content-type: application/json

{
  "id": 1,
  "name": "SpringBoot入门教程",
  "category1Id": 10,
  "category2Id": 20,
  "cover": "/image/cover1.png",
  "description": "这是一项测试"
}
###

在这里插入图片描述
在这里插入图片描述
需要注意的是,如果http请求的Content-Typeapplication/json,则EbookController中的接口方法save,其参数前需要添加@RequestBody注解;
在这里插入图片描述
如果http请求的Content-Typeapplication/x-www-form-urlencoded,则EbookController中的接口方法save中,其请求参数前不需要@RequestBody
在这里插入图片描述
后端使用@RequestBody接收从前端传递过来的json字符串,通常是通过post请求发送过来的请求体数据。

前端调用接口

admin-book.vue进行修改。

<template>
  <a-layout>
    <a-layout-content
        :style="{ background: '#fff', padding: '24px', margin: 0, minHeight: '280px' }"
    >
      <a-table :columns="columns" 
        :dataSource="ebooks"
        :row-key="record=>record.id"
        :pagination="pagination"
        :loading="loading"
        @change="handleTableChange">
        <template #cover="{text:cover}">
          <img v-if="cover" :src="cover" alt="avatar">
        </template>
        <template #action="{text,record}">
          <a-space>
            <a-button type="primary" @click="handleEdit(record)">编辑</a-button>
            <a-button type="danger">删除</a-button>
          </a-space>
        </template>
      </a-table>
    </a-layout-content>

  </a-layout>

  <a-modal
    title="电子书表单"
    v-model:visible="visible"
    :confirm-loading="confirmLoading"
    @ok="handleOk"
  >
    <a-form :model="ebook" :label-col="{span:4}" :wrapper-col="{span:16}">
      <a-form-item label="封面">
        <a-input v-model:value="ebook.cover" />
      </a-form-item>
      <a-form-item label="名称">
        <a-input v-model:value="ebook.name" />
      </a-form-item>
      <a-form-item label="分类一">
        <a-input v-model:value="ebook.category1Id" />
      </a-form-item>  
      <a-form-item label="分类二">
        <a-input v-model:value="ebook.category2Id" />
      </a-form-item>     
      <a-form-item label="描述">
        <a-input v-model:value="ebook.description" />
      </a-form-item>      
    </a-form>
  </a-modal>

</template>


<script lang="ts">

import { defineComponent,ref,onMounted} from 'vue';
import axios from "axios";
export default defineComponent({
  name:"AdminEbook",
  setup() {
    const ebooks = ref();
    const pagination = ref({
      current:1,
      pageSize:4,
      total:0
    });
    const loading = ref(false);
    const columns = [
      {
        title:"封面",
        dataIndex:"cover",
        key:"cover",
        slots:{customRender:'cover'}
      },
      {
        title:"名称",
        key:"name",
        dataIndex:"name"
      },
      {
        title:"分类一",
        key:"category1Id",
        dataIndex:"category1Id"
      },
      {
        title:"分类二",
        key:"category2Id",
        dataIndex:"category2Id"
      },
      {
        title:"文档数",
        key:"docCount",
        dataIndex:"docCount"
      },
      {
        title:"阅读数",
        key:"viewCount",
        dataIndex:"viewCount"
      },
      {
        title:"点赞数",
        key:"vouteCount",
        dataIndex:"voteCount"
      },
      {
        title:"操作",
        key:"action",
        dataIndex:"action",
        slots:{customRender:'action'}

      }
    ];

    const visible = ref(false);
    const modalText = ref('test');
    const confirmLoading = ref(false);
    const ebook= ref({});

    const handleQuery = (params:any) => {
      loading.value = true;
      axios.get("/ebook/list",{params:params}).then(response => {
        loading.value = false;
        const data = response.data.content;
        ebooks.value = data.list;
        
        pagination.value.total = data.total;
        pagination.value.current = params.page;
      })
    };

    const handleTableChange = (pagination:any) => {
      handleQuery({
        page:pagination.current,
        size:pagination.pageSize
      });
    }

    const handleEdit = (record:any) => {
      visible.value = true;
      ebook.value = record;
    }

    const handleOk = () => {
      // modalText.value = 'The modal will be closed after two seconds';
      // confirmLoading.value = true;
      axios.post("/ebook/save",ebook.value).then(response => {
        const data = response.data;
        if(data.success){
          visible.value = false;
          confirmLoading.value = false;

          handleQuery({
            page:pagination.value.current,
            size:pagination.value.pageSize
          })
        }
        
      })
      // setTimeout(() => {
      //   visible.value = false;
      //   confirmLoading.value = false;
      // }, 2000);
    };
    
    onMounted(() => {
      handleQuery({
        page:1,
        size:pagination.value.pageSize
      });
    })

    return {
      columns,
      ebooks,
      loading,
      pagination,
      handleTableChange,
      visible,
      modalText,
      confirmLoading,
      handleEdit,
      handleOk,
      ebook
    }
  }
})
</script>


<style scoped>
img{
  width: 48px;
  height: 48px;
}
</style>

在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值