feat:网页段缓存书签数据完成

This commit is contained in:
fanxb 2020-01-28 01:51:17 +08:00
parent d95441d860
commit 3c93016bd3
8 changed files with 167 additions and 33 deletions

View File

@ -106,7 +106,7 @@ public class UserController {
/**
* 功能描述: 校验密码生成一个actionId
*
* @param password password
* @param obj obj
* @return com.fanxb.bookmark.common.entity.Result
* @author fanxb
* @date 2019/11/11 23:31

View File

@ -22,4 +22,8 @@ public class User {
private String password;
private long createTime;
private long lastLoginTime;
/**
* 上次更新书签时间
*/
private long bookmarkChangeTime;
}

View File

@ -34,5 +34,6 @@
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
<script src="/js/localforage.main.js"></script>
</body>
</html>

File diff suppressed because one or more lines are too long

View File

@ -1,10 +1,13 @@
import React from "react";
import { Link, withRouter } from "react-router-dom";
import { Menu, Dropdown, Divider } from "antd";
import { Menu, Dropdown, Divider, Modal } from "antd";
import httpUtil from "../../util/httpUtil";
import { connect } from "react-redux";
import styles from "./index.module.less";
import * as infoAction from "../../redux/action/LoginInfoAction";
import { checkCacheStatus, clearCache } from "../../util/cacheUtil";
const { confirm } = Modal;
function mapStateToProps(state) {
return state[infoAction.DATA_NAME];
@ -20,13 +23,44 @@ function mapDispatchToProps(dispatch) {
class MainLayout extends React.Component {
constructor(props) {
super(props);
this.state = {};
this.state = {
timer: null,
//
showDialog: false
};
}
async componentWillMount() {
if (!this.props.username) {
let res = await httpUtil.get("/user/currentUserInfo");
this.props.changeUserInfo(res);
if (this.state.timer != null) {
clearInterval(this.state.timer);
}
await this.checkCache();
this.state.timer = setInterval(this.checkCache.bind(this), 5 * 60 * 1000);
}
}
async checkCache() {
//
if (this.state.showDialog) {
return;
}
let _this = this;
if (!(await checkCacheStatus())) {
this.state.showDialog = true;
confirm({
title: "缓存过期",
content: "书签数据有更新,是否立即刷新?",
onOk() {
_this.state.showDialog = false;
clearCache();
},
onCancel() {
_this.state.showDialog = false;
}
});
}
}
@ -40,7 +74,11 @@ class MainLayout extends React.Component {
);
if (username != null) {
return (
<Dropdown overlay={menu} placement="bottomCenter" trigger={["hover", "click"]}>
<Dropdown
overlay={menu}
placement="bottomCenter"
trigger={["hover", "click"]}
>
<span style={{ cursor: "pointer" }}>
<img className={styles.icon} src={icon} alt="icon" />
{username}
@ -77,20 +115,34 @@ class MainLayout extends React.Component {
<div className={styles.main}>
<div className={styles.header}>
<a href="/">
<img style={{ width: "1.5rem" }} src="/img/bookmarkLogo.png" alt="logo" />
<img
style={{ width: "1.5rem" }}
src="/img/bookmarkLogo.png"
alt="logo"
/>
</a>
{this.renderUserArea()}
</div>
<Divider style={{ margin: 0 }} />
<div style={{ minHeight: `calc(${document.body.clientHeight}px - 1.45rem)` }} className={styles.content}>
<div
style={{
minHeight: `calc(${document.body.clientHeight}px - 1.45rem)`
}}
className={styles.content}
>
{this.props.children}
</div>
<div className={styles.footer}>
开源地址<a href="https://github.com/FleyX/bookmark">github.com/FleyX/bookmark</a>
开源地址
<a href="https://github.com/FleyX/bookmark">
github.com/FleyX/bookmark
</a>
</div>
</div>
);
}
}
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(MainLayout));
export default withRouter(
connect(mapStateToProps, mapDispatchToProps)(MainLayout)
);

View File

@ -7,8 +7,7 @@ import { stopTransfer } from "../../../util/eventUtil";
const { TreeNode } = Tree;
function menuVisible(item, visible) {
if (visible) {
window.copyUrl = item.url;
if (visible) { window.copyUrl = item.url;
}
this.props.changeCurrentClickItem(item);
}
@ -56,7 +55,11 @@ export function renderNodeContent(item) {
return (
<React.Fragment>
{/* 触发右键菜单 */}
<Dropdown overlay={menu} trigger={["contextMenu"]} onVisibleChange={menuVisible.bind(this, item)}>
<Dropdown
overlay={menu}
trigger={["contextMenu"]}
onVisibleChange={menuVisible.bind(this, item)}
>
{item.type === 0 ? (
<a href={item.url} className={styles.nodeContent}>
{item.name}
@ -66,8 +69,18 @@ export function renderNodeContent(item) {
)}
</Dropdown>
{isEdit ? (
<Dropdown overlay={menu} trigger={["click"]} onVisibleChange={menuVisible.bind(this, item)}>
<Button size="small" onClick={stopTransfer.bind(this)} type="primary" icon="menu" shape="circle" />
<Dropdown
overlay={menu}
trigger={["click"]}
onVisibleChange={menuVisible.bind(this, item)}
>
<Button
size="small"
onClick={stopTransfer.bind(this)}
type="primary"
icon="menu"
shape="circle"
/>
</Dropdown>
) : null}
</React.Fragment>
@ -130,7 +143,9 @@ export function batchDelete() {
bookmarkIdList = [];
checkedNodes.forEach(item => {
const data = item.props.dataRef;
data.type === 0 ? bookmarkIdList.push(data.bookmarkId) : folderIdList.push(data.bookmarkId);
data.type === 0
? bookmarkIdList.push(data.bookmarkId)
: folderIdList.push(data.bookmarkId);
});
deleteBookmark.call(this, folderIdList, bookmarkIdList);
}
@ -203,11 +218,13 @@ export function onDrop(info) {
sort: -1
};
//从原来所属的节点列表中删除当前节点
const currentBelowList = current.path === "" ? treeData : getBelowList(treeData, current);
const currentBelowList =
current.path === "" ? treeData : getBelowList(treeData, current);
currentBelowList.splice(currentBelowList.indexOf(current), 1);
if (info.dropToGap) {
body.targetPath = target.path;
const targetBelowList = target.path === "" ? treeData : getBelowList(treeData, target);
const targetBelowList =
target.path === "" ? treeData : getBelowList(treeData, target);
const index = targetBelowList.indexOf(target);
if (info.dropPosition > index) {
body.sort = target.sort + 1;
@ -236,7 +253,11 @@ export function onDrop(info) {
current.sort = body.sort;
//如果当前节点和目标节点不在一个层级中需要更新当前子节点的path信息
if (body.sourcePath !== body.targetPath) {
updateChildrenPath(current.children, body.sourcePath + "." + body.bookmarkId, body.targetPath + "." + body.bookmarkId);
updateChildrenPath(
current.children,
body.sourcePath + "." + body.bookmarkId,
body.targetPath + "." + body.bookmarkId
);
}
}
httpUtil

View File

@ -1,9 +1,9 @@
import React from "react";
import { Tree, Empty, Button, Spin } from "antd";
import MainLayout from "../../../layout/MainLayout";
import httpUtil from "../../../util/httpUtil";
import styles from "./index.module.less";
import { batchDelete, renderTreeNodes, onDrop } from "./function.js";
import { cacheBookmarkData, getBookmarkList } from "../../../util/cacheUtil";
import AddModal from "./AddModal";
import Search from "../../../components/Search";
@ -43,15 +43,11 @@ class OverView extends React.Component {
/**
* 初始化第一级书签
*/
componentDidMount() {
async componentDidMount() {
this.props.refresh();
httpUtil
.get("/bookmark/currentUser/path?path=")
.then(res => {
this.props.updateTreeData(res);
await cacheBookmarkData();
this.props.updateTreeData(getBookmarkList(""));
this.props.changeIsInit(true);
})
.catch(() => this.props.changeIsInit(true));
}
/**
@ -62,14 +58,12 @@ class OverView extends React.Component {
return new Promise(resolve => {
const item = e.props.dataRef;
const newPath = item.path + "." + item.bookmarkId;
httpUtil.get("/bookmark/currentUser/path?path=" + newPath).then(res => {
item.children = res;
item.children = getBookmarkList(newPath);
this.props.updateTreeData([...treeData]);
loadedKeys.push(item.bookmarkId.toString());
this.props.changeLoadedKeys(loadedKeys);
resolve();
});
});
};
/**
* 节点选择

View File

@ -0,0 +1,55 @@
/* eslint-disable no-undef */
import httpUtil from "./httpUtil";
/**
* 缓存工具类
*/
/**
* 全部书签数据key
*/
export const TREE_LIST_KEY = "treeListData";
/**
* 获取全部书签时间
*/
export const TREE_LIST_TIME_KEY = "treeListDataTime";
/**
* 缓存书签数据
*/
export async function cacheBookmarkData() {
let res = await localforage.getItem(TREE_LIST_KEY);
if (!res) {
res = await httpUtil.get("/bookmark/currentUser");
await localforage.setItem(TREE_LIST_KEY, res);
await localforage.setItem(TREE_LIST_TIME_KEY, Date.now());
}
window[TREE_LIST_KEY] = res;
}
/**
* 获取缓存数据
* @param {*} path path
*/
export function getBookmarkList(path) {
return window[TREE_LIST_KEY][path];
}
/**
* 检查缓存情况
* @return 返回true说明未过期否则说明过期了
*/
export async function checkCacheStatus() {
let date = await localforage.getItem(TREE_LIST_TIME_KEY, Date.now());
let userInfo = await httpUtil.get("/user/currentUserInfo");
return !date || date > userInfo.bookmarkChangeTime;
}
/**
* 清楚缓存数据
*/
export async function clearCache() {
await localforage.removeItem(TREE_LIST_KEY);
await localforage.removeItem(TREE_LIST_TIME_KEY);
window.location.reload();
}