<template>
  <div>
    <el-container>
      <!-- 侧边栏 -->
      <el-aside style="width: 200px;min-height: 100vh;background-color:rgb(254, 64, 74)">
        <div style="height: 60px; display: flex; align-items: center; justify-content: center;">
          <img src="./photo/GH.jpg" alt="Logo" style="width: 100%; height: auto;">
        </div>
        <el-menu class="custom-menu" style="width: 200px; background-color: #fe8f8f;" popper-append-to-body>
          <el-row>
            <el-col :span="12">
              <el-menu class="custom-menu" style="width: 200px; background-color: #fe8f8f;" popper-append-to-body>
                <el-submenu index="1">
                  <template slot="title">
                    <i class="el-icon-location"></i>
                    <span>导航栏</span>
                  </template>
                  <el-menu-item-group>
                    <template slot="title"></template>
                    <el-menu-item index="2">
                      <router-link to="/home#section1">首页</router-link>
                    </el-menu-item>
                    <el-menu-item index="4">
                      <router-link to="/borrow">借阅系统</router-link>
                    </el-menu-item>
                  </el-menu-item-group>
                </el-submenu>
              </el-menu>
            </el-col>
          </el-row>
        </el-menu>
      </el-aside>
      <el-container>

        <!-- 头部 -->
        <el-header style="font-family: 楷体;text-align: center;font-weight: bold;background-color:rgb(254, 64, 74);color: white;font-size: 50px;">
          红色精神图书管理系统
        </el-header>

        <!-- 主要内容区域 -->
        <el-main>
          <el-form :inline="true" :model="queryForm" class="demo-form-inline" style="margin-bottom: 20px;">
            <el-form-item label="书名">
              <el-input v-model="queryForm.name" placeholder="书名"></el-input>
            </el-form-item>
            <el-form-item>
              <el-button type="primary" @click="handleQuery">查询</el-button>
              <el-button type="default" @click="resetQuery" style="margin-left: 10px;">复原</el-button>
            </el-form-item>
          </el-form>

          <el-button type="primary" style="margin-top: 20px;" @click="handleMyBorrowed">我的借阅</el-button>

          <el-table
              :data="tableData"
              tooltip-effect="dark"
              style="width: 100%; margin-top: 20px;"
              @selection-change="handleSelectionChange"
          >
            <el-table-column type="selection" width="55"></el-table-column>
            <el-table-column prop="name" label="书名" width="180"></el-table-column>
            <el-table-column prop="publisher" label="出版社" width="180"></el-table-column>
            <el-table-column prop="author" label="作者" width="180"></el-table-column>
            <el-table-column label="数量" prop="quantity" width="100"></el-table-column>
            <el-table-column label="存入时间" width="180">
              <template #default="{ row }">
                {{ formatDateTime(row.storeTime) }}
              </template>
            </el-table-column>
            <el-table-column label="操作" width="120">
              <template #default="{ row }">
                <el-button size="mini" @click="handleBorrow(row)">借阅</el-button>
              </template>
            </el-table-column>
          </el-table>

          <el-pagination
              @size-change="handleSizeChange"
              @current-change="handlePageChange"
              :current-page="currentPage"
              :page-sizes="[10, 20, 30, 40]"
              :page-size="pageSize"
              layout="total, sizes, prev, pager, next, jumper"
              style="text-align: right; margin-top: 20px;">
          </el-pagination>

          <!-- 我的借阅记录对话框 -->
          <el-dialog title="我的借阅记录" :visible.sync="myBorrowedVisible">
            <el-table :data="myBorrowedData" style="width: 100%">
              <el-table-column prop="bookName" label="书名" width="180"></el-table-column>
              <el-table-column prop="borrowTime" label="借阅时间" width="180"></el-table-column>
              <el-table-column prop="returnTime" label="归还时间" width="180"></el-table-column>
            </el-table>
          </el-dialog>
        </el-main>
      </el-container>
    </el-container>
  </div>
</template>

<script>
import axios from 'axios';

export default {
  data() {
    return {
      queryForm: {
        name: '',
      },
      tableData: [],
      currentPage: 1,
      pageSize: 10,
      selectedRows: [],
      myBorrowedVisible: false,
      myBorrowedData: [],
    };
  },
  methods: {
    // 查询书籍列表
    async handleQuery() {
      try {
        const response = await axios.get('http://localhost:8080/books', {
          params: {
            page: this.currentPage,
            pageSize: this.pageSize,
            name: this.queryForm.name,
          },
        });
        if (response.data.code === 1) {
          this.tableData = response.data.data.rows;
        } else {
          this.$message.error(response.data.msg || '查询失败');
        }
      } catch (error) {
        this.$message.error('查询失败，请重试');
        console.error(error);
      }
    },

    // 重置查询
    resetQuery() {
      this.queryForm.name = '';
      this.handleQuery();
    },

   
    // 页大小变化
    handleSizeChange(val) {
      this.pageSize = val;
      this.handleQuery();
    },

    // 当前页变化
    handlePageChange(val) {
      this.currentPage = val;
      this.handleQuery();
    },

    // 选择项变化
    handleSelectionChange(val) {
      this.selectedRows = val;
    },

    // 格式化时间
    formatDateTime(value) {
      if (!value) return '';
      return new Date(value).toLocaleString();
    },
  },
  mounted() {
    this.handleQuery();
  },
};
</script>

<style scoped>
.custom-menu.el-menu-item span,
.custom-menu.el-menu-item {
  color: white!important;
  font-weight: bold;
}
.el-menu-item:hover {
  background-color: yellow!important;
  color: red!important;
}

.el-table .el-table__body-wrapper {
  margin-top: 10px;
}

.el-table .el-table__row {
  margin: 10px 0;
}
</style>
在上面代码的基础上添加功能：点击借阅（可以批量借阅，但借阅过的书和数量为0的书不允许框选），就会自动加到我的借阅里面，点击我的借阅，跳出一个弹窗，需要输入用户名和密码核验正确才能查看我借阅的书籍，点击确认借阅，books表的所对应的书籍会减1，并且数据库会存入借书人的用户名，密码，借的书名，借书时间（borrow表）。-- CREATE TABLE books (
--     id INT PRIMARY KEY AUTO_INCREMENT,
--     name VARCHAR(255) NOT NULL,
--     publisher VARCHAR(255) NOT NULL,
--     author VARCHAR(255) NOT NULL,
--     store_time DATETIME NOT NULL,
--     quantity INT NOT NULL
-- );


-- CREATE TABLE users (
--     id BIGINT AUTO_INCREMENT PRIMARY KEY,
--     username VARCHAR(50) NOT NULL UNIQUE,
--     password VARCHAR(255) NOT NULL,
--     role VARCHAR(20) NOT NULL,
--     created_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP
-- );package com.wwq.bookproject.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Book {
    private Integer id; // 书ID
    private String name; // 书名
    private String publisher; // 出版社
    private String author; // 作者
    private LocalDateTime storeTime; // 存入时间
    private Integer quantity; // 书的数量
}
package com.wwq.bookproject.controller;

import com.wwq.bookproject.pojo.Book;
import com.wwq.bookproject.pojo.PageBean;
import com.wwq.bookproject.pojo.Result;
import com.wwq.bookproject.service.BookService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.List;

@Slf4j
@RestController
@RequestMapping("/books")
public class BookController {

    @Autowired
    private BookService bookService;

    @GetMapping
    public Result page(@RequestParam(defaultValue = "1") Integer page,
                       @RequestParam(defaultValue = "10") Integer pageSize,
                       String name, String publisher, String author,
                       @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime begin,
                       @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime end) {
        log.info("分页查询, 参数: {},{},{},{},{},{}", page, pageSize, name, publisher, author, begin, end);
        PageBean pageBean = bookService.page(page, pageSize, name, publisher, author, begin, end);
        return Result.success(pageBean);
    }

    @DeleteMapping("/{ids}")
    public Result delete(@PathVariable List<Integer> ids) {
        log.info("批量删除操作，ids:{}", ids);
        bookService.delete(ids);
        return Result.success();
    }

    @PostMapping
    public Result save(@RequestBody Book book) {
        bookService.save(book);
        return Result.success();
    }

    @GetMapping("/{id}")
    public Result getById(@PathVariable Integer id) {
        log.info("根据ID查询信息，id:{}", id);
        Book book = bookService.getById(id);
        return Result.success(book);
    }

    @PutMapping
    public Result update(@RequestBody Book book) {
        log.info("更新图书信息:{}", book);
        bookService.update(book);
        return Result.success();

    }
}
package com.wwq.bookproject.mapper;

import com.wwq.bookproject.pojo.Book;
import org.apache.ibatis.annotations.*;
import java.time.LocalDateTime;
import java.util.List;

/**
 * 书籍Mapper接口
 */
@Mapper
public interface BookMapper {

    /**
     * 查询书籍总数
     * @return 书籍总数
     */
    @Select("SELECT COUNT(*) FROM books")
    Long count();

    /**
     * 条件查询书籍列表
     * @param name 书籍名称
     * @param publisher 出版社
     * @param author 作者
     * @param begin 上架开始时间
     * @param end 上架结束时间
     * @return 书籍列表
     */
    @Select("<script>" +
            "SELECT * FROM books" +
            "<where>" +
            "<if test='name != null and name != \"\"'>" +
            "name LIKE CONCAT('%', #{name}, '%')" +
            "</if>" +
            "<if test='publisher != null and publisher != \"\"'>" +
            "AND publisher = #{publisher}" +
            "</if>" +
            "<if test='author != null and author != \"\"'>" +
            "AND author = #{author}" +
            "</if>" +
            "<if test='begin != null and end != null'>" +
            "AND store_time BETWEEN #{begin} AND #{end}" +
            "</if>" +
            "</where>" +
            "ORDER BY store_time DESC" +
            "</script>")
    List<Book> list(String name, String publisher, String author, LocalDateTime begin, LocalDateTime end);

    /**
     * 根据id列表批量删除书籍
     * @param ids 书籍id列表
     */
    @Delete("<script>" +
            "DELETE FROM books WHERE id IN" +
            "<foreach item='id' index='index' collection='ids' open='(' separator=',' close=')'>" +
            "#{id}" +
            "</foreach>" +
            "</script>")
    void delete(@Param("ids") List<Integer> ids);

    /**
     * 新增书籍
     * @param book 书籍对象
     */
    @Insert("INSERT INTO books(name, publisher, author, store_time, quantity) " +
            "VALUES(#{name}, #{publisher}, #{author}, #{storeTime}, #{quantity})")
    void save(Book book);

    /**
     * 根据id查询书籍
     * @param id 书籍id
     * @return 书籍对象
     */
    @Select("SELECT * FROM books WHERE id = #{id}")
    Book getById(Integer id);

    /**
     * 更新书籍信息
     * @param book 书籍对象
     */
    @Update("UPDATE books SET name = #{name}, publisher = #{publisher}, author = #{author}, store_time = #{storeTime}, quantity = #{quantity} WHERE id = #{id}")
    void update(Book book);
}
package com.wwq.bookproject.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.wwq.bookproject.mapper.BookMapper;
import com.wwq.bookproject.pojo.Book;
import com.wwq.bookproject.pojo.PageBean;
import com.wwq.bookproject.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;

@Service
public class BookServiceImpl implements BookService {

    @Autowired
    private BookMapper bookMapper;

    @Override
    public PageBean page(Integer page, Integer pageSize, String name, String publisher, String author, LocalDateTime begin, LocalDateTime end) {
        PageHelper.startPage(page, pageSize);
        List<Book> bookList = bookMapper.list(name, publisher, author, begin, end);
        Page<Book> pageInfo = (Page<Book>) bookList;
        PageBean pageBean = new PageBean(pageInfo.getTotal(), pageInfo.getResult());
        return pageBean;
    }

    @Override
    public void delete(List<Integer> ids) {
        bookMapper.delete(ids);
    }

    @Override
    public void save(Book book) {
        book.setStoreTime(LocalDateTime.now());
        bookMapper.save(book);
    }

    @Override
    public Book getById(Integer id) {
        return bookMapper.getById(id);
    }

    @Override
    public void update(Book book) {
        book.setStoreTime(LocalDateTime.now()); // 这里可以根据实际情况决定是否更新存入时间
        bookMapper.update(book);
    }
}
package com.wwq.bookproject.service;

import com.wwq.bookproject.pojo.Book;
import com.wwq.bookproject.pojo.PageBean;
import java.time.LocalDateTime;
import java.util.List;

public interface BookService {
    PageBean page(Integer page, Integer pageSize, String name, String publisher, String author, LocalDateTime begin, LocalDateTime end);
    void delete(List<Integer> ids);
    void save(Book book);
    Book getById(Integer id);
    void update(Book book);
}


package com.wwq.bookproject.controller;

import com.wwq.bookproject.pojo.User;
import com.wwq.bookproject.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/loginRegister")
public class AuthController {

    @Autowired
    private UserService userService;

    // 注册
    @PostMapping("/register")
    public ResponseEntity<String> register(@RequestBody User user) {
        // 在注册用户时，统一加密密码
        userService.register(user);
        return ResponseEntity.ok("注册成功！");
    }

    // 登录
    @PostMapping("/login")
    public ResponseEntity<User> login(@RequestBody User loginRequest) {
        // 登录时校验用户名和密码
        User user = userService.login(loginRequest.getUsername(), loginRequest.getPassword());
        if (user == null) {
            return ResponseEntity.status(401).body(null); // 用户不存在或密码错误
        }
        return ResponseEntity.ok(user); // 登录成功，返回用户信息
    }
}
package com.wwq.bookproject.mapper;


import com.wwq.bookproject.pojo.User;
import org.apache.ibatis.annotations.*;

@Mapper
public interface UserMapper {

    @Insert("INSERT INTO users (username, password, role) VALUES (#{username}, #{password}, #{role})")
    void register(User user);

    // 根据用户名查询用户信息
    @Select("SELECT * FROM users WHERE username = #{username}")
    User findByUsername(@Param("username") String username);
}
package com.wwq.bookproject.pojo;

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

public class PasswordUtils {

    private static final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();

    // 密码加密方法
    public static String encode(String rawPassword) {
        return encoder.encode(rawPassword);
    }

    // 校验用户输入的密码是否匹配数据库中的加密密码
    public static boolean matches(String rawPassword, String encodedPassword) {
        return encoder.matches(rawPassword, encodedPassword);
    }

        public static void main(String[] args) {
            String rawPassword = "123456"; // 明文密码
            String encryptedPassword = PasswordUtils.encode(rawPassword); // 加密密码
            System.out.println("明文密码: " + rawPassword);
            System.out.println("加密后的密码: " + encryptedPassword);
        }
//    INSERT INTO users (username, password, role)
//    VALUES ('root', '$2a$10$0NUEwzJp1Vu6MzR0Sd/M7OFun2CByNSnJOSo8uStrkm0dcMxMhgYS', 'ADMIN');

}
package com.wwq.bookproject.pojo;

import lombok.Data;

@Data
public class User {
    private Long id;
    private String username;
    private String password;
    private String role; // USER or ADMIN
    private String createdAt;
}
package com.wwq.bookproject.service.impl;

import com.wwq.bookproject.pojo.PasswordUtils;
import com.wwq.bookproject.pojo.User;
import com.wwq.bookproject.mapper.UserMapper;
import com.wwq.bookproject.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public void register(User user) {
        // 对用户密码加密存储
        user.setPassword(PasswordUtils.encode(user.getPassword()));
        userMapper.register(user);
    }

    @Override
    public User login(String username, String password) {
        // 通过用户名查询用户信息
        User user = userMapper.findByUsername(username);
        if (user == null || !PasswordUtils.matches(password, user.getPassword())) {
            return null; // 用户不存在 或 密码错误
        }
        return user; // 登录成功
    }
}
package com.wwq.bookproject.service;

import com.wwq.bookproject.pojo.User;

public interface UserService {
    void register(User user); // 用户注册
    User login(String username, String password); // 用户登录
}