mirror of
https://gitee.com/bookshelfplus/bookshelfplus
synced 2025-09-01 22:53:29 +08:00
文件关联书籍功能完成
This commit is contained in:
@@ -89,6 +89,12 @@ router.get('/callback/:platform', function (req, res) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.get('/dashboard/iframe/:page', function (req, res) {
|
||||||
|
res.render(`dashboard/component/iframe/${req.params.page}`, {
|
||||||
|
pageUrl: (req._parsedUrl.pathname + "/").replace("//", "/"),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
router.get('/dashboard/:group/:page/:subpage?', function (req, res) {
|
router.get('/dashboard/:group/:page/:subpage?', function (req, res) {
|
||||||
// baseTemplate 基于哪个html模板渲染页面
|
// baseTemplate 基于哪个html模板渲染页面
|
||||||
// pageTemplate 引入这个文件中的页面脚本
|
// pageTemplate 引入这个文件中的页面脚本
|
||||||
|
@@ -3,6 +3,12 @@
|
|||||||
</p>
|
</p>
|
||||||
<h3>文件详情</h3>
|
<h3>文件详情</h3>
|
||||||
<div id="file-detail-container"></div>
|
<div id="file-detail-container"></div>
|
||||||
|
<div id="book-selector-container" style="display: none;">
|
||||||
|
<p>
|
||||||
|
请选择需要绑定的书籍
|
||||||
|
</p>
|
||||||
|
<iframe id="book-selector-iframe" src="" style="width: 100%; height: 55vh;"></iframe>
|
||||||
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
<h3>关联文件对象</h3>
|
<h3>关联文件对象</h3>
|
||||||
<div id="file-object-container"></div>
|
<div id="file-object-container"></div>
|
||||||
@@ -43,7 +49,7 @@
|
|||||||
<tr><td>文件大小</td><td>${stringifyFileSize(data.fileSize)}</td></tr>
|
<tr><td>文件大小</td><td>${stringifyFileSize(data.fileSize)}</td></tr>
|
||||||
<tr><td>SHA1</td><td>${data.fileSha1}</td></tr>
|
<tr><td>SHA1</td><td>${data.fileSha1}</td></tr>
|
||||||
<tr><td>文件Id</td><td>${data.id}</td></tr>
|
<tr><td>文件Id</td><td>${data.id}</td></tr>
|
||||||
<tr><td>关联书籍Id</td><td>${data.bookId == 0 ? "未关联书籍" : data.bookId}</td></tr>
|
<tr><td>关联书籍Id</td><td>${data.bookId == 0 ? "未关联书籍" : data.bookId} <button onclick="toggleSelectBook();">关联书籍</button></td></tr>
|
||||||
<tr><td>是否有广告</td><td>${data.advertising ? "是" : "否"}</td></tr>
|
<tr><td>是否有广告</td><td>${data.advertising ? "是" : "否"}</td></tr>
|
||||||
<tr><td>是否有水印</td><td>${data.watermark ? "是" : "否"}</td></tr>
|
<tr><td>是否有水印</td><td>${data.watermark ? "是" : "否"}</td></tr>
|
||||||
<tr><td>文件创建日期</td><td>${data.fileCreateAt}</td></tr>
|
<tr><td>文件创建日期</td><td>${data.fileCreateAt}</td></tr>
|
||||||
@@ -110,3 +116,51 @@
|
|||||||
}
|
}
|
||||||
getFileObjectInfo();
|
getFileObjectInfo();
|
||||||
</script>
|
</script>
|
||||||
|
<script>
|
||||||
|
window.addEventListener('message', function (event) {
|
||||||
|
var data = JSON.parse(event.data);
|
||||||
|
console.log("子页面消息:", data);
|
||||||
|
var bookId = data.id;
|
||||||
|
if (data.iframe != "book-selector") return;
|
||||||
|
if (data.id == null) {
|
||||||
|
toggleSelectBook();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户选择了书籍,现在需要绑定到文件
|
||||||
|
postRequest("/file/bindBook", { token: localStorageUtils.getToken(), fileId: fileId, bookId: bookId })
|
||||||
|
.then(function (responseData) {
|
||||||
|
var axiosData = responseData.data;
|
||||||
|
var status = axiosData.status;
|
||||||
|
var data = axiosData.data;
|
||||||
|
if (status === "success") {
|
||||||
|
console.log(data);
|
||||||
|
if(data == "success") {
|
||||||
|
// alert("绑定成功!");
|
||||||
|
} else {
|
||||||
|
alert("绑定失败!");
|
||||||
|
}
|
||||||
|
getFileInfo();
|
||||||
|
} else {
|
||||||
|
alert(`出错啦!${data.errMsg}(错误码: ${data.errCode}) `);
|
||||||
|
}
|
||||||
|
}).catch(function (error) {
|
||||||
|
console.log(error);
|
||||||
|
alert("无法连接到服务器,请检查网络连接!");
|
||||||
|
}).finally(function () {
|
||||||
|
toggleSelectBook();
|
||||||
|
});
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
function toggleSelectBook() {
|
||||||
|
if($("#book-selector-container").css("display") === "none") {
|
||||||
|
document.getElementById("book-selector-iframe").src = "/dashboard/iframe/book-selector";
|
||||||
|
$("#book-selector-container").slideDown();
|
||||||
|
} else {
|
||||||
|
$("#book-selector-container").slideUp();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function selectBook() {
|
||||||
|
$("#book-selector-container").slideDown();
|
||||||
|
}
|
||||||
|
</script>
|
@@ -0,0 +1,151 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<% htmlTitle = "选择书籍" %>
|
||||||
|
<%- include("./header.html"); %>
|
||||||
|
<style>
|
||||||
|
.main {
|
||||||
|
width: 92vw !important;
|
||||||
|
max-width: initial !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#book-table {
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 30px;
|
||||||
|
line-height: 2.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
table, tr, th, td {
|
||||||
|
border: 1px solid black;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr:hover {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr a {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- 获取参数 -->
|
||||||
|
<script src="/assets/javascripts/getParams.js"></script>
|
||||||
|
<!-- 渲染表格 -->
|
||||||
|
<script src="/assets/javascripts/renderTable.js"></script>
|
||||||
|
<main class="main">
|
||||||
|
<input id="searchInput" type="text" />
|
||||||
|
<input id="searchButton" type="button" value="搜索" />
|
||||||
|
<table id="book-table"></table>
|
||||||
|
</div>
|
||||||
|
<button onclick="closeWindow();" style="position: fixed; right: 0; top: 0;">×</button>
|
||||||
|
</main>
|
||||||
|
<!-- 搜索书籍 -->
|
||||||
|
<script>
|
||||||
|
var requestParams = getParams();
|
||||||
|
var searchbox = document.getElementById("searchInput");
|
||||||
|
var keyword = (requestParams["keyword"] || "").trim();
|
||||||
|
search({
|
||||||
|
tableElementId: "book-table",
|
||||||
|
searchText: null,
|
||||||
|
categoryId: null
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#searchButton").click(function () {
|
||||||
|
search({
|
||||||
|
tableElementId: "book-table",
|
||||||
|
searchText: $("#searchInput").val(),
|
||||||
|
categoryId: null
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function search({ tableElementId = "", searchText = "", categoryId = 0 }) {
|
||||||
|
getRequest("/book/search", { bookName: searchText, categoryId: categoryId })
|
||||||
|
.then(function (responseData) {
|
||||||
|
var axiosData = responseData.data;
|
||||||
|
var status = axiosData.status;
|
||||||
|
var data = axiosData.data;
|
||||||
|
if (status === "success") {
|
||||||
|
// console.log(data)
|
||||||
|
|
||||||
|
// 数据进行转换
|
||||||
|
var renderData = [];
|
||||||
|
data.forEach(element => {
|
||||||
|
var mainDivWidth = 96/*vw*/; // 定义div的宽度(用于计算表格中的数据的显示长度)
|
||||||
|
var columnWidth = [20, 15, 10, 15, 5, 35];
|
||||||
|
renderData.push({
|
||||||
|
编号: `${element.id}`,
|
||||||
|
书名: `<a target="_blank" href="/book?id=${element.id}">
|
||||||
|
<span class="overflow-omit" style="max-width: ${columnWidth[0] * mainDivWidth / 100}vw; max-height: 2em; margin: 0 auto;">
|
||||||
|
${element.bookName}
|
||||||
|
</span>
|
||||||
|
</a>`,
|
||||||
|
分类: `<a target="_blank" href="/category?id=${element.category.id}">
|
||||||
|
<span class="overflow-omit" style="max-width: ${columnWidth[1] * mainDivWidth / 100}vw; max-height: 2em; margin: 0 auto;">
|
||||||
|
${element.category.name}
|
||||||
|
</span>
|
||||||
|
</a>`,
|
||||||
|
作者: `${element.author}`,
|
||||||
|
语言: `<span class="overflow-omit" style="max-width: ${columnWidth[2] * mainDivWidth / 100}vw; max-height: 2em; margin: 0 auto;">
|
||||||
|
${element.language}
|
||||||
|
</span>`,
|
||||||
|
出版社: `<span class="overflow-omit" style="max-width: ${columnWidth[3] * mainDivWidth / 100}vw; max-height: 2em; margin: 0 auto;">
|
||||||
|
${element.publishingHouse}
|
||||||
|
</span>`,
|
||||||
|
来源: `<span class="overflow-omit" style="max-width: ${columnWidth[4] * mainDivWidth / 100}vw; max-height: 2em; margin: 0 auto;">
|
||||||
|
${element.publishingHouse}
|
||||||
|
</span>`,
|
||||||
|
管理: `<span class="overflow-omit" style="max-width: ${columnWidth[5] * mainDivWidth / 100}vw; max-height: 2em; margin: 0 auto;">
|
||||||
|
<a href="javascript:selectItem(${element.id});">选择</a>
|
||||||
|
</span>`,
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
if (renderData.length == 0) {
|
||||||
|
console.log("没有搜索到相关书籍");
|
||||||
|
function htmlEncode(str) {
|
||||||
|
// refer: https://stackoverflow.com/questions/4183801/escape-html-chracters
|
||||||
|
var div = document.createElement('div');
|
||||||
|
var txt = document.createTextNode(str);
|
||||||
|
div.appendChild(txt);
|
||||||
|
return div.innerHTML;
|
||||||
|
}
|
||||||
|
if (searchText && searchText != "") {
|
||||||
|
//
|
||||||
|
renderTable({ data: `没有搜索到与 <span style="color: red;">${htmlEncode(searchText)}</span> 相关的书籍,请换个关键词再试试吧`, tableId: tableElementId, renderTableHead: true });
|
||||||
|
} else if (categoryId && categoryId != 0) {
|
||||||
|
//
|
||||||
|
renderTable({ data: `该分类下暂无电子书`, tableId: tableElementId, renderTableHead: true });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
renderTable({ data: renderData, tableId: tableElementId, renderTableHead: true });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
alert(`出错啦!${data.errMsg} (错误码: ${data.errCode}) `);
|
||||||
|
}
|
||||||
|
}).catch(function (error) {
|
||||||
|
console.log(error);
|
||||||
|
alert("无法连接到服务器,请检查网络连接!");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectItem(id) {
|
||||||
|
window.parent.postMessage(JSON.stringify({
|
||||||
|
id: id,
|
||||||
|
iframe: "book-selector"
|
||||||
|
}), "*");
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeWindow() {
|
||||||
|
window.parent.postMessage(JSON.stringify({
|
||||||
|
id: null,
|
||||||
|
iframe: "book-selector"
|
||||||
|
}), "*");
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@@ -0,0 +1,17 @@
|
|||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||||
|
|
||||||
|
<title><%= htmlTitle %></title>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="/assets/stylesheets/style.css">
|
||||||
|
<script src="/assets/lib/jquery/3.6.0/jquery.min.js"></script>
|
||||||
|
<script src="/assets/lib/axios/0.26.1/axios.min.js"></script>
|
||||||
|
|
||||||
|
<script src="/assets/javascripts/httpRequestUtils.js"></script>
|
||||||
|
<script src="/assets/javascripts/localStorageUtils.js"></script>
|
||||||
|
<script>
|
||||||
|
// API地址
|
||||||
|
const APIHOST = '<%= global.site.api.prefix %>';
|
||||||
|
axios.defaults.baseURL = APIHOST;
|
||||||
|
</script>
|
@@ -30,6 +30,7 @@ public enum BusinessErrorCode implements CommonError {
|
|||||||
|
|
||||||
// 60000开头为文件、文件对象相关错误定义
|
// 60000开头为文件、文件对象相关错误定义
|
||||||
FILE_ALREADY_EXIST(60001, "文件已存在"),
|
FILE_ALREADY_EXIST(60001, "文件已存在"),
|
||||||
|
FILE_NOT_EXIST(60002, "文件不存在"),
|
||||||
|
|
||||||
// 占位
|
// 占位
|
||||||
PLACE_HOLDER(99999, "这是一个占位符错误");
|
PLACE_HOLDER(99999, "这是一个占位符错误");
|
||||||
|
@@ -16,6 +16,7 @@ import plus.bookshelf.Config.QCloudCosConfig;
|
|||||||
import plus.bookshelf.Controller.VO.FileObjectVO;
|
import plus.bookshelf.Controller.VO.FileObjectVO;
|
||||||
import plus.bookshelf.Controller.VO.FileVO;
|
import plus.bookshelf.Controller.VO.FileVO;
|
||||||
import plus.bookshelf.Service.Impl.*;
|
import plus.bookshelf.Service.Impl.*;
|
||||||
|
import plus.bookshelf.Service.Model.BookModel;
|
||||||
import plus.bookshelf.Service.Model.FileModel;
|
import plus.bookshelf.Service.Model.FileModel;
|
||||||
import plus.bookshelf.Service.Model.FileObjectModel;
|
import plus.bookshelf.Service.Model.FileObjectModel;
|
||||||
import plus.bookshelf.Service.Model.UserModel;
|
import plus.bookshelf.Service.Model.UserModel;
|
||||||
@@ -140,6 +141,44 @@ public class FileController extends BaseController {
|
|||||||
return CommonReturnType.create(fileVO);
|
return CommonReturnType.create(fileVO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
BookServiceImpl bookService;
|
||||||
|
|
||||||
|
@ApiOperation(value = "【管理员】将书籍和文件进行绑定", notes = "")
|
||||||
|
@RequestMapping(value = "bindBook", method = {RequestMethod.POST}, consumes = {CONTENT_TYPE_FORMED})
|
||||||
|
@ResponseBody
|
||||||
|
public CommonReturnType bindBook(@RequestParam(value = "token", required = false) String token,
|
||||||
|
@RequestParam(value = "fileId", required = true) Integer fileId,
|
||||||
|
@RequestParam(value = "bookId", required = true) Integer bookId) throws BusinessException {
|
||||||
|
|
||||||
|
UserModel userModel = userService.getUserByToken(redisTemplate, token);
|
||||||
|
if (userModel == null || !Objects.equals(userModel.getGroup(), "ADMIN")) {
|
||||||
|
throw new BusinessException(BusinessErrorCode.OPERATION_NOT_ALLOWED, "非管理员用户无权进行此操作");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileId == null || bookId == null) {
|
||||||
|
throw new BusinessException(BusinessErrorCode.PARAMETER_VALIDATION_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
FileModel fileModel = fileService.getFileById(fileId);
|
||||||
|
if (fileModel == null) {
|
||||||
|
throw new BusinessException(BusinessErrorCode.FILE_NOT_EXIST);
|
||||||
|
}
|
||||||
|
|
||||||
|
BookModel bookModel = bookService.getBookById(bookId);
|
||||||
|
if (bookModel == null) {
|
||||||
|
throw new BusinessException(BusinessErrorCode.BOOK_NOT_EXIST);
|
||||||
|
}
|
||||||
|
|
||||||
|
fileModel.setBookId(bookModel.getId());
|
||||||
|
Integer affectRows = fileService.updateSelective(fileModel);
|
||||||
|
if (affectRows > 0) {
|
||||||
|
return CommonReturnType.create("success");
|
||||||
|
} else {
|
||||||
|
throw new BusinessException(BusinessErrorCode.UNKNOWN_ERROR, "绑定失败,未知错误");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private FileVO convertFileVOFromModel(FileModel fileModel) {
|
private FileVO convertFileVOFromModel(FileModel fileModel) {
|
||||||
if (fileModel == null) {
|
if (fileModel == null) {
|
||||||
return null;
|
return null;
|
||||||
|
@@ -164,6 +164,22 @@ public class FileServiceImpl implements FileService {
|
|||||||
return fileDO;
|
return fileDO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新文件
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Integer updateSelective(FileModel fileModel) {
|
||||||
|
FileDO fileDO = convertFromFileModel(fileModel);
|
||||||
|
|
||||||
|
// 如果文件 id 不对,那么不能更新
|
||||||
|
if (fileDO.getId() == 0 || fileDO.getId() == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return fileDOMapper.updateByPrimaryKeySelective(fileDO);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 取消文件和书籍的关联
|
* 取消文件和书籍的关联
|
||||||
*
|
*
|
||||||
|
@@ -60,6 +60,14 @@ public interface FileService {
|
|||||||
*/
|
*/
|
||||||
Boolean addFile(FileModel fileModel) throws InvocationTargetException, IllegalAccessException;
|
Boolean addFile(FileModel fileModel) throws InvocationTargetException, IllegalAccessException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新文件对象
|
||||||
|
*
|
||||||
|
* @param fileModel
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Integer updateSelective(FileModel fileModel);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 取消文件和书籍的关联
|
* 取消文件和书籍的关联
|
||||||
*
|
*
|
||||||
|
Reference in New Issue
Block a user