feat:浏览器插件新增书签功能实现

This commit is contained in:
fanxb 2022-04-15 15:45:19 +08:00
parent 50e1e0e951
commit d44700a971
18 changed files with 369 additions and 353 deletions

View File

@ -36,12 +36,14 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.io.File;
import java.io.InputStream; import java.io.InputStream;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -324,7 +326,6 @@ public class BookmarkServiceImpl implements BookmarkService {
* *
* @param url url * @param url url
* @return {@link String} * @return {@link String}
* @throws
* @author fanxb * @author fanxb
*/ */
private String getIconPath(String url) { private String getIconPath(String url) {
@ -343,10 +344,7 @@ public class BookmarkServiceImpl implements BookmarkService {
if (iconPath != null) { if (iconPath != null) {
return iconPath; return iconPath;
} }
iconPath = saveFile(host, "http://" + host + "/favicon.ico"); iconPath = saveFile(host, urlIconAddress + "/icon?url=" + host + "&size=16..64..256");
if (StrUtil.isEmpty(iconPath)) {
iconPath = saveFile(host, urlIconAddress + "/icon?url=" + host + "&size=16..64..256");
}
if (StrUtil.isNotEmpty(iconPath)) { if (StrUtil.isNotEmpty(iconPath)) {
hostIconDao.insert(host, iconPath); hostIconDao.insert(host, iconPath);
} }
@ -366,9 +364,9 @@ public class BookmarkServiceImpl implements BookmarkService {
if (data.length > 0) { if (data.length > 0) {
String iconUrl = res.request().url().toString(); String iconUrl = res.request().url().toString();
String fileName = URLEncoder.encode(host, StandardCharsets.UTF_8) + iconUrl.substring(iconUrl.lastIndexOf(".")); String fileName = URLEncoder.encode(host, StandardCharsets.UTF_8) + iconUrl.substring(iconUrl.lastIndexOf("."));
String filePath = Paths.get(CommonConstant.fileSavePath, FileConstant.FAVICON_PATH, host.substring(0, 2), fileName).toString(); String filePath = Paths.get(FileConstant.FAVICON_PATH, host.substring(0, 2), fileName).toString();
FileUtil.writeBytes(data, filePath); FileUtil.writeBytes(data, Paths.get(CommonConstant.fileSavePath, filePath).toString());
return filePath; return File.separator + filePath;
} else { } else {
log.info("未获取到icon:{}", url); log.info("未获取到icon:{}", url);
} }

View File

@ -3,6 +3,7 @@ node_modules
/dist /dist
package-lock.json package-lock.json
yarn.lock yarn.lock
public/files
# local env files # local env files
.env.local .env.local

Binary file not shown.

View File

@ -17,7 +17,7 @@ body {
margin: 0; margin: 0;
padding: 0; padding: 0;
font-size: 100px; font-size: 100px;
// background-color: @bgColor; background-color: @bgColor;
height: initial; height: initial;
} }
#app { #app {

View File

@ -30,6 +30,10 @@ export const clear = "clear";
* 删除书签数据 * 删除书签数据
*/ */
export const deleteData = "deleteData"; export const deleteData = "deleteData";
/**
* 新增节点
*/
export const addNode = "addNode";
/** /**
* 版本检查定时调度 * 版本检查定时调度
@ -44,277 +48,273 @@ let toastShow = false;
* 书签树相关配置 * 书签树相关配置
*/ */
const state = { const state = {
//全部书签数据 //全部书签数据
[TOTAL_TREE_DATA]: {}, [TOTAL_TREE_DATA]: {},
//版本 //版本
[VERSION]: null, [VERSION]: null,
//是否已经初始化书签数据 //是否已经初始化书签数据
[IS_INIT]: false, [IS_INIT]: false,
// 是否正在加载数据 // 是否正在加载数据
[IS_INITING]: false, [IS_INITING]: false,
[SHOW_REFRESH_TOAST]: false, [SHOW_REFRESH_TOAST]: false,
[HOME_PIN_LIST]: [], [HOME_PIN_LIST]: [],
[HOME_PIN_BOOKMARK_ID_MAP]: {} [HOME_PIN_BOOKMARK_ID_MAP]: {}
}; };
const getters = { const getters = {
[getById]: state => id => { [getById]: state => id => {
let arr = Object.values(state[TOTAL_TREE_DATA]); let arr = Object.values(state[TOTAL_TREE_DATA]);
for (let i in arr) { for (let i in arr) {
for (let j in arr[i]) { for (let j in arr[i]) {
if (arr[i][j].bookmarkId === id) { if (arr[i][j].bookmarkId === id) {
return arr[i][j]; return arr[i][j];
} }
} }
} }
return null; return null;
} }
}; };
const actions = { const actions = {
async [noLoginInit] () { async [noLoginInit]() {},
async [loginInit](context) {
}, if (context.state.isInit || context.state.isIniting) {
async [loginInit] (context) { return;
if (context.state.isInit || context.state.isIniting) { }
return; await context.dispatch(refreshHomePinList);
} context.commit(IS_INITING, true);
await context.dispatch(refreshHomePinList); context.commit(TOTAL_TREE_DATA, await localforage.getItem(TOTAL_TREE_DATA));
context.commit(IS_INITING, true); context.commit(VERSION, await localforage.getItem(VERSION));
context.commit(TOTAL_TREE_DATA, await localforage.getItem(TOTAL_TREE_DATA)); await treeDataCheck(context, true);
context.commit(VERSION, await localforage.getItem(VERSION)); context.commit(IS_INIT, true);
await treeDataCheck(context, true); context.commit(IS_INITING, false);
context.commit(IS_INIT, true); timer = setInterval(() => treeDataCheck(context, false), CHECK_INTERVAL);
context.commit(IS_INITING, false); },
timer = setInterval(() => treeDataCheck(context, false), CHECK_INTERVAL); /**
}, * 确保数据加载完毕
/** */
* 确保数据加载完毕 ensureDataOk(context) {
*/ return new Promise((resolve, reject) => {
ensureDataOk (context) { let timer = setInterval(() => {
return new Promise((resolve, reject) => { try {
let timer = setInterval(() => { if (context.state[IS_INIT] && context.state[IS_INITING] == false) {
try { clearInterval(timer);
if (context.state[IS_INIT] && context.state[IS_INITING] == false) { resolve();
clearInterval(timer); }
resolve(); } catch (err) {
} reject(err);
} catch (err) { }
reject(err); }, 50);
} });
}, 50); },
}); //刷新缓存数据
}, async [refresh](context) {
//刷新缓存数据 let treeData = await HttpUtil.get("/bookmark/currentUser");
async [refresh] (context) { if (!treeData[""]) {
let treeData = await HttpUtil.get("/bookmark/currentUser"); treeData[""] = [];
if (!treeData[""]) { }
treeData[""] = []; Object.values(treeData).forEach(item =>
} item.forEach(item1 => {
Object.values(treeData).forEach(item => item1.isLeaf = item1.type === 0;
item.forEach(item1 => { item1.class = "treeNodeItem";
item1.isLeaf = item1.type === 0; item1.scopedSlots = { title: "nodeTitle" };
item1.class = "treeNodeItem"; })
item1.scopedSlots = { title: "nodeTitle" }; );
}) let version = await HttpUtil.get("/user/version");
); await context.dispatch("updateVersion", version);
let version = await HttpUtil.get("/user/version"); await context.dispatch(refreshHomePinList);
await context.dispatch("updateVersion", version); context.commit(TOTAL_TREE_DATA, treeData);
await context.dispatch(refreshHomePinList); await localforage.setItem(TOTAL_TREE_DATA, treeData);
context.commit(TOTAL_TREE_DATA, treeData); },
await localforage.setItem(TOTAL_TREE_DATA, treeData); //清除缓存数据
}, async [clear](context) {
//清除缓存数据 context.commit(TOTAL_TREE_DATA, null);
async [clear] (context) { context.commit(VERSION, null);
context.commit(TOTAL_TREE_DATA, null); context.commit(SHOW_REFRESH_TOAST, false);
context.commit(VERSION, null); context.commit(IS_INIT, false);
context.commit(SHOW_REFRESH_TOAST, false); context.commit(IS_INITING, false);
context.commit(IS_INIT, false); context.commit(HOME_PIN_LIST, []);
context.commit(IS_INITING, false); if (timer != null) {
context.commit(HOME_PIN_LIST, []); clearInterval(timer);
if (timer != null) { }
clearInterval(timer); await localforage.removeItem(TOTAL_TREE_DATA);
} await localforage.removeItem(VERSION);
await localforage.removeItem(TOTAL_TREE_DATA); },
await localforage.removeItem(VERSION); /**
}, * 移动节点
/** */
* 移动节点 async moveNode(context, info) {
*/ let data = context.state[TOTAL_TREE_DATA];
async moveNode (context, info) { const target = info.node.dataRef;
let data = context.state[TOTAL_TREE_DATA]; const current = info.dragNode.dataRef;
const target = info.node.dataRef; //从原来位置中删除当前节点
const current = info.dragNode.dataRef; let currentList = data[current.path];
//从原来位置中删除当前节点 currentList.splice(
let currentList = data[current.path]; currentList.findIndex(item => item.bookmarkId === current.bookmarkId),
currentList.splice( 1
currentList.findIndex(item => item.bookmarkId === current.bookmarkId), );
1 //请求体
); const body = {
//请求体 bookmarkId: current.bookmarkId,
const body = { sourcePath: current.path,
bookmarkId: current.bookmarkId, targetPath: "",
sourcePath: current.path, //-1 表示排在最后
targetPath: "", sort: -1
//-1 表示排在最后 };
sort: -1 if (info.dropToGap) {
}; body.targetPath = target.path;
if (info.dropToGap) { //移动到目标节点的上面或者下面
body.targetPath = target.path; let targetList = data[target.path];
//移动到目标节点的上面或者下面 //目标节点index
let targetList = data[target.path]; let index = targetList.indexOf(target);
//目标节点index //移动节点相对于目标节点位置的增量
let index = targetList.indexOf(target); let addIndex = info.dropPosition > index ? 1 : 0;
//移动节点相对于目标节点位置的增量 body.sort = target.sort + addIndex;
let addIndex = info.dropPosition > index ? 1 : 0; targetList.splice(index + addIndex, 0, current);
body.sort = target.sort + addIndex; for (let i = index + 1; i < targetList.length; i++) {
targetList.splice(index + addIndex, 0, current); targetList[i].sort += 1;
for (let i = index + 1; i < targetList.length; i++) { }
targetList[i].sort += 1; } else {
} //移动到一个文件夹下面
} else { body.targetPath = target.path + "." + target.bookmarkId;
//移动到一个文件夹下面 let targetList = data[body.targetPath];
body.targetPath = target.path + "." + target.bookmarkId; if (!targetList) {
let targetList = data[body.targetPath]; targetList = [];
if (!targetList) { data[body.targetPath] = targetList;
targetList = []; }
data[body.targetPath] = targetList; body.sort = targetList.length > 0 ? targetList[targetList.length - 1].sort + 1 : 1;
} targetList.push(current);
body.sort = targetList.length > 0 ? targetList[targetList.length - 1].sort + 1 : 1; }
targetList.push(current); //更新节点的path和对应子节点path
} current.path = body.targetPath;
//更新节点的path和对应子节点path current.sort = body.sort;
current.path = body.targetPath; //如果为文件夹还要更新所有子书签的path
current.sort = body.sort; if (body.sourcePath !== body.targetPath) {
//如果为文件夹还要更新所有子书签的path let keys = Object.keys(data);
if (body.sourcePath !== body.targetPath) { //旧路径
let keys = Object.keys(data); let oldPath = body.sourcePath + "." + current.bookmarkId;
//旧路径 //新路径
let oldPath = body.sourcePath + "." + current.bookmarkId; let newPath = body.targetPath + "." + current.bookmarkId;
//新路径 keys.forEach(item => {
let newPath = body.targetPath + "." + current.bookmarkId; if (!item.startsWith(oldPath)) {
keys.forEach(item => { return;
if (!item.startsWith(oldPath)) { }
return; let newPathStr = item.replace(oldPath, newPath);
} let list = data[item];
let newPathStr = item.replace(oldPath, newPath); delete data[item];
let list = data[item]; data[newPathStr] = list;
delete data[item]; list.forEach(item1 => (item1.path = newPathStr));
data[newPathStr] = list; });
list.forEach(item1 => (item1.path = newPathStr)); }
}); context.commit(TOTAL_TREE_DATA, context.state[TOTAL_TREE_DATA]);
} await context.dispatch("updateVersion", null);
context.commit(TOTAL_TREE_DATA, context.state[TOTAL_TREE_DATA]); await localforage.setItem(TOTAL_TREE_DATA, state[TOTAL_TREE_DATA]);
await context.dispatch("updateVersion", null); return body;
await localforage.setItem(TOTAL_TREE_DATA, state[TOTAL_TREE_DATA]); },
return body; async [refreshHomePinList]({ commit }) {
}, let list = await HttpUtil.get("/home/pin");
async [refreshHomePinList] ({ commit }) { commit(HOME_PIN_LIST, list);
let list = await HttpUtil.get("/home/pin"); let map = {};
commit(HOME_PIN_LIST, list); list.filter(item => item.id).forEach(item => (map[item.bookmarkId] = true));
let map = {}; commit(HOME_PIN_BOOKMARK_ID_MAP, map);
list.filter(item => item.id).forEach(item => map[item.bookmarkId] = true); },
commit(HOME_PIN_BOOKMARK_ID_MAP, map); /**
* 更新版本数据
}, */
/** async updateVersion({ commit, state }, version) {
* 更新版本数据 commit(VERSION, version == null ? state[VERSION] + 1 : version);
*/ await localforage.setItem(VERSION, state[VERSION]);
async updateVersion ({ commit, state }, version) { },
commit(VERSION, version == null ? state[VERSION] + 1 : version); /**
await localforage.setItem(VERSION, state[VERSION]); * 新增书签文件夹
}, */
/** async [addNode](context, { sourceNode, targetNode }) {
* 新增书签文件夹 if (sourceNode === null) {
*/ if (context.state[TOTAL_TREE_DATA][""] === undefined) {
async addNode (context, { sourceNode, targetNode }) { context.state[TOTAL_TREE_DATA][""] = [];
if (sourceNode === null) { }
if (context.state[TOTAL_TREE_DATA][""] === undefined) { context.state[TOTAL_TREE_DATA][""].push(targetNode);
context.state[TOTAL_TREE_DATA][""] = []; } else {
} if (sourceNode.children === undefined) {
context.state[TOTAL_TREE_DATA][""].push(targetNode); sourceNode.children = [];
} else { }
if (sourceNode.children === undefined) { sourceNode.children.push(targetNode);
sourceNode.children = []; }
} if (targetNode.type === 0) {
sourceNode.children.push(targetNode); context.state[TOTAL_TREE_DATA][targetNode.path + "." + targetNode.bookmarkId] = [];
} }
if (targetNode.type === 0) { targetNode.isLeaf = targetNode.type === 0;
context.state[TOTAL_TREE_DATA][targetNode.path + "." + targetNode.bookmarkId] = []; targetNode.class = "treeNodeItem";
} targetNode.scopedSlots = { title: "nodeTitle" };
targetNode.isLeaf = targetNode.type === 0; context.commit(TOTAL_TREE_DATA, context.state[TOTAL_TREE_DATA]);
targetNode.class = "treeNodeItem"; await context.dispatch("updateVersion", null);
targetNode.scopedSlots = { title: "nodeTitle" }; await localforage.setItem(TOTAL_TREE_DATA, state[TOTAL_TREE_DATA]);
context.commit(TOTAL_TREE_DATA, context.state[TOTAL_TREE_DATA]); },
await context.dispatch("updateVersion", null); /**
await localforage.setItem(TOTAL_TREE_DATA, state[TOTAL_TREE_DATA]); * 删除节点数据
}, */
/** async [deleteData](context, { pathList, bookmarkIdList }) {
* 删除节点数据 //待删除的书签
*/ let bookmarkIdSet = new Set();
async [deleteData] (context, { pathList, bookmarkIdList }) { bookmarkIdList.forEach(item => bookmarkIdSet.add(item));
//待删除的书签 //删除子节点
let bookmarkIdSet = new Set(); pathList.forEach(item => {
bookmarkIdList.forEach(item => bookmarkIdSet.add(item)); delete state[TOTAL_TREE_DATA][item];
//删除子节点 Object.keys(context.state[TOTAL_TREE_DATA])
pathList.forEach(item => { .filter(key => key.startsWith(item + "."))
delete state[TOTAL_TREE_DATA][item]; .forEach(key => delete state[TOTAL_TREE_DATA][key]);
Object.keys(context.state[TOTAL_TREE_DATA]) bookmarkIdSet.add(parseInt(item.split(".").reverse()));
.filter(key => key.startsWith(item + ".")) });
.forEach(key => delete state[TOTAL_TREE_DATA][key]); //删除直接选中的节点
bookmarkIdSet.add(parseInt(item.split(".").reverse())); Object.keys(context.state[TOTAL_TREE_DATA]).forEach(item => {
}); let list = context.state[TOTAL_TREE_DATA][item];
//删除直接选中的节点 for (let i = list.length - 1; i >= 0; i--) {
Object.keys(context.state[TOTAL_TREE_DATA]).forEach(item => { if (bookmarkIdSet.has(list[i].bookmarkId)) {
let list = context.state[TOTAL_TREE_DATA][item]; list.splice(i, 1);
for (let i = list.length - 1; i >= 0; i--) { }
if (bookmarkIdSet.has(list[i].bookmarkId)) { }
list.splice(i, 1); });
} context.commit(TOTAL_TREE_DATA, context.state[TOTAL_TREE_DATA]);
} await context.dispatch("updateVersion", null);
}); await localforage.setItem(TOTAL_TREE_DATA, state[TOTAL_TREE_DATA]);
context.commit(TOTAL_TREE_DATA, context.state[TOTAL_TREE_DATA]); },
await context.dispatch("updateVersion", null); /**
await localforage.setItem(TOTAL_TREE_DATA, state[TOTAL_TREE_DATA]); * 编辑书签节点
}, */
/** async editNode({ dispatch, state, commit }, { node, newName, newUrl, newIcon }) {
* 编辑书签节点 node.name = newName;
*/ node.url = newUrl;
async editNode ({ dispatch, state, commit }, { node, newName, newUrl, newIcon }) { node.icon = newIcon;
node.name = newName; commit(TOTAL_TREE_DATA, state[TOTAL_TREE_DATA]);
node.url = newUrl; await dispatch("updateVersion", null);
node.icon = newIcon; await localforage.setItem(TOTAL_TREE_DATA, state[TOTAL_TREE_DATA]);
commit(TOTAL_TREE_DATA, state[TOTAL_TREE_DATA]); }
await dispatch("updateVersion", null);
await localforage.setItem(TOTAL_TREE_DATA, state[TOTAL_TREE_DATA]);
}
}; };
const mutations = { const mutations = {
[TOTAL_TREE_DATA]: (state, totalTreeData) => { [TOTAL_TREE_DATA]: (state, totalTreeData) => {
state.totalTreeData = totalTreeData; state.totalTreeData = totalTreeData;
}, },
[IS_INIT] (state, isInit) { [IS_INIT](state, isInit) {
state.isInit = isInit; state.isInit = isInit;
}, },
[IS_INITING] (state, isIniting) { [IS_INITING](state, isIniting) {
state.isIniting = isIniting; state.isIniting = isIniting;
}, },
[VERSION]: (state, version) => { [VERSION]: (state, version) => {
state[VERSION] = version; state[VERSION] = version;
}, },
[SHOW_REFRESH_TOAST]: (state, val) => { [SHOW_REFRESH_TOAST]: (state, val) => {
state[SHOW_REFRESH_TOAST] = val; state[SHOW_REFRESH_TOAST] = val;
}, },
[HOME_PIN_LIST]: (state, val) => { [HOME_PIN_LIST]: (state, val) => {
state[HOME_PIN_LIST] = val; state[HOME_PIN_LIST] = val;
}, },
[HOME_PIN_BOOKMARK_ID_MAP]: (state, val) => { [HOME_PIN_BOOKMARK_ID_MAP]: (state, val) => {
state[HOME_PIN_BOOKMARK_ID_MAP] = val; state[HOME_PIN_BOOKMARK_ID_MAP] = val;
} }
}; };
/** /**
* 检查书签缓存是否最新 * 检查书签缓存是否最新
* *
@ -322,43 +322,42 @@ const mutations = {
* @param {*} isFirst * @param {*} isFirst
* @returns * @returns
*/ */
async function treeDataCheck (context, isFirst) { async function treeDataCheck(context, isFirst) {
if (toastShow || !checkJwtValid(context.rootState.globalConfig.token)) { if (toastShow || !checkJwtValid(context.rootState.globalConfig.token)) {
return; return;
} }
let realVersion = await HttpUtil.get("/user/version"); let realVersion = await HttpUtil.get("/user/version");
if (realVersion !== context.state[VERSION]) { if (realVersion !== context.state[VERSION]) {
if (context.state[SHOW_REFRESH_TOAST] && !isFirst) { if (context.state[SHOW_REFRESH_TOAST] && !isFirst) {
//如果在书签管理页面需要弹窗提示 //如果在书签管理页面需要弹窗提示
window.vueInstance.$confirm({ window.vueInstance.$confirm({
title: "书签数据有更新,是否立即刷新?", title: "书签数据有更新,是否立即刷新?",
cancelText: "稍后提醒", cancelText: "稍后提醒",
closable: false, closable: false,
keyboard: false, keyboard: false,
maskClosable: false, maskClosable: false,
onOk () { onOk() {
toastShow = false; toastShow = false;
return new Promise(async (resolve) => { return new Promise(async resolve => {
await context.dispatch(refresh); await context.dispatch(refresh);
resolve(); resolve();
}); });
}, },
onCancel () { onCancel() {
toastShow = false; toastShow = false;
} }
}); });
toastShow = true; toastShow = true;
} else { } else {
await context.dispatch(refresh); await context.dispatch(refresh);
} }
} }
} }
export const store = { export const store = {
namespaced: true, namespaced: true,
state, state,
getters, getters,
actions, actions,
mutations mutations
}; };

View File

@ -15,7 +15,7 @@
<a-tooltip <a-tooltip
v-if=" v-if="
(checkedKeys.length === 0 && (currentSelect == null || currentSelect.type === 1)) || (checkedKeys.length === 0 && (currentSelect == null || currentSelect.type === 1)) ||
(checkedKeys.length === 1 && checkedNodes[0].type === 1) (checkedKeys.length === 1 && checkedNodes[0].type === 1)
" "
title="添加书签" title="添加书签"
> >
@ -77,7 +77,7 @@
<a-menu-item v-if="!rec.dataRef.isLeaf" key="add">新增</a-menu-item> <a-menu-item v-if="!rec.dataRef.isLeaf" key="add">新增</a-menu-item>
<a-menu-item v-else key="copy" class="copy-to-board" :data="rec.dataRef.url">复制URL</a-menu-item> <a-menu-item v-else key="copy" class="copy-to-board" :data="rec.dataRef.url">复制URL</a-menu-item>
<a-menu-item v-if="rec.dataRef.isLeaf" key="pin"> <a-menu-item v-if="rec.dataRef.isLeaf" key="pin">
{{ homePinList.filter((item) => item.id && item.bookmarkId == rec.dataRef.bookmarkId).length > 0 ? "从首页移除" : "固定到首页" }} {{ homePinList.filter(item => item.id && item.bookmarkId == rec.dataRef.bookmarkId).length > 0 ? "从首页移除" : "固定到首页" }}
</a-menu-item> </a-menu-item>
<a-menu-item key="edit">编辑</a-menu-item> <a-menu-item key="edit">编辑</a-menu-item>
<a-menu-item key="delete">删除</a-menu-item> <a-menu-item key="delete">删除</a-menu-item>
@ -114,7 +114,7 @@ export default {
loadedKeys: [], // loadedKeys: [], //
replaceFields: { replaceFields: {
title: "name", title: "name",
key: "bookmarkId", key: "bookmarkId"
}, },
mulSelect: false, // mulSelect: false, //
currentSelect: null, // currentSelect: null, //
@ -126,19 +126,19 @@ export default {
// null // null
targetNode: null, targetNode: null,
// //
isAdd: false, isAdd: false
}, },
copyBoard: null, // copyBoard: null //
}; };
}, },
computed: { computed: {
...mapState("treeData", ["totalTreeData", HOME_PIN_LIST]), ...mapState("treeData", ["totalTreeData", HOME_PIN_LIST]),
...mapState("globalConfig", ["isPhone"]), ...mapState("globalConfig", ["isPhone"])
}, },
watch: { watch: {
totalTreeData(newVal, oldVal) { totalTreeData(newVal, oldVal) {
this.resetData(); this.resetData();
}, }
}, },
async mounted() { async mounted() {
this.$store.commit(TREE_DATA + "/" + SHOW_REFRESH_TOAST, true); this.$store.commit(TREE_DATA + "/" + SHOW_REFRESH_TOAST, true);
@ -147,14 +147,21 @@ export default {
this.loading = false; this.loading = false;
//clipboard //clipboard
this.copyBoard = new ClipboardJS(".copy-to-board", { this.copyBoard = new ClipboardJS(".copy-to-board", {
text: function (trigger) { text: function(trigger) {
return trigger.attributes.data.nodeValue; return trigger.attributes.data.nodeValue;
}, }
}); });
this.copyBoard.on("success", (e) => { this.copyBoard.on("success", e => {
this.$message.success("复制成功"); this.$message.success("复制成功");
e.clearSelection(); e.clearSelection();
}); });
window.onblur = e => {
console.log("窗口非激活");
};
window.onfocus = e => {
console.log("窗口激活");
};
}, },
beforeDestroy() { beforeDestroy() {
this.$store.commit(TREE_DATA + "/" + SHOW_REFRESH_TOAST, false); this.$store.commit(TREE_DATA + "/" + SHOW_REFRESH_TOAST, false);
@ -168,7 +175,7 @@ export default {
*/ */
loadData(treeNode) { loadData(treeNode) {
console.log("加载数据", treeNode); console.log("加载数据", treeNode);
return new Promise((resolve) => { return new Promise(resolve => {
const data = typeof treeNode === "number" ? this.$store.getters["treeData/getById"](treeNode) : treeNode.dataRef; const data = typeof treeNode === "number" ? this.$store.getters["treeData/getById"](treeNode) : treeNode.dataRef;
let newPath = data.path + "." + data.bookmarkId; let newPath = data.path + "." + data.bookmarkId;
if (!this.totalTreeData[newPath]) { if (!this.totalTreeData[newPath]) {
@ -212,9 +219,9 @@ export default {
this.expandedKeys = [ this.expandedKeys = [
...item.path ...item.path
.split(".") .split(".")
.filter((item) => item.length > 0) .filter(item => item.length > 0)
.map((item) => parseInt(item)), .map(item => parseInt(item)),
item.bookmarkId, item.bookmarkId
]; ];
} else { } else {
this.expandedKeys.pop(); this.expandedKeys.pop();
@ -228,7 +235,7 @@ export default {
} else { } else {
this.checkedKeys.splice(this.checkedKeys.indexOf(item.bookmarkId), 1); this.checkedKeys.splice(this.checkedKeys.indexOf(item.bookmarkId), 1);
this.checkedNodes.splice( this.checkedNodes.splice(
this.checkedNodes.findIndex((item1) => item1.bookmarkId === item.bookmarkId), this.checkedNodes.findIndex(item1 => item1.bookmarkId === item.bookmarkId),
1 1
); );
} }
@ -248,9 +255,9 @@ export default {
this.expandedKeys = [ this.expandedKeys = [
...item.path ...item.path
.split(".") .split(".")
.filter((item) => item.length > 0) .filter(item => item.length > 0)
.map((item) => parseInt(item)), .map(item => parseInt(item)),
item.bookmarkId, item.bookmarkId
]; ];
} }
} else { } else {
@ -273,7 +280,7 @@ export default {
const bookmarkIdList = []; const bookmarkIdList = [];
const pathList = []; const pathList = [];
if (this.checkedNodes) { if (this.checkedNodes) {
this.checkedNodes.forEach((item) => this.checkedNodes.forEach(item =>
item.type === 1 ? pathList.push(item.path + "." + item.bookmarkId) : bookmarkIdList.push(item.bookmarkId) item.type === 1 ? pathList.push(item.path + "." + item.bookmarkId) : bookmarkIdList.push(item.bookmarkId)
); );
} }
@ -290,7 +297,7 @@ export default {
await HttpUtil.post("/bookmark/batchDelete", null, { pathList, bookmarkIdList }); await HttpUtil.post("/bookmark/batchDelete", null, { pathList, bookmarkIdList });
await this.$store.dispatch(TREE_DATA + "/" + deleteData, { pathList, bookmarkIdList }); await this.$store.dispatch(TREE_DATA + "/" + deleteData, { pathList, bookmarkIdList });
// //
pathList.forEach((item) => { pathList.forEach(item => {
const id = parseInt(item.split(".").reverse()[0]); const id = parseInt(item.split(".").reverse()[0]);
let index = this.loadedKeys.indexOf(id); let index = this.loadedKeys.indexOf(id);
if (index > -1) { if (index > -1) {
@ -322,13 +329,13 @@ export default {
this.refresh(false); this.refresh(false);
this.expandedKeys = item.path this.expandedKeys = item.path
.split(".") .split(".")
.filter((one) => one.length > 0) .filter(one => one.length > 0)
.map((one) => parseInt(one)); .map(one => parseInt(one));
this.loadedKeys = item.path this.loadedKeys = item.path
.split(".") .split(".")
.filter((one) => one.length > 0) .filter(one => one.length > 0)
.map((one) => parseInt(one)); .map(one => parseInt(one));
this.expandedKeys.forEach(async (one) => await this.loadData(one)); this.expandedKeys.forEach(async one => await this.loadData(one));
this.currentSelect = item; this.currentSelect = item;
}, },
/** /**
@ -344,7 +351,7 @@ export default {
this.addModal = { this.addModal = {
show: false, show: false,
targetNode: null, targetNode: null,
isAdd: false, isAdd: false
}; };
}, },
async onDrop(info) { async onDrop(info) {
@ -388,12 +395,12 @@ export default {
await this.deleteBookmarks(); await this.deleteBookmarks();
resolve(); resolve();
}); });
}, }
}); });
} else if (key === "edit") { } else if (key === "edit") {
this.editData(); this.editData();
} else if (key === "pin") { } else if (key === "pin") {
let pin = this.homePinList.filter((one) => one.id && one.bookmarkId == item.bookmarkId); let pin = this.homePinList.filter(one => one.id && one.bookmarkId == item.bookmarkId);
if (pin.length > 0) { if (pin.length > 0) {
await HttpUtil.delete("/home/pin", { id: pin[0].id }); await HttpUtil.delete("/home/pin", { id: pin[0].id });
} else { } else {
@ -411,8 +418,8 @@ export default {
dealList(root, map[""], map); dealList(root, map[""], map);
let content = exportFileHead + root.outerHTML; let content = exportFileHead + root.outerHTML;
downloadFile(moment().format("YYYY-MM-DD") + "导出书签.html", content); downloadFile(moment().format("YYYY-MM-DD") + "导出书签.html", content);
}, }
}, }
}; };
</script> </script>

View File

@ -1,17 +1,17 @@
<template> <template>
<div class="ssoAddBookmark"> <div class="ssoAddBookmark">
正在添加请稍后 正在添加请稍后
<button @click="closeIframe">关闭</button> <!-- <button @click="closeIframe">关闭</button> -->
</div> </div>
</template> </template>
<script> <script>
import HttpUtil from "@/util/HttpUtil"; import HttpUtil from "@/util/HttpUtil";
import { TREE_DATA, addNode } from "@/store/modules/treeData";
export default { export default {
data() { data() {
return { return {
form: { form: {
icon: null,
name: null, name: null,
url: null, url: null,
type: 0, type: 0,
@ -20,6 +20,7 @@ export default {
}; };
}, },
mounted() { mounted() {
//
window.addEventListener("message", event => { window.addEventListener("message", event => {
if (!event.data.code) { if (!event.data.code) {
return; return;
@ -27,7 +28,6 @@ export default {
console.log("收到content消息", event); console.log("收到content消息", event);
if (event.data.code == "addBookmarkAction") { if (event.data.code == "addBookmarkAction") {
console.log("新增书签"); console.log("新增书签");
this.form.icon = event.data.data.icon ? event.data.data.icon : null;
this.form.name = event.data.data.name; this.form.name = event.data.data.name;
this.form.url = event.data.data.url; this.form.url = event.data.data.url;
this.addBookmark(); this.addBookmark();
@ -44,7 +44,8 @@ export default {
async addBookmark() { async addBookmark() {
let res = await HttpUtil.put("/bookmark", null, this.form); let res = await HttpUtil.put("/bookmark", null, this.form);
this.$message.success("添加成功"); this.$message.success("添加成功");
// setTimeout(this.closeIframe, 2000); await this.$store.dispatch(TREE_DATA + "/" + addNode, { sourceNode: null, targetNode: res });
setTimeout(this.closeIframe, 500);
} }
} }
}; };
@ -55,5 +56,8 @@ export default {
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
background: white;
width: 100%;
height: 100vh;
} }
</style> </style>

View File

@ -9,6 +9,11 @@
使用教程 使用教程
<a href="https://blog.fleyx.com/blog/detail/20220329" target="_blank">点击跳转</a> <a href="https://blog.fleyx.com/blog/detail/20220329" target="_blank">点击跳转</a>
</div> </div>
<div>
浏览器插件
<a href="/static/bookmarkBrowserPlugin.7z" download="浏览器插件.7z" target="_blank">点击下载</a>
,使用详情请参考使用教程
</div>
<div>交流反馈qq群150056494,邮箱fleyx20@outlook.com</div> <div>交流反馈qq群150056494,邮箱fleyx20@outlook.com</div>
<div> <div>
统计 统计
@ -38,7 +43,7 @@ export default {
script.defer = true; script.defer = true;
script.src = "https://qiezi.fleyx.com/qiezijs/1.0/qiezi_statistic.min.js"; script.src = "https://qiezi.fleyx.com/qiezijs/1.0/qiezi_statistic.min.js";
document.getElementsByTagName("head")[0].appendChild(script); document.getElementsByTagName("head")[0].appendChild(script);
}, }
}; };
</script> </script>

View File

@ -15,7 +15,6 @@ chrome.contextMenus.onClicked.addListener(async function (info, tab) {
let body = { let body = {
name: tab.title, name: tab.title,
url: tab.url, url: tab.url,
iconUrl: tab.favIconUrl
}; };
sendToContent(tab.id, { code: "addBookmark", data: body, token: await getVal("token") }); sendToContent(tab.id, { code: "addBookmark", data: body, token: await getVal("token") });
}); });

View File

@ -1,6 +1,6 @@
{ {
"name": "bookmark-chrome", "name": "签签世界",
"description": "A Vue.js web extension", "description": "云书签管理平台",
"version": "1.0", "version": "1.0",
"manifest_version": 3, "manifest_version": 3,
"permissions": ["contextMenus", "storage"], "permissions": ["contextMenus", "storage"],
@ -8,8 +8,8 @@
"default_popup": "popup/index.html" "default_popup": "popup/index.html"
}, },
"icons": { "icons": {
"48": "static/icons/icon_48.png", "48": "static/icons/favicon.png",
"128": "static/icons/icon_128.png" "128": "static/icons/favicon.png"
}, },
"background": { "background": {
"service_worker": "background.js" "service_worker": "background.js"

View File

@ -19,10 +19,11 @@
<a id="login" href="https://fleyx.com/userSpace/ssoAuth" target="_blank">点击登录</a> <a id="login" href="https://fleyx.com/userSpace/ssoAuth" target="_blank">点击登录</a>
<div id="action" style="display: none"> <div id="action" style="display: none">
<button id="logout">退出登陆</button> <button id="logout">退出登陆</button>
<button title="同步云端书签到浏览器(覆盖本地)">同步云端书签</button> <!-- <button title="同步云端书签到浏览器(覆盖本地)">同步云端书签</button> -->
<button title="同步浏览器书签到云端(覆盖云端)">同步浏览器</button> <!-- <button title="同步浏览器书签到云端(覆盖云端)">同步浏览器</button> -->
</div> </div>
<p id="content"></p> <p id="content"></p>
<div class="bottom">插件版本:<span id="version"></span></div>
<script type="text/javascript" src="/static/js/axios.min.js"></script> <script type="text/javascript" src="/static/js/axios.min.js"></script>
<script type="text/javascript" src="/static/js/config.js"></script> <script type="text/javascript" src="/static/js/config.js"></script>
<script type="text/javascript" src="/popup/index.js"></script> <script type="text/javascript" src="/popup/index.js"></script>

View File

@ -8,6 +8,7 @@ var action = document.getElementById("action");
(async () => { (async () => {
//初始化 //初始化
login.href = bookmarkHost + "/manage/sso/auth"; login.href = bookmarkHost + "/manage/sso/auth";
document.getElementById("version").innerText = version;
sendToBg("getToken", null); sendToBg("getToken", null);
})(); })();

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -1,6 +1,7 @@
// var bookmarkHost = "https://fleyx.com"; var bookmarkHost = "https://fleyx.com";
var bookmarkHost = "http://localhost:8080"; // var bookmarkHost = "http://localhost:8080";
var version = "0.1";
window.token = localStorage.getItem('token'); window.token = localStorage.getItem('token');
axios.defaults.baseURL = bookmarkHost + '/bookmark/api'; axios.defaults.baseURL = bookmarkHost + '/bookmark/api';