Compare commits
No commits in common. "master" and "1.2" have entirely different histories.
24
.drone.yml
24
.drone.yml
@ -1,24 +0,0 @@
|
|||||||
kind: pipeline
|
|
||||||
type: docker
|
|
||||||
name: bookmarkPublish
|
|
||||||
|
|
||||||
trigger:
|
|
||||||
branch:
|
|
||||||
- master
|
|
||||||
|
|
||||||
clone:
|
|
||||||
disable: true
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: deploy
|
|
||||||
image: appleboy/drone-ssh
|
|
||||||
settings:
|
|
||||||
host:
|
|
||||||
from_secret: devHost
|
|
||||||
port: 22
|
|
||||||
user: root
|
|
||||||
key:
|
|
||||||
from_secret: privateSsh
|
|
||||||
command_timeout: 30m
|
|
||||||
script:
|
|
||||||
- cd /root/bookmark && git pull && bash build.sh && bash syncFile.sh
|
|
20
DEPLOY.md
20
DEPLOY.md
@ -1,20 +1,10 @@
|
|||||||
本程序基于 docker 来进行部署,使用 docker-compose 管理服务。
|
本程序基于 docker 来进行部署,使用 docker-compose 管理服务。
|
||||||
|
|
||||||
**注意,仅在 x86 环境下测试,arm 下不保证可用性(目前测试可用)**
|
部署过程如下:
|
||||||
|
|
||||||
## 首次部署
|
**注意,仅在 x86 环境下测试**
|
||||||
|
|
||||||
0. 克隆代码`git clone https://github.com/FleyX/bookmark.git`
|
1. 安装新版的 docker 和 docker-compose(注意:以下操作均在项目根目录下执行)
|
||||||
1. 进入文件夹`cd bookmark`
|
2. 执行`build.sh`编译前后端代码
|
||||||
2. 安装新版的 docker,docker-compose,zip `apt install docker docker-compose zip`
|
|
||||||
3. 修改.env 文件中的参数,改为你的实际配置
|
3. 修改.env 文件中的参数,改为你的实际配置
|
||||||
4. 修改`浏览器插件/bookmarkBrowserPlugin/static/js/config.js`中的 bookmarkHost,改为你的实际部署路径
|
4. root 权限运行 `docker-compose up -d` 启动服务。
|
||||||
5. 修改`浏览器插件/bookmarkBrowserPlugin/tab/index.html`中的`<meta http-equiv="Refresh" content="0;url=https://bm.fleyx.com" />`,将 url 改为你的实际部署地址
|
|
||||||
6. 执行`build.sh`编译前后端代码 `bash build.sh`
|
|
||||||
7. root 权限运行 `docker-compose up -d` 启动服务。
|
|
||||||
|
|
||||||
## 更新系统
|
|
||||||
|
|
||||||
0. 代码库更新`cd bookmark;git pull`
|
|
||||||
1. 执行`build.sh`编译前后端代码 `bash build.sh`
|
|
||||||
2. root 权限运行 `docker-compose restart` 启动服务
|
|
||||||
|
46
README.md
46
README.md
@ -1,12 +1,10 @@
|
|||||||
![图片](https://s3.fleyx.com/picbed/2023/08/Snipaste_2023-08-13_15-33-16.png)
|
本项目是一个云书签的项目,取名为:签签世界.
|
||||||
|
|
||||||
本项目是一个在线书签管理的项目,名为:签签世界.
|
部署地址:[fleyx.com](https://fleyx.com),
|
||||||
|
|
||||||
在线使用地址(长期提供服务):[bm.fleyx.com](https://bm.fleyx.com),
|
也可自己搭建,教程如下:
|
||||||
|
|
||||||
**为获得更好的体验,建议将主页设置为 bm.fleyx.com,并安装浏览器拓展,[点击查看如何安装](https://blog.fleyx.com/blog/detail/20220329/#%e6%b5%8f%e8%a7%88%e5%99%a8%e6%8f%92%e4%bb%b6)**
|
部署教程:[docker-compose 部署](https://github.com/FleyX/bookmark/blob/master/DEPLOY.md)
|
||||||
|
|
||||||
也可自己部署搭建,教程见:[docker-compose 部署](https://github.com/FleyX/bookmark/blob/master/DEPLOY.md)
|
|
||||||
|
|
||||||
# 缘由
|
# 缘由
|
||||||
|
|
||||||
@ -20,37 +18,27 @@
|
|||||||
|
|
||||||
# 主要功能
|
# 主要功能
|
||||||
|
|
||||||
帮助文档:[点击跳转](https://blog.fleyx.com/blog/detail/20220329/)
|
使用帮助见:[使用帮助](https://github.com/FleyX/bookmark/blob/master/HELP.md)
|
||||||
|
|
||||||
- 支持从 chrome,edge,firefox 等浏览器导入书签数据。
|
1. 基础的书签增删改查功能。支持 chrome、firefox 等浏览器书签文件导入,导出。
|
||||||
- 支持从 OneEnv 导入书签数据
|
|
||||||
- 树型多级目录支持
|
|
||||||
- 支持导出标准 html 书签文件
|
|
||||||
- 强大的检索功能,支持拼音检索
|
|
||||||
- 支持浏览器插件,安装插件以后可右键添加书签
|
|
||||||
|
|
||||||
# 更新日志
|
![](https://qiniupic.fleyx.com/blog/20220329214126.png?imageView2/2/w/1920)
|
||||||
|
|
||||||
## 1.4.1
|
2. 强大的书签检索功能,毫秒级的关键字检索。
|
||||||
|
|
||||||
- 修复书签名过长无法导入问题
|
![](https://qiniupic.fleyx.com/blog/20220329214210.png?imageView2/2/w/1920)
|
||||||
|
|
||||||
## 1.4
|
3. 首页功能,参考 bing 首页实现
|
||||||
|
|
||||||
- 优化首图加载逻辑
|
![](https://qiniupic.fleyx.com/blog/20220329214236.png?imageView2/2/w/1920)
|
||||||
- 支持 OneEnv 备份文件导入
|
|
||||||
|
|
||||||
## 1.3
|
4. 移动端支持,手机端也可使用(部分功能比如拖拽等无法使用)
|
||||||
|
|
||||||
![pic](https://s3.fleyx.com/picbed/2023/08/Snipaste_2023-08-13_15-01-20.png)
|
![](https://qiniupic.fleyx.com/blog/20220329214312.png?imageView2/2/w/1920)
|
||||||
|
|
||||||
搜索引擎支持自定义[#43](https://github.com/FleyX/bookmark/issues/43)
|
|
||||||
|
|
||||||
位置:右上角个人中心-管理搜索引擎
|
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
|
|
||||||
- [x] 主页功能
|
- 主页功能 Ok!
|
||||||
- [x] 拼音检索
|
- 拼音检索 Ok!
|
||||||
- [x] 书签导出
|
- 书签导出 OK!
|
||||||
- [x] 浏览器插件
|
- 侧边栏显示
|
||||||
|
@ -22,18 +22,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jsoup</groupId>
|
<groupId>org.jsoup</groupId>
|
||||||
<artifactId>jsoup</artifactId>
|
<artifactId>jsoup</artifactId>
|
||||||
<version>1.15.3</version>
|
<version>1.14.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.houbb</groupId>
|
<groupId>com.github.houbb</groupId>
|
||||||
<artifactId>pinyin</artifactId>
|
<artifactId>pinyin</artifactId>
|
||||||
<version>0.3.1</version>
|
<version>0.3.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.xerial</groupId>
|
|
||||||
<artifactId>sqlite-jdbc</artifactId>
|
|
||||||
<version>3.44.1.0</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ public class BookmarkController {
|
|||||||
*/
|
*/
|
||||||
@RequestMapping("/uploadBookmarkFile")
|
@RequestMapping("/uploadBookmarkFile")
|
||||||
public Result uploadFile(@RequestParam("file") MultipartFile file, @RequestParam("path") String path) throws Exception {
|
public Result uploadFile(@RequestParam("file") MultipartFile file, @RequestParam("path") String path) throws Exception {
|
||||||
bookmarkService.parseBookmarkFile(UserContextHolder.get().getUserId(), file, path);
|
bookmarkService.parseBookmarkFile(UserContextHolder.get().getUserId(), file.getInputStream(), path);
|
||||||
return Result.success(null);
|
return Result.success(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
package com.fanxb.bookmark.business.bookmark.dao;
|
package com.fanxb.bookmark.business.bookmark.dao;
|
||||||
|
|
||||||
import org.apache.ibatis.annotations.*;
|
import org.apache.ibatis.annotations.Insert;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import org.apache.ibatis.annotations.Select;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
@ -25,15 +28,6 @@ public interface HostIconDao {
|
|||||||
* @return {@link String}
|
* @return {@link String}
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
*/
|
*/
|
||||||
@Select("select iconPath from host_icon where host=#{host} limit 1")
|
@Select("select iconPath from host_icon where host=#{host}")
|
||||||
String selectByHost(String host);
|
String selectByHost(String host);
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除一条
|
|
||||||
*
|
|
||||||
* @param host host
|
|
||||||
* @author FleyX
|
|
||||||
*/
|
|
||||||
@Delete("delete from host_icon where host=#{host}")
|
|
||||||
void deleteByHost(String host);
|
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package com.fanxb.bookmark.business.bookmark.service;
|
|||||||
import com.fanxb.bookmark.business.bookmark.entity.BookmarkEs;
|
import com.fanxb.bookmark.business.bookmark.entity.BookmarkEs;
|
||||||
import com.fanxb.bookmark.business.bookmark.entity.MoveNodeBody;
|
import com.fanxb.bookmark.business.bookmark.entity.MoveNodeBody;
|
||||||
import com.fanxb.bookmark.common.entity.po.Bookmark;
|
import com.fanxb.bookmark.common.entity.po.Bookmark;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -55,7 +54,7 @@ public interface BookmarkService {
|
|||||||
* @author fanxb
|
* @author fanxb
|
||||||
* @date 2019/7/9 18:44
|
* @date 2019/7/9 18:44
|
||||||
*/
|
*/
|
||||||
void parseBookmarkFile(int userId, MultipartFile file, String path) throws Exception;
|
void parseBookmarkFile(int userId, InputStream stream, String path) throws Exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description: 详情
|
* Description: 详情
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package com.fanxb.bookmark.business.bookmark.service.impl;
|
package com.fanxb.bookmark.business.bookmark.service.impl;
|
||||||
|
|
||||||
import cn.hutool.core.codec.Base64Decoder;
|
|
||||||
import cn.hutool.core.io.FileUtil;
|
import cn.hutool.core.io.FileUtil;
|
||||||
import cn.hutool.core.util.*;
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
import cn.hutool.core.util.HashUtil;
|
import cn.hutool.core.util.CharsetUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.fanxb.bookmark.business.api.UserApi;
|
import com.fanxb.bookmark.business.api.UserApi;
|
||||||
import com.fanxb.bookmark.business.bookmark.constant.FileConstant;
|
import com.fanxb.bookmark.business.bookmark.constant.FileConstant;
|
||||||
@ -21,7 +21,6 @@ import com.fanxb.bookmark.common.constant.RedisConstant;
|
|||||||
import com.fanxb.bookmark.common.entity.po.Bookmark;
|
import com.fanxb.bookmark.common.entity.po.Bookmark;
|
||||||
import com.fanxb.bookmark.common.exception.CustomException;
|
import com.fanxb.bookmark.common.exception.CustomException;
|
||||||
import com.fanxb.bookmark.common.util.*;
|
import com.fanxb.bookmark.common.util.*;
|
||||||
import com.mysql.cj.conf.url.SingleConnectionUrl;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import okhttp3.Request;
|
import okhttp3.Request;
|
||||||
import okhttp3.Response;
|
import okhttp3.Response;
|
||||||
@ -36,24 +35,16 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.beans.factory.annotation.Value;
|
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 org.springframework.web.multipart.MultipartFile;
|
|
||||||
|
|
||||||
import java.awt.print.Book;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.SocketTimeoutException;
|
|
||||||
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.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.sql.Connection;
|
|
||||||
import java.sql.DriverManager;
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.Statement;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@ -62,6 +53,7 @@ import java.util.stream.Collectors;
|
|||||||
* 类功能详述:
|
* 类功能详述:
|
||||||
*
|
*
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
|
* @date 2019/7/8 15:00
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ -86,25 +78,18 @@ public class BookmarkServiceImpl implements BookmarkService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void parseBookmarkFile(int userId, MultipartFile file, String path) throws Exception {
|
public void parseBookmarkFile(int userId, InputStream stream, String path) throws Exception {
|
||||||
List<Bookmark> bookmarks = new ArrayList<>();
|
Document doc = Jsoup.parse(stream, "utf-8", "");
|
||||||
|
Elements elements = doc.select("html>body>dl>dt");
|
||||||
//获取当前层sort最大值
|
//获取当前层sort最大值
|
||||||
Integer sortBase = bookmarkDao.selectMaxSort(userId, path);
|
Integer sortBase = bookmarkDao.selectMaxSort(userId, path);
|
||||||
if (sortBase == null) {
|
if (sortBase == null) {
|
||||||
sortBase = 0;
|
sortBase = 0;
|
||||||
}
|
}
|
||||||
if (file.getOriginalFilename().endsWith(".db3")) {
|
List<Bookmark> bookmarks = new ArrayList<>();
|
||||||
//处理db文件
|
for (int i = 0, length = elements.size(); i < length; i++) {
|
||||||
readFromOneEnv(bookmarks, userId, file, path, sortBase);
|
dealBookmark(userId, elements.get(i), path, sortBase + i, bookmarks);
|
||||||
} else {
|
|
||||||
InputStream stream = file.getInputStream();
|
|
||||||
Document doc = Jsoup.parse(stream, "utf-8", "");
|
|
||||||
Elements elements = doc.select("html>body>dl>dt");
|
|
||||||
for (int i = 0, length = elements.size(); i < length; i++) {
|
|
||||||
dealBookmark(userId, elements.get(i), path, sortBase + i, bookmarks);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//每一千条处理插入一次,批量更新搜索字段
|
//每一千条处理插入一次,批量更新搜索字段
|
||||||
List<Bookmark> tempList = new ArrayList<>(1000);
|
List<Bookmark> tempList = new ArrayList<>(1000);
|
||||||
for (int i = 0; i < bookmarks.size(); i++) {
|
for (int i = 0; i < bookmarks.size(); i++) {
|
||||||
@ -131,6 +116,7 @@ public class BookmarkServiceImpl implements BookmarkService {
|
|||||||
* @param path 节点路径,不包含自身
|
* @param path 节点路径,不包含自身
|
||||||
* @param sort 当前层级中的排序序号
|
* @param sort 当前层级中的排序序号
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
|
* @date 2019/7/8 14:49
|
||||||
*/
|
*/
|
||||||
private void dealBookmark(int userId, Element ele, String path, int sort, List<Bookmark> bookmarks) {
|
private void dealBookmark(int userId, Element ele, String path, int sort, List<Bookmark> bookmarks) {
|
||||||
if (!DT.equalsIgnoreCase(ele.tagName())) {
|
if (!DT.equalsIgnoreCase(ele.tagName())) {
|
||||||
@ -139,7 +125,7 @@ public class BookmarkServiceImpl implements BookmarkService {
|
|||||||
Element first = ele.child(0);
|
Element first = ele.child(0);
|
||||||
if (A.equalsIgnoreCase(first.tagName())) {
|
if (A.equalsIgnoreCase(first.tagName())) {
|
||||||
//说明为链接
|
//说明为链接
|
||||||
Bookmark node = new Bookmark(userId, path, first.ownText(), first.attr("href"), ""
|
Bookmark node = new Bookmark(userId, path, first.ownText(), first.attr("href"), first.attr("icon")
|
||||||
, Long.parseLong(first.attr("add_date")) * 1000, sort);
|
, Long.parseLong(first.attr("add_date")) * 1000, sort);
|
||||||
//存入数据库
|
//存入数据库
|
||||||
insertOne(node);
|
insertOne(node);
|
||||||
@ -163,63 +149,13 @@ public class BookmarkServiceImpl implements BookmarkService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理oneenv的导出
|
|
||||||
*
|
|
||||||
* @param bookmarks 书签列表
|
|
||||||
* @param userId 用户id
|
|
||||||
* @param file file
|
|
||||||
* @param path path
|
|
||||||
* @param sort sort
|
|
||||||
*/
|
|
||||||
private void readFromOneEnv(List<Bookmark> bookmarks, int userId, MultipartFile file, String path, int sort) {
|
|
||||||
String filePath = CommonConstant.fileSavePath + "/files/" + IdUtil.simpleUUID() + ".db3";
|
|
||||||
try {
|
|
||||||
file.transferTo(FileUtil.newFile(filePath));
|
|
||||||
try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + filePath)) {
|
|
||||||
Statement stat = conn.createStatement();
|
|
||||||
ResultSet rs = stat.executeQuery("select * from on_categorys");
|
|
||||||
Map<Long, Bookmark> folderMap = new HashMap<>();
|
|
||||||
Map<Long, Integer> childSortBaseMap = new HashMap<>();
|
|
||||||
while (rs.next()) {
|
|
||||||
long addTime = rs.getLong("add_time");
|
|
||||||
Bookmark folder = new Bookmark(userId, path, StrUtil.nullToEmpty(rs.getString("name")), addTime == 0 ? System.currentTimeMillis() : addTime * 1000, sort++);
|
|
||||||
int childSortBase = 0;
|
|
||||||
if (insertOne(folder)) {
|
|
||||||
childSortBase = ObjectUtil.defaultIfNull(bookmarkDao.selectMaxSort(userId, path), 0);
|
|
||||||
}
|
|
||||||
long id = rs.getLong("id");
|
|
||||||
folderMap.put(id, folder);
|
|
||||||
childSortBaseMap.put(id, childSortBase);
|
|
||||||
}
|
|
||||||
rs.close();
|
|
||||||
rs = stat.executeQuery("select * from on_links");
|
|
||||||
while (rs.next()) {
|
|
||||||
long fId = rs.getLong("fid");
|
|
||||||
long addTime = rs.getLong("add_time");
|
|
||||||
int tempSort = childSortBaseMap.get(fId);
|
|
||||||
childSortBaseMap.put(fId, tempSort + 1);
|
|
||||||
Bookmark folder = folderMap.get(fId);
|
|
||||||
String curPath = folder == null ? "" : folder.getPath() + "." + folder.getBookmarkId();
|
|
||||||
Bookmark bookmark = new Bookmark(userId, curPath, StrUtil.nullToEmpty(rs.getString("title"))
|
|
||||||
, StrUtil.nullToEmpty(rs.getString("url")), "", addTime == 0 ? System.currentTimeMillis() : addTime * 1000, tempSort);
|
|
||||||
bookmarks.add(bookmark);
|
|
||||||
insertOne(bookmark);
|
|
||||||
}
|
|
||||||
rs.close();
|
|
||||||
stat.close();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description: 插入一条书签,如果已经存在同名书签将跳过
|
* Description: 插入一条书签,如果已经存在同名书签将跳过
|
||||||
*
|
*
|
||||||
* @param node node
|
* @param node node
|
||||||
* @return boolean 如果已经存在返回true,否则false
|
* @return boolean 如果已经存在返回true,否则false
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
|
* @date 2019/7/8 17:25
|
||||||
*/
|
*/
|
||||||
private boolean insertOne(Bookmark node) {
|
private boolean insertOne(Bookmark node) {
|
||||||
//先根据name,userId,parentId获取此节点id
|
//先根据name,userId,parentId获取此节点id
|
||||||
@ -281,14 +217,11 @@ public class BookmarkServiceImpl implements BookmarkService {
|
|||||||
bookmark.setUserId(userId);
|
bookmark.setUserId(userId);
|
||||||
bookmark.setCreateTime(System.currentTimeMillis());
|
bookmark.setCreateTime(System.currentTimeMillis());
|
||||||
bookmark.setAddTime(bookmark.getCreateTime());
|
bookmark.setAddTime(bookmark.getCreateTime());
|
||||||
bookmark.setIcon(bookmark.getType() == 1 ? "" : getIconPath(bookmark.getUrl(), bookmark.getIcon(), bookmark.getIconUrl(), true));
|
bookmark.setIcon(getIconPath(bookmark.getUrl()));
|
||||||
//文件夹和书签都建立搜索key
|
//文件夹和书签都建立搜索key
|
||||||
pinYinService.changeBookmark(bookmark);
|
pinYinService.changeBookmark(bookmark);
|
||||||
bookmarkDao.insertOne(bookmark);
|
bookmarkDao.insertOne(bookmark);
|
||||||
userApi.versionPlus(userId);
|
userApi.versionPlus(userId);
|
||||||
if (StrUtil.isEmpty(bookmark.getIcon()) && bookmark.getType() == 0) {
|
|
||||||
updateIconAsync(bookmark.getBookmarkId(), bookmark.getUrl(), userId);
|
|
||||||
}
|
|
||||||
return bookmark;
|
return bookmark;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,33 +231,13 @@ public class BookmarkServiceImpl implements BookmarkService {
|
|||||||
bookmark.setUserId(userId);
|
bookmark.setUserId(userId);
|
||||||
if (bookmark.getType() == 0) {
|
if (bookmark.getType() == 0) {
|
||||||
pinYinService.changeBookmark(bookmark);
|
pinYinService.changeBookmark(bookmark);
|
||||||
bookmark.setIcon(getIconPath(bookmark.getUrl(), null, null, true));
|
bookmark.setIcon(getIconPath(bookmark.getUrl()));
|
||||||
if (StrUtil.isEmpty(bookmark.getIcon())) {
|
|
||||||
updateIconAsync(bookmark.getBookmarkId(), bookmark.getUrl(), userId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
bookmarkDao.editBookmark(bookmark);
|
bookmarkDao.editBookmark(bookmark);
|
||||||
userApi.versionPlus(userId);
|
userApi.versionPlus(userId);
|
||||||
return bookmark.getIcon();
|
return bookmark.getIcon();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 异步更新书签icon
|
|
||||||
*
|
|
||||||
* @param id 书签id
|
|
||||||
* @param url 书签url
|
|
||||||
* @param userId userId
|
|
||||||
*/
|
|
||||||
private void updateIconAsync(int id, String url, int userId) {
|
|
||||||
ThreadPoolUtil.execute(() -> {
|
|
||||||
String icon = getIconPath(url, null, null, false);
|
|
||||||
if (StrUtil.isEmpty(icon)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
bookmarkDao.updateIcon(id, icon);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@ -374,10 +287,10 @@ public class BookmarkServiceImpl implements BookmarkService {
|
|||||||
int size = 100;
|
int size = 100;
|
||||||
int start = 0;
|
int start = 0;
|
||||||
List<Bookmark> deal;
|
List<Bookmark> deal;
|
||||||
while (!(deal = bookmarkDao.selectUserNoIcon(userId, start, size)).isEmpty()) {
|
while ((deal = bookmarkDao.selectUserNoIcon(userId, start, size)).size() > 0) {
|
||||||
start += size;
|
start += size;
|
||||||
deal.forEach(item -> {
|
deal.forEach(item -> {
|
||||||
String icon = getIconPath(item.getUrl(), null, null, false);
|
String icon = getIconPath(item.getUrl());
|
||||||
if (StrUtil.isNotEmpty(icon)) {
|
if (StrUtil.isNotEmpty(icon)) {
|
||||||
bookmarkDao.updateIcon(item.getBookmarkId(), icon);
|
bookmarkDao.updateIcon(item.getBookmarkId(), icon);
|
||||||
}
|
}
|
||||||
@ -409,95 +322,58 @@ public class BookmarkServiceImpl implements BookmarkService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取icon,通过网络获取,或者从base64还原
|
* 获取icon
|
||||||
*
|
*
|
||||||
* @param url 书签url路径
|
* @param url url
|
||||||
* @param icon base64编码的icon
|
|
||||||
* @param iconUrl base64编码的文件,文件名,用于获取文件名后缀
|
|
||||||
* @param quick 是否快速获取
|
|
||||||
* @return {@link String}
|
* @return {@link String}
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
*/
|
*/
|
||||||
private String getIconPath(String url, String icon, String iconUrl, boolean quick) {
|
private String getIconPath(String url) {
|
||||||
|
if (StrUtil.isEmpty(url)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
String host;
|
String host;
|
||||||
try {
|
try {
|
||||||
URL urlObj = new URL(url);
|
URL urlObj = new URL(url);
|
||||||
host = urlObj.getAuthority();
|
host = urlObj.getHost();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("url无法解析出domain:{}", url);
|
log.warn("url无法解析出domain:{}", url);
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
if (StrUtil.isNotBlank(icon)) {
|
|
||||||
//优先从base64还原出图片
|
|
||||||
try {
|
|
||||||
byte[] b = Base64Decoder.decode(icon.substring(icon.indexOf(",") + 1));
|
|
||||||
String iconPath = saveToFile(iconUrl, host, b);
|
|
||||||
hostIconDao.deleteByHost(host);
|
|
||||||
hostIconDao.insert(host, iconPath);
|
|
||||||
return iconPath;
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("解析base64获取icon故障:{}", iconUrl, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String iconPath = hostIconDao.selectByHost(host);
|
String iconPath = hostIconDao.selectByHost(host);
|
||||||
if (iconPath != null) {
|
if (iconPath != null) {
|
||||||
return iconPath;
|
return iconPath;
|
||||||
}
|
}
|
||||||
//再根据url解析
|
iconPath = saveFile(host, urlIconAddress + "/icon?url=" + host + "&size=16..64..256");
|
||||||
iconPath = saveFile(host, urlIconAddress + "/icon?url=" + host + "&size=16..128..256", quick);
|
|
||||||
if (StrUtil.isNotEmpty(iconPath)) {
|
if (StrUtil.isNotEmpty(iconPath)) {
|
||||||
hostIconDao.insert(host, iconPath);
|
hostIconDao.insert(host, iconPath);
|
||||||
}
|
}
|
||||||
return iconPath;
|
return iconPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private String saveFile(String host, String url) {
|
||||||
* 保存文件到icon路径
|
try {
|
||||||
*
|
try (Response res = HttpUtil.getClient(false).newCall(new Request.Builder().url(url)
|
||||||
* @param host host
|
.header("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Safari/537.36 Edg/100.0.1185.36")
|
||||||
* @param url url
|
.get().build()).execute()) {
|
||||||
* @param quick 是否快速获取,快速获取超时时间1s
|
assert res.body() != null;
|
||||||
* @return {@link String}
|
if (!HttpUtil.checkIsOk(res.code())) {
|
||||||
* @author FleyX
|
throw new CustomException("请求错误:" + res.code());
|
||||||
*/
|
}
|
||||||
private String saveFile(String host, String url, boolean quick) {
|
byte[] data = res.body().byteStream().readAllBytes();
|
||||||
try (Response res = (quick ? HttpUtil.getSHORT_CLIENT() : HttpUtil.getClient(false)).newCall(new Request.Builder().url(url)
|
if (data.length > 0) {
|
||||||
.header("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Safari/537.36 Edg/100.0.1185.36")
|
String iconUrl = res.request().url().toString();
|
||||||
.get().build()).execute()) {
|
String fileName = URLEncoder.encode(host, StandardCharsets.UTF_8) + iconUrl.substring(iconUrl.lastIndexOf("."));
|
||||||
assert res.body() != null;
|
String filePath = Paths.get(FileConstant.FAVICON_PATH, host.substring(0, 2), fileName).toString();
|
||||||
if (!HttpUtil.checkIsOk(res.code())) {
|
FileUtil.writeBytes(data, Paths.get(CommonConstant.fileSavePath, filePath).toString());
|
||||||
throw new CustomException("请求错误:" + res.code());
|
return File.separator + filePath;
|
||||||
|
} else {
|
||||||
|
log.info("未获取到icon:{}", url);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
byte[] data = res.body().byteStream().readAllBytes();
|
|
||||||
if (data.length > 0) {
|
|
||||||
String iconUrl = new URL(res.request().url().toString()).getPath();
|
|
||||||
return saveToFile(iconUrl, host, data);
|
|
||||||
} else {
|
|
||||||
log.info("未获取到icon:{}", url);
|
|
||||||
}
|
|
||||||
} catch (SocketTimeoutException timeoutException) {
|
|
||||||
log.info("获取icon超时:{}", host);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("url获取icon故障:{}", url, e);
|
log.error("url获取icon故障:{}", url, e);
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 保存到文件中
|
|
||||||
*
|
|
||||||
* @param iconUrl icon文件名
|
|
||||||
* @param host host
|
|
||||||
* @param b 数据
|
|
||||||
* @return {@link String}
|
|
||||||
* @author FleyX
|
|
||||||
*/
|
|
||||||
private String saveToFile(String iconUrl, String host, byte[] b) {
|
|
||||||
String fileName = host.replace(":", ".") + iconUrl.substring(iconUrl.lastIndexOf("."));
|
|
||||||
String filePath = Paths.get(FileConstant.FAVICON_PATH, host.replace("www", "").replaceAll("\\.", "").substring(0, 2), fileName).toString();
|
|
||||||
FileUtil.writeBytes(b, Paths.get(CommonConstant.fileSavePath, filePath).toString());
|
|
||||||
return File.separator + filePath;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,12 @@
|
|||||||
<artifactId>bookmark-common</artifactId>
|
<artifactId>bookmark-common</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
package com.fanxb.bookmark.business.user.controller;
|
|
||||||
|
|
||||||
import com.fanxb.bookmark.business.user.dao.SearchEngineDao;
|
|
||||||
import com.fanxb.bookmark.business.user.entity.SearchEngine;
|
|
||||||
import com.fanxb.bookmark.business.user.service.SearchEngineService;
|
|
||||||
import com.fanxb.bookmark.common.entity.Result;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/searchEngine")
|
|
||||||
public class SearchEngineController {
|
|
||||||
@Autowired
|
|
||||||
private SearchEngineService searchEngineService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 列表查询
|
|
||||||
*/
|
|
||||||
@GetMapping("/list")
|
|
||||||
public Result list() {
|
|
||||||
return Result.success(searchEngineService.list());
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/insert")
|
|
||||||
public Result insert(@RequestBody SearchEngine body){
|
|
||||||
searchEngineService.insertOne(body);
|
|
||||||
return Result.success();
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/edit")
|
|
||||||
public Result edit(@RequestBody SearchEngine body){
|
|
||||||
searchEngineService.editOne(body);
|
|
||||||
return Result.success();
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/delete")
|
|
||||||
public Result delete(@RequestBody SearchEngine body){
|
|
||||||
searchEngineService.deleteOne(body.getId());
|
|
||||||
return Result.success();
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/setChecked")
|
|
||||||
public Result setChecked(@RequestBody SearchEngine body){
|
|
||||||
searchEngineService.setChecked(body.getId());
|
|
||||||
return Result.success();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
package com.fanxb.bookmark.business.user.dao;
|
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
|
||||||
import com.fanxb.bookmark.business.user.entity.SearchEngine;
|
|
||||||
|
|
||||||
public interface SearchEngineDao extends BaseMapper<SearchEngine> {
|
|
||||||
|
|
||||||
}
|
|
@ -1,6 +1,5 @@
|
|||||||
package com.fanxb.bookmark.business.user.dao;
|
package com.fanxb.bookmark.business.user.dao;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
|
||||||
import com.fanxb.bookmark.common.entity.po.User;
|
import com.fanxb.bookmark.common.entity.po.User;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
import org.apache.ibatis.annotations.Select;
|
import org.apache.ibatis.annotations.Select;
|
||||||
@ -17,7 +16,7 @@ import java.util.List;
|
|||||||
* @date 2019/7/6 11:36
|
* @date 2019/7/6 11:36
|
||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
public interface UserDao extends BaseMapper<User> {
|
public interface UserDao {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description: 新增一个用户
|
* Description: 新增一个用户
|
||||||
@ -183,6 +182,16 @@ public interface UserDao extends BaseMapper<User> {
|
|||||||
@Select("select userId from user order by userId limit #{start},#{size}")
|
@Select("select userId from user order by userId limit #{start},#{size}")
|
||||||
List<Integer> selectUserIdPage(@Param("start") int start, @Param("size") int size);
|
List<Integer> selectUserIdPage(@Param("start") int start, @Param("size") int size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新用户搜索引擎
|
||||||
|
*
|
||||||
|
* @param userId userId
|
||||||
|
* @param engine engine
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/3/14
|
||||||
|
**/
|
||||||
|
@Update("update user set defaultSearchEngine=#{engine} where userId=#{userId}")
|
||||||
|
void updateSearchEngine(@Param("userId") int userId, @Param("engine") String engine);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新一个字段-一个条件
|
* 更新一个字段-一个条件
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
package com.fanxb.bookmark.business.user.entity;
|
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.annotation.IdType;
|
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.experimental.Accessors;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@Accessors(chain = true)
|
|
||||||
@TableName("search_engine")
|
|
||||||
public class SearchEngine {
|
|
||||||
@TableId(type = IdType.AUTO)
|
|
||||||
private Integer id;
|
|
||||||
private Integer userId;
|
|
||||||
private Integer checked;
|
|
||||||
/**
|
|
||||||
* 名称
|
|
||||||
*/
|
|
||||||
private String name;
|
|
||||||
/**
|
|
||||||
* url
|
|
||||||
*/
|
|
||||||
private String url;
|
|
||||||
/**
|
|
||||||
* 图标
|
|
||||||
*/
|
|
||||||
private String icon;
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
package com.fanxb.bookmark.business.user.service;
|
|
||||||
|
|
||||||
import com.fanxb.bookmark.business.user.entity.SearchEngine;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public interface SearchEngineService {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 列表查询
|
|
||||||
*/
|
|
||||||
List<SearchEngine> list();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* delete one by id
|
|
||||||
*
|
|
||||||
* @param id id
|
|
||||||
*/
|
|
||||||
void deleteOne(int id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* insert one
|
|
||||||
*
|
|
||||||
* @param body body
|
|
||||||
*/
|
|
||||||
void insertOne(SearchEngine body);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* edit one
|
|
||||||
*
|
|
||||||
* @param body body
|
|
||||||
*/
|
|
||||||
void editOne(SearchEngine body);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设为默认搜索项
|
|
||||||
*
|
|
||||||
* @param id
|
|
||||||
*/
|
|
||||||
void setChecked(Integer id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 新用户初始化
|
|
||||||
*
|
|
||||||
* @param userId userId
|
|
||||||
*/
|
|
||||||
void newUserInit(int userId);
|
|
||||||
}
|
|
@ -87,6 +87,6 @@ public class BaseInfoServiceImpl implements BaseInfoService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void changeDefaultSearchEngine(User user) {
|
public void changeDefaultSearchEngine(User user) {
|
||||||
userDao.updateById(user);
|
userDao.updateSearchEngine(user.getUserId(), user.getDefaultSearchEngine());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import cn.hutool.core.util.StrUtil;
|
|||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.fanxb.bookmark.business.user.dao.UserDao;
|
import com.fanxb.bookmark.business.user.dao.UserDao;
|
||||||
import com.fanxb.bookmark.business.user.service.OauthService;
|
import com.fanxb.bookmark.business.user.service.OauthService;
|
||||||
import com.fanxb.bookmark.business.user.service.SearchEngineService;
|
|
||||||
import com.fanxb.bookmark.business.user.service.UserService;
|
import com.fanxb.bookmark.business.user.service.UserService;
|
||||||
import com.fanxb.bookmark.business.user.vo.OauthBody;
|
import com.fanxb.bookmark.business.user.vo.OauthBody;
|
||||||
import com.fanxb.bookmark.common.constant.CommonConstant;
|
import com.fanxb.bookmark.common.constant.CommonConstant;
|
||||||
@ -39,8 +38,6 @@ public class OauthServiceImpl implements OauthService {
|
|||||||
private String githubClientId;
|
private String githubClientId;
|
||||||
@Value("${OAuth.github.secret}")
|
@Value("${OAuth.github.secret}")
|
||||||
private String githubSecret;
|
private String githubSecret;
|
||||||
@Autowired
|
|
||||||
private SearchEngineService searchEngineService;
|
|
||||||
private final UserDao userDao;
|
private final UserDao userDao;
|
||||||
private final UserService userService;
|
private final UserService userService;
|
||||||
|
|
||||||
@ -108,7 +105,6 @@ public class OauthServiceImpl implements OauthService {
|
|||||||
other.setLastLoginTime(System.currentTimeMillis());
|
other.setLastLoginTime(System.currentTimeMillis());
|
||||||
other.setVersion(0);
|
other.setVersion(0);
|
||||||
userDao.addOne(other);
|
userDao.addOne(other);
|
||||||
searchEngineService.newUserInit(other.getUserId());
|
|
||||||
return other;
|
return other;
|
||||||
} else {
|
} else {
|
||||||
if (!current.getEmail().equals(other.getEmail()) || !current.getGithubId().equals(other.getGithubId())) {
|
if (!current.getEmail().equals(other.getEmail()) || !current.getGithubId().equals(other.getGithubId())) {
|
||||||
|
@ -1,88 +0,0 @@
|
|||||||
package com.fanxb.bookmark.business.user.service.impl;
|
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import com.alibaba.druid.support.ibatis.SpringIbatisBeanNameAutoProxyCreator;
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
|
||||||
import com.fanxb.bookmark.business.user.dao.SearchEngineDao;
|
|
||||||
import com.fanxb.bookmark.business.user.dao.UserDao;
|
|
||||||
import com.fanxb.bookmark.business.user.entity.SearchEngine;
|
|
||||||
import com.fanxb.bookmark.business.user.service.SearchEngineService;
|
|
||||||
import com.fanxb.bookmark.common.entity.UserContext;
|
|
||||||
import com.fanxb.bookmark.common.entity.po.User;
|
|
||||||
import com.fanxb.bookmark.common.exception.CustomException;
|
|
||||||
import com.fanxb.bookmark.common.util.UserContextHolder;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
public class SearchEngineServiceImpl implements SearchEngineService {
|
|
||||||
@Autowired
|
|
||||||
private SearchEngineDao searchEngineDao;
|
|
||||||
@Autowired
|
|
||||||
private UserDao userDao;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<SearchEngine> list() {
|
|
||||||
return searchEngineDao.selectList(new LambdaQueryWrapper<SearchEngine>().eq(SearchEngine::getUserId, UserContextHolder.get().getUserId()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deleteOne(int id) {
|
|
||||||
SearchEngine engine = searchEngineDao.selectById(id);
|
|
||||||
if (engine.getUserId() != UserContextHolder.get().getUserId()) {
|
|
||||||
throw new CustomException("无法操作其他人数据");
|
|
||||||
}
|
|
||||||
if (engine.getChecked() == 1) {
|
|
||||||
throw new CustomException("默认搜索引擎无法删除");
|
|
||||||
}
|
|
||||||
searchEngineDao.deleteById(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void insertOne(SearchEngine body) {
|
|
||||||
checkOne(body);
|
|
||||||
body.setId(null).setChecked(0).setUserId(UserContextHolder.get().getUserId());
|
|
||||||
searchEngineDao.insert(body);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkOne(SearchEngine body) {
|
|
||||||
if (StrUtil.hasBlank(body.getIcon(), body.getUrl(), body.getName())) {
|
|
||||||
throw new CustomException("请填写完整");
|
|
||||||
}
|
|
||||||
if (!body.getUrl().contains("%s")) {
|
|
||||||
throw new CustomException("路径中必须包含%s");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void editOne(SearchEngine body) {
|
|
||||||
SearchEngine engine = searchEngineDao.selectById(body.getId());
|
|
||||||
if (engine.getUserId() != UserContextHolder.get().getUserId()) {
|
|
||||||
throw new CustomException("无法操作其他人数据");
|
|
||||||
}
|
|
||||||
checkOne(body);
|
|
||||||
searchEngineDao.updateById(body);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public void setChecked(Integer id) {
|
|
||||||
int userId = UserContextHolder.get().getUserId();
|
|
||||||
LambdaUpdateWrapper<SearchEngine> update = new LambdaUpdateWrapper<SearchEngine>().set(SearchEngine::getChecked, 0).eq(SearchEngine::getUserId, userId).eq(SearchEngine::getChecked, 1);
|
|
||||||
searchEngineDao.update(null, update);
|
|
||||||
update = new LambdaUpdateWrapper<SearchEngine>().set(SearchEngine::getChecked, 1).eq(SearchEngine::getId, id).eq(SearchEngine::getUserId, userId);
|
|
||||||
searchEngineDao.update(null, update);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void newUserInit(int userId) {
|
|
||||||
searchEngineDao.insert(new SearchEngine().setUserId(userId).setIcon("icon-baidu").setName("百度").setUrl("https://www.baidu.com/s?ie=UTF-8&wd=%s").setChecked(1));
|
|
||||||
searchEngineDao.insert(new SearchEngine().setUserId(userId).setIcon("icon-bing").setName("必应").setUrl("https://www.bing.com/search?q=%s").setChecked(0));
|
|
||||||
searchEngineDao.insert(new SearchEngine().setUserId(userId).setIcon("icon-google").setName("谷歌").setUrl("https://www.google.com/search?q=%s").setChecked(0));
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,7 +5,6 @@ import cn.hutool.core.util.StrUtil;
|
|||||||
import com.fanxb.bookmark.business.api.BookmarkApi;
|
import com.fanxb.bookmark.business.api.BookmarkApi;
|
||||||
import com.fanxb.bookmark.business.user.constant.FileConstant;
|
import com.fanxb.bookmark.business.user.constant.FileConstant;
|
||||||
import com.fanxb.bookmark.business.user.dao.UserDao;
|
import com.fanxb.bookmark.business.user.dao.UserDao;
|
||||||
import com.fanxb.bookmark.business.user.service.SearchEngineService;
|
|
||||||
import com.fanxb.bookmark.business.user.service.UserService;
|
import com.fanxb.bookmark.business.user.service.UserService;
|
||||||
import com.fanxb.bookmark.business.user.vo.LoginBody;
|
import com.fanxb.bookmark.business.user.vo.LoginBody;
|
||||||
import com.fanxb.bookmark.business.user.vo.RegisterBody;
|
import com.fanxb.bookmark.business.user.vo.RegisterBody;
|
||||||
@ -21,7 +20,6 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -44,8 +42,6 @@ public class UserServiceImpl implements UserService {
|
|||||||
* 登陆最大重试次数
|
* 登陆最大重试次数
|
||||||
*/
|
*/
|
||||||
private static final int LOGIN_COUNT = 5;
|
private static final int LOGIN_COUNT = 5;
|
||||||
@Autowired
|
|
||||||
private SearchEngineService searchEngineService;
|
|
||||||
|
|
||||||
private final UserDao userDao;
|
private final UserDao userDao;
|
||||||
private final StringRedisTemplate redisTemplate;
|
private final StringRedisTemplate redisTemplate;
|
||||||
@ -87,7 +83,6 @@ public class UserServiceImpl implements UserService {
|
|||||||
* @author fanxb
|
* @author fanxb
|
||||||
* @date 2019/7/6 11:30
|
* @date 2019/7/6 11:30
|
||||||
*/
|
*/
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public String register(RegisterBody body) {
|
public String register(RegisterBody body) {
|
||||||
User user = userDao.selectByUsernameOrEmail(body.getUsername(), body.getEmail());
|
User user = userDao.selectByUsernameOrEmail(body.getUsername(), body.getEmail());
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
@ -107,7 +102,6 @@ public class UserServiceImpl implements UserService {
|
|||||||
user.setLastLoginTime(System.currentTimeMillis());
|
user.setLastLoginTime(System.currentTimeMillis());
|
||||||
user.setVersion(0);
|
user.setVersion(0);
|
||||||
userDao.addOne(user);
|
userDao.addOne(user);
|
||||||
searchEngineService.newUserInit(user.getUserId());
|
|
||||||
Map<String, String> data = new HashMap<>(1);
|
Map<String, String> data = new HashMap<>(1);
|
||||||
data.put("userId", String.valueOf(user.getUserId()));
|
data.put("userId", String.valueOf(user.getUserId()));
|
||||||
return JwtUtil.encode(data, CommonConstant.jwtSecret, LONG_EXPIRE_TIME);
|
return JwtUtil.encode(data, CommonConstant.jwtSecret, LONG_EXPIRE_TIME);
|
||||||
|
@ -37,10 +37,16 @@
|
|||||||
<artifactId>commons-pool2</artifactId>
|
<artifactId>commons-pool2</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!--mybatis依赖-->
|
||||||
|
<!-- <dependency>-->
|
||||||
|
<!-- <groupId>org.mybatis.spring.boot</groupId>-->
|
||||||
|
<!-- <artifactId>mybatis-spring-boot-starter</artifactId>-->
|
||||||
|
<!-- <version>2.0.1</version>-->
|
||||||
|
<!-- </dependency>-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.baomidou</groupId>
|
<groupId>com.baomidou</groupId>
|
||||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||||
<version>3.5.3.2</version>
|
<version>3.5.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -53,66 +59,21 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba</groupId>
|
<groupId>com.alibaba</groupId>
|
||||||
<artifactId>druid-spring-boot-starter</artifactId>
|
<artifactId>druid-spring-boot-starter</artifactId>
|
||||||
<version>1.2.18</version>
|
<version>1.1.18</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!--数据库版本管理-->
|
<!--数据库版本管理-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.flywaydb</groupId>
|
<groupId>org.flywaydb</groupId>
|
||||||
<artifactId>flyway-core</artifactId>
|
<artifactId>flyway-core</artifactId>
|
||||||
<version>9.21.1</version>
|
<version>5.2.4</version>
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.flywaydb</groupId>
|
|
||||||
<artifactId>flyway-mysql</artifactId>
|
|
||||||
<version>9.21.1</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<!--mysql jdbc依赖-->
|
<!--mysql jdbc依赖-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>mysql</groupId>
|
<groupId>mysql</groupId>
|
||||||
<artifactId>mysql-connector-java</artifactId>
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
<version>8.0.33</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- <!–邮件依赖–>-->
|
|
||||||
<!-- <dependency>-->
|
|
||||||
<!-- <groupId>org.springframework.boot</groupId>-->
|
|
||||||
<!-- <artifactId>spring-boot-starter-mail</artifactId>-->
|
|
||||||
<!-- </dependency>-->
|
|
||||||
|
|
||||||
<!-- <!–减负依赖–>-->
|
|
||||||
<!-- <dependency>-->
|
|
||||||
<!-- <groupId>org.projectlombok</groupId>-->
|
|
||||||
<!-- <artifactId>lombok</artifactId>-->
|
|
||||||
<!-- </dependency>-->
|
|
||||||
<!-- <!–json工具依赖–>-->
|
|
||||||
<!-- <dependency>-->
|
|
||||||
<!-- <groupId>com.alibaba</groupId>-->
|
|
||||||
<!-- <artifactId>fastjson</artifactId>-->
|
|
||||||
<!-- <version>1.2.83</version>-->
|
|
||||||
<!-- </dependency>-->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- <dependency>-->
|
|
||||||
<!-- <groupId>org.elasticsearch.client</groupId>-->
|
|
||||||
<!-- <artifactId>elasticsearch-rest-high-level-client</artifactId>-->
|
|
||||||
<!-- </dependency>-->
|
|
||||||
|
|
||||||
<!-- <dependency>-->
|
|
||||||
<!-- <groupId>cn.hutool</groupId>-->
|
|
||||||
<!-- <artifactId>hutool-all</artifactId>-->
|
|
||||||
<!-- <version>5.8.21</version>-->
|
|
||||||
<!-- </dependency>-->
|
|
||||||
|
|
||||||
<!--单元测试-->
|
|
||||||
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test -->
|
|
||||||
<!--mysql jdbc依赖-->
|
|
||||||
<!-- <dependency>-->
|
|
||||||
<!-- <groupId>mysql</groupId>-->
|
|
||||||
<!-- <artifactId>mysql-connector-java</artifactId>-->
|
|
||||||
<!-- <version>8.0.33</version>-->
|
|
||||||
<!-- </dependency>-->
|
|
||||||
|
|
||||||
<!--邮件依赖-->
|
<!--邮件依赖-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
@ -128,7 +89,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba</groupId>
|
<groupId>com.alibaba</groupId>
|
||||||
<artifactId>fastjson</artifactId>
|
<artifactId>fastjson</artifactId>
|
||||||
<version>1.2.83</version>
|
<version>1.2.73</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
@ -140,7 +101,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.hutool</groupId>
|
<groupId>cn.hutool</groupId>
|
||||||
<artifactId>hutool-all</artifactId>
|
<artifactId>hutool-all</artifactId>
|
||||||
<version>5.8.25</version>
|
<version>5.2.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!--单元测试-->
|
<!--单元测试-->
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
package com.fanxb.bookmark.common.configuration;
|
package com.fanxb.bookmark.common.configuration;
|
||||||
|
|
||||||
import com.fanxb.bookmark.common.factory.CustomThreadFactory;
|
import com.fanxb.bookmark.common.factory.CustomThreadFactory;
|
||||||
import com.fanxb.bookmark.common.factory.ThreadPoolFactory;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.scheduling.annotation.SchedulingConfigurer;
|
import org.springframework.scheduling.annotation.SchedulingConfigurer;
|
||||||
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
|
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
|
||||||
|
|
||||||
@ -14,16 +11,15 @@ import java.util.concurrent.ScheduledThreadPoolExecutor;
|
|||||||
* Created with IntelliJ IDEA
|
* Created with IntelliJ IDEA
|
||||||
*
|
*
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
|
* @date 2020/1/26
|
||||||
*/
|
*/
|
||||||
@Configuration
|
|
||||||
@Slf4j
|
|
||||||
public class ScheduleConfig implements SchedulingConfigurer {
|
public class ScheduleConfig implements SchedulingConfigurer {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
|
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
|
||||||
|
|
||||||
ScheduledExecutorService service = new ScheduledThreadPoolExecutor(5, new CustomThreadFactory("schedule"));
|
ScheduledExecutorService service = new ScheduledThreadPoolExecutor(5, new CustomThreadFactory("schedule"));
|
||||||
scheduledTaskRegistrar.setScheduler(service);
|
scheduledTaskRegistrar.setScheduler(service);
|
||||||
log.info("自定义schedule线程池成功");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
package com.fanxb.bookmark.common.dao;
|
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
|
||||||
import com.fanxb.bookmark.common.entity.po.GlobalConfigPo;
|
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author fanxb
|
|
||||||
*/
|
|
||||||
@Mapper
|
|
||||||
public interface GlobalConfigDao extends BaseMapper<GlobalConfigPo> {
|
|
||||||
}
|
|
@ -12,6 +12,7 @@ import java.util.List;
|
|||||||
* 类功能详述:
|
* 类功能详述:
|
||||||
*
|
*
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
|
* @date 2019/7/8 11:19
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public class Bookmark {
|
public class Bookmark {
|
||||||
@ -35,7 +36,6 @@ public class Bookmark {
|
|||||||
private String name;
|
private String name;
|
||||||
private String url = "";
|
private String url = "";
|
||||||
private String icon = "";
|
private String icon = "";
|
||||||
private String iconUrl;
|
|
||||||
private Integer sort;
|
private Integer sort;
|
||||||
private String searchKey = "";
|
private String searchKey = "";
|
||||||
private Long addTime;
|
private Long addTime;
|
||||||
@ -53,7 +53,7 @@ public class Bookmark {
|
|||||||
this.setUserId(userId);
|
this.setUserId(userId);
|
||||||
this.setPath(path);
|
this.setPath(path);
|
||||||
this.setType(FOLDER_TYPE);
|
this.setType(FOLDER_TYPE);
|
||||||
this.setName(name.length() > 2000 ? name.substring(0, 1999) : name);
|
this.setName(name);
|
||||||
this.setAddTime(addTime);
|
this.setAddTime(addTime);
|
||||||
this.setSort(sort);
|
this.setSort(sort);
|
||||||
this.setCreateTime(System.currentTimeMillis());
|
this.setCreateTime(System.currentTimeMillis());
|
||||||
@ -64,7 +64,7 @@ public class Bookmark {
|
|||||||
this.setUserId(userId);
|
this.setUserId(userId);
|
||||||
this.setPath(path);
|
this.setPath(path);
|
||||||
this.setType(BOOKMARK_TYPE);
|
this.setType(BOOKMARK_TYPE);
|
||||||
this.setName(name.length() > 2000 ? name.substring(0, 1999) : name);
|
this.setName(name);
|
||||||
this.setUrl(url);
|
this.setUrl(url);
|
||||||
this.setIcon(icon);
|
this.setIcon(icon);
|
||||||
this.setSort(sort);
|
this.setSort(sort);
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
package com.fanxb.bookmark.common.entity.po;
|
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.annotation.IdType;
|
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 全局配置表
|
|
||||||
*
|
|
||||||
* @author FleyX
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@TableName("global_config")
|
|
||||||
public class GlobalConfigPo {
|
|
||||||
@TableId(value = "code")
|
|
||||||
private String code;
|
|
||||||
private String value;
|
|
||||||
private String description;
|
|
||||||
}
|
|
@ -2,10 +2,6 @@ package com.fanxb.bookmark.common.entity.po;
|
|||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.alibaba.fastjson.annotation.JSONField;
|
import com.alibaba.fastjson.annotation.JSONField;
|
||||||
import com.baomidou.mybatisplus.annotation.IdType;
|
|
||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@ -20,11 +16,9 @@ import java.util.Map;
|
|||||||
* @date 2019/7/4 20:14
|
* @date 2019/7/4 20:14
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@TableName("user")
|
|
||||||
public class User {
|
public class User {
|
||||||
|
|
||||||
@TableId(type = IdType.AUTO)
|
private int userId;
|
||||||
private Integer userId;
|
|
||||||
/**
|
/**
|
||||||
* 第三方github登陆id,-1说明非github登陆
|
* 第三方github登陆id,-1说明非github登陆
|
||||||
*/
|
*/
|
||||||
@ -36,7 +30,6 @@ public class User {
|
|||||||
/**
|
/**
|
||||||
* 是否未设置密码
|
* 是否未设置密码
|
||||||
*/
|
*/
|
||||||
@TableField(exist = false)
|
|
||||||
private Boolean noPassword;
|
private Boolean noPassword;
|
||||||
@JSONField(serialize = false)
|
@JSONField(serialize = false)
|
||||||
private String password;
|
private String password;
|
||||||
@ -49,10 +42,9 @@ public class User {
|
|||||||
* 书签同步版本
|
* 书签同步版本
|
||||||
*/
|
*/
|
||||||
private int version;
|
private int version;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 默认搜索引擎
|
* 默认搜索引擎
|
||||||
*/
|
*/
|
||||||
private Integer searchEngineId;
|
private String defaultSearchEngine;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,6 @@ package com.fanxb.bookmark.common.entity.vo;
|
|||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 全局公共配置
|
* 全局公共配置
|
||||||
*
|
*
|
||||||
@ -19,8 +17,4 @@ public class GlobalConfigVo {
|
|||||||
* bing每日一图地址
|
* bing每日一图地址
|
||||||
*/
|
*/
|
||||||
private String bingImgSrc;
|
private String bingImgSrc;
|
||||||
/**
|
|
||||||
* 浏览器插件版本plugin
|
|
||||||
*/
|
|
||||||
private Map<String, String> map;
|
|
||||||
}
|
}
|
||||||
|
@ -2,32 +2,23 @@ package com.fanxb.bookmark.common.service.impl;
|
|||||||
|
|
||||||
import cn.hutool.core.date.DateUnit;
|
import cn.hutool.core.date.DateUnit;
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
import cn.hutool.core.io.FileUtil;
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.fanxb.bookmark.common.constant.CommonConstant;
|
|
||||||
import com.fanxb.bookmark.common.constant.NumberConstant;
|
import com.fanxb.bookmark.common.constant.NumberConstant;
|
||||||
import com.fanxb.bookmark.common.constant.RedisConstant;
|
import com.fanxb.bookmark.common.constant.RedisConstant;
|
||||||
import com.fanxb.bookmark.common.dao.GlobalConfigDao;
|
|
||||||
import com.fanxb.bookmark.common.entity.po.GlobalConfigPo;
|
|
||||||
import com.fanxb.bookmark.common.entity.vo.GlobalConfigVo;
|
import com.fanxb.bookmark.common.entity.vo.GlobalConfigVo;
|
||||||
import com.fanxb.bookmark.common.service.ConfigService;
|
import com.fanxb.bookmark.common.service.ConfigService;
|
||||||
import com.fanxb.bookmark.common.util.HttpUtil;
|
import com.fanxb.bookmark.common.util.HttpUtil;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import okhttp3.Request;
|
|
||||||
import okhttp3.Response;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.io.File;
|
import java.util.Date;
|
||||||
import java.nio.file.Files;
|
import java.util.HashMap;
|
||||||
import java.nio.file.StandardOpenOption;
|
import java.util.Map;
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
@ -39,12 +30,10 @@ public class ConfigServiceImpl implements ConfigService {
|
|||||||
|
|
||||||
|
|
||||||
private final StringRedisTemplate stringRedisTemplate;
|
private final StringRedisTemplate stringRedisTemplate;
|
||||||
private final GlobalConfigDao globalConfigDao;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public ConfigServiceImpl(StringRedisTemplate stringRedisTemplate, GlobalConfigDao globalConfigDao) {
|
public ConfigServiceImpl(StringRedisTemplate stringRedisTemplate) {
|
||||||
this.stringRedisTemplate = stringRedisTemplate;
|
this.stringRedisTemplate = stringRedisTemplate;
|
||||||
this.globalConfigDao = globalConfigDao;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Value("${bing.host}")
|
@Value("${bing.host}")
|
||||||
@ -54,11 +43,9 @@ public class ConfigServiceImpl implements ConfigService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GlobalConfigVo getGlobalConfig() {
|
public GlobalConfigVo getGlobalConfig() {
|
||||||
List<GlobalConfigPo> pos = globalConfigDao.selectByMap(Collections.emptyMap());
|
|
||||||
Map<String, String> map = pos.stream().collect(Collectors.toMap(GlobalConfigPo::getCode, GlobalConfigPo::getValue));
|
|
||||||
GlobalConfigVo vo = new GlobalConfigVo();
|
GlobalConfigVo vo = new GlobalConfigVo();
|
||||||
|
vo.setProxyExist(HttpUtil.getProxyExist());
|
||||||
vo.setBingImgSrc(getCacheBingImg());
|
vo.setBingImgSrc(getCacheBingImg());
|
||||||
vo.setMap(map);
|
|
||||||
return vo;
|
return vo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,7 +56,9 @@ public class ConfigServiceImpl implements ConfigService {
|
|||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
str = getBingImg();
|
str = getBingImg();
|
||||||
stringRedisTemplate.opsForValue().set(RedisConstant.BING_IMG, str, 2, TimeUnit.HOURS);
|
if (str != null) {
|
||||||
|
stringRedisTemplate.opsForValue().set(RedisConstant.BING_IMG, str, 2, TimeUnit.HOURS);
|
||||||
|
}
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,19 +66,11 @@ public class ConfigServiceImpl implements ConfigService {
|
|||||||
try {
|
try {
|
||||||
JSONObject bingObj = HttpUtil.getObj(bingHost + bingUrl, null, false);
|
JSONObject bingObj = HttpUtil.getObj(bingHost + bingUrl, null, false);
|
||||||
String path = bingObj.getJSONArray("images").getJSONObject(0).getString("url");
|
String path = bingObj.getJSONArray("images").getJSONObject(0).getString("url");
|
||||||
String picUrl = bingHost + path;
|
return bingHost + path;
|
||||||
Request request = new Request.Builder().url(picUrl).build();
|
|
||||||
try (Response res = HttpUtil.getClient(false).newCall(request).execute()) {
|
|
||||||
byte[] bytes = res.body().bytes();
|
|
||||||
String filePath = CommonConstant.fileSavePath + "/files/public/bing.jpg";
|
|
||||||
FileUtil.writeBytes(bytes, filePath);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("获取bing每日一图错误:{}", e.getLocalizedMessage(), e);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("获取bing每日一图错误:{}", e.getLocalizedMessage(), e);
|
log.error("获取bing每日一图错误:{}", e.getLocalizedMessage(), e);
|
||||||
}
|
}
|
||||||
return "/files/public/bing.jpg";
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -53,14 +53,6 @@ public class HttpUtil {
|
|||||||
.readTimeout(60, TimeUnit.SECONDS)
|
.readTimeout(60, TimeUnit.SECONDS)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
/**
|
|
||||||
* 超时时间1s
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
private static final OkHttpClient SHORT_CLIENT = new OkHttpClient.Builder().connectTimeout(1, TimeUnit.SECONDS)
|
|
||||||
.readTimeout(1, TimeUnit.SECONDS)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取客户端
|
* 获取客户端
|
||||||
*
|
*
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-parent</artifactId>
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
<version>2.7.17</version>
|
<version>2.3.12.RELEASE</version>
|
||||||
<relativePath/>
|
<relativePath/>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
CREATE TABLE bookmark.global_config
|
|
||||||
(
|
|
||||||
code varchar(20) NOT NULL,
|
|
||||||
value varchar(100) NOT NULL COMMENT '值',
|
|
||||||
description varchar(100) NOT NULL COMMENT '描述',
|
|
||||||
CONSTRAINT global_config_pk PRIMARY KEY (code)
|
|
||||||
) ENGINE=InnoDB
|
|
||||||
DEFAULT CHARSET=utf8mb4
|
|
||||||
COLLATE=utf8mb4_0900_ai_ci
|
|
||||||
COMMENT='全局配置表';
|
|
||||||
|
|
||||||
insert into global_config
|
|
||||||
values ("pluginVersion", "0.1.1", "浏览器插件版本");
|
|
@ -1,3 +0,0 @@
|
|||||||
update global_config
|
|
||||||
set value='0.1.2'
|
|
||||||
where code = "pluginVersion";
|
|
@ -1,22 +0,0 @@
|
|||||||
create table search_engine
|
|
||||||
(
|
|
||||||
id int auto_increment
|
|
||||||
primary key,
|
|
||||||
userId int not null,
|
|
||||||
checked tinyint not null default 0,
|
|
||||||
name varchar(20) null,
|
|
||||||
url varchar(500) null,
|
|
||||||
icon varchar(20) null
|
|
||||||
) auto_increment=1001;
|
|
||||||
create index search_engine_userId_index
|
|
||||||
on search_engine (userId);
|
|
||||||
|
|
||||||
insert into search_engine(userId, checked, name, url, icon)
|
|
||||||
select userId, if(defaultSearchEngine = 'baidu', 1, 0), '百度', 'https://www.baidu.com/s?ie=UTF-8&wd=%s', 'icon-baidu'
|
|
||||||
from user;
|
|
||||||
insert into search_engine(userId, checked, name, url, icon)
|
|
||||||
select userId, if(defaultSearchEngine = 'bing', 1, 0), '必应', 'https://www.bing.com/search?q=%s', 'icon-bing'
|
|
||||||
from user;
|
|
||||||
insert into search_engine(userId, checked, name, url, icon)
|
|
||||||
select userId, if(defaultSearchEngine = 'google', 1, 0), '谷歌', 'https://www.google.com/search?q=%s', 'icon-google'
|
|
||||||
from user;
|
|
@ -1,2 +0,0 @@
|
|||||||
alter table bookmark
|
|
||||||
modify name varchar(2000) not null;
|
|
2
bookmark_front/.gitignore
vendored
2
bookmark_front/.gitignore
vendored
@ -4,7 +4,6 @@ node_modules
|
|||||||
package-lock.json
|
package-lock.json
|
||||||
yarn.lock
|
yarn.lock
|
||||||
public/files
|
public/files
|
||||||
public\static\bookmarkBrowserPlugin.zip
|
|
||||||
|
|
||||||
# local env files
|
# local env files
|
||||||
.env.local
|
.env.local
|
||||||
@ -24,4 +23,3 @@ pnpm-debug.log*
|
|||||||
*.njsproj
|
*.njsproj
|
||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
|
|
||||||
|
@ -20,11 +20,11 @@
|
|||||||
"vuex": "^3.4.0"
|
"vuex": "^3.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vue/cli-plugin-babel": "~5.0.8",
|
"@vue/cli-plugin-babel": "~4.4.0",
|
||||||
"@vue/cli-plugin-eslint": "~5.0.8",
|
"@vue/cli-plugin-eslint": "~4.4.0",
|
||||||
"@vue/cli-plugin-router": "~5.0.8",
|
"@vue/cli-plugin-router": "~4.4.0",
|
||||||
"@vue/cli-plugin-vuex": "~5.0.8",
|
"@vue/cli-plugin-vuex": "~4.4.0",
|
||||||
"@vue/cli-service": "~5.0.8",
|
"@vue/cli-service": "~4.4.0",
|
||||||
"@vue/eslint-config-airbnb": "^5.0.2",
|
"@vue/eslint-config-airbnb": "^5.0.2",
|
||||||
"babel-eslint": "^10.1.0",
|
"babel-eslint": "^10.1.0",
|
||||||
"eslint": "^6.7.2",
|
"eslint": "^6.7.2",
|
||||||
|
9549
bookmark_front/pnpm-lock.yaml
generated
9549
bookmark_front/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
BIN
bookmark_front/public/static/bookmarkBrowserPlugin.7z
Normal file
BIN
bookmark_front/public/static/bookmarkBrowserPlugin.7z
Normal file
Binary file not shown.
@ -6,21 +6,12 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: "App",
|
name: "App"
|
||||||
mounted() {
|
|
||||||
window.qieziStatisticKey = "b74c4b571b644782a837433209827874";
|
|
||||||
let script = document.createElement("script");
|
|
||||||
script.type = "text/javascript";
|
|
||||||
script.defer = true;
|
|
||||||
script.src = "https://qiezi.fleyx.com/qiezijs/1.0/qiezi_statistic.min.js";
|
|
||||||
document.getElementsByTagName("head")[0].appendChild(script);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
@import "./global.less";
|
@import "./global.less";
|
||||||
|
|
||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@ -29,7 +20,6 @@ body {
|
|||||||
background-color: @bgColor;
|
background-color: @bgColor;
|
||||||
height: initial;
|
height: initial;
|
||||||
}
|
}
|
||||||
|
|
||||||
#app {
|
#app {
|
||||||
font-family: Avenir, Helvetica, Arial, sans-serif;
|
font-family: Avenir, Helvetica, Arial, sans-serif;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="search">
|
<div class="search">
|
||||||
<div :class="{ listShow: focused && list.length > 0 }" class="newSearch">
|
<div :class="{ listShow: focused && list.length > 0 }" class="newSearch">
|
||||||
<input ref="searchInput" class="input" type="text" v-model="value" @keydown="keyPress" @focus="inputFocus"
|
<input ref="searchInput" class="input" type="text" v-model="value" @keydown="keyPress" @focus="inputFocus" @blur="inputBlur" />
|
||||||
@blur="inputBlur" />
|
|
||||||
<div class="action">
|
<div class="action">
|
||||||
<a-dropdown :trigger="['click']">
|
<a-dropdown :trigger="['click']">
|
||||||
<a-tooltip title="点击切换网页搜索">
|
<a-tooltip title="点击切换网页搜索">
|
||||||
<my-icon class="icon" style="margin-right: 0.5em" :type="checkedSearchEngine.icon"
|
<my-icon class="icon" style="margin-right: 0.5em" :type="searchIcon" />
|
||||||
@click="searchIconClick" />
|
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<a-menu slot="overlay" @click="searchEngineChange">
|
<a-menu slot="overlay" @click="searchEngineChange">
|
||||||
<a-menu-item v-for="item in searchEngineList" :key="item.id">{{ item.name }}</a-menu-item>
|
<a-menu-item key="google">谷歌</a-menu-item>
|
||||||
|
<a-menu-item key="bing">bing</a-menu-item>
|
||||||
|
<a-menu-item key="baidu">baidu</a-menu-item>
|
||||||
</a-menu>
|
</a-menu>
|
||||||
</a-dropdown>
|
</a-dropdown>
|
||||||
<a-icon class="icon" type="search" @click="submit(true)" />
|
<a-icon class="icon" type="search" @click="submit(true)" />
|
||||||
@ -30,8 +30,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="icons">
|
<div class="icons">
|
||||||
<a-tooltip title="定位到书签树中" v-if="showLocation">
|
<a-tooltip title="定位到书签树中" v-if="showLocation">
|
||||||
<my-icon style="color: white; font-size: 1.3em" type="icon-et-location"
|
<my-icon style="color: white; font-size: 1.3em" type="icon-et-location" @mousedown="location($event, item)" />
|
||||||
@mousedown="location($event, item)" />
|
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<a-tooltip title="复制链接">
|
<a-tooltip title="复制链接">
|
||||||
<a-icon
|
<a-icon
|
||||||
@ -52,7 +51,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<a ref="targetA" style="left: 1000000px" />
|
<a ref="targetA" style="left: 1000000px" target="_blank" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -62,11 +61,10 @@ import { mapState } from "vuex";
|
|||||||
import ClipboardJS from "clipboard";
|
import ClipboardJS from "clipboard";
|
||||||
import { GLOBAL_CONFIG, USER_INFO } from "@/store/modules/globalConfig";
|
import { GLOBAL_CONFIG, USER_INFO } from "@/store/modules/globalConfig";
|
||||||
import { TREE_DATA, refreshHomePinList, HOME_PIN_BOOKMARK_ID_MAP } from "@/store/modules/treeData";
|
import { TREE_DATA, refreshHomePinList, HOME_PIN_BOOKMARK_ID_MAP } from "@/store/modules/treeData";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "Search",
|
name: "Search",
|
||||||
props: {
|
props: {
|
||||||
showLocation: Boolean //是否显示定位等按钮
|
showLocation: Boolean, //是否显示定位等按钮
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -76,25 +74,19 @@ export default {
|
|||||||
//上下选中
|
//上下选中
|
||||||
selectIndex: null,
|
selectIndex: null,
|
||||||
copyBoard: null, //剪贴板对象
|
copyBoard: null, //剪贴板对象
|
||||||
searchEngineList: [],
|
|
||||||
checkedSearchEngine: { icon: "icon-baidu", name: "百度", url: "https://www.baidu.com/s?ie=UTF-8&wd=%s" }
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
async mounted() {
|
mounted() {
|
||||||
//初始化clipboard
|
//初始化clipboard
|
||||||
this.copyBoard = new ClipboardJS(".search-copy-to-board", {
|
this.copyBoard = new ClipboardJS(".search-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();
|
||||||
});
|
});
|
||||||
if (this.$store.state.globalConfig.token != null) {
|
|
||||||
this.searchEngineList = await HttpUtil.get("/searchEngine/list");
|
|
||||||
this.checkedSearchEngine = this.searchEngineList.find(item => item.checked === 1);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
destroyed() {
|
destroyed() {
|
||||||
if (this.copyBoard != null) {
|
if (this.copyBoard != null) {
|
||||||
@ -103,20 +95,26 @@ export default {
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState("treeData", ["totalTreeData", HOME_PIN_BOOKMARK_ID_MAP]),
|
...mapState("treeData", ["totalTreeData", HOME_PIN_BOOKMARK_ID_MAP]),
|
||||||
...mapState("globalConfig", ["userInfo"])
|
...mapState("globalConfig", ["userInfo"]),
|
||||||
|
searchIcon() {
|
||||||
|
let search = this.userInfo != null ? this.userInfo.defaultSearchEngine : "baidu";
|
||||||
|
return search === "baidu" ? "icon-baidu" : search === "bing" ? "icon-bing" : "icon-google";
|
||||||
|
},
|
||||||
|
searchUrl() {
|
||||||
|
let search = this.userInfo && this.userInfo.defaultSearchEngine ? this.userInfo.defaultSearchEngine : "baidu";
|
||||||
|
return search === "baidu"
|
||||||
|
? "https://www.baidu.com/s?ie=UTF-8&wd="
|
||||||
|
: search === "bing"
|
||||||
|
? "https://www.bing.com/search?q="
|
||||||
|
: "https://www.google.com/search?q=";
|
||||||
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
value(newVal, oldVal) {
|
value(newVal, oldVal) {
|
||||||
this.search(newVal);
|
this.search(newVal);
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
searchIconClick() {
|
|
||||||
if (this.userInfo == null) {
|
|
||||||
this.searchEngineList = [];
|
|
||||||
this.$message.warning("未登录,请登录后操作");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
search(content) {
|
search(content) {
|
||||||
console.log(content);
|
console.log(content);
|
||||||
let val = content.toLocaleLowerCase().trim();
|
let val = content.toLocaleLowerCase().trim();
|
||||||
@ -125,7 +123,6 @@ export default {
|
|||||||
} else {
|
} else {
|
||||||
this.list = this.dealSearch(val);
|
this.list = this.dealSearch(val);
|
||||||
}
|
}
|
||||||
this.selectIndex = null;
|
|
||||||
},
|
},
|
||||||
//下方列表点击
|
//下方列表点击
|
||||||
itemClick(index) {
|
itemClick(index) {
|
||||||
@ -137,7 +134,7 @@ export default {
|
|||||||
let url;
|
let url;
|
||||||
if (forceSearch || this.selectIndex == null) {
|
if (forceSearch || this.selectIndex == null) {
|
||||||
//说明使用网页搜索
|
//说明使用网页搜索
|
||||||
url = this.checkedSearchEngine.url.replace("%s", encodeURIComponent(this.value));
|
url = this.searchUrl + encodeURIComponent(this.value);
|
||||||
} else {
|
} else {
|
||||||
//说明跳转到书签
|
//说明跳转到书签
|
||||||
let bookmark = this.list[this.selectIndex];
|
let bookmark = this.list[this.selectIndex];
|
||||||
@ -178,10 +175,15 @@ export default {
|
|||||||
},
|
},
|
||||||
//修改默认搜索引擎
|
//修改默认搜索引擎
|
||||||
async searchEngineChange(item) {
|
async searchEngineChange(item) {
|
||||||
|
if (this.userInfo == null) {
|
||||||
let target = this.searchEngineList.find(one => one.id === item.key);
|
this.$message.warning("未登录,请登录后操作");
|
||||||
await HttpUtil.post("/searchEngine/setChecked", null, { id: item.key });
|
return;
|
||||||
this.checkedSearchEngine = target;
|
}
|
||||||
|
if (item.key !== this.userInfo.defaultSearchEngine) {
|
||||||
|
await HttpUtil.post("/baseInfo/updateSearchEngine", null, { defaultSearchEngine: item.key });
|
||||||
|
this.userInfo.defaultSearchEngine = item.key;
|
||||||
|
this.$store.commit(GLOBAL_CONFIG + "/" + USER_INFO, this.userInfo);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
//固定书签到首页
|
//固定书签到首页
|
||||||
async pinBookmark(event, { bookmarkId }) {
|
async pinBookmark(event, { bookmarkId }) {
|
||||||
@ -225,8 +227,8 @@ export default {
|
|||||||
}
|
}
|
||||||
console.log("阻止成功");
|
console.log("阻止成功");
|
||||||
return false;
|
return false;
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -237,12 +239,10 @@ export default {
|
|||||||
@listActiveBgColor: #454545;
|
@listActiveBgColor: #454545;
|
||||||
.search {
|
.search {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
.listShow {
|
.listShow {
|
||||||
border-bottom-left-radius: 0 !important;
|
border-bottom-left-radius: 0 !important;
|
||||||
border-bottom-right-radius: 0 !important;
|
border-bottom-right-radius: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.newSearch {
|
.newSearch {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -251,7 +251,6 @@ export default {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
color: @textColor;
|
color: @textColor;
|
||||||
|
|
||||||
.input {
|
.input {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
border: 0;
|
border: 0;
|
||||||
@ -260,13 +259,11 @@ export default {
|
|||||||
padding-left: 0.19rem;
|
padding-left: 0.19rem;
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.action {
|
.action {
|
||||||
padding: 0.1rem;
|
padding: 0.1rem;
|
||||||
padding-right: 0.19rem;
|
padding-right: 0.19rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
color: @textColor;
|
color: @textColor;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@ -284,7 +281,6 @@ export default {
|
|||||||
border-bottom-left-radius: 0.18rem;
|
border-bottom-left-radius: 0.18rem;
|
||||||
border-bottom-right-radius: 0.18rem;
|
border-bottom-right-radius: 0.18rem;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
.listItem {
|
.listItem {
|
||||||
font-size: 0.16rem;
|
font-size: 0.16rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -295,7 +291,6 @@ export default {
|
|||||||
margin: 0.05rem 0 0.05rem 0;
|
margin: 0.05rem 0 0.05rem 0;
|
||||||
padding: 0 0.19rem 0 0.19rem;
|
padding: 0 0.19rem 0 0.19rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
.name {
|
.name {
|
||||||
padding-right: 1em;
|
padding-right: 1em;
|
||||||
max-width: calc(100% - 2em);
|
max-width: calc(100% - 2em);
|
||||||
@ -303,21 +298,17 @@ export default {
|
|||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icons {
|
.icons {
|
||||||
display: none;
|
display: none;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.listItem:hover {
|
.listItem:hover {
|
||||||
background-color: @listActiveBgColor;
|
background-color: @listActiveBgColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
.itemActive {
|
.itemActive {
|
||||||
background-color: @listActiveBgColor;
|
background-color: @listActiveBgColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
.listItem:hover .icons {
|
.listItem:hover .icons {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
@ -6,10 +6,10 @@
|
|||||||
</a-form-model-item>
|
</a-form-model-item>
|
||||||
<template v-if="form.type !== 'file'">
|
<template v-if="form.type !== 'file'">
|
||||||
<a-form-model-item prop="name" label="名称" :required="false">
|
<a-form-model-item prop="name" label="名称" :required="false">
|
||||||
<a-input v-model="form.name" placeholder="名称" @pressEnter="submit" ref="inputName" />
|
<a-input v-model="form.name" placeholder="名称" />
|
||||||
</a-form-model-item>
|
</a-form-model-item>
|
||||||
<a-form-model-item v-if="form.type === 'bookmark'" prop="url" label="URL">
|
<a-form-model-item v-if="form.type === 'bookmark'" prop="url" label="URL">
|
||||||
<a-input v-model="form.url" placeholder="url" @pressEnter="submit" />
|
<a-input v-model="form.url" placeholder="url" />
|
||||||
</a-form-model-item>
|
</a-form-model-item>
|
||||||
<div class="btns">
|
<div class="btns">
|
||||||
<a-button type="primary" @click="submit" :loading="loading" :disabled="loading">提交</a-button>
|
<a-button type="primary" @click="submit" :loading="loading" :disabled="loading">提交</a-button>
|
||||||
@ -21,7 +21,6 @@
|
|||||||
:data="{ path: form.path }"
|
:data="{ path: form.path }"
|
||||||
:headers="{ 'jwt-token': token }"
|
:headers="{ 'jwt-token': token }"
|
||||||
action="/bookmark/api/bookmark/uploadBookmarkFile"
|
action="/bookmark/api/bookmark/uploadBookmarkFile"
|
||||||
accept=".html,.db3"
|
|
||||||
@change="fileChange"
|
@change="fileChange"
|
||||||
>
|
>
|
||||||
<p class="ant-upload-drag-icon">
|
<p class="ant-upload-drag-icon">
|
||||||
@ -63,7 +62,7 @@ export default {
|
|||||||
file: null,
|
file: null,
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
name: [{ required: true, min: 1, max: 1000, message: "名称长度为1-200", trigger: "change" }],
|
name: [{ required: true, min: 1, max: 1000, message: "名称长度为1-1000", trigger: "change" }],
|
||||||
url: [{ required: true, min: 1, message: "不能为空", trigger: "change" }],
|
url: [{ required: true, min: 1, message: "不能为空", trigger: "change" }],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -79,12 +78,6 @@ export default {
|
|||||||
}
|
}
|
||||||
this.token = this.$store.state.globalConfig.token;
|
this.token = this.$store.state.globalConfig.token;
|
||||||
this.form.path = !this.targetNode ? "" : this.targetNode.path + (this.isAdd ? "." + this.targetNode.bookmarkId : "");
|
this.form.path = !this.targetNode ? "" : this.targetNode.path + (this.isAdd ? "." + this.targetNode.bookmarkId : "");
|
||||||
|
|
||||||
this.$nextTick(() => {
|
|
||||||
if (this.$refs.inputName) {
|
|
||||||
this.$refs.inputName.focus();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
/**
|
/**
|
||||||
|
@ -1,10 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="bottom">
|
<div class="bottom">
|
||||||
<router-link style="color: white" to="/public/about"><span class="text">关于</span></router-link>
|
<router-link to="/public/about">关于</router-link>
|
||||||
<a-tooltip v-if="bgSrc">
|
|
||||||
<template #title>点击后鼠标右键-将图像另存为</template>
|
|
||||||
<a style="color: white; margin-left: 1em" :href="bgSrc" download="bing每日一图"><span class="text">下载壁纸</span></a>
|
|
||||||
</a-tooltip>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -12,7 +8,6 @@
|
|||||||
import { mapState } from "vuex";
|
import { mapState } from "vuex";
|
||||||
export default {
|
export default {
|
||||||
name: "homeTop",
|
name: "homeTop",
|
||||||
props: ["bgSrc"],
|
|
||||||
data() {
|
data() {
|
||||||
return {};
|
return {};
|
||||||
},
|
},
|
||||||
@ -23,11 +18,6 @@ export default {
|
|||||||
.bottom {
|
.bottom {
|
||||||
height: 0.4rem;
|
height: 0.4rem;
|
||||||
padding: 0.1rem;
|
padding: 0.1rem;
|
||||||
text-align: center;
|
text-align: right;
|
||||||
color: black;
|
|
||||||
|
|
||||||
.text {
|
|
||||||
color: rgba(255, 255, 255, 0.9);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -6,18 +6,15 @@
|
|||||||
/
|
/
|
||||||
<router-link to="/public/register">注册</router-link>
|
<router-link to="/public/register">注册</router-link>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="topAction">
|
<div v-else>
|
||||||
<a-tooltip style="margin-right: 1em">
|
|
||||||
<template #title>书签管理</template>
|
|
||||||
<router-link to="/manage">
|
|
||||||
<a-icon class="bookmarkIcon" type="setting" />
|
|
||||||
</router-link>
|
|
||||||
</a-tooltip>
|
|
||||||
<a-dropdown>
|
<a-dropdown>
|
||||||
<div class="user">
|
<div class="user">
|
||||||
<img :src="userInfo.icon" class="userIcon" />
|
<img :src="userInfo.icon" class="userIcon" />
|
||||||
</div>
|
</div>
|
||||||
<a-menu slot="overlay" :trigger="['hover', 'click']" @click="menuClick">
|
<a-menu slot="overlay" :trigger="['hover', 'click']" @click="menuClick">
|
||||||
|
<a-menu-item key="manage">
|
||||||
|
<router-link to="manage">书签管理</router-link>
|
||||||
|
</a-menu-item>
|
||||||
<a-menu-item key="personSpace">
|
<a-menu-item key="personSpace">
|
||||||
<router-link to="/manage/personSpace/userInfo">个人中心</router-link>
|
<router-link to="/manage/personSpace/userInfo">个人中心</router-link>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
@ -66,16 +63,5 @@ export default {
|
|||||||
width: 2.5em;
|
width: 2.5em;
|
||||||
height: 2.5em;
|
height: 2.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.topAction {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
.bookmarkIcon {
|
|
||||||
font-size: 2em;
|
|
||||||
background-color: rgb(74, 74, 74, 0.5);
|
|
||||||
color: rgba(255, 255, 255, 0.8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,34 +1,32 @@
|
|||||||
import Vue from "vue";
|
import Vue from "vue";
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
FormModel,
|
FormModel,
|
||||||
Input,
|
Input,
|
||||||
Icon,
|
Icon,
|
||||||
message,
|
message,
|
||||||
Checkbox,
|
Checkbox,
|
||||||
Dropdown,
|
Dropdown,
|
||||||
Menu,
|
Menu,
|
||||||
Tree,
|
Tree,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
Spin,
|
Spin,
|
||||||
notification,
|
notification,
|
||||||
Empty,
|
Empty,
|
||||||
Modal,
|
Modal,
|
||||||
Radio,
|
Radio,
|
||||||
Upload,
|
Upload,
|
||||||
Popconfirm,
|
Popconfirm,
|
||||||
AutoComplete,
|
AutoComplete,
|
||||||
Select,
|
Select,
|
||||||
Popover,
|
Popover
|
||||||
Breadcrumb,
|
|
||||||
Table
|
|
||||||
} from "ant-design-vue";
|
} from "ant-design-vue";
|
||||||
import App from "./App.vue";
|
import App from "./App.vue";
|
||||||
import router from "./router";
|
import router from "./router";
|
||||||
import store from "./store";
|
import store from "./store";
|
||||||
|
|
||||||
const IconFont = Icon.createFromIconfontCN({
|
const IconFont = Icon.createFromIconfontCN({
|
||||||
scriptUrl: "//at.alicdn.com/t/c/font_1261825_v7m0rilm4hm.js"
|
scriptUrl: "//at.alicdn.com/t/font_1261825_1cgngjf5r4f.js"
|
||||||
});
|
});
|
||||||
Vue.use(Button);
|
Vue.use(Button);
|
||||||
Vue.use(FormModel);
|
Vue.use(FormModel);
|
||||||
@ -48,8 +46,6 @@ Vue.use(Popconfirm);
|
|||||||
Vue.use(AutoComplete);
|
Vue.use(AutoComplete);
|
||||||
Vue.use(Select);
|
Vue.use(Select);
|
||||||
Vue.use(Popover);
|
Vue.use(Popover);
|
||||||
Vue.use(Breadcrumb);
|
|
||||||
Vue.use(Table);
|
|
||||||
Vue.component("my-icon", IconFont);
|
Vue.component("my-icon", IconFont);
|
||||||
|
|
||||||
Vue.prototype.$message = message;
|
Vue.prototype.$message = message;
|
||||||
@ -58,9 +54,9 @@ Vue.prototype.$confirm = Modal.confirm;
|
|||||||
Vue.config.productionTip = false;
|
Vue.config.productionTip = false;
|
||||||
|
|
||||||
window.vueInstance = new Vue({
|
window.vueInstance = new Vue({
|
||||||
router,
|
router,
|
||||||
store,
|
store,
|
||||||
render: h => h(App)
|
render: h => h(App)
|
||||||
}).$mount("#app");
|
}).$mount("#app");
|
||||||
|
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ router.beforeEach(async (to, from, next) => {
|
|||||||
await vuex.default.dispatch("treeData/clear");
|
await vuex.default.dispatch("treeData/clear");
|
||||||
await vuex.default.dispatch("globalConfig/clear");
|
await vuex.default.dispatch("globalConfig/clear");
|
||||||
next({
|
next({
|
||||||
path: "/public/login?to=" + btoa(to.fullPath),
|
path: "/public/login?to=" + btoa(location.href),
|
||||||
replace: true
|
replace: true
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -8,61 +8,58 @@ import { checkJwtValid } from "@/util/UserUtil";
|
|||||||
Vue.use(Vuex);
|
Vue.use(Vuex);
|
||||||
|
|
||||||
let store = new Vuex.Store({
|
let store = new Vuex.Store({
|
||||||
state: {},
|
state: {},
|
||||||
mutations: {},
|
mutations: {},
|
||||||
actions: {},
|
actions: {},
|
||||||
modules: {
|
modules: {
|
||||||
[globalConfig.GLOBAL_CONFIG]: globalConfig.store,
|
[globalConfig.GLOBAL_CONFIG]: globalConfig.store,
|
||||||
[treeData.TREE_DATA]: treeData.store
|
[treeData.TREE_DATA]: treeData.store
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let noLoginFinish = false;
|
let noLoginFinish = false;
|
||||||
|
|
||||||
//执行各自的非登陆初始化
|
//执行各自的非登陆初始化
|
||||||
(async () => {
|
(async () => {
|
||||||
await store.dispatch(globalConfig.GLOBAL_CONFIG + "/" + globalConfig.noLoginInit);
|
await store.dispatch(globalConfig.GLOBAL_CONFIG + "/" + globalConfig.noLoginInit);
|
||||||
//无需等待执行
|
await store.dispatch(treeData.TREE_DATA + "/" + treeData.noLoginInit);
|
||||||
store.dispatch(treeData.TREE_DATA + "/" + treeData.noLoginInit);
|
noLoginFinish = true;
|
||||||
noLoginFinish = true;
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 执行各模块的登陆后初始化
|
* 执行各模块的登陆后初始化
|
||||||
*/
|
*/
|
||||||
export async function loginInit() {
|
export async function loginInit () {
|
||||||
if (!noLoginFinish) {
|
if (!noLoginFinish) {
|
||||||
await finishNoLogin();
|
await finishNoLogin();
|
||||||
}
|
}
|
||||||
console.log(store.state[globalConfig.GLOBAL_CONFIG][globalConfig.TOKEN]);
|
console.log(store.state[globalConfig.GLOBAL_CONFIG][globalConfig.TOKEN]);
|
||||||
if (checkJwtValid(store.state[globalConfig.GLOBAL_CONFIG][globalConfig.TOKEN])) {
|
if (checkJwtValid(store.state[globalConfig.GLOBAL_CONFIG][globalConfig.TOKEN])) {
|
||||||
//无需等待执行完毕
|
await store.dispatch(globalConfig.GLOBAL_CONFIG + "/" + globalConfig.loginInit);
|
||||||
store.dispatch(globalConfig.GLOBAL_CONFIG + "/" + globalConfig.loginInit);
|
await store.dispatch(treeData.TREE_DATA + "/" + treeData.loginInit);
|
||||||
store.dispatch(treeData.TREE_DATA + "/" + treeData.loginInit);
|
}
|
||||||
}
|
|
||||||
console.log("初始化完成");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 推出登陆时需要清理的
|
* 推出登陆时需要清理的
|
||||||
*/
|
*/
|
||||||
export async function logoutClear() {
|
export async function logoutClear () {
|
||||||
await store.dispatch(globalConfig.GLOBAL_CONFIG + "/" + globalConfig.clear);
|
await store.dispatch(globalConfig.GLOBAL_CONFIG + "/" + globalConfig.clear);
|
||||||
await store.dispatch(treeData.TREE_DATA + "/" + treeData.clear);
|
await store.dispatch(treeData.TREE_DATA + "/" + treeData.clear);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 确保未登录前要初始化的初始化完了
|
* 确保未登录前要初始化的初始化完了
|
||||||
*/
|
*/
|
||||||
async function finishNoLogin() {
|
async function finishNoLogin () {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
let timer = setInterval(() => {
|
let timer = setInterval(() => {
|
||||||
if (noLoginFinish) {
|
if (noLoginFinish) {
|
||||||
clearInterval(timer);
|
clearInterval(timer);
|
||||||
resolve();
|
resolve();
|
||||||
}
|
}
|
||||||
}, 100);
|
}, 100);
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export default store;
|
export default store;
|
||||||
|
@ -69,7 +69,6 @@ const actions = {
|
|||||||
let userInfo = await HttpUtil.get("/user/currentUserInfo");
|
let userInfo = await HttpUtil.get("/user/currentUserInfo");
|
||||||
context.commit(USER_INFO, userInfo);
|
context.commit(USER_INFO, userInfo);
|
||||||
context.commit(IS_INIT, true);
|
context.commit(IS_INIT, true);
|
||||||
console.log("用户完了");
|
|
||||||
},
|
},
|
||||||
async [setToken]({ commit }, token) {
|
async [setToken]({ commit }, token) {
|
||||||
await localforage.setItem(TOKEN, token);
|
await localforage.setItem(TOKEN, token);
|
||||||
|
@ -22,13 +22,7 @@ export const refreshHomePinList = "refreshHomePinList";
|
|||||||
* 通过id获取书签数据
|
* 通过id获取书签数据
|
||||||
*/
|
*/
|
||||||
export const getById = "getById";
|
export const getById = "getById";
|
||||||
/**
|
|
||||||
* 登录前初始化
|
|
||||||
*/
|
|
||||||
export const noLoginInit = "noLoginInit";
|
export const noLoginInit = "noLoginInit";
|
||||||
/**
|
|
||||||
* 登陆后初始化
|
|
||||||
*/
|
|
||||||
export const loginInit = "loginInit";
|
export const loginInit = "loginInit";
|
||||||
export const refresh = "refresh";
|
export const refresh = "refresh";
|
||||||
export const clear = "clear";
|
export const clear = "clear";
|
||||||
@ -45,10 +39,6 @@ export const addNode = "addNode";
|
|||||||
* 版本检查定时调度
|
* 版本检查定时调度
|
||||||
*/
|
*/
|
||||||
let timer = null;
|
let timer = null;
|
||||||
/**
|
|
||||||
* 检查本地版本是否有更新
|
|
||||||
*/
|
|
||||||
let checkLocalDataTimer = null;
|
|
||||||
/**
|
/**
|
||||||
* 刷新书签确认弹窗是否展示
|
* 刷新书签确认弹窗是否展示
|
||||||
*/
|
*/
|
||||||
@ -86,8 +76,8 @@ const getters = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
async [noLoginInit] () { },
|
async [noLoginInit]() {},
|
||||||
async [loginInit] (context) {
|
async [loginInit](context) {
|
||||||
if (context.state.isInit || context.state.isIniting) {
|
if (context.state.isInit || context.state.isIniting) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -99,12 +89,11 @@ const actions = {
|
|||||||
context.commit(IS_INIT, true);
|
context.commit(IS_INIT, true);
|
||||||
context.commit(IS_INITING, false);
|
context.commit(IS_INITING, false);
|
||||||
timer = setInterval(() => treeDataCheck(context, false), CHECK_INTERVAL);
|
timer = setInterval(() => treeDataCheck(context, false), CHECK_INTERVAL);
|
||||||
checkLocalDataTimer = setInterval(() => checkLocalData(context), 2000);
|
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 确保数据加载完毕
|
* 确保数据加载完毕
|
||||||
*/
|
*/
|
||||||
ensureDataOk (context) {
|
ensureDataOk(context) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let timer = setInterval(() => {
|
let timer = setInterval(() => {
|
||||||
try {
|
try {
|
||||||
@ -119,7 +108,7 @@ const actions = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
//刷新缓存数据
|
//刷新缓存数据
|
||||||
async [refresh] (context) {
|
async [refresh](context) {
|
||||||
let treeData = await HttpUtil.get("/bookmark/currentUser");
|
let treeData = await HttpUtil.get("/bookmark/currentUser");
|
||||||
if (!treeData[""]) {
|
if (!treeData[""]) {
|
||||||
treeData[""] = [];
|
treeData[""] = [];
|
||||||
@ -138,7 +127,7 @@ const actions = {
|
|||||||
await localforage.setItem(TOTAL_TREE_DATA, treeData);
|
await localforage.setItem(TOTAL_TREE_DATA, treeData);
|
||||||
},
|
},
|
||||||
//清除缓存数据
|
//清除缓存数据
|
||||||
async [clear] (context) {
|
async [clear](context) {
|
||||||
context.commit(TOTAL_TREE_DATA, null);
|
context.commit(TOTAL_TREE_DATA, null);
|
||||||
context.commit(VERSION, null);
|
context.commit(VERSION, null);
|
||||||
context.commit(SHOW_REFRESH_TOAST, false);
|
context.commit(SHOW_REFRESH_TOAST, false);
|
||||||
@ -148,16 +137,13 @@ const actions = {
|
|||||||
if (timer != null) {
|
if (timer != null) {
|
||||||
clearInterval(timer);
|
clearInterval(timer);
|
||||||
}
|
}
|
||||||
if (checkLocalDataTimer != null) {
|
|
||||||
clearInterval(checkLocalDataTimer);
|
|
||||||
}
|
|
||||||
await localforage.removeItem(TOTAL_TREE_DATA);
|
await localforage.removeItem(TOTAL_TREE_DATA);
|
||||||
await localforage.removeItem(VERSION);
|
await localforage.removeItem(VERSION);
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 移动节点
|
* 移动节点
|
||||||
*/
|
*/
|
||||||
async moveNode (context, info) {
|
async moveNode(context, info) {
|
||||||
let data = context.state[TOTAL_TREE_DATA];
|
let data = context.state[TOTAL_TREE_DATA];
|
||||||
const target = info.node.dataRef;
|
const target = info.node.dataRef;
|
||||||
const current = info.dragNode.dataRef;
|
const current = info.dragNode.dataRef;
|
||||||
@ -225,7 +211,7 @@ const actions = {
|
|||||||
await localforage.setItem(TOTAL_TREE_DATA, state[TOTAL_TREE_DATA]);
|
await localforage.setItem(TOTAL_TREE_DATA, state[TOTAL_TREE_DATA]);
|
||||||
return body;
|
return body;
|
||||||
},
|
},
|
||||||
async [refreshHomePinList] ({ commit }) {
|
async [refreshHomePinList]({ commit }) {
|
||||||
let list = await HttpUtil.get("/home/pin");
|
let list = await HttpUtil.get("/home/pin");
|
||||||
commit(HOME_PIN_LIST, list);
|
commit(HOME_PIN_LIST, list);
|
||||||
let map = {};
|
let map = {};
|
||||||
@ -235,30 +221,26 @@ const actions = {
|
|||||||
/**
|
/**
|
||||||
* 更新版本数据
|
* 更新版本数据
|
||||||
*/
|
*/
|
||||||
async updateVersion ({ commit, state }, version) {
|
async updateVersion({ commit, state }, version) {
|
||||||
commit(VERSION, version == null ? state[VERSION] + 1 : version);
|
commit(VERSION, version == null ? state[VERSION] + 1 : version);
|
||||||
await localforage.setItem(VERSION, state[VERSION]);
|
await localforage.setItem(VERSION, state[VERSION]);
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 新增书签、文件夹
|
* 新增书签、文件夹
|
||||||
*/
|
*/
|
||||||
async [addNode] (context, { sourceNode, targetNode }) {
|
async [addNode](context, { sourceNode, targetNode }) {
|
||||||
if (sourceNode === null) {
|
if (sourceNode === null) {
|
||||||
if (context.state[TOTAL_TREE_DATA][""] === undefined) {
|
if (context.state[TOTAL_TREE_DATA][""] === undefined) {
|
||||||
context.state[TOTAL_TREE_DATA][""] = [];
|
context.state[TOTAL_TREE_DATA][""] = [];
|
||||||
}
|
}
|
||||||
context.state[TOTAL_TREE_DATA][""].push(targetNode);
|
context.state[TOTAL_TREE_DATA][""].push(targetNode);
|
||||||
} else {
|
} else {
|
||||||
let path = sourceNode.path + "." + sourceNode.bookmarkId;
|
|
||||||
if (!context.state[TOTAL_TREE_DATA][path]) {
|
|
||||||
context.state[TOTAL_TREE_DATA][path] = [];
|
|
||||||
}
|
|
||||||
if (sourceNode.children === undefined) {
|
if (sourceNode.children === undefined) {
|
||||||
sourceNode.children = context.state[TOTAL_TREE_DATA][path];
|
sourceNode.children = [];
|
||||||
}
|
}
|
||||||
sourceNode.children.push(targetNode);
|
sourceNode.children.push(targetNode);
|
||||||
}
|
}
|
||||||
if (targetNode.type === 1) {
|
if (targetNode.type === 0) {
|
||||||
context.state[TOTAL_TREE_DATA][targetNode.path + "." + targetNode.bookmarkId] = [];
|
context.state[TOTAL_TREE_DATA][targetNode.path + "." + targetNode.bookmarkId] = [];
|
||||||
}
|
}
|
||||||
targetNode.isLeaf = targetNode.type === 0;
|
targetNode.isLeaf = targetNode.type === 0;
|
||||||
@ -271,7 +253,7 @@ const actions = {
|
|||||||
/**
|
/**
|
||||||
* 删除节点数据
|
* 删除节点数据
|
||||||
*/
|
*/
|
||||||
async [deleteData] (context, { pathList, bookmarkIdList }) {
|
async [deleteData](context, { pathList, bookmarkIdList }) {
|
||||||
//待删除的书签
|
//待删除的书签
|
||||||
let bookmarkIdSet = new Set();
|
let bookmarkIdSet = new Set();
|
||||||
bookmarkIdList.forEach(item => bookmarkIdSet.add(item));
|
bookmarkIdList.forEach(item => bookmarkIdSet.add(item));
|
||||||
@ -299,7 +281,7 @@ const actions = {
|
|||||||
/**
|
/**
|
||||||
* 编辑书签节点
|
* 编辑书签节点
|
||||||
*/
|
*/
|
||||||
async editNode ({ dispatch, state, commit }, { node, newName, newUrl, newIcon }) {
|
async editNode({ dispatch, state, commit }, { node, newName, newUrl, newIcon }) {
|
||||||
node.name = newName;
|
node.name = newName;
|
||||||
node.url = newUrl;
|
node.url = newUrl;
|
||||||
node.icon = newIcon;
|
node.icon = newIcon;
|
||||||
@ -313,10 +295,10 @@ 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) => {
|
||||||
@ -340,7 +322,7 @@ 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;
|
||||||
}
|
}
|
||||||
@ -354,14 +336,14 @@ async function treeDataCheck (context, isFirst) {
|
|||||||
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;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -372,24 +354,6 @@ async function treeDataCheck (context, isFirst) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查本地缓存数据是否有更新
|
|
||||||
* @param {*} context
|
|
||||||
*/
|
|
||||||
async function checkLocalData (context) {
|
|
||||||
let data = await localforage.getItem(TOTAL_TREE_DATA);
|
|
||||||
let version = await localforage.getItem(VERSION);
|
|
||||||
if (!data || !version) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (version > context.state[VERSION]) {
|
|
||||||
console.log("从local缓存更新数据:", version);
|
|
||||||
context.commit(TOTAL_TREE_DATA, data);
|
|
||||||
context.commit(VERSION, version);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export const store = {
|
export const store = {
|
||||||
namespaced: true,
|
namespaced: true,
|
||||||
state,
|
state,
|
||||||
|
@ -12,54 +12,54 @@ import router from "../router/index";
|
|||||||
* @param {*} redirect 接口返回未认证是否跳转到登陆
|
* @param {*} redirect 接口返回未认证是否跳转到登陆
|
||||||
* @returns 数据
|
* @returns 数据
|
||||||
*/
|
*/
|
||||||
async function request(url, method, params, body, isForm, redirect) {
|
async function request (url, method, params, body, isForm, redirect) {
|
||||||
let options = {
|
let options = {
|
||||||
url,
|
url,
|
||||||
baseURL: "/bookmark/api",
|
baseURL: "/bookmark/api",
|
||||||
method,
|
method,
|
||||||
params,
|
params,
|
||||||
headers: {
|
headers: {
|
||||||
"jwt-token": window.jwtToken
|
"jwt-token": window.jwtToken
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
//如果是表单类型的请求,添加请求头
|
//如果是表单类型的请求,添加请求头
|
||||||
if (isForm) {
|
if (isForm) {
|
||||||
options.headers["Content-Type"] = "multipart/form-data";
|
options.headers["Content-Type"] = "multipart/form-data";
|
||||||
}
|
}
|
||||||
if (body) {
|
if (body) {
|
||||||
options.data = body;
|
options.data = body;
|
||||||
}
|
}
|
||||||
let res;
|
let res;
|
||||||
try {
|
try {
|
||||||
res = await http.default.request(options);
|
res = await http.default.request(options);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
window.vueInstance.$message.error("网络连接异常");
|
window.vueInstance.$message.error("网络连接异常");
|
||||||
console.error(err);
|
console.error(err);
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
const { code, data, message } = res.data;
|
const { code, data, message } = res.data;
|
||||||
if (code === 1) {
|
if (code === 1) {
|
||||||
return data;
|
return data;
|
||||||
} else if (code === -1 && redirect) {
|
} else if (code === -1 && redirect) {
|
||||||
//未登陆,根据redirect参数判断是否需要跳转到登陆页
|
//未登陆,根据redirect参数判断是否需要跳转到登陆页
|
||||||
window.vueInstance.$message.error("您尚未登陆,请先登陆");
|
window.vueInstance.$message.error("您尚未登陆,请先登陆");
|
||||||
//跳转到登录页面需要清理缓存
|
//跳转到登录页面需要清理缓存
|
||||||
await this.$store.dispatch("treeData/clear");
|
await this.$store.dispatch("treeData/clear");
|
||||||
await this.$store.dispatch("globalConfig/clear");
|
await this.$store.dispatch("globalConfig/clear");
|
||||||
router.replace(`/public/login?redirect=${encodeURIComponent(router.currentRoute.fullPath)}`);
|
router.replace(`/public/login?redirect=${encodeURIComponent(router.currentRoute.fullPath)}`);
|
||||||
throw new Error(message);
|
throw new Error(message);
|
||||||
} else if (code === 0) {
|
} else if (code === 0) {
|
||||||
//通用异常,使用error提示
|
//通用异常,使用error提示
|
||||||
window.vueInstance.$notification.error({
|
window.vueInstance.$notification.error({
|
||||||
message: "异常",
|
message: "异常",
|
||||||
description: message
|
description: message
|
||||||
});
|
});
|
||||||
throw new Error(message);
|
throw new Error(message);
|
||||||
} else if (code === -2) {
|
} else if (code === -2) {
|
||||||
//表单异常,使用message提示
|
//表单异常,使用message提示
|
||||||
window.vueInstance.$message.error(message);
|
window.vueInstance.$message.error(message);
|
||||||
throw new Error(message);
|
throw new Error(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -68,8 +68,8 @@ async function request(url, method, params, body, isForm, redirect) {
|
|||||||
* @param {*} params url参数
|
* @param {*} params url参数
|
||||||
* @param {*} redirect 未登陆是否跳转到登陆页
|
* @param {*} redirect 未登陆是否跳转到登陆页
|
||||||
*/
|
*/
|
||||||
async function get(url, params = null, redirect = true) {
|
async function get (url, params = null, redirect = true) {
|
||||||
return request(url, "get", params, null, false, redirect);
|
return request(url, "get", params, null, false, redirect);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -80,8 +80,8 @@ async function get(url, params = null, redirect = true) {
|
|||||||
* @param {*} isForm 是否表单数据
|
* @param {*} isForm 是否表单数据
|
||||||
* @param {*} redirect 是否重定向
|
* @param {*} redirect 是否重定向
|
||||||
*/
|
*/
|
||||||
async function post(url, params, body, isForm = false, redirect = true) {
|
async function post (url, params, body, isForm = false, redirect = true) {
|
||||||
return request(url, "post", params, body, isForm, redirect);
|
return request(url, "post", params, body, isForm, redirect);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -92,8 +92,8 @@ async function post(url, params, body, isForm = false, redirect = true) {
|
|||||||
* @param {*} isForm 是否表单数据
|
* @param {*} isForm 是否表单数据
|
||||||
* @param {*} redirect 是否重定向
|
* @param {*} redirect 是否重定向
|
||||||
*/
|
*/
|
||||||
async function put(url, params, body, isForm = false, redirect = true) {
|
async function put (url, params, body, isForm = false, redirect = true) {
|
||||||
return request(url, "put", params, body, isForm, redirect);
|
return request(url, "put", params, body, isForm, redirect);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -102,14 +102,13 @@ async function put(url, params, body, isForm = false, redirect = true) {
|
|||||||
* @param {*} params url参数
|
* @param {*} params url参数
|
||||||
* @param {*} redirect 是否重定向
|
* @param {*} redirect 是否重定向
|
||||||
*/
|
*/
|
||||||
async function deletes(url, params = null, redirect = true) {
|
async function deletes (url, params = null, redirect = true) {
|
||||||
return request(url, "delete", params, null, redirect);
|
return request(url, "delete", params, null, redirect);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
get,
|
get,
|
||||||
post,
|
post,
|
||||||
put,
|
put,
|
||||||
delete: deletes,
|
delete: deletes
|
||||||
http
|
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<a :href="pinObj.url" v-if="pinObj" class="pinBookmarkItem">
|
<a :href="pinObj.url" v-if="pinObj" class="pinBookmarkItem" target="_blank">
|
||||||
<img :src="pinObj.icon.length > 0 ? pinObj.icon : '/favicon.ico'" class="icon" />
|
<img :src="pinObj.icon.length > 0 ? pinObj.icon : '/favicon.ico'" class="icon" />
|
||||||
<span class="text" :title="pinObj.name">{{ pinObj.name }}</span>
|
<span class="text" :title="pinObj.name">{{ pinObj.name }}</span>
|
||||||
<a-dropdown :trigger="['click']">
|
<a-dropdown :trigger="['click']">
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<search :style="{ width: isPhone ? '100%' : '60%' }" />
|
<search :style="{ width: isPhone ? '100%' : '60%' }" />
|
||||||
<div :style="{ width: isPhone ? '100%' : '70%' }"><pin-bookmark /></div>
|
<div :style="{ width: isPhone ? '100%' : '70%' }"><pin-bookmark /></div>
|
||||||
</div>
|
</div>
|
||||||
<bottom :bgSrc="serverConfig.bingImgSrc" />
|
<bottom />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -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="添加书签"
|
||||||
>
|
>
|
||||||
@ -65,7 +65,7 @@
|
|||||||
@drop="onDrop"
|
@drop="onDrop"
|
||||||
>
|
>
|
||||||
<a-dropdown :trigger="['contextmenu']" slot="nodeTitle" slot-scope="rec">
|
<a-dropdown :trigger="['contextmenu']" slot="nodeTitle" slot-scope="rec">
|
||||||
<div class="titleContext" :title="rec.dataRef.url">
|
<div class="titleContext">
|
||||||
<a-icon type="folder" v-if="!rec.dataRef.isLeaf" />
|
<a-icon type="folder" v-if="!rec.dataRef.isLeaf" />
|
||||||
<img v-else-if="rec.dataRef.icon.length > 0" :src="rec.dataRef.icon" style="width: 16px" />
|
<img v-else-if="rec.dataRef.icon.length > 0" :src="rec.dataRef.icon" style="width: 16px" />
|
||||||
<a-icon type="book" v-else />
|
<a-icon type="book" v-else />
|
||||||
@ -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>
|
||||||
|
|
||||||
|
@ -1,164 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<a-button type="primary" @click="addOne">新增</a-button>
|
|
||||||
<a-table :columns="columns" :data-source="list" :pagination="false">
|
|
||||||
<template v-for="col in ['name', 'url']" :slot="col" slot-scope="text, record, index">
|
|
||||||
<div :key="col">
|
|
||||||
<a-input v-if="record.isEdit" style="margin: -5px 0" :value="text"
|
|
||||||
@change="e => handleChange(e.target.value, record.id, col)" />
|
|
||||||
<template v-else>{{ text }}</template>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template slot="icon" slot-scope="text, record, index">
|
|
||||||
<div key="icon">
|
|
||||||
<a-select v-if="record.isEdit" :default-value="text" style="width: 120px"
|
|
||||||
@change="e => handleChange(e, record.id, 'icon')">
|
|
||||||
<a-select-option v-for="item in iconList" :key="item.icon" :value="item.icon">
|
|
||||||
<my-icon :type="item.icon" />
|
|
||||||
{{ item.label }}
|
|
||||||
</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
<template v-else>
|
|
||||||
<my-icon style="font-size: 1.2em" :type="text" />
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template slot="checked" slot-scope="text">
|
|
||||||
<span>{{ text === 1 ? "是" : "否" }}</span>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template slot="operation" slot-scope="text, record, index">
|
|
||||||
<div class="editable-row-operations">
|
|
||||||
<span v-if="record.isEdit">
|
|
||||||
<a @click="() => save(record.id)">保存</a>
|
|
||||||
<a @click="() => cancel(record.id)">取消</a>
|
|
||||||
</span>
|
|
||||||
<div v-else>
|
|
||||||
<a :disabled="currentEditCache" @click="() => edit(record.id)">编辑</a>
|
|
||||||
<a-popconfirm title="确认删除吗?" ok-text="是" cancel-text="否" @confirm="() => deleteOne(record.id)">
|
|
||||||
<a :disabled="currentEditCache">删除</a>
|
|
||||||
</a-popconfirm>
|
|
||||||
<a :disabled="currentEditCache || record.checked===1" @click="() => setDefault(record.id)">设为默认</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
</a-table>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import HttpUtil from "@/util/HttpUtil";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: "manageSearchEngine",
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
list: [],
|
|
||||||
currentEditCache: null,
|
|
||||||
iconList: [
|
|
||||||
{ icon: "icon-baidu", label: "百度" },
|
|
||||||
{ icon: "icon-bing", label: "必应" },
|
|
||||||
{ icon: "icon-google", label: "谷歌" },
|
|
||||||
{ icon: "icon-yandex", label: "yandex" },
|
|
||||||
{ icon: "icon-sogou", label: "搜狗" },
|
|
||||||
{ icon: "icon-yahoo", label: "雅虎" },
|
|
||||||
{ icon: "icon-qita", label: "其他" }
|
|
||||||
],
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
title: "名称",
|
|
||||||
dataIndex: "name",
|
|
||||||
width: "10em",
|
|
||||||
scopedSlots: { customRender: "name" }
|
|
||||||
}, {
|
|
||||||
title: "图标",
|
|
||||||
dataIndex: "icon",
|
|
||||||
width: "8em",
|
|
||||||
scopedSlots: { customRender: "icon" }
|
|
||||||
}, {
|
|
||||||
title: "路径(%s 会被替换为搜索内容)",
|
|
||||||
dataIndex: "url",
|
|
||||||
scopedSlots: { customRender: "url" }
|
|
||||||
}, {
|
|
||||||
title: "默认",
|
|
||||||
dataIndex: "checked",
|
|
||||||
width: "10em",
|
|
||||||
scopedSlots: { customRender: "checked" }
|
|
||||||
}, {
|
|
||||||
title: "操作",
|
|
||||||
width: "15em",
|
|
||||||
dataIndex: "operation",
|
|
||||||
scopedSlots: { customRender: "operation" }
|
|
||||||
}]
|
|
||||||
};
|
|
||||||
},
|
|
||||||
async created() {
|
|
||||||
await this.getData();
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
//是否可点击删除
|
|
||||||
deleteOk() {
|
|
||||||
return this.list.filter(item => item.isEdit).length === 0;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
addOne() {
|
|
||||||
let body = { id: -1, icon: "", name: "", url: "", checked: 0, isEdit: true };
|
|
||||||
this.list = [body, ...this.list];
|
|
||||||
this.currentEditCache = body;
|
|
||||||
|
|
||||||
},
|
|
||||||
handleChange(value, id, column) {
|
|
||||||
console.log(value, id, column);
|
|
||||||
const target = this.list.find(item => item.id === id);
|
|
||||||
target[column] = value;
|
|
||||||
this.list = [...this.list];
|
|
||||||
},
|
|
||||||
async edit(id) {
|
|
||||||
let target = this.list.find(item => item.id === id);
|
|
||||||
this.currentEditCache = { ...target };
|
|
||||||
target.isEdit = true;
|
|
||||||
this.list = [...this.list];
|
|
||||||
},
|
|
||||||
async save(id) {
|
|
||||||
let target = this.list.find(item => item.id === id);
|
|
||||||
if (target.id > 0) {
|
|
||||||
await HttpUtil.post("/searchEngine/edit", null, target);
|
|
||||||
} else {
|
|
||||||
await HttpUtil.post("/searchEngine/insert", null, target);
|
|
||||||
}
|
|
||||||
target.isEdit = false;
|
|
||||||
this.currentEditCache = null;
|
|
||||||
await this.getData();
|
|
||||||
},
|
|
||||||
cancel(id) {
|
|
||||||
let target = this.list.find(item => item.id === id);
|
|
||||||
Object.assign(target, this.currentEditCache);
|
|
||||||
target.isEdit = false;
|
|
||||||
this.list = [...this.list];
|
|
||||||
this.currentEditCache = null;
|
|
||||||
},
|
|
||||||
async deleteOne(id) {
|
|
||||||
await HttpUtil.post("/searchEngine/delete", null, { id });
|
|
||||||
this.list = await HttpUtil.get("/searchEngine/list");
|
|
||||||
},
|
|
||||||
async setDefault(id) {
|
|
||||||
await HttpUtil.post("/searchEngine/setChecked", null, { id });
|
|
||||||
this.list = await HttpUtil.get("/searchEngine/list");
|
|
||||||
},
|
|
||||||
async getData() {
|
|
||||||
this.list = await HttpUtil.get("/searchEngine/list");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.icon {
|
|
||||||
color: black;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 1.3em;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="userInfo" class="userInfo">
|
<div class="userInfo">
|
||||||
<div class="icon">
|
<div class="icon">
|
||||||
<img :src="userInfo.icon" class="full" />
|
<img :src="userInfo.icon" class="full" />
|
||||||
<label class="full">
|
<label class="full">
|
||||||
@ -12,8 +12,7 @@
|
|||||||
<div class="baseInfo">
|
<div class="baseInfo">
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<a-tooltip title="点击修改" v-if="currentAction != 'name'">
|
<a-tooltip title="点击修改" v-if="currentAction != 'name'">
|
||||||
<span style="font-size: 2em; cursor: pointer"
|
<span style="font-size: 2em; cursor: pointer" @click="() => (this.currentAction = 'name')">{{ userInfo.username }}</span>
|
||||||
@click="() => (this.currentAction = 'name')">{{ userInfo.username }}</span>
|
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<div class="inputGroup" v-else-if="currentAction === 'name'">
|
<div class="inputGroup" v-else-if="currentAction === 'name'">
|
||||||
<a-input type="text" v-model="name" placeholder="修改昵称" />
|
<a-input type="text" v-model="name" placeholder="修改昵称" />
|
||||||
@ -27,9 +26,7 @@
|
|||||||
<div class="item">
|
<div class="item">
|
||||||
<span style="width: 5em">密码</span>
|
<span style="width: 5em">密码</span>
|
||||||
<a-tooltip title="点击修改" v-if="currentAction != 'password'">
|
<a-tooltip title="点击修改" v-if="currentAction != 'password'">
|
||||||
<span style="cursor: pointer"
|
<span style="cursor: pointer" @click="() => (this.currentAction = 'password')">{{ userInfo.noPassword ? "设置密码" : "**********" }}</span>
|
||||||
@click="() => (this.currentAction = 'password')">{{ userInfo.noPassword ? "设置密码" : "**********"
|
|
||||||
}}</span>
|
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<div class="inputGroup" v-else-if="currentAction === 'password'">
|
<div class="inputGroup" v-else-if="currentAction === 'password'">
|
||||||
<a-input type="password" v-model="oldPassword" placeholder="旧密码(如无置空)" />
|
<a-input type="password" v-model="oldPassword" placeholder="旧密码(如无置空)" />
|
||||||
@ -61,24 +58,26 @@
|
|||||||
<a-tooltip title="搜索框默认搜索引擎">
|
<a-tooltip title="搜索框默认搜索引擎">
|
||||||
<span style="width: 5em">搜索</span>
|
<span style="width: 5em">搜索</span>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<div @click="showSearchEngineManage=true" style=" cursor: pointer;color:blue">管理搜索引擎</div>
|
<a-tooltip title="点击修改" v-if="currentAction != 'defaultSearchEngine'">
|
||||||
|
<span style="cursor: pointer" @click="() => (this.currentAction = 'defaultSearchEngine')">{{ defaultSearchEngine }}</span>
|
||||||
|
</a-tooltip>
|
||||||
|
<div class="inputGroup" v-else-if="currentAction === 'defaultSearchEngine'">
|
||||||
|
<a-select :default-value="userInfo.defaultSearchEngine" style="width: 100%" @change="submit">
|
||||||
|
<a-select-option value="baidu">百度</a-select-option>
|
||||||
|
<a-select-option value="google">谷歌</a-select-option>
|
||||||
|
<a-select-option value="bing">Bing</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a-modal v-model="showSearchEngineManage" title="管理搜索引擎" :footer="null" width="70%">
|
|
||||||
<manage-search-engine />
|
|
||||||
</a-modal>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import manageSearchEngine from "./components/manageSearchEngine.vue";
|
|
||||||
import { mapState } from "vuex";
|
import { mapState } from "vuex";
|
||||||
import HttpUtil from "@/util/HttpUtil";
|
import HttpUtil from "@/util/HttpUtil";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "UserInfo",
|
name: "UserInfo",
|
||||||
components: { manageSearchEngine },
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
currentAction: null, //当前操作,name,password,email
|
currentAction: null, //当前操作,name,password,email
|
||||||
@ -87,11 +86,21 @@ export default {
|
|||||||
password: "",
|
password: "",
|
||||||
rePassword: "",
|
rePassword: "",
|
||||||
email: "",
|
email: "",
|
||||||
showSearchEngineManage: false
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState("globalConfig", ["userInfo"])
|
...mapState("globalConfig", ["userInfo"]),
|
||||||
|
defaultSearchEngine() {
|
||||||
|
switch (this.userInfo.defaultSearchEngine) {
|
||||||
|
case "baidu":
|
||||||
|
return "百度";
|
||||||
|
case "google":
|
||||||
|
return "谷歌";
|
||||||
|
case "bing":
|
||||||
|
return "Bing";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async changeIcon(e) {
|
async changeIcon(e) {
|
||||||
@ -118,18 +127,21 @@ export default {
|
|||||||
url = "/baseInfo/password";
|
url = "/baseInfo/password";
|
||||||
body = {
|
body = {
|
||||||
oldPassword: this.oldPassword,
|
oldPassword: this.oldPassword,
|
||||||
password: this.password
|
password: this.password,
|
||||||
};
|
};
|
||||||
} else if (this.currentAction === "email") {
|
} else if (this.currentAction === "email") {
|
||||||
url = "/baseInfo/email";
|
url = "/baseInfo/email";
|
||||||
body = { oldPassword: this.oldPassword, email: this.email };
|
body = { oldPassword: this.oldPassword, email: this.email };
|
||||||
|
} else if (this.currentAction === "defaultSearchEngine") {
|
||||||
|
url = "/baseInfo/updateSearchEngine";
|
||||||
|
body = { defaultSearchEngine: e };
|
||||||
}
|
}
|
||||||
await HttpUtil.post(url, null, body);
|
await HttpUtil.post(url, null, body);
|
||||||
await this.$store.dispatch("globalConfig/refreshUserInfo");
|
await this.$store.dispatch("globalConfig/refreshUserInfo");
|
||||||
this.$message.success("操作成功");
|
this.$message.success("操作成功");
|
||||||
this.currentAction = null;
|
this.currentAction = null;
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -183,7 +195,6 @@ export default {
|
|||||||
border-bottom: 1px solid #ebebeb;
|
border-bottom: 1px solid #ebebeb;
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
.inputGroup {
|
.inputGroup {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
@ -1,76 +1,27 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="ssoAddBookmark">
|
<div class="ssoAddBookmark">
|
||||||
<div class="body">
|
正在添加,请稍后!!!
|
||||||
<div>
|
<!-- <button @click="closeIframe">关闭</button> -->
|
||||||
<a-input placeholder="标题" v-model="form.name" @pressEnter="addBookmark" ref="nameInput" />
|
|
||||||
<a-input placeholder="网址" v-model="form.url" @pressEnter="addBookmark" />
|
|
||||||
</div>
|
|
||||||
<div class="list">
|
|
||||||
<div class="path">
|
|
||||||
<div>保存路径:</div>
|
|
||||||
<a-breadcrumb>
|
|
||||||
<a-breadcrumb-item class="breadItem"><span @click="breadClick(null)">根</span></a-breadcrumb-item>
|
|
||||||
<a-breadcrumb-item class="breadItem" v-for="item in breadList" :key="item.bookmarkId">
|
|
||||||
<span @click="breadClick(item)">{{ item.name.length > 4 ? item.name.substr(0, 3) + "..." : item.name }}</span>
|
|
||||||
</a-breadcrumb-item>
|
|
||||||
</a-breadcrumb>
|
|
||||||
</div>
|
|
||||||
<div class="folderList">
|
|
||||||
<div :class="{ item: true, bg: item.type == 1 }" v-for="item in dataList" :key="item.bookmarkId" :title="item.url">
|
|
||||||
<span class="text" @click="folderClick(item)">{{ item.name }}</span>
|
|
||||||
<a-popconfirm class="actionBar" placement="left" title="确认删除?" ok-text="是" cancel-text="否" @confirm="deleteOne(item, $event)">
|
|
||||||
<a-icon type="delete" />
|
|
||||||
</a-popconfirm>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="action">
|
|
||||||
<div v-if="showAddInput" style="display: flex">
|
|
||||||
<a-input v-model="addFolderName" style="width: 8em" @pressEnter="addFolder" ref="folderInput" />
|
|
||||||
<a-button shape="circle" icon="close" @click="showAddInput = false" />
|
|
||||||
<a-button type="primary" shape="circle" icon="check" @click="addFolder" />
|
|
||||||
</div>
|
|
||||||
<a-button v-else type="link" @click="showFolderInput">新建文件夹</a-button>
|
|
||||||
<div>
|
|
||||||
<a-button style="marging-right: 1em" type="" @click="closeIframe">取消</a-button>
|
|
||||||
<a-button type="primary" @click="addBookmark">{{ breadList.length === 0 ? "保存到根" : "保存" }}</a-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import HttpUtil from "@/util/HttpUtil";
|
import HttpUtil from "@/util/HttpUtil";
|
||||||
import { mapState } from "vuex";
|
import { TREE_DATA, addNode } from "@/store/modules/treeData";
|
||||||
import { TREE_DATA, TOTAL_TREE_DATA, addNode, deleteData } from "@/store/modules/treeData";
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
breadList: [],
|
|
||||||
showAddInput: false,
|
|
||||||
addFolderName: "",
|
|
||||||
form: {
|
form: {
|
||||||
name: null,
|
name: null,
|
||||||
url: null,
|
url: null,
|
||||||
icon: null,
|
|
||||||
iconUrl: null,
|
|
||||||
type: 0,
|
type: 0,
|
||||||
path: "",
|
path: ""
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
|
||||||
...mapState(TREE_DATA, [TOTAL_TREE_DATA]),
|
|
||||||
dataList() {
|
|
||||||
let path = this.getCurrentPath();
|
|
||||||
return this.totalTreeData[path] ? this.totalTreeData[path] : [];
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mounted() {
|
mounted() {
|
||||||
//接受父节点传递的书签信息
|
//接受父节点传递的书签信息
|
||||||
window.addEventListener("message", (event) => {
|
window.addEventListener("message", event => {
|
||||||
if (!event.data.code) {
|
if (!event.data.code) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -79,13 +30,11 @@ export default {
|
|||||||
console.log("新增书签");
|
console.log("新增书签");
|
||||||
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.form.icon = event.data.data.icon;
|
this.addBookmark();
|
||||||
this.form.iconUrl = event.data.data.iconUrl;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
console.log("向父节点获取数据");
|
console.log("向父节点获取数据");
|
||||||
window.parent.postMessage({ code: "getBookmarkData", receiver: "content" }, "*");
|
window.parent.postMessage({ code: "getBookmarkData", receiver: "content" }, "*");
|
||||||
this.$refs.nameInput.focus();
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
closeIframe() {
|
closeIframe() {
|
||||||
@ -93,174 +42,22 @@ export default {
|
|||||||
},
|
},
|
||||||
//新增书签
|
//新增书签
|
||||||
async addBookmark() {
|
async addBookmark() {
|
||||||
this.form.path = this.getCurrentPath();
|
|
||||||
let res = await HttpUtil.put("/bookmark", null, this.form);
|
let res = await HttpUtil.put("/bookmark", null, this.form);
|
||||||
this.$message.success("添加成功");
|
this.$message.success("添加成功");
|
||||||
await this.$store.dispatch(TREE_DATA + "/" + addNode, {
|
await this.$store.dispatch(TREE_DATA + "/" + addNode, { sourceNode: null, targetNode: res });
|
||||||
sourceNode: this.breadList.length == 0 ? null : this.breadList[this.breadList.length - 1],
|
|
||||||
targetNode: res,
|
|
||||||
});
|
|
||||||
setTimeout(this.closeIframe, 500);
|
setTimeout(this.closeIframe, 500);
|
||||||
},
|
}
|
||||||
//面包屑点击
|
}
|
||||||
async breadClick(item) {
|
|
||||||
console.log(item);
|
|
||||||
//点击最后一个无效
|
|
||||||
if (item == null && this.breadList.length == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (item === this.breadList[this.breadList.length - 1]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (item == null) {
|
|
||||||
this.breadList = [];
|
|
||||||
} else {
|
|
||||||
let index = this.breadList.indexOf(item);
|
|
||||||
this.breadList = [...this.breadList.slice(0, index + 1)];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
//点击文件夹
|
|
||||||
folderClick(item) {
|
|
||||||
this.form.path = item.path + "." + item.bookmarkId;
|
|
||||||
this.breadList.push(item);
|
|
||||||
},
|
|
||||||
//新增文件夹
|
|
||||||
async addFolder() {
|
|
||||||
let length = this.addFolderName.trim().length;
|
|
||||||
if (length == 0) {
|
|
||||||
this.$message.error("文件夹名称不为空");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (length > 200) {
|
|
||||||
this.$message.error("文件夹名称长度不能大于200");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let form = {
|
|
||||||
name: this.addFolderName,
|
|
||||||
path: this.getCurrentPath(),
|
|
||||||
type: 1,
|
|
||||||
url: "",
|
|
||||||
};
|
|
||||||
let res = await HttpUtil.put("/bookmark", null, form);
|
|
||||||
await this.$store.dispatch(TREE_DATA + "/" + addNode, {
|
|
||||||
sourceNode: this.breadList.length == 0 ? null : this.breadList[this.breadList.length - 1],
|
|
||||||
targetNode: res,
|
|
||||||
});
|
|
||||||
this.addFolderName = "";
|
|
||||||
this.showAddInput = false;
|
|
||||||
this.breadList = [...this.breadList];
|
|
||||||
this.$message.success("新增成功");
|
|
||||||
},
|
|
||||||
//获取当前文件夹路径
|
|
||||||
getCurrentPath() {
|
|
||||||
if (this.breadList.length == 0) {
|
|
||||||
return "";
|
|
||||||
} else {
|
|
||||||
let lastOne = this.breadList[this.breadList.length - 1];
|
|
||||||
return lastOne.path + "." + lastOne.bookmarkId;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
//删除一个
|
|
||||||
async deleteOne(item) {
|
|
||||||
let body = { pathList: [], bookmarkIdList: [] };
|
|
||||||
item.type == 0 ? body.bookmarkIdList.push(item.bookmarkId) : body.pathList.push(item.path + "." + item.bookmarkId);
|
|
||||||
await HttpUtil.post("/bookmark/batchDelete", null, body);
|
|
||||||
await this.$store.dispatch(TREE_DATA + "/" + deleteData, body);
|
|
||||||
this.$message.success("删除成功");
|
|
||||||
},
|
|
||||||
//显示输入框
|
|
||||||
showFolderInput() {
|
|
||||||
this.showAddInput = true;
|
|
||||||
console.log(this.$refs);
|
|
||||||
this.$nextTick(() => this.$refs.folderInput.focus());
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.ssoAddBookmark {
|
.ssoAddBookmark {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
justify-content: center;
|
||||||
padding: 0.5em;
|
align-items: center;
|
||||||
padding-bottom: 1em;
|
|
||||||
background: white;
|
background: white;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
|
|
||||||
.body {
|
|
||||||
flex: 1;
|
|
||||||
height: 0;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
.list {
|
|
||||||
padding-top: 1em;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
flex: 1;
|
|
||||||
height: 0;
|
|
||||||
|
|
||||||
.path {
|
|
||||||
display: flex;
|
|
||||||
overflow: auto;
|
|
||||||
font-size: 0.9em;
|
|
||||||
|
|
||||||
.breadItem {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.breadItem:last-child {
|
|
||||||
cursor: text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.folderList {
|
|
||||||
flex: 1;
|
|
||||||
overflow: auto;
|
|
||||||
height: 0;
|
|
||||||
margin-left: 0.5em;
|
|
||||||
|
|
||||||
.item {
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
.text {
|
|
||||||
flex: 1;
|
|
||||||
width: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.actionBar {
|
|
||||||
display: none;
|
|
||||||
width: 2em;
|
|
||||||
align-items: center;
|
|
||||||
color: red;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.bg {
|
|
||||||
cursor: pointer;
|
|
||||||
color: rgb(24, 144, 255);
|
|
||||||
}
|
|
||||||
|
|
||||||
.bg:hover {
|
|
||||||
background: rgba(74, 74, 74, 0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.item:hover .actionBar {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.action {
|
|
||||||
padding-top: 1em;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -5,23 +5,18 @@
|
|||||||
源码地址:
|
源码地址:
|
||||||
<a href="https://github.com/FleyX/bookmark" target="_blank">github.com/FleyX/bookmark</a>
|
<a href="https://github.com/FleyX/bookmark" target="_blank">github.com/FleyX/bookmark</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
当前版本:{{ appVersion }}  <a v-if="showNewVersion"
|
|
||||||
href="https://github.com/FleyX/bookmark/blob/master/DEPLOY.md">最新版本:{{ latestVersion
|
|
||||||
}}</a>
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
使用教程:
|
使用教程:
|
||||||
<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>
|
<div>
|
||||||
浏览器插件:
|
浏览器插件:
|
||||||
<a href="/static/bookmarkBrowserPlugin.zip" download="浏览器插件.zip"
|
<a href="/static/bookmarkBrowserPlugin.7z" download="浏览器插件.7z" target="_blank">点击下载</a>
|
||||||
target="_blank">最新版本{{ serverConfig.map.pluginVersion }}(注意更新)</a>
|
|
||||||
,使用详情请参考使用教程
|
,使用详情请参考使用教程
|
||||||
</div>
|
</div>
|
||||||
<div>交流反馈qq群:150056494,邮箱:fleyx20@outlook.com</div>
|
<div>交流反馈qq群:150056494,邮箱:fleyx20@outlook.com</div>
|
||||||
<div>
|
<div>
|
||||||
|
统计:
|
||||||
<a href="https://qiezi.fleyx.com" style="" target="_blank">
|
<a href="https://qiezi.fleyx.com" style="" target="_blank">
|
||||||
<div id="qieziStatisticHtmlHostPv" style="display: none">
|
<div id="qieziStatisticHtmlHostPv" style="display: none">
|
||||||
总访问次数:
|
总访问次数:
|
||||||
@ -39,51 +34,17 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState } from "vuex";
|
|
||||||
import { GLOBAL_CONFIG, SERVER_CONFIG } from "@/store/modules/globalConfig";
|
|
||||||
import httpUtil from "@/util/HttpUtil";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "about",
|
name: "about",
|
||||||
data() {
|
mounted() {
|
||||||
return {
|
window.qieziStatisticKey = "b74c4b571b644782a837433209827874";
|
||||||
appVersion: "1.4", //应用版本
|
let script = document.createElement("script");
|
||||||
latestVersion: null,
|
script.type = "text/javascript";
|
||||||
showNewVersion: false
|
script.defer = true;
|
||||||
};
|
script.src = "https://qiezi.fleyx.com/qiezijs/1.0/qiezi_statistic.min.js";
|
||||||
},
|
document.getElementsByTagName("head")[0].appendChild(script);
|
||||||
computed: { ...mapState(GLOBAL_CONFIG, [SERVER_CONFIG]) },
|
|
||||||
async mounted() {
|
|
||||||
|
|
||||||
|
|
||||||
//获取最新版本
|
|
||||||
let res = await httpUtil.http.default.get("https://s3.fleyx.com/picbed/bookmark/config.json");
|
|
||||||
console.log(res);
|
|
||||||
this.latestVersion = res.data.latestAppVersion;
|
|
||||||
this.showNewVersion = this.checkVersion(this.appVersion, this.latestVersion);
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
checkVersion: function(version, latestVersion) {
|
|
||||||
if (version === latestVersion) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
let versions = version.split(".");
|
|
||||||
let latestVersions = latestVersion.split(".");
|
|
||||||
for (let i = 0; i < versions.length; i++) {
|
|
||||||
if (i >= latestVersions.length) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
let versionNum = parseInt(versions[i]);
|
|
||||||
let latestVersionNum = parseInt(latestVersions[i]);
|
|
||||||
if (versionNum !== latestVersionNum) {
|
|
||||||
return versionNum < latestVersionNum;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
;
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped></style>
|
<style lang="less" scoped></style>
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="thirdPart">
|
<div class="thirdPart">
|
||||||
<span>第三方登陆</span>
|
<span>第三方登陆</span>
|
||||||
<a-tooltip title="github登陆" class="oneIcon" placement="bottom">
|
<a-tooltip v-if="serverConfig.proxyExist" title="github登陆" class="oneIcon" placement="bottom">
|
||||||
<a-icon type="github" @click="toGithub" style="font-size: 1.4em" />
|
<a-icon type="github" @click="toGithub" style="font-size: 1.4em" />
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</div>
|
</div>
|
||||||
@ -39,44 +39,39 @@ import Header from "@/components/public/Switch.vue";
|
|||||||
import httpUtil from "../../../util/HttpUtil.js";
|
import httpUtil from "../../../util/HttpUtil.js";
|
||||||
import { mapMutations, mapState } from "vuex";
|
import { mapMutations, mapState } from "vuex";
|
||||||
import HttpUtil from "../../../util/HttpUtil.js";
|
import HttpUtil from "../../../util/HttpUtil.js";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "Login",
|
name: "Login",
|
||||||
components: {
|
components: {
|
||||||
Header
|
Header,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState("globalConfig", ["serverConfig"])
|
...mapState("globalConfig", ["serverConfig"]),
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
form: {
|
form: {
|
||||||
str: "",
|
str: "",
|
||||||
password: "",
|
password: "",
|
||||||
rememberMe: false
|
rememberMe: false,
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
str: [
|
str: [
|
||||||
{ required: true, message: "请输入用户名", trigger: "blur" },
|
{ required: true, message: "请输入用户名", trigger: "blur" },
|
||||||
{ min: 1, max: 50, message: "最短1,最长50", trigger: "change" }
|
{ min: 1, max: 50, message: "最短1,最长50", trigger: "change" },
|
||||||
],
|
],
|
||||||
password: [
|
password: [
|
||||||
{ required: true, message: "请输入密码", trigger: "blur" },
|
{ required: true, message: "请输入密码", trigger: "blur" },
|
||||||
{ pattern: "^\\w{6,18}$", message: "密码为6-18位数字,字母,下划线组合", trigger: "change" }
|
{ pattern: "^\\w{6,18}$", message: "密码为6-18位数字,字母,下划线组合", trigger: "change" },
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
loading: false, //是否加载中
|
loading: false, //是否加载中
|
||||||
oauthLogining: false, //true:正在进行oauth后台操作
|
oauthLogining: false, //true:正在进行oauth后台操作
|
||||||
page: null, //oauth打开的页面实例
|
page: null, //oauth打开的页面实例
|
||||||
redirect: null
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
async created() {
|
async created() {
|
||||||
let _this = this;
|
let _this = this;
|
||||||
window.addEventListener("storage", this.storageDeal.bind(this));
|
window.addEventListener("storage", this.storageDeal.bind(this));
|
||||||
if (this.$route.query.to) {
|
|
||||||
this.redirect = atob(this.$route.query.to);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
destroyed() {
|
destroyed() {
|
||||||
window.removeEventListener("storage", this.storageDeal);
|
window.removeEventListener("storage", this.storageDeal);
|
||||||
@ -90,7 +85,7 @@ export default {
|
|||||||
this.loading = true;
|
this.loading = true;
|
||||||
let token = await httpUtil.post("/user/login", null, this.form);
|
let token = await httpUtil.post("/user/login", null, this.form);
|
||||||
await this.$store.dispatch("globalConfig/setToken", token);
|
await this.$store.dispatch("globalConfig/setToken", token);
|
||||||
this.$router.replace(this.redirect ? this.redirect : "/");
|
this.$router.replace("/");
|
||||||
} finally {
|
} finally {
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
}
|
}
|
||||||
@ -131,8 +126,8 @@ export default {
|
|||||||
} finally {
|
} finally {
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -140,13 +135,11 @@ export default {
|
|||||||
.form {
|
.form {
|
||||||
margin: 0.3rem;
|
margin: 0.3rem;
|
||||||
margin-bottom: 0.1rem;
|
margin-bottom: 0.1rem;
|
||||||
|
|
||||||
.reset {
|
.reset {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.thirdPart {
|
.thirdPart {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
@ -1,21 +1,20 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
lintOnSave: false,
|
lintOnSave: false,
|
||||||
configureWebpack: {
|
configureWebpack: {
|
||||||
devtool: "source-map"
|
devtool: "source-map"
|
||||||
},
|
},
|
||||||
devServer: {
|
devServer: {
|
||||||
port: 4531,
|
proxy: {
|
||||||
proxy: {
|
"/bookmark/api": {
|
||||||
"/bookmark/api": {
|
//这里最好有一个 /
|
||||||
//这里最好有一个 /
|
target: "http://localhost:8088", // 服务器端接口地址
|
||||||
target: "http://localhost:8088", // 服务器端接口地址
|
ws: true, //如果要代理 websockets,配置这个参数
|
||||||
ws: true, //如果要代理 websockets,配置这个参数
|
// 如果是https接口,需要配置这个参数
|
||||||
// 如果是https接口,需要配置这个参数
|
changeOrigin: true, //是否跨域
|
||||||
changeOrigin: true, //是否跨域
|
pathRewrite: {
|
||||||
pathRewrite: {
|
"^/bookmark/api": "/bookmark/api"
|
||||||
"^/bookmark/api": "/bookmark/api"
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
7
build.sh
7
build.sh
@ -3,11 +3,8 @@ base=$(cd "$(dirname "$0")";pwd)
|
|||||||
echo $base
|
echo $base
|
||||||
cd $base
|
cd $base
|
||||||
|
|
||||||
cd 浏览器插件/bookmarkBrowserPlugin
|
|
||||||
zip -q -r ../../bookmark_front/public/static/bookmarkBrowserPlugin.zip *
|
|
||||||
|
|
||||||
cd ../../
|
|
||||||
# 前端打包
|
# 前端打包
|
||||||
docker run --rm --user ${UID} -v $base/bookmark_front:/opt/front node:16-slim bash -c "cd /opt/front && yarn --registry https://registry.npm.taobao.org && yarn build"
|
docker run --rm --user ${UID} -v $base/bookmark_front:/opt/front node:lts-buster-slim bash -c "cd /opt/front && yarn --registry https://registry.npm.taobao.org && yarn build"
|
||||||
# 后端打包
|
# 后端打包
|
||||||
docker run --rm --user ${UID} -v $base/data/maven/mavenRep:/var/maven/.m2 -v $base/data/maven/settings.xml:/usr/share/maven/conf/settings.xml -v $base/bookMarkService:/code maven:3-openjdk-11-slim bash -c "cd /code && mvn clean install"
|
docker run --rm --user ${UID} -v $base/data/maven/mavenRep:/var/maven/.m2: -v $base/data/maven/settings.xml:/usr/share/maven/conf/settings.xml -v $base/bookMarkService:/code maven:3-openjdk-11-slim bash -c "cd /code && mvn clean install"
|
@ -14,7 +14,6 @@ services:
|
|||||||
- ./data/mysql/my.cnf:/etc/mysql/my.cnf
|
- ./data/mysql/my.cnf:/etc/mysql/my.cnf
|
||||||
- /etc/localtime:/etc/localtime
|
- /etc/localtime:/etc/localtime
|
||||||
- ./data/timezone:/etc/timezone
|
- ./data/timezone:/etc/timezone
|
||||||
restart: unless-stopped
|
|
||||||
environment:
|
environment:
|
||||||
- MYSQL_ROOT_PASSWORD=${MYSQL_PASSWORD}
|
- MYSQL_ROOT_PASSWORD=${MYSQL_PASSWORD}
|
||||||
- MYSQL_DATABASE=bookmark
|
- MYSQL_DATABASE=bookmark
|
||||||
@ -26,7 +25,6 @@ services:
|
|||||||
- /etc/localtime:/etc/localtime
|
- /etc/localtime:/etc/localtime
|
||||||
- ./data/timezone:/etc/timezone
|
- ./data/timezone:/etc/timezone
|
||||||
- ./data/redis:/data
|
- ./data/redis:/data
|
||||||
restart: unless-stopped
|
|
||||||
networks:
|
networks:
|
||||||
- bookmark
|
- bookmark
|
||||||
|
|
||||||
@ -40,7 +38,6 @@ services:
|
|||||||
- ./bookmark_front/dist:/opt/dist
|
- ./bookmark_front/dist:/opt/dist
|
||||||
- ./data/nginx/nginx.conf:/etc/nginx/nginx.conf
|
- ./data/nginx/nginx.conf:/etc/nginx/nginx.conf
|
||||||
- ${BOOKMARK_FILE_SAVE_PATH}/files/public:/opt/files/public
|
- ${BOOKMARK_FILE_SAVE_PATH}/files/public:/opt/files/public
|
||||||
restart: unless-stopped
|
|
||||||
ports:
|
ports:
|
||||||
- 8080:8080
|
- 8080:8080
|
||||||
|
|
||||||
@ -63,7 +60,6 @@ services:
|
|||||||
- ./bookMarkService/web/target/bookmark-web-1.0-SNAPSHOT.jar:/opt/app/service.jar
|
- ./bookMarkService/web/target/bookmark-web-1.0-SNAPSHOT.jar:/opt/app/service.jar
|
||||||
- ${BOOKMARK_FILE_SAVE_PATH}:/opt/files
|
- ${BOOKMARK_FILE_SAVE_PATH}:/opt/files
|
||||||
working_dir: /opt/app
|
working_dir: /opt/app
|
||||||
restart: unless-stopped
|
|
||||||
command:
|
command:
|
||||||
- /bin/bash
|
- /bin/bash
|
||||||
- -c
|
- -c
|
||||||
|
15
浏览器插件/bookmark-chrome/.babelrc
Normal file
15
浏览器插件/bookmark-chrome/.babelrc
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"plugins": [
|
||||||
|
"@babel/plugin-proposal-optional-chaining"
|
||||||
|
],
|
||||||
|
"presets": [
|
||||||
|
["@babel/preset-env", {
|
||||||
|
"useBuiltIns": "usage",
|
||||||
|
"corejs": 3,
|
||||||
|
"targets": {
|
||||||
|
// https://jamie.build/last-2-versions
|
||||||
|
"browsers": ["> 0.25%", "not ie 11", "not op_mini all"]
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
]
|
||||||
|
}
|
8
浏览器插件/bookmark-chrome/.editorConfig
Normal file
8
浏览器插件/bookmark-chrome/.editorConfig
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
33
浏览器插件/bookmark-chrome/.eslintrc.js
Normal file
33
浏览器插件/bookmark-chrome/.eslintrc.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// https://eslint.org/docs/user-guide/configuring
|
||||||
|
// File taken from https://github.com/vuejs-templates/webpack/blob/1.3.1/template/.eslintrc.js, thanks.
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
root: true,
|
||||||
|
parserOptions: {
|
||||||
|
parser: 'babel-eslint'
|
||||||
|
},
|
||||||
|
env: {
|
||||||
|
browser: true,
|
||||||
|
webextensions: true,
|
||||||
|
},
|
||||||
|
extends: [
|
||||||
|
// https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention
|
||||||
|
// consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules.
|
||||||
|
'plugin:vue/essential',
|
||||||
|
// https://github.com/standard/standard/blob/master/docs/RULES-en.md
|
||||||
|
'standard',
|
||||||
|
// https://prettier.io/docs/en/index.html
|
||||||
|
'plugin:prettier/recommended'
|
||||||
|
],
|
||||||
|
// required to lint *.vue files
|
||||||
|
plugins: [
|
||||||
|
'vue'
|
||||||
|
],
|
||||||
|
// add your custom rules here
|
||||||
|
rules: {
|
||||||
|
// allow async-await
|
||||||
|
'generator-star-spacing': 'off',
|
||||||
|
// allow debugger during development
|
||||||
|
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
|
||||||
|
}
|
||||||
|
}
|
4
浏览器插件/bookmark-chrome/.gitignore
vendored
Normal file
4
浏览器插件/bookmark-chrome/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
/node_modules
|
||||||
|
/*.log
|
||||||
|
/dist
|
||||||
|
/dist-zip
|
5
浏览器插件/bookmark-chrome/.prettierrc
Normal file
5
浏览器插件/bookmark-chrome/.prettierrc
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"singleQuote": true,
|
||||||
|
"printWidth": 180,
|
||||||
|
"trailingComma": "es5"
|
||||||
|
}
|
68
浏览器插件/bookmark-chrome/package.json
Normal file
68
浏览器插件/bookmark-chrome/package.json
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
{
|
||||||
|
"name": "bookmark-chrome",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "A Vue.js web extension",
|
||||||
|
"author": "fanxb <fanxb.tl@gmail.com>",
|
||||||
|
"license": "MIT",
|
||||||
|
"scripts": {
|
||||||
|
"lint": "eslint --ext .js,.vue src",
|
||||||
|
"prettier": "prettier \"src/**/*.{js,vue}\"",
|
||||||
|
"prettier:write": "npm run prettier -- --write",
|
||||||
|
"build": "cross-env NODE_ENV=production webpack --hide-modules",
|
||||||
|
"build:dev": "cross-env NODE_ENV=development webpack --hide-modules",
|
||||||
|
"build-zip": "node scripts/build-zip.js",
|
||||||
|
"watch": "npm run build -- --watch",
|
||||||
|
"watch:dev": "cross-env HMR=true npm run build:dev -- --watch"
|
||||||
|
},
|
||||||
|
"husky": {
|
||||||
|
"hooks": {
|
||||||
|
"pre-commit": "pretty-quick --staged"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^0.19.0",
|
||||||
|
"element-ui": "^2.12.0",
|
||||||
|
"vue": "^2.6.10",
|
||||||
|
"vue-router": "^3.0.1",
|
||||||
|
"vuex": "^3.0.1",
|
||||||
|
"webextension-polyfill": "^0.3.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.1.2",
|
||||||
|
"@babel/plugin-proposal-optional-chaining": "^7.0.0",
|
||||||
|
"@babel/preset-env": "^7.1.0",
|
||||||
|
"@babel/runtime-corejs3": "^7.4.0",
|
||||||
|
"archiver": "^3.0.0",
|
||||||
|
"babel-eslint": "^10.0.1",
|
||||||
|
"babel-loader": "^8.0.2",
|
||||||
|
"copy-webpack-plugin": "^4.5.3",
|
||||||
|
"core-js": "^3.0.1",
|
||||||
|
"cross-env": "^5.2.0",
|
||||||
|
"css-loader": "^2.1.1",
|
||||||
|
"ejs": "^2.6.1",
|
||||||
|
"eslint": "^5.16.0",
|
||||||
|
"eslint-config-prettier": "^4.3.0",
|
||||||
|
"eslint-config-standard": "^12.0.0",
|
||||||
|
"eslint-friendly-formatter": "^4.0.1",
|
||||||
|
"eslint-loader": "^2.1.2",
|
||||||
|
"eslint-plugin-import": "^2.16.0",
|
||||||
|
"eslint-plugin-node": "^7.0.1",
|
||||||
|
"eslint-plugin-prettier": "^3.1.0",
|
||||||
|
"eslint-plugin-promise": "^4.1.1",
|
||||||
|
"eslint-plugin-standard": "^4.0.0",
|
||||||
|
"eslint-plugin-vue": "^5.2.2",
|
||||||
|
"file-loader": "^1.1.11",
|
||||||
|
"husky": "^2.4.0",
|
||||||
|
"mini-css-extract-plugin": "^0.4.4",
|
||||||
|
"node-sass": "^4.9.3",
|
||||||
|
"prettier": "^1.17.1",
|
||||||
|
"pretty-quick": "^1.8.0",
|
||||||
|
"sass-loader": "^7.1.0",
|
||||||
|
"vue-loader": "^15.4.2",
|
||||||
|
"vue-template-compiler": "^2.6.10",
|
||||||
|
"web-ext-types": "^2.1.0",
|
||||||
|
"webpack": "^4.20.2",
|
||||||
|
"webpack-cli": "^3.1.2",
|
||||||
|
"webpack-extension-reloader": "^1.1.0"
|
||||||
|
}
|
||||||
|
}
|
53
浏览器插件/bookmark-chrome/scripts/build-zip.js
Normal file
53
浏览器插件/bookmark-chrome/scripts/build-zip.js
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const archiver = require('archiver');
|
||||||
|
|
||||||
|
const DEST_DIR = path.join(__dirname, '../dist');
|
||||||
|
const DEST_ZIP_DIR = path.join(__dirname, '../dist-zip');
|
||||||
|
|
||||||
|
const extractExtensionData = () => {
|
||||||
|
const extPackageJson = require('../package.json');
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: extPackageJson.name,
|
||||||
|
version: extPackageJson.version,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const makeDestZipDirIfNotExists = () => {
|
||||||
|
if (!fs.existsSync(DEST_ZIP_DIR)) {
|
||||||
|
fs.mkdirSync(DEST_ZIP_DIR);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const buildZip = (src, dist, zipFilename) => {
|
||||||
|
console.info(`Building ${zipFilename}...`);
|
||||||
|
|
||||||
|
const archive = archiver('zip', { zlib: { level: 9 } });
|
||||||
|
const stream = fs.createWriteStream(path.join(dist, zipFilename));
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
archive
|
||||||
|
.directory(src, false)
|
||||||
|
.on('error', err => reject(err))
|
||||||
|
.pipe(stream);
|
||||||
|
|
||||||
|
stream.on('close', () => resolve());
|
||||||
|
archive.finalize();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const main = () => {
|
||||||
|
const { name, version } = extractExtensionData();
|
||||||
|
const zipFilename = `${name}-v${version}.zip`;
|
||||||
|
|
||||||
|
makeDestZipDirIfNotExists();
|
||||||
|
|
||||||
|
buildZip(DEST_DIR, DEST_ZIP_DIR, zipFilename)
|
||||||
|
.then(() => console.info('OK'))
|
||||||
|
.catch(console.err);
|
||||||
|
};
|
||||||
|
|
||||||
|
main();
|
52
浏览器插件/bookmark-chrome/src/background.js
Normal file
52
浏览器插件/bookmark-chrome/src/background.js
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import httpUtil from './util/httpUtil.js';
|
||||||
|
global.browser = require('webextension-polyfill');
|
||||||
|
|
||||||
|
window.envType = 'background';
|
||||||
|
window.token = localStorage.getItem('token');
|
||||||
|
|
||||||
|
let token = null;
|
||||||
|
let globalPort = null;
|
||||||
|
|
||||||
|
chrome.extension.onConnect.addListener(port => {
|
||||||
|
console.log(port);
|
||||||
|
globalPort = port;
|
||||||
|
port.onMessage.addListener(msg => {
|
||||||
|
switch (msg.type) {
|
||||||
|
case 'sendToken':
|
||||||
|
console.log(msg);
|
||||||
|
localStorage.setItem('token', msg.data);
|
||||||
|
window.token = msg.data;
|
||||||
|
token = msg.data;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.error('未知的数据', msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
chrome.contextMenus.create(
|
||||||
|
{
|
||||||
|
title: '添加到书签',
|
||||||
|
onclick: (info, tab) => {
|
||||||
|
console.log(info, tab);
|
||||||
|
httpUtil.put('/bookmark', {
|
||||||
|
type: 0,
|
||||||
|
path: '',
|
||||||
|
name: tab.title,
|
||||||
|
url: tab.url,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
err => {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建一个标准命令
|
||||||
|
* @param {*} code code
|
||||||
|
* @param {*} data data
|
||||||
|
*/
|
||||||
|
function createMsg(code, data) {
|
||||||
|
return JSON.stringify({ code, data });
|
||||||
|
}
|
BIN
浏览器插件/bookmark-chrome/src/icons/icon.xcf
Normal file
BIN
浏览器插件/bookmark-chrome/src/icons/icon.xcf
Normal file
Binary file not shown.
BIN
浏览器插件/bookmark-chrome/src/icons/icon_128.png
Normal file
BIN
浏览器插件/bookmark-chrome/src/icons/icon_128.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.8 KiB |
BIN
浏览器插件/bookmark-chrome/src/icons/icon_48.png
Normal file
BIN
浏览器插件/bookmark-chrome/src/icons/icon_48.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.5 KiB |
32
浏览器插件/bookmark-chrome/src/manifest.json
Normal file
32
浏览器插件/bookmark-chrome/src/manifest.json
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"name": "bookmark-chrome",
|
||||||
|
"description": "A Vue.js web extension",
|
||||||
|
"version": null,
|
||||||
|
"manifest_version": 2,
|
||||||
|
"permissions": [
|
||||||
|
"contextMenus"
|
||||||
|
],
|
||||||
|
"icons": {
|
||||||
|
"48": "icons/icon_48.png",
|
||||||
|
"128": "icons/icon_128.png"
|
||||||
|
},
|
||||||
|
"browser_action": {
|
||||||
|
"default_title": "bookmark-chrome",
|
||||||
|
"default_popup": "popup/popup.html"
|
||||||
|
},
|
||||||
|
"background": {
|
||||||
|
"scripts": [
|
||||||
|
"background.js"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"options_ui": {
|
||||||
|
"page": "options/options.html",
|
||||||
|
"chrome_style": true
|
||||||
|
},
|
||||||
|
"content_scripts": [{
|
||||||
|
"matches": ["*://*/*"],
|
||||||
|
"js": ["static/sso.js"]
|
||||||
|
}
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
17
浏览器插件/bookmark-chrome/src/options/App.vue
Normal file
17
浏览器插件/bookmark-chrome/src/options/App.vue
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<p>Hello world!这是选项页</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'App',
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
p {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
15
浏览器插件/bookmark-chrome/src/options/options.html
Normal file
15
浏览器插件/bookmark-chrome/src/options/options.html
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>bookmark-chrome - Options</title>
|
||||||
|
<link rel="stylesheet" href="options.css">
|
||||||
|
<% if (NODE_ENV === 'development') { %>
|
||||||
|
<!-- Load some resources only in development environment -->
|
||||||
|
<% } %>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script src="options.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
10
浏览器插件/bookmark-chrome/src/options/options.js
Normal file
10
浏览器插件/bookmark-chrome/src/options/options.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import Vue from 'vue';
|
||||||
|
import App from './App';
|
||||||
|
|
||||||
|
global.browser = require('webextension-polyfill');
|
||||||
|
|
||||||
|
/* eslint-disable no-new */
|
||||||
|
new Vue({
|
||||||
|
el: '#app',
|
||||||
|
render: h => h(App),
|
||||||
|
});
|
20
浏览器插件/bookmark-chrome/src/popup/App.vue
Normal file
20
浏览器插件/bookmark-chrome/src/popup/App.vue
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<template>
|
||||||
|
<div class="app">
|
||||||
|
<router-view></router-view>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.app {
|
||||||
|
width: 600px;
|
||||||
|
height: 580px;
|
||||||
|
}
|
||||||
|
</style>
|
18
浏览器插件/bookmark-chrome/src/popup/popup.html
Normal file
18
浏览器插件/bookmark-chrome/src/popup/popup.html
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Title</title>
|
||||||
|
<link rel="stylesheet" href="popup.css">
|
||||||
|
<% if (NODE_ENV === 'development') { %>
|
||||||
|
<!-- Load some resources only in development environment -->
|
||||||
|
<% } %>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<script src="/static/js/localforage.min.js"></script>
|
||||||
|
<script src="popup.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
55
浏览器插件/bookmark-chrome/src/popup/popup.js
Normal file
55
浏览器插件/bookmark-chrome/src/popup/popup.js
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import Vue from 'vue';
|
||||||
|
import App from './App';
|
||||||
|
import store from '../store';
|
||||||
|
import router from './router';
|
||||||
|
import ElementUI from 'element-ui';
|
||||||
|
import 'element-ui/lib/theme-chalk/index.css';
|
||||||
|
import config from '../util/config';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
global.browser = require('webextension-polyfill');
|
||||||
|
Vue.prototype.$browser = global.browser;
|
||||||
|
Vue.use(ElementUI);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置axios
|
||||||
|
*/
|
||||||
|
axios.defaults.timeout = 15000;
|
||||||
|
axios.defaults.baseURL = config.baseUrl;
|
||||||
|
/**
|
||||||
|
* 请求拦截器
|
||||||
|
*/
|
||||||
|
axios.interceptors.request.use(
|
||||||
|
function(config) {
|
||||||
|
config.headers['jwt-token'] = window.token;
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
function(error) {
|
||||||
|
console.error(error);
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
axios.interceptors.response.use(
|
||||||
|
res => {
|
||||||
|
if (res.data.code === -1) {
|
||||||
|
localStorage.removeItem('token');
|
||||||
|
window.vueInstance.$router.replace('/public/login');
|
||||||
|
} else if (res.data.code === 1) {
|
||||||
|
return res.data.data;
|
||||||
|
} else {
|
||||||
|
Promise.reject(res);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
/* eslint-disable no-new */
|
||||||
|
window.vueInstance = new Vue({
|
||||||
|
el: '#app',
|
||||||
|
store,
|
||||||
|
router,
|
||||||
|
render: h => h(App),
|
||||||
|
});
|
@ -0,0 +1,74 @@
|
|||||||
|
<template>
|
||||||
|
<div class="main">
|
||||||
|
<el-tree :props="props" :load="loadNode" accordion @node-click="nodeClick" lazy>
|
||||||
|
<span class="treeItem" slot-scope="{ node }">
|
||||||
|
<span>{{ node.label }}</span>
|
||||||
|
</span>
|
||||||
|
</el-tree>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import axios from 'axios';
|
||||||
|
export default {
|
||||||
|
name: 'BookmarkTree',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
label: 'name',
|
||||||
|
children: 'children',
|
||||||
|
isLeaf: 'leaf',
|
||||||
|
},
|
||||||
|
treeObj: null,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async loadNode(node, resolve) {
|
||||||
|
if (window.treeData == null) {
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
if ((window.treeData = await localforage.getItem('treeData')) == null) {
|
||||||
|
window.treeData = await axios.get('/bookmark/currentUser');
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
await localforage.setItem('treeData', window.treeData);
|
||||||
|
}
|
||||||
|
console.log(window.treeData);
|
||||||
|
}
|
||||||
|
console.log(node, resolve);
|
||||||
|
let list;
|
||||||
|
if (node.level === 0) {
|
||||||
|
list = window.treeData[''];
|
||||||
|
} else {
|
||||||
|
list = window.treeData[node.data.path + '.' + node.data.bookmarkId];
|
||||||
|
}
|
||||||
|
list.forEach(item => (item.leaf = item.type === 0));
|
||||||
|
console.log(list);
|
||||||
|
return resolve(list);
|
||||||
|
},
|
||||||
|
nodeClick(data) {
|
||||||
|
if (data.type === 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let url = data.url;
|
||||||
|
if (!url.startsWith('http')) {
|
||||||
|
url = 'http://' + url;
|
||||||
|
}
|
||||||
|
console.log(url);
|
||||||
|
window.open(data.url);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.main {
|
||||||
|
width: 95%;
|
||||||
|
height: 500px;
|
||||||
|
overflow: auto;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.treeItem {
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,92 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-popover placement="bottom-start" width="550" popper-class="popover" trigger="manual" :visible-arrow="false" v-model="isShow">
|
||||||
|
<div>
|
||||||
|
<div class="item" v-for="item in searchList" :key="item.bookmarkId">
|
||||||
|
<a target="_blank" :href="item.url">{{ item.name }}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-input
|
||||||
|
ref="searchInput"
|
||||||
|
type="text"
|
||||||
|
placeholder="搜索"
|
||||||
|
v-model="searchContent"
|
||||||
|
clearable
|
||||||
|
:autofocus="true"
|
||||||
|
slot="reference"
|
||||||
|
@blur="clear"
|
||||||
|
@keyup.enter.native="searchKey"
|
||||||
|
@focus="focus"
|
||||||
|
>
|
||||||
|
<el-button slot="append" icon="el-icon-search" @click="searchKey"></el-button>
|
||||||
|
</el-input>
|
||||||
|
</el-popover>
|
||||||
|
<div class="searchResult"></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import axios from 'axios';
|
||||||
|
export default {
|
||||||
|
name: 'searchBookmark',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
searchContent: '',
|
||||||
|
// 是否展示结果列表
|
||||||
|
isShow: false,
|
||||||
|
// 是否有焦点
|
||||||
|
isFocus: false,
|
||||||
|
searchList: [],
|
||||||
|
timeOut: null,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
searchContent(newVal, oldVal) {
|
||||||
|
if (newVal.trim().length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (newVal.trim() !== oldVal) {
|
||||||
|
if (this.timeOut != null) {
|
||||||
|
clearTimeout(this.timeOut);
|
||||||
|
}
|
||||||
|
this.searchList = [];
|
||||||
|
this.timeOut = setTimeout(async () => {
|
||||||
|
this.searchList = await axios.get(`bookmark/searchUserBookmark?content=${newVal}`);
|
||||||
|
this.isShow = this.searchList.length > 0;
|
||||||
|
this.timeOut = null;
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs['searchInput'].focus();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
searchKey() {
|
||||||
|
window.open('https://www.baidu.com/s?ie=UTF-8&wd=' + window.encodeURIComponent(this.searchContent));
|
||||||
|
},
|
||||||
|
focus() {
|
||||||
|
this.isFocus = true;
|
||||||
|
},
|
||||||
|
clear() {
|
||||||
|
this.isFocus = false;
|
||||||
|
if (this.timeOut != null) {
|
||||||
|
clearTimeout(this.timeOut);
|
||||||
|
}
|
||||||
|
this.searchContent = '';
|
||||||
|
this.searchList = [];
|
||||||
|
this.isShow = false;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.item {
|
||||||
|
width: 500px;
|
||||||
|
padding: 5px;
|
||||||
|
border-bottom: 1px solid black;
|
||||||
|
}
|
||||||
|
</style>
|
9
浏览器插件/bookmark-chrome/src/popup/router/index.js
Normal file
9
浏览器插件/bookmark-chrome/src/popup/router/index.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import Vue from 'vue';
|
||||||
|
import VueRouter from 'vue-router';
|
||||||
|
import routes from './routes';
|
||||||
|
|
||||||
|
Vue.use(VueRouter);
|
||||||
|
|
||||||
|
export default new VueRouter({
|
||||||
|
routes,
|
||||||
|
});
|
50
浏览器插件/bookmark-chrome/src/popup/router/pages/Index.vue
Normal file
50
浏览器插件/bookmark-chrome/src/popup/router/pages/Index.vue
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="head">
|
||||||
|
<img width="30%" src="/static/img/bookmarkLogo.png" alt="icon" />
|
||||||
|
<span>{{ personInfo.username }}</span>
|
||||||
|
</div>
|
||||||
|
<!-- 书签检索 -->
|
||||||
|
<search />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import axios from 'axios';
|
||||||
|
import Search from '../components/SearchBookmark';
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
Search,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
personInfo: {},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
created() {
|
||||||
|
window.token = localStorage.getItem('token');
|
||||||
|
if (!window.token) {
|
||||||
|
this.$router.replace('/public/login');
|
||||||
|
} else {
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async init() {
|
||||||
|
let personInfo = await axios.get('/user/currentUserInfo');
|
||||||
|
window.personInfo = personInfo;
|
||||||
|
this.personInfo = personInfo;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.head {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 5% 0 5%;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,37 @@
|
|||||||
|
<template>
|
||||||
|
<div class="main">您还未登陆授权<br />
|
||||||
|
<el-button type="primary" @click="go">前往授权页面</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import config from '../../../../util/config';
|
||||||
|
export default {
|
||||||
|
name: 'login',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
};
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.checkToken();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
go() {
|
||||||
|
window.open(config.ssoUrl);
|
||||||
|
},
|
||||||
|
// 循环检测token是否生效
|
||||||
|
checkToken() {
|
||||||
|
console.log('检测token是否获取到了');
|
||||||
|
let token = localStorage.getItem('token');
|
||||||
|
if (token == null || token.length === 0) {
|
||||||
|
setTimeout(this.checkToken.bind(this), 1000);
|
||||||
|
} else {
|
||||||
|
this.$router.replace('/');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
13
浏览器插件/bookmark-chrome/src/popup/router/routes.js
Normal file
13
浏览器插件/bookmark-chrome/src/popup/router/routes.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import PageIndex from './pages/Index';
|
||||||
|
import Login from './pages/public/Login';
|
||||||
|
|
||||||
|
export default [
|
||||||
|
{
|
||||||
|
path: '/',
|
||||||
|
component: PageIndex,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/public/login',
|
||||||
|
component: Login,
|
||||||
|
},
|
||||||
|
];
|
BIN
浏览器插件/bookmark-chrome/src/static/fonts/element-icons.ttf
Normal file
BIN
浏览器插件/bookmark-chrome/src/static/fonts/element-icons.ttf
Normal file
Binary file not shown.
BIN
浏览器插件/bookmark-chrome/src/static/fonts/element-icons.woff
Normal file
BIN
浏览器插件/bookmark-chrome/src/static/fonts/element-icons.woff
Normal file
Binary file not shown.
BIN
浏览器插件/bookmark-chrome/src/static/img/bookmarkLogo.png
Normal file
BIN
浏览器插件/bookmark-chrome/src/static/img/bookmarkLogo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.3 KiB |
7
浏览器插件/bookmark-chrome/src/static/js/localforage.min.js
vendored
Normal file
7
浏览器插件/bookmark-chrome/src/static/js/localforage.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
33
浏览器插件/bookmark-chrome/src/static/sso.js
Normal file
33
浏览器插件/bookmark-chrome/src/static/sso.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
console.log('注入了页面');
|
||||||
|
var port = chrome.extension.connect({ name: 'data' });
|
||||||
|
/**
|
||||||
|
* 接受background传来的消息
|
||||||
|
*/
|
||||||
|
port.onMessage.addListener(msg => {
|
||||||
|
console.log('收到消息:' + msg);
|
||||||
|
let obj = JSON.parse(msg);
|
||||||
|
switch (obj.code) {
|
||||||
|
case 'addBookmark':
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.error('未知的命令:' + obj.code);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接收当前注入页面传来的消息
|
||||||
|
*/
|
||||||
|
window.addEventListener('message', function(event) {
|
||||||
|
if (event.data.type === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log('接受到消息', event.data);
|
||||||
|
switch (event.data.type) {
|
||||||
|
case 'sendToken':
|
||||||
|
port.postMessage(event.data);
|
||||||
|
window.token = event.data;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.error('未知的事件', event);
|
||||||
|
}
|
||||||
|
});
|
5
浏览器插件/bookmark-chrome/src/store/actions.js
Normal file
5
浏览器插件/bookmark-chrome/src/store/actions.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import * as types from './mutation-types'
|
||||||
|
|
||||||
|
export const setFoo = ({commit}, payload) => {
|
||||||
|
commit(types.UPDATE_FOO, payload)
|
||||||
|
}
|
1
浏览器插件/bookmark-chrome/src/store/getters.js
Normal file
1
浏览器插件/bookmark-chrome/src/store/getters.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export const foo = (state) => state.foo
|
17
浏览器插件/bookmark-chrome/src/store/index.js
Normal file
17
浏览器插件/bookmark-chrome/src/store/index.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import Vue from 'vue';
|
||||||
|
import Vuex from 'vuex';
|
||||||
|
|
||||||
|
import * as getters from './getters';
|
||||||
|
import mutations from './mutations';
|
||||||
|
import * as actions from './actions';
|
||||||
|
|
||||||
|
Vue.use(Vuex);
|
||||||
|
|
||||||
|
export default new Vuex.Store({
|
||||||
|
state: {
|
||||||
|
foo: 'bar',
|
||||||
|
},
|
||||||
|
getters,
|
||||||
|
mutations,
|
||||||
|
actions,
|
||||||
|
});
|
1
浏览器插件/bookmark-chrome/src/store/mutation-types.js
Normal file
1
浏览器插件/bookmark-chrome/src/store/mutation-types.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export const UPDATE_FOO = 'UPDATE_FOO'
|
7
浏览器插件/bookmark-chrome/src/store/mutations.js
Normal file
7
浏览器插件/bookmark-chrome/src/store/mutations.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import * as types from './mutation-types'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
[types.UPDATE_FOO] (state, payload) {
|
||||||
|
state.foo = payload
|
||||||
|
}
|
||||||
|
}
|
16
浏览器插件/bookmark-chrome/src/util/config.js
Normal file
16
浏览器插件/bookmark-chrome/src/util/config.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// const baseUri = ;
|
||||||
|
var baseUri;
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
baseUri = 'http://localhost:3000';
|
||||||
|
// baseUri = 'https://bm.tapme.top';
|
||||||
|
} else {
|
||||||
|
baseUri = 'https://bm.tapme.top';
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
baseUrl: baseUri + '/bookmark/api',
|
||||||
|
ssoUrl: baseUri + '/userSpace/ssoAuth',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
0
浏览器插件/bookmark-chrome/src/util/const.js
Normal file
0
浏览器插件/bookmark-chrome/src/util/const.js
Normal file
37
浏览器插件/bookmark-chrome/src/util/httpUtil.js
Normal file
37
浏览器插件/bookmark-chrome/src/util/httpUtil.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import config from './config';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
axios.defaults.timeout = 15000;
|
||||||
|
axios.defaults.baseURL = config.baseUrl;
|
||||||
|
|
||||||
|
axios.interceptors.request.use(
|
||||||
|
function(config) {
|
||||||
|
config.headers['jwt-token'] = window.token;
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
function(error) {
|
||||||
|
console.error(error);
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
axios.interceptors.response.use(
|
||||||
|
res => {
|
||||||
|
if (res.data.code === -1) {
|
||||||
|
localStorage.removeItem('token');
|
||||||
|
if (window.envType === 'background') {
|
||||||
|
window.open(config.ssoUrl);
|
||||||
|
} else {
|
||||||
|
window.vueInstance.$router.replace('/public/login');
|
||||||
|
}
|
||||||
|
} else if (res.data.code === 1) {
|
||||||
|
return res.data.data;
|
||||||
|
} else {
|
||||||
|
Promise.reject(res);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
export default axios;
|
123
浏览器插件/bookmark-chrome/webpack.config.js
Normal file
123
浏览器插件/bookmark-chrome/webpack.config.js
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
const webpack = require('webpack');
|
||||||
|
const ejs = require('ejs');
|
||||||
|
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||||
|
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||||
|
const ExtensionReloader = require('webpack-extension-reloader');
|
||||||
|
const { VueLoaderPlugin } = require('vue-loader');
|
||||||
|
const { version } = require('./package.json');
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
mode: process.env.NODE_ENV,
|
||||||
|
context: __dirname + '/src',
|
||||||
|
entry: {
|
||||||
|
background: './background.js',
|
||||||
|
'popup/popup': './popup/popup.js',
|
||||||
|
'options/options': './options/options.js',
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
path: __dirname + '/dist',
|
||||||
|
filename: '[name].js',
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.js', '.vue'],
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.vue$/,
|
||||||
|
loaders: 'vue-loader',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.js$/,
|
||||||
|
loader: 'babel-loader',
|
||||||
|
exclude: /node_modules/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
use: [MiniCssExtractPlugin.loader, 'css-loader'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.scss$/,
|
||||||
|
use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.sass$/,
|
||||||
|
use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader?indentedSyntax'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(png|jpg|jpeg|gif|svg|ico)$/,
|
||||||
|
loader: 'file-loader',
|
||||||
|
options: {
|
||||||
|
name: '[name].[ext]',
|
||||||
|
outputPath: '/images/',
|
||||||
|
emitFile: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
|
||||||
|
loader: 'file-loader',
|
||||||
|
options: {
|
||||||
|
name: '[name].[ext]',
|
||||||
|
outputPath: '/fonts/',
|
||||||
|
emitFile: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
global: 'window',
|
||||||
|
}),
|
||||||
|
new VueLoaderPlugin(),
|
||||||
|
new MiniCssExtractPlugin({
|
||||||
|
filename: '[name].css',
|
||||||
|
}),
|
||||||
|
new CopyWebpackPlugin([
|
||||||
|
{ from: 'icons', to: 'icons', ignore: ['icon.xcf'] },
|
||||||
|
{ from: 'static', to: 'static' },
|
||||||
|
{ from: 'static/fonts', to: 'fonts' },
|
||||||
|
{ from: 'popup/popup.html', to: 'popup/popup.html', transform: transformHtml },
|
||||||
|
{ from: 'options/options.html', to: 'options/options.html', transform: transformHtml },
|
||||||
|
{
|
||||||
|
from: 'manifest.json',
|
||||||
|
to: 'manifest.json',
|
||||||
|
transform: content => {
|
||||||
|
const jsonContent = JSON.parse(content);
|
||||||
|
jsonContent.version = version;
|
||||||
|
|
||||||
|
if (config.mode === 'development') {
|
||||||
|
jsonContent['content_security_policy'] = "script-src 'self' 'unsafe-eval'; object-src 'self'";
|
||||||
|
}
|
||||||
|
|
||||||
|
return JSON.stringify(jsonContent, null, 2);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
if (config.mode === 'production') {
|
||||||
|
config.plugins = (config.plugins || []).concat([
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
'process.env': {
|
||||||
|
NODE_ENV: '"production"',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.env.HMR === 'true') {
|
||||||
|
config.plugins = (config.plugins || []).concat([
|
||||||
|
new ExtensionReloader({
|
||||||
|
manifest: __dirname + '/src/manifest.json',
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function transformHtml(content) {
|
||||||
|
return ejs.render(content.toString(), {
|
||||||
|
...process.env,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = config;
|
@ -4,18 +4,17 @@ chrome.runtime.onInstalled.addListener(() => {
|
|||||||
title: '添加到书签',
|
title: '添加到书签',
|
||||||
id: "addBookmark",
|
id: "addBookmark",
|
||||||
},
|
},
|
||||||
() => console.debug("创建右键菜单成功")
|
() => console.log("创建右键菜单成功")
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
chrome.contextMenus.onClicked.addListener(async function (info, tab) {
|
chrome.contextMenus.onClicked.addListener(async function (info, tab) {
|
||||||
console.debug(info, tab);
|
console.log(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") });
|
||||||
});
|
});
|
||||||
@ -27,15 +26,14 @@ chrome.runtime.onMessage.addListener(async (data, sender, sendResponse) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sendResponse("ok");
|
sendResponse("ok");
|
||||||
console.debug("收到消息:", data, sender);
|
console.log("收到消息:", data, sender);
|
||||||
if (data.code == 'setToken') {
|
if (data.code == 'setToken') {
|
||||||
await setVal("token", data.data);
|
await setVal("token", data.data);
|
||||||
// sendToContent
|
// sendToContent
|
||||||
await sendToContent(sender.tab.id, { code: "setTokenOk" });
|
await sendToContent(sender.tab.id, { code: "setTokenOk" });
|
||||||
} else if (data.code == 'getToken') {
|
} else if (data.code == 'getToken') {
|
||||||
let token = await getVal("token");
|
let token = await getVal("token");
|
||||||
|
sendToPopup({ code: "setToken", data: await getVal("token") });
|
||||||
sendToPopup({ code: "setToken", data: token });
|
|
||||||
} else if (data.code == "clearToken") {
|
} else if (data.code == "clearToken") {
|
||||||
await clearVal("token");
|
await clearVal("token");
|
||||||
}
|
}
|
||||||
@ -47,10 +45,10 @@ chrome.runtime.onMessage.addListener(async (data, sender, sendResponse) => {
|
|||||||
* @param {*} data
|
* @param {*} data
|
||||||
*/
|
*/
|
||||||
function sendToContent (tabId, data) {
|
function sendToContent (tabId, data) {
|
||||||
console.debug(tabId, data);
|
console.log(tabId, data);
|
||||||
data.receiver = "content";
|
data.receiver = "content";
|
||||||
chrome.tabs.sendMessage(tabId, data, res => {
|
chrome.tabs.sendMessage(tabId, data, res => {
|
||||||
console.debug("接受响应", res);
|
console.log("接受响应", res);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,7 +58,7 @@ function sendToContent (tabId, data) {
|
|||||||
*/
|
*/
|
||||||
function sendToPopup (data) {
|
function sendToPopup (data) {
|
||||||
data.receiver = "popup";
|
data.receiver = "popup";
|
||||||
chrome.runtime.sendMessage(data, res => console.debug(res));
|
chrome.runtime.sendMessage(data, res => console.log(res));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -72,7 +70,7 @@ function sendToPopup (data) {
|
|||||||
function setVal (key, val) {
|
function setVal (key, val) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
chrome.storage.local.set({ [key]: val }, function () {
|
chrome.storage.local.set({ [key]: val }, function () {
|
||||||
console.debug("设置值成功:", key, val)
|
console.log("设置值成功:", key, val)
|
||||||
resolve();
|
resolve();
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -85,13 +83,8 @@ function setVal (key, val) {
|
|||||||
*/
|
*/
|
||||||
function getVal (key) {
|
function getVal (key) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
chrome.storage.local.get([key], async function (res) {
|
chrome.storage.local.get([key], function (res) {
|
||||||
if (key === 'token' && !checkTokenValid(res[key])) {
|
console.log("取值成功", res);
|
||||||
console.debug("token过期");
|
|
||||||
await clearVal("token");
|
|
||||||
res[key] = null;
|
|
||||||
}
|
|
||||||
console.debug("取值成功", res);
|
|
||||||
resolve(res[key]);
|
resolve(res[key]);
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -100,28 +93,8 @@ function getVal (key) {
|
|||||||
function clearVal (key) {
|
function clearVal (key) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
chrome.storage.local.remove(key, function () {
|
chrome.storage.local.remove(key, function () {
|
||||||
console.debug("remove成功", key);
|
console.log("remove成功", key);
|
||||||
resolve();
|
resolve();
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查token是否有效
|
|
||||||
* @param {*} token
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
function checkTokenValid (token) {
|
|
||||||
try {
|
|
||||||
if (token && token.trim().length > 0) {
|
|
||||||
//检查token是否还有效
|
|
||||||
let content = JSON.parse(atob(token.split(".")[1]));
|
|
||||||
if (content.exp > Date.now() / 1000) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error(token, err);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
@ -4,15 +4,8 @@
|
|||||||
"version": "1.0",
|
"version": "1.0",
|
||||||
"manifest_version": 3,
|
"manifest_version": 3,
|
||||||
"permissions": ["contextMenus", "storage"],
|
"permissions": ["contextMenus", "storage"],
|
||||||
"chrome_url_overrides": {
|
|
||||||
"newtab": "tab/index.html"
|
|
||||||
},
|
|
||||||
"action": {
|
"action": {
|
||||||
"default_popup": "popup/index.html",
|
"default_popup": "popup/index.html"
|
||||||
"default_icon": {
|
|
||||||
"48": "static/icons/favicon.png",
|
|
||||||
"128": "static/icons/favicon.png"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"icons": {
|
"icons": {
|
||||||
"48": "static/icons/favicon.png",
|
"48": "static/icons/favicon.png",
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
padding: 0.2em;
|
padding: 0.2em;
|
||||||
min-width: 8em;
|
width: 8em;
|
||||||
}
|
}
|
||||||
#content {
|
#content {
|
||||||
color: red;
|
color: red;
|
||||||
@ -16,18 +16,14 @@
|
|||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<a id="login" href="https://bm.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">
|
<div class="bottom">插件版本:<span id="version"></span></div>
|
||||||
<div>插件版本:<span id="version"></span></div>
|
|
||||||
<div>最新版本:<a href="" id="newestVersion">最新版本</a></div>
|
|
||||||
<div><a id="about" target="_blank">关于</a></span></div>
|
|
||||||
</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>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
console.debug("asdf");
|
console.log("asdf");
|
||||||
console.debug(bookmarkHost);
|
console.log(bookmarkHost);
|
||||||
|
|
||||||
var token;
|
var token;
|
||||||
var login = document.getElementById("login");
|
var login = document.getElementById("login");
|
||||||
@ -9,20 +9,14 @@ var action = document.getElementById("action");
|
|||||||
//初始化
|
//初始化
|
||||||
login.href = bookmarkHost + "/manage/sso/auth";
|
login.href = bookmarkHost + "/manage/sso/auth";
|
||||||
document.getElementById("version").innerText = version;
|
document.getElementById("version").innerText = version;
|
||||||
document.getElementById("about").href = bookmarkHost + "/public/about";
|
|
||||||
sendToBg("getToken", null);
|
sendToBg("getToken", null);
|
||||||
let newestBlock = document.getElementById("newestVersion");
|
|
||||||
newestBlock.href = bookmarkHost + "/static/bookmarkBrowserPlugin.zip";
|
|
||||||
let res = await axios.get("/common/config/global");
|
|
||||||
console.debug(res);
|
|
||||||
newestBlock.innerText = res.data.data.map.pluginVersion;
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 退出登陆
|
* 退出登陆
|
||||||
*/
|
*/
|
||||||
document.getElementById("logout").addEventListener("click", () => {
|
document.getElementById("logout").addEventListener("click", () => {
|
||||||
console.debug("click");
|
console.log("click");
|
||||||
sendToBg("clearToken", null);
|
sendToBg("clearToken", null);
|
||||||
action.style.display = "none";
|
action.style.display = "none";
|
||||||
login.style.display = "block";
|
login.style.display = "block";
|
||||||
@ -33,7 +27,7 @@ document.getElementById("logout").addEventListener("click", () => {
|
|||||||
* @param {*} data
|
* @param {*} data
|
||||||
*/
|
*/
|
||||||
function sendToBg (code, data) {
|
function sendToBg (code, data) {
|
||||||
chrome.runtime.sendMessage({ code, data, receiver: "background" }, res => console.debug(res));
|
chrome.runtime.sendMessage({ code, data, receiver: "background" }, res => console.log(res));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -43,7 +37,7 @@ chrome.runtime.onMessage.addListener(async (data, sender, sendResponse) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sendResponse("ok");
|
sendResponse("ok");
|
||||||
console.debug("popup收到消息:", data);
|
console.log("popup收到消息:", data);
|
||||||
if (data.code == 'setToken') {
|
if (data.code == 'setToken') {
|
||||||
token = data.data;
|
token = data.data;
|
||||||
if (token) {
|
if (token) {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user