提交 5b8ca0cc authored 作者: 龙菲's avatar 龙菲

整理原有接口;迁移奇文网盘逻辑;设计我的笔记原型;重写我的笔记模块

上级 572ceea9
......@@ -36,12 +36,14 @@
"url": "https://gitee.com/y_project/RuoYi-Vue.git"
},
"dependencies": {
"@pdftron/webviewer": "^7.3.2",
"@riophae/vue-treeselect": "0.4.0",
"axios": "0.24.0",
"babel-plugin-transform-remove-strict-mode": "^0.0.2",
"canvas-nest.js": "^2.0.4",
"clipboard": "2.0.8",
"core-js": "3.25.3",
"easy-marker": "^1.1.23",
"echarts": "5.4.0",
"element-ui": "2.15.13",
"file-saver": "2.0.5",
......
/**
* 笔记相关接口
*/
import request from '@/utils/request'
const baseUrl = '/v1/api'
export const getBookList = params => {
return request({
url: baseUrl + '/doc/bookmark/mine',
method: 'get',
params
})
}
// 根据文章获取笔记
export const getBookMark = params => {
return request({
url: baseUrl + '/doc/bookmark',
method: 'get',
params
})
}
export const getBookMarkByTag = params => {
return request({
url: baseUrl + '/doc/bookmark/tag',
method: 'get',
params
})
}
export const removeMark = data => {
return request({
url: baseUrl + '/doc/bookmark/delete',
method: 'post',
data
})
}
export const pdfRemoveMark = data => {
return request({
url: baseUrl + '/doc/bookmark/pdf/delete',
method: 'post',
data
})
}
export const addOrUpdate = data => {
return request({
url: baseUrl + '/doc/bookmark/addOrUpdate',
method: 'post',
data
})
}
export const pdfAddOrUpdate = data => {
return request({
url: baseUrl + '/doc/bookmark/pdf/addOrUpdate',
method: 'post',
data
})
}
\ No newline at end of file
/**
* 文档相关的一些接口
*/
import request from '@/utils/request'
const baseUrl = '/v1/api'
// 最近阅读
export function getNearRead(params) {
export const catlog = params => {
return request({
url: '/v1/api/index/nearRead',
url: baseUrl + '/doc/doc/catlog',
method: 'get',
params
})
}
// 最近创作
export const getNearCreation = (params) => {
// return request.get(baseUrl + '/user/nearCreation', {params: params})
export const detail = params => {
return request({
url: baseUrl + '/user/nearCreation',
url: baseUrl + '/doc/detail',
method: 'get',
params
})
}
export const loginIn = (params) => {
return request.post(baseUrl + '/user/login', params)
}
export const loginOut = (params) => {
return request.get(baseUrl + '/user/logout', { params: params })
}
// 获取后台文件预览地址
export const getViewUrlDbPath = params => {
return request.get(baseUrl + '/wps/getViewUrlDbPath', { params: params })
}
export const getBookList = params => {
return request.get(baseUrl + '/doc/bookmark/mine', { params: params })
}
export const getBookMark = params => {
return request.get(baseUrl + '/doc/bookmark', { params: params })
}
export const getBookMarkByTag = params => {
return request.get(baseUrl + '/doc/bookmark/tag', { params: params })
}
export const removeMark = params => {
return request.post(baseUrl + '/doc/bookmark/delete', params)
}
export const pdfRemoveMark = params => {
return request.post(baseUrl + '/doc/bookmark/pdf/delete', params)
}
export const getServiceTime = () => {
return request.get(baseUrl + '/index/serverDateMillis')
}
export const recommend = params => {
return request.get(baseUrl + '/index/recommend', { params: params })
}
export const hot = params => {
return request.get(baseUrl + '/index/hot', { params: params })
}
export const templateList = params => {
return request.get(baseUrl + '/wps/getTemplateList', { params: params })
}
// 新建文件
export const newfile = params => {
return request.post(baseUrl + '/wps/newfile', params)
}
// 新建模板
export const newfileTemplate = params => {
return request.post(baseUrl + '/wps/newfileTemplate', params)
}
export const delFile = params => {
return request.post(baseUrl + '/wps/delFile', params)
}
export const detail = params => {
return request.get(baseUrl + '/doc/detail', { params: params })
}
export const search = params => {
return request.get(baseUrl + '/index/search', { params: params })
}
export const collect = params => {
return request.post(baseUrl + '/user/collect', params)
}
export const addOrUpdate = params => {
return request.post(baseUrl + '/doc/bookmark/addOrUpdate', params)
}
export const pdfAddOrUpdate = params => {
return request.post(baseUrl + '/doc/bookmark/pdf/addOrUpdate', params)
}
export const catlog = params => {
return request.get(baseUrl + '/doc/doc/catlog', { params: params })
}
export const QueryKBaseData = params => {
return request.post(baseUrl + '/index/QueryKBaseData', params)
}
export const getCollect = params => {
return request.get(baseUrl + '/user/collect/mine', { params: params })
}
export const share = params => {
return request.post(baseUrl + '/doc/share', params)
}
export const getShare = params => {
return request.get(baseUrl + '/user/todolist/mine', { params: params })
}
export const verity = params => {
return request.post(baseUrl + '/user/todolist/verity', params)
}
export const wordcloud = params => {
return request.get(baseUrl + '/index/wordcloud', { params: params })
}
export const tagSuggest = params => {
return request.get(baseUrl + '/doc/tag/tips', { params: params })
}
export const tagPage = params => {
return request.get(baseUrl + '/doc/tag/page', { params: params })
}
}
\ No newline at end of file
/**
* 标签相关接口
*/
import request from '@/utils/request'
const baseUrl = '/v1/api'
export const tagSuggest = params => {
return request({
url: baseUrl + '/doc/tag/tips',
method: 'get',
params
})
}
export const tagPage = params => {
return request({
url: baseUrl + '/doc/tag/page',
method: 'get',
params
})
}
import axios from 'axios'
let baseUrl = '/webapi/v1/api'
//zwj
// let baseUrl ='http://222.85.214.245:9558/webapi/v1/api'
//let baseUrl ='http://localhost:8090/v1/api'
// 最近创作列表
export const nearCreation = (params) => {
return axios.get(baseUrl + '/user/nearCreation', {params: params})
}
export const nearRead = (params) => {
return axios.get(baseUrl + '/index/nearRead', {params: params})
}
export const loginIn = (params) => {
return axios.post(baseUrl + '/user/login', params)
}
export const loginOut = (params) => {
return axios.get(baseUrl + '/user/logout', {params: params})
}
// 获取后台文件预览地址
export const getViewUrlDbPath = params => {
return axios.get(baseUrl + '/wps/getViewUrlDbPath', {params: params})
}
export const getBookList = params => {
return axios.get(baseUrl + '/doc/bookmark/mine', {params: params})
}
export const getBookMark = params => {
return axios.get(baseUrl + '/doc/bookmark', {params: params})
}
export const getBookMarkByTag = params => {
return axios.get(baseUrl + '/doc/bookmark/tag', {params: params})
}
export const removeMark = params => {
return axios.post(baseUrl + '/doc/bookmark/delete', params)
}
export const pdfRemoveMark = params => {
return axios.post(baseUrl + '/doc/bookmark/pdf/delete', params)
}
export const getServiceTime = () => {
return axios.get(baseUrl + '/index/serverDateMillis')
}
export const recommend = params => {
return axios.get(baseUrl + '/index/recommend', {params: params})
}
export const hot = params => {
return axios.get(baseUrl + '/index/hot', {params: params})
}
export const templateList = params => {
return axios.get(baseUrl + '/wps/getTemplateList', {params: params})
}
export const newfile = params => {
return axios.post(baseUrl + '/wps/newfile', params)
}
export const newfileTemplate = params => {
return axios.post(baseUrl + '/wps/newfileTemplate', params)
}
export const delFile = params => {
return axios.post(baseUrl + '/wps/delFile', params)
}
export const detail = params => {
return axios.get(baseUrl + '/doc/detail', {params: params})
}
export const search = params => {
return axios.get(baseUrl + '/index/search', {params: params})
}
export const collect = params => {
return axios.post(baseUrl + '/user/collect', params)
}
export const addOrUpdate = params => {
return axios.post(baseUrl + '/doc/bookmark/addOrUpdate', params)
}
export const pdfAddOrUpdate = params => {
return axios.post(baseUrl + '/doc/bookmark/pdf/addOrUpdate', params)
}
export const catlog = params => {
return axios.get(baseUrl + '/doc/doc/catlog', {params: params})
}
export const QueryKBaseData = params => {
return axios.post(baseUrl + '/index/QueryKBaseData', params)
}
export const getCollect = params => {
return axios.get(baseUrl + '/user/collect/mine', {params: params})
}
export const share = params => {
return axios.post(baseUrl + '/doc/share', params)
}
export const getShare = params => {
return axios.get(baseUrl + '/user/todolist/mine', {params: params})
}
export const verity = params => {
return axios.post(baseUrl + '/user/todolist/verity', params)
}
export const wordcloud = params => {
return axios.get(baseUrl + '/index/wordcloud', {params: params})
}
export const tagSuggest = params => {
return axios.get(baseUrl + '/doc/tag/tips', {params: params})
}
export const tagPage = params => {
return axios.get(baseUrl + '/doc/tag/page', {params: params})
}
/**
* 首页相关接口(原有工程的首页policy-research-ui)
*/
import request from '@/utils/request'
const baseUrl = '/v1/api'
// 最近阅读
export const getNearRead = (params) => {
return request({
url: baseUrl + '/index/nearRead',
method: 'get',
params
})
}
// 最近创作
export const getNearCreation = (params) => {
return request({
url: baseUrl + '/user/nearCreation',
method: 'get',
params
})
}
// 推荐
export const recommend = params => {
return request({
url: baseUrl + '/index/recommend',
method: 'get',
params
})
}
// 热门
export const hot = params => {
return request({
url: baseUrl + '/index/hot',
method: 'get',
params
})
}
export const getServiceTime = (params) => {
return request({
url: baseUrl + '/index/serverDateMillis',
method: 'get',
params
})
}
export const search = params => {
return request({
url: baseUrl + '/index/search',
method: 'get',
params
})
}
export const QueryKBaseData = data => {
return request({
url: baseUrl + '/index/QueryKBaseData',
method: 'post',
data
})
}
export const wordcloud = params => {
return request({
url: baseUrl + '/index/wordcloud',
method: 'get',
params
})
}
/**
* 此文件是奇文网盘中的文件相关操作的接口
*/
// 文件(夹)模块相关接口
import request from '@/utils/request'
const baseUrl = '/v1/api/folder'
/**
* 获取文件列表相关接口
*/
// 获取文件列表(区分文件路径)
export const getFileListByPath = (params) => {
return request({
url: baseUrl + '/file/getfilelist',
method: 'post',
params
})
}
// 获取文件列表(区分文件类型)
export const getFileListByType = (params) => {
return request({
url: baseUrl + '/file/selectfilebyfiletype',
method: 'get',
params
})
}
// 获取回收站文件列表
export const getRecoveryFile = (params) => {
return request({
url: baseUrl + '/recoveryfile/list',
method: 'get',
params
})
}
// 获取我已分享的文件列表
export const getMyShareFileList = (params) => {
return request({
url: baseUrl + '/share/shareList',
method: 'get',
params
})
}
// 获取存储占用
export const getStorage = (params) => {
return request({
url: baseUrl + '/filetransfer/getstorage',
method: 'get',
params
})
}
// 获取文件目录树
export const getFoldTree = (params) => {
return request({
url: baseUrl + '/file/getfiletree',
method: 'get',
params
})
}
/**
* 单文件操作相关接口
*/
// 创建文件
export const createFold = (params) => {
return request({
url: baseUrl + '/file/createFold',
method: 'post',
params
})
}
// 获取文件详细信息
export const getFileDetail = (params) => {
return request({
url: baseUrl + '/file/detail',
method: 'get',
params
})
}
// 删除文件
export const deleteFile = (params) => {
return request({
url: baseUrl + '/file/deletefile',
method: 'post',
params
})
}
// 复制文件
export const copyFile = (data) => {
return request({
url: baseUrl + '/file/copyfile',
method: 'post',
data
})
}
// 移动文件
export const moveFile = (data) => {
return request({
url: baseUrl + '/file/movefile',
method: 'post',
data
})
}
// 重命名文件
export const renameFile = (data) => {
return request({
url: baseUrl + '/file/renamefile',
method: 'post',
data
})
}
// 解压文件
export const unzipFile = (params) => {
return request({
url: baseUrl + '/file/unzipfile',
method: 'post',
params
})
}
// 全局搜索文件
export const searchFile = (params) => {
return request({
url: baseUrl + '/file/search',
method: 'get',
params
})
}
// 分享文件
export const shareFile = (params) => {
return request({
url: baseUrl + '/share/sharefile',
method: 'post',
params
})
}
// 校验分享链接过期时间
export const checkShareLinkEndtime = (params) => {
return request({
url: baseUrl + '/share/checkendtime',
method: 'get',
params
})
}
// 校验分享链接是否需要提取码
export const checkShareLinkType = (params) => {
return request({
url: baseUrl + '/share/sharetype',
method: 'get',
params
})
}
// 校验分享链接提取码是否正确
export const checkShareLinkCode = (params) => {
return request({
url: baseUrl + '/share/checkextractioncode',
method: 'get',
params
})
}
// 获取分享文件列表
export const getShareFileList = (params) => {
return request({
url: baseUrl + '/share/sharefileList',
method: 'get',
params
})
}
// 保存分享文件
export const saveShareFile = (params) => {
return request({
url: baseUrl + '/share/savesharefile',
method: 'post',
params
})
}
/**
* 文件批量操作相关接口
*/
// 批量删除文件
export const batchDeleteFile = (data) => {
return request({
url: baseUrl + '/file/batchdeletefile',
method: 'post',
data
})
}
// 批量移动文件
export const batchMoveFile = (data) => {
return request({
url: baseUrl + '/file/batchmovefile',
method: 'post',
data
})
}
/**
* 回收站文件操作相关接口
*/
// 回收站文件删除
export const deleteRecoveryFile = (params) => {
return request({
url: baseUrl + '/recoveryfile/deleterecoveryfile',
method: 'post',
params
})
}
// 回收站文件还原
export const restoreRecoveryFile = (params) => {
return request({
url: baseUrl + '/recoveryfile/restorefile',
method: 'post',
params
})
}
// 回收站文件批量删除
export const batchDeleteRecoveryFile = (data) => {
return request({
url: baseUrl + '/recoveryfile/batchdelete',
method: 'post',
data
})
}
/**
* 文件公共接口
*/
// 文件预览
export const getFilePreview = (params) => {
return request({
url: baseUrl + '/filetransfer/preview',
method: 'get',
params
})
}
// 文件修改
export const modifyFileContent = (data) => {
return request({
url: baseUrl + '/file/update',
method: 'post',
data
})
}
/**
* 收藏相关接口
*/
import request from '@/utils/request'
const baseUrl = '/v1/api'
//用户点击收藏
export const collect = params => {
return request({
url: baseUrl + '/user/collect',
method: 'post',
params
})
}
// 获取我的收藏列表
export const getCollect = params => {
return request({
url: baseUrl + '/user/collect/mine',
method: 'get',
params
})
}
/**
* 用户个人相关一些接口
*/
import request from '@/utils/request'
const baseUrl = '/v1/api'
export const verity = params => {
return request({
url: baseUrl + '/user/todolist/verity',
method: 'post',
params
})
}
\ No newline at end of file
/**
* 分享相关接口
*/
import request from '@/utils/request'
const baseUrl = '/v1/api'
export const share = data => {
return request({
url: baseUrl + '/doc/share',
method: 'post',
data
})
}
export const getShare = params => {
return request({
url: baseUrl + '/user/todolist/mine',
method: 'get',
params
})
}
\ No newline at end of file
/**
* WPS相关接口
*/
import request from '@/utils/request'
const baseUrl = '/v1/api'
// 获取模板列表
export const getTemplateList = params => {
return request({
url: baseUrl + '/wps/getTemplateList',
method: 'get',
params
})
}
// 新建文件
export const newfile = data => {
return request({
url: baseUrl + '/wps/newfile',
method: 'post',
data
})
}
// 新建模板
export const newfileTemplate = data => {
return request({
url: baseUrl + '/wps/newfileTemplate',
method: 'post',
data
})
}
// 删除文件
export const delFile = data => {
return request({
url: baseUrl + '/wps/delFile',
method: 'post',
data
})
}
// 获取后台文件预览地址
export const getViewUrlDbPath = params => {
return request({
url: baseUrl + '/wps/getViewUrlDbPath',
method: 'get',
params
})
}
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1689238424396" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3724" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M535.198324 0h69.53853v95.276816c124.175945 0.677323 248.351891-1.354647 373.205159 0.677324a40.6394 40.6394 0 0 1 45.154889 45.154889c1.919083 234.579649 0 469.272186 1.128872 703.851835-1.128872 24.044979 2.257744 50.686363-11.288722 72.022049-17.045971 12.417595-38.946092 11.288722-58.814243 11.288722H604.962628v95.276816h-72.925146C354.917429 990.924044 177.458715 960.557381 0 928.723184V95.502591C178.361812 63.555507 356.836512 32.51152 535.198324 0z" fill="#A33639" p-id="3725"></path><path d="M604.736854 130.949179h383.816558v762.101642h-383.816558v-95.276816h302.42487v-47.638408H604.736854v-59.491567h302.42487V643.457171H604.736854v-60.056002h302.42487v-47.638409H604.736854v-59.491566h302.42487V428.971447H604.736854v-59.830228h302.42487v-47.638408H604.736854V261.898357h302.42487v597.17341H604.736854z" fill="#FFFFFF" p-id="3726"></path><path d="M645.489141 529.66685h302.424871v47.638409H645.489141zM645.489141 611.510087h302.424871v47.638408H645.489141zM645.489141 693.353324h302.424871v47.638408H645.489141zM596.383199 775.19656h351.530813v47.638409H596.383199z" fill="#A33639" p-id="3727"></path><path d="M180.619557 317.325984c59.265792 2.822181 130.949179-24.044979 180.619557 21.335685 46.961085 58.475582 34.54349 165.831331-35.107927 200.713483-24.722302 12.982031-53.169882 11.288722-80.037041 10.272737v130.949179L180.619557 675.065594c-0.903098-119.208908-1.128872-238.530702 0-357.73961z" fill="#FFFFFF" p-id="3728"></path><path d="M245.642597 377.720648c21.448572-1.015985 48.089957-5.079925 62.539522 15.578437a82.407673 82.407673 0 0 1 1.467534 73.263808c-12.417595 22.577445-40.526513 20.771249-62.313747 23.367655-2.257744-37.365671-2.03197-74.731342-1.693309-112.2099zM885.713152 379.865505a83.988094 83.988094 0 0 1-48.315732-19.642376 460.57987 460.57987 0 0 0-77.666409 24.835189c-20.3197 36.011024-39.171866 54.411641-55.540514 54.411641a17.384632 17.384632 0 0 1-9.821188-2.596406 19.416602 19.416602 0 0 1-11.288723-17.723294c0-5.870136 1.354647-22.577445 63.329733-49.105942a467.917539 467.917539 0 0 0 34.656377-81.278801c-7.902106-15.691324-24.835189-54.298754-13.094918-73.941131a20.658362 20.658362 0 0 1 20.206813-10.498511 21.900121 21.900121 0 0 1 17.045971 8.466541c8.466542 11.288722 7.789218 36.688347-3.27373 73.376695A196.988204 196.988204 0 0 0 842.70312 338.661669a221.14607 221.14607 0 0 1 41.090949-4.515489c30.705325 0.677323 35.333701 15.014001 34.656377 23.59343 0 22.577445-21.56146 22.577445-32.624407 22.577444z m-185.022159 42.106935l2.257745-0.564436a45.154889 45.154889 0 0 0 23.932091-16.820197 56.443612 56.443612 0 0 0-26.189836 17.384633z m93.357734-200.261934h-2.144858a4.402602 4.402602 0 0 0-2.82218 0.677323 52.492559 52.492559 0 0 0 4.176827 33.866167 53.282769 53.282769 0 0 0 0.790211-34.54349zM790.210561 317.551758v1.24176l-0.677323-0.677324c-5.418587 14.336677-11.288722 28.44758-18.061956 42.332709l1.128872-0.677323V361.239114A346.338 346.338 0 0 1 812.788006 348.595745l-0.677324-0.564436h1.806196a196.310881 196.310881 0 0 1-23.706317-30.479551z m94.599493 34.769265a66.151913 66.151913 0 0 0-18.174843 1.693308 50.686363 50.686363 0 0 0 20.997024 6.660347 26.076949 26.076949 0 0 0 13.885128-1.580422c-0.451549-2.596406-3.273729-6.773233-17.158858-6.773233z" fill="#A33639" p-id="3729"></path></svg>
\ No newline at end of file
<template>
<div class="listRoot">
<ul>
<el-tooltip
class="item"
popper-class="myTooltip"
effect="dark"
:key="index"
disabled
:content="getContent(item)"
placement="left"
v-for="(item, index) of data"
>
<li :anchor="item.id" @click="jump(item)">
<el-row type="flex" class="row1" justify="space-between">
<span class="time"
><i class="el-icon-date" style="margin-right: 1em" />{{
item.time
}}</span
>
<span class="tools">
<i
title="跳转至文档"
@click.stop="redirect"
class="el-icon-s-promotion"
v-if="$route.path === '/write'"
></i>
<i
title="插入文字至光标所在处"
@click.stop="insert(item)"
class="el-icon-copy-document"
v-if="$route.path === '/write'"
></i>
<el-popover
popper-class="tagWindow"
title="添加标签"
trigger="click"
placement="left"
>
<div>
<span>新增标签:</span>
<el-autocomplete
class="inline-input"
v-model="noteTags"
:fetch-suggestions="querySearch"
placeholder="请输入内容"
:maxlength="tagMaxLength"
show-word-limit
@input="getSuggest"
@change="handleSelect"
@select="handleSelect"
>
<el-button slot="append" icon="el-icon-plus"></el-button>
</el-autocomplete>
</div>
<div style="margin-top: 10px">
<span>当前标签:</span>
<span v-if="tags.length === 0">暂无</span>
<div class="myTags">
<el-tag
closable
style="margin-left: 4px; margin-bottom: 4px"
:key="i"
v-for="(item, i) in tags"
@close="removeTag(item)"
>
{{ item.tagName }}
</el-tag>
</div>
</div>
<div style="margin-top: 20px; float: right">
<el-button type="primary" @click="addTags(item, index)"
>确定</el-button
>
<el-button @click="addTagsCancel">取消</el-button>
</div>
<i
slot="reference"
title="添加标签"
class="el-icon-price-tag"
v-if="item.detail[0].icon !== 'note'"
></i>
</el-popover>
<i
title="编辑"
@click.stop="edit(item)"
class="el-icon-edit-outline"
v-if="item.detail[0].icon === 'note'"
></i>
<el-popconfirm
title="确定要删除本条记录吗?"
@confirm="remove(item)"
>
<i
slot="reference"
@click.stop="removeClick"
title="删除"
class="el-icon-delete"
></i>
</el-popconfirm>
</span>
</el-row>
<el-row
type="flex"
class="row2"
v-for="(target, i) of item.detail"
:key="'note' + i"
>
<span>
<svg class="icon" aria-hidden="true">
<use
:xlink:href="`#icon-${target.icon.replace(
'highlight',
'heigh'
)}`"
></use>
</svg>
<span
class="noteText"
v-html="noteText(target.key, target.value)"
></span>
</span>
</el-row>
<!-- <el-row type="flex" class="row3" v-for="(target,i) of item.detail" :key="i"
v-if="item.detail[0].icon!=='note'">
<i class="el-icon-price-tag"/>
<div class="tagBox">
<el-tag closable title="测试数据,测试数据,测试数据,测试数据,测试数据,测试数据,测试数据,测试数据">测试数据,测试数据,测试数据...</el-tag>
<el-tag closable>测试数据</el-tag>
<el-tag closable>测试数据,测试</el-tag>
<el-tag closable>数据</el-tag>
<el-tag closable>测试数据</el-tag>
<el-tag closable>测试</el-tag>
</div>
</el-row> -->
</li>
</el-tooltip>
</ul>
</div>
</template>
<script>
import { tagSuggest } from "@/api/doc/index";
export default {
name: "list",
props: ["data"],
data() {
return {
tags: [],
tagMaxLength: 22,
noteTags: "",
};
},
methods: {
addTagsCancel() {
document.querySelectorAll(".tagWindow").forEach((item) => {
item.remove();
});
},
addTag(e) {
if (e.length > this.tagMaxLength) {
this.$message.error(
"当前文字长度:" + e.length + ",不能超过" + this.tagMaxLength
);
return;
}
for (let i = 0; i < this.tags.length; i++) {
let item = this.tags[i];
if (item.tagName === e) {
this.$message.error("当前标签已存在,不能重复添加");
return;
}
}
let tag = {
tagName: e,
};
this.tags.push(tag);
},
handleSelect(e) {
this.addTag(e.value || e);
this.noteTags = "";
},
async getSuggest(e) {
let p = {
keyword: e,
};
await tagSuggest(p).then((res) => {
if (res.code === 200) {
this.restaurants = res.result.map((item) => {
let model = {
value: item.tagName,
};
return model;
});
}
});
},
async querySearch(queryString, cb) {
await this.getSuggest();
let restaurants = this.restaurants;
let results = queryString
? restaurants.filter(this.createFilter(queryString))
: restaurants;
cb(results);
},
createFilter(queryString) {
return (restaurant) => {
return (
restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) !==
-1
);
};
},
removeTag(e) {
this.tags.splice(this.tags.indexOf(e), 1);
},
noteText(key, value) {
return key + ":" + value;
},
getContent(e) {
if (e.detail.length > 1) {
return e.detail[1].value;
} else {
return e.detail[0].value;
}
},
addTags(e) {
let tagStr = [];
this.tags.forEach((item) => {
tagStr.push(item.tagName);
});
let res = {
id: e.uid,
tags: tagStr.join(","),
};
this.$emit("addTags", res);
},
redirect(e) {
this.$emit("redirect");
},
insert(e) {
this.$emit("insert", e);
},
removeClick() {},
jump(e) {
this.$emit("jump", e);
},
remove(item) {
this.$emit("removeMark", item.id);
},
edit(e) {
this.$emit("editMark", e.id);
},
},
};
</script>
<style lang="scss">
.listRoot {
ul {
li {
p {
display: inline;
}
}
}
.noteText {
max-height: 98px;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 4;
overflow: hidden;
}
}
.tagWindow {
margin-left: -710px !important;
margin-top: 48px !important;
}
.myTooltip {
max-width: 300px !important;
}
</style>
<style lang="scss" scoped>
.listRoot {
& > ul {
& > .active {
box-shadow: 0 0 16px rgba(53, 148, 255, 1);
}
li {
overflow: hidden;
box-shadow: 0 0 6px rgba(0, 0, 0, 0.2);
font-size: 16px;
cursor: pointer;
display: inline-block;
width: 100%;
/*max-height: 180px;*/
background-color: #ffffff;
margin-bottom: 10px;
& > .row1 {
margin: 20px 20px 10px 20px;
& > .userInfo {
display: inline-block;
& > .avatar {
float: left;
}
}
& > .time {
width: 150px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
line-height: 28px;
}
& > .tools {
line-height: 28px;
i {
font-size: 24px;
margin-left: 4px;
cursor: pointer;
color: #409eff;
}
i:hover {
transform: scale(1.4);
transition: all 0.3s ease;
color: #ff6e04;
}
}
}
& > .row2 {
color: #848383;
margin: 6px 20px 0 50px;
font-size: 18px;
.icon {
margin-top: 3px;
margin-left: -22px;
position: absolute;
width: 20px;
height: 20px;
}
}
& > .row2:last-child {
margin-bottom: 20px;
}
& > .row3 {
color: #848383;
margin: 6px 20px 0 28px;
font-size: 18px;
.tagBox {
margin-left: 4px;
width: 300px;
display: inline-block;
.el-tag {
margin: 0 4px 4px 0;
font-size: 18px;
max-width: 310px;
}
}
}
& > .row3:last-child {
margin-bottom: 20px;
}
}
& > li:hover {
box-shadow: 0 0 10px rgba(53, 148, 255, 0.9);
}
}
}
</style>
......@@ -85,7 +85,7 @@
</template>
<script>
import { templateList, newfile, newfileTemplate } from "@/api/doc/index";
import { getTemplateList, newfile, newfileTemplate } from "@/api/wps";
export default {
name: "templete",
......
......@@ -275,7 +275,7 @@ export default {
// 监听左侧菜单切换,修改浏览器标签标题
activeIndex(newValue) {
document.title = `${this.myFileMenuMap[Number(newValue)]} - ${
this.$config.siteName
this.$qwConfig.siteName
}`;
this.isDrawer = false;
},
......@@ -293,7 +293,7 @@ export default {
},
mounted() {
document.title = `${this.myFileMenuMap[Number(this.activeIndex)]} - ${
this.$config.siteName
this.$qwConfig.siteName
}`;
},
};
......
......@@ -82,7 +82,7 @@ import {
getRecoveryFile,
getMyShareFileList,
searchFile,
} from "@/request/file.js";
} from "@/api/qwFile";
export default {
name: "FileList",
......@@ -146,8 +146,8 @@ export default {
},
},
created() {
// this.setPageCount();
// this.getTableDataByType();
this.setPageCount();
this.getTableDataByType();
},
methods: {
/**
......@@ -332,7 +332,8 @@ export default {
@import "@/assets/styles/varibles.scss";
.file-list-wrapper {
>>> .el-header {
padding: 20px;
::v-deep .el-header {
padding: 0;
}
......
......@@ -218,7 +218,7 @@
</template>
<script>
import { getFileDetail } from "@/request/file.js";
import { getFileDetail } from "@/api/qwFile";
import * as Base64 from "js-base64";
export default {
......
......@@ -133,10 +133,10 @@ import {
fontSizeList,
fileSuffixCodeModeMap,
codeMirrorThemeList,
} from "@/libs/map.js";
} from "@/libs/qiwen/map.js";
// 文件修改相关
import store from "@/store/index.js";
import { getFilePreview, modifyFileContent } from "@/request/file.js";
import { getFilePreview, modifyFileContent } from "@/api/qwFile.js";
export default {
name: "ImgPreview",
......@@ -237,7 +237,7 @@ export default {
isMin: false,
shareBatchNum: this.fileInfo.shareBatchNum,
extractionCode: this.fileInfo.extractionCode,
token: this.$common.getCookies(this.$config.tokenKeyName),
token: this.$common.getCookies(this.$qwConfig.tokenKeyName),
}).then((res) => {
this.codeMirrorLoading = false;
this.originalCodeText =
......
......@@ -181,7 +181,7 @@ import {
officeFileType,
fileSuffixCodeModeMap,
markdownFileType,
} from "@/libs/map.js";
} from "@/libs/qiwen/map.js";
export default {
name: "ContextMenu",
......@@ -654,3 +654,4 @@ export default {
}
}
</style>
@/libs/qiwen/map.js
......@@ -64,7 +64,7 @@ import "mavon-editor/dist/css/index.css";
import "/public/mavonEditor/css/tomorrow-night.css";
import "/public/mavonEditor/css/github-markdown.css";
import store from "@/store/index.js";
import { getFilePreview, modifyFileContent } from "@/request/file.js";
import { getFilePreview, modifyFileContent } from "@/api/qwFile.js";
export default {
name: "ImgPreview",
......@@ -195,7 +195,7 @@ export default {
isMin: false,
shareBatchNum: this.fileInfo.shareBatchNum,
extractionCode: this.fileInfo.extractionCode,
token: this.$common.getCookies(this.$config.tokenKeyName),
token: this.$common.getCookies(this.$qwConfig.tokenKeyName),
}).then((res) => {
this.markdownLoading = false;
this.originalMarkdownText = res;
......
......@@ -146,7 +146,7 @@ export default {
}
},
headers: {
token: this.$common.getCookies(this.$config.tokenKeyName),
token: this.$common.getCookies(this.$qwConfig.tokenKeyName),
},
query() {},
},
......@@ -196,7 +196,7 @@ export default {
*/
handlePrepareUpload() {
this.options.headers.token = this.$common.getCookies(
this.$config.tokenKeyName
this.$qwConfig.tokenKeyName
);
switch (this.uploadWay) {
case 1: {
......
......@@ -47,7 +47,7 @@
<el-dropdown-item divided @click.native="handleCreateFile('docx')">
<div class="img-text-wrapper"><img :src="wordImg" />Word 文档</div>
</el-dropdown-item>
<el-dropdown-item @click.native="handleCreateFile('xlsx')">
<!-- <el-dropdown-item @click.native="handleCreateFile('xlsx')">
<div class="img-text-wrapper">
<img :src="excelImg" />Excel 工作表
</div>
......@@ -56,7 +56,7 @@
<div class="img-text-wrapper">
<img :src="pptImg" />PPT 演示文稿
</div>
</el-dropdown-item>
</el-dropdown-item> -->
</el-dropdown-menu>
</el-dropdown>
</el-button-group>
......@@ -493,7 +493,7 @@ export default {
.create-operate-group {
.upload-drop {
float: left;
>>> .el-button {
::v-deep .el-button {
border-radius: 4px 0 0 4px;
}
}
......
......@@ -39,7 +39,7 @@
</template>
<script>
import { createOfficeFile } from "@/request/onlyoffice.js";
// import { createOfficeFile } from "@/request/onlyoffice.js";
export default {
name: "AddFileDialog",
......@@ -76,25 +76,26 @@ export default {
this.sureBtnLoading = true;
this.$refs[formName].validate((valid) => {
if (valid) {
createOfficeFile({
extendName: this.extendName,
filePath: this.filePath,
fileName: this.form.fileName,
})
.then((res) => {
this.sureBtnLoading = false;
if (res.success && res.code === 0) {
this.$message.success("文件创建成功");
this.$refs[formName].resetFields();
this.visible = false;
this.callback("confirm");
} else {
this.$message.warning(res.message);
}
})
.catch(() => {
this.sureBtnLoading = false;
});
console.log("TODO:创建文件");
// createOfficeFile({
// extendName: this.extendName,
// filePath: this.filePath,
// fileName: this.form.fileName,
// })
// .then((res) => {
// this.sureBtnLoading = false;
// if (res.success && res.code === 0) {
// this.$message.success("文件创建成功");
// this.$refs[formName].resetFields();
// this.visible = false;
// this.callback("confirm");
// } else {
// this.$message.warning(res.message);
// }
// })
// .catch(() => {
// this.sureBtnLoading = false;
// });
} else {
this.sureBtnLoading = false;
return false;
......
......@@ -40,7 +40,7 @@
</template>
<script>
import { createFold } from "@/request/file.js";
import { createFold } from "@/api/qwFile.js";
export default {
name: "AddFolderDialog",
......
......@@ -22,7 +22,7 @@
</template>
<script>
import { getWeChatAuthState } from "@/request/user.js";
// import { getWeChatAuthState } from "@/request/user.js";
export default {
name: "AddFolderDialog",
......@@ -54,17 +54,18 @@ export default {
process.env.NODE_ENV !== "development" &&
location.origin === "https://pan.qiwenshare.com"
) {
getWeChatAuthState().then((res) => {
if (res.success) {
if (res.data) {
this.callback("go");
} else {
this.visible = true;
}
} else {
this.$message.error(res.message);
}
});
console.log("getWeChatAuthStateData", getWeChatAuthStateData);
// getWeChatAuthState().then((res) => {
// if (res.success) {
// if (res.data) {
// this.callback("go");
// } else {
// this.visible = true;
// }
// } else {
// this.$message.error(res.message);
// }
// });
} else {
this.callback("go");
}
......
......@@ -58,7 +58,7 @@
</template>
<script>
import { getFoldTree, copyFile } from "@/request/file.js";
import { getFoldTree, copyFile } from "@/api/qwFile.js";
export default {
name: "CopyFileDialog",
......
......@@ -27,7 +27,7 @@ import {
batchDeleteRecoveryFile,
deleteFile,
deleteRecoveryFile,
} from "@/request/file.js";
} from "@/api/qwFile.js";
export default {
name: "DeleteFileDialog",
......
......@@ -58,7 +58,7 @@
</template>
<script>
import { getFoldTree, moveFile, batchMoveFile } from "@/request/file.js";
import { getFoldTree, moveFile, batchMoveFile } from "@/api/qwFile.js";
export default {
name: "MoveFileDialog",
......
......@@ -40,7 +40,7 @@
</template>
<script>
import { renameFile } from "@/request/file.js";
import { renameFile } from "@/api/qwFile.js";
export default {
name: "RenameFileDialog",
......
......@@ -15,7 +15,7 @@
</template>
<script>
import { restoreRecoveryFile } from "@/request/file.js";
import { restoreRecoveryFile } from "@/api/qwFile.js";
export default {
name: "DeleteFileDialog",
......
......@@ -58,7 +58,7 @@
</template>
<script>
import { getFoldTree, saveShareFile } from "@/request/file.js";
import { getFoldTree, saveShareFile } from "@/api/qwFile.js";
export default {
name: "SaveShareFileDialog",
......
......@@ -89,7 +89,7 @@
<script>
import store from "@/store/index.js";
import { shareFile } from "@/request/file.js";
import { shareFile } from "@/api/qwFile.js";
export default {
name: "ShareFileDialog",
......
......@@ -62,7 +62,7 @@
</template>
<script>
import { getFoldTree, unzipFile } from "@/request/file.js";
import { getFoldTree, unzipFile } from "@/api/qwFile.js";
export default {
name: "UnzipFileDialog",
......
/**
* 存放工程配置项
* @author 李雅婷
*/
const config = {
/**
* @description 域名
* 区分生产环境和开发环境,用来存放session及一些用户配置信息(左侧菜单栏是否收缩等)
* 冒号之前配置生产环境域名
* 冒号之后配置开发环境域名,开发环境域名默认使用主机名
*/
domain:
process.env.NODE_ENV === 'production'
? location.host.indexOf('.qiwenshare.com') !== -1
? '.qiwenshare.com'
: ''
: location.hostname,
/**
* 网站名称
*/
siteName:
process.env.NODE_ENV === 'production' &&
location.host.indexOf('.qiwenshare.com') !== -1
? '奇文网盘'
: '网盘名称',
/**
* 请求后台接口 URL 代理时的上下文
* @description 仅适用于本地开发环境代理时使用,
* 生产环境需要在 nginx 配置中将 /api/ 代理到生产环境后台地址
* 对应 vue.config.js 中配置的 devServer.proxy 中的代理之一
* 若修改了此值,请同步修改 vue.config.js 中 devServer.proxy 对应的值
*/
baseContext: '/api',
/**
* 存放 token 时的命名方式
*/
tokenKeyName: 'token'
}
export default config
import Cookies from 'js-cookie'
import config from '@/config/index.js'
import qwConfig from '@/utils/qwConfig'
// 全局函数 - 公共操作相关
const commonFunction = {
......
import Vue from 'vue'
import router from '@/router/index'
import config from '@/config/index.js'
import qwConfig from '@/utils/qwConfig'
import { Message } from 'element-ui'
import {
fileImgMap,
unknownImg,
fileSuffixCodeModeMap,
markdownFileType
} from '@/libs/map.js'
import { officeFileType } from '@/libs/map.js'
} from '@/libs/qiwen/map.js'
import { officeFileType } from '@/libs/qiwen/map.js'
// 全局函数 - 文件相关
const fileFunction = {
......
......@@ -21,10 +21,11 @@ import { getConfigKey } from "@/api/system/config";
import { parseTime, resetForm, addDateRange, selectDictLabel, selectDictLabels, handleTree } from "@/utils/ruoyi";
// 引入全局函数-奇文
import globalFunction from '@/libs/globalFunction/index.js'
import globalFunction from '@/libs/qiwen/globalFunction/index.js'
// 引入全局配置-奇文
import config from '@/config/index.js'
import qwConfig from '@/utils/qwConfig'
// 引入上传文件组件-奇文
import uploader from 'vue-simple-uploader'
// 分页组件
import Pagination from "@/components/Pagination";
// 自定义表格工具组件
......@@ -60,8 +61,8 @@ Vue.prototype.handleTree = handleTree
for (let key in globalFunction) {
Vue.prototype[`$${key}`] = globalFunction[key]
}
// 全局配置挂载
Vue.prototype.$config = config
// 全局配置挂载-奇文
Vue.prototype.$qwConfig = qwConfig
// 全局组件挂载
Vue.component('DictTag', DictTag)
......@@ -75,6 +76,7 @@ Vue.component('ImagePreview', ImagePreview)
Vue.use(directive)
Vue.use(plugins)
Vue.use(VueMeta)
Vue.use(uploader) //奇文
DictData.install()
/**
......
// 文件模块相关接口
import { get, post } from './http'
/**
* 以登录接口为例
* export const login = p => get('/user/login', p);
*
* login ---------- 接口名称
* p -------------- 传参,若需要在url中拼接其他信息,传参可以改为(p, other)
* get ------------ 接口调用的方法,来自 http.js 中封装好的四个axios方法 get/post/put/axiosDelete
* '/user/login' -- 接口url,若需要在url中拼接其他信息:
* 首先需要在传参处改为(p, other1, other2)
* 然后将url改为`/user/${other1}/login/${other2}`
* p -------------- 传递给 get/post/put/axiosDelete 中的查询参数/请求体
*
*
*
* 除此之外,POST 请求支持请求体格式为 FormData,那么就需要多传递一个参数,true,如下示例:
* export const example = p => post('/test/example', p, true);
*/
const baseApi = '/qw-api' //用于统一拦截
/**
* 获取文件列表相关接口
*/
// 获取文件列表(区分文件路径)
export const getFileListByPath = (p) => get(baseApi + '/file/getfilelist', p)
// 获取文件列表(区分文件类型)
export const getFileListByType = (p) => get('/file/selectfilebyfiletype', p)
// 获取回收站文件列表
export const getRecoveryFile = (p) => get('/recoveryfile/list', p)
// 获取我已分享的文件列表
export const getMyShareFileList = (p) => get('/share/shareList', p)
// 获取存储占用
export const getStorage = (p) => get('/filetransfer/getstorage', p)
// 获取文件目录树
export const getFoldTree = (p) => get('/file/getfiletree', p)
/**
* 单文件操作相关接口
*/
// 创建文件
export const createFold = (p) => post('/file/createFold', p)
// 获取文件详细信息
export const getFileDetail = (p) => get('/file/detail', p)
// 删除文件
export const deleteFile = (p) => post('/file/deletefile', p)
// 复制文件
export const copyFile = (p) => post('/file/copyfile', p)
// 移动文件
export const moveFile = (p) => post('/file/movefile', p)
// 重命名文件
export const renameFile = (p) => post('/file/renamefile', p)
// 解压文件
export const unzipFile = (p) => post('/file/unzipfile', p)
// 全局搜索文件
export const searchFile = (p) => get('/file/search', p)
// 分享文件
export const shareFile = (p) => post('/share/sharefile', p)
// 校验分享链接过期时间
export const checkShareLinkEndtime = (p) => get('/share/checkendtime', p)
// 校验分享链接是否需要提取码
export const checkShareLinkType = (p) => get('/share/sharetype', p)
// 校验分享链接提取码是否正确
export const checkShareLinkCode = (p) => get('/share/checkextractioncode', p)
// 获取分享文件列表
export const getShareFileList = (p) => get('/share/sharefileList', p)
// 保存分享文件
export const saveShareFile = (p) => post('/share/savesharefile', p)
/**
* 文件批量操作相关接口
*/
// 批量删除文件
export const batchDeleteFile = (p) => post('/file/batchdeletefile', p)
// 批量移动文件
export const batchMoveFile = (p) => post('/file/batchmovefile', p)
/**
* 回收站文件操作相关接口
*/
// 回收站文件删除
export const deleteRecoveryFile = (p) =>
post('/recoveryfile/deleterecoveryfile', p)
// 回收站文件还原
export const restoreRecoveryFile = (p) => post('/recoveryfile/restorefile', p)
// 回收站文件批量删除
export const batchDeleteRecoveryFile = (p) =>
post('/recoveryfile/batchdelete', p)
/**
* 文件公共接口
*/
// 文件预览
export const getFilePreview = (p) => get('/filetransfer/preview', p)
// 文件修改
export const modifyFileContent = (p) => post('/file/update', p)
// 文件模块相关接口
import { get } from './http'
/**
* 获取首页相关接口
*/
// 获取公告列表 - 带分页查询
export const getNoticeList = (p) => get('/notice/list', p)
// 获取公告详情
export const getNoticeDetail = (p) => get('/notice/detail', p)
/**
* 底部信息栏
*/
// 查询系统参数组
export const getParamsDetail = (p) => get('/param/grouplist', p)
import axios from 'axios'
import globalConfig from '@/config/index.js'
import common from '@/libs/globalFunction/common.js'
import router from '@/router/index'
import { MessageBox, Message } from 'element-ui'
// 登录提醒
const loginTip = function () {
MessageBox.alert('您尚未登录,请先登录', '操作提示', {
confirmButtonText: '确定',
callback: () => {
router.push({
path: '/login',
query: { Rurl: router.currentRoute.fullPath } // 将当前页面的url传递给login页面进行操作
})
}
})
}
// 请求超时时间
axios.defaults.timeout = 10000 * 5
// 请求基础 URL
axios.defaults.baseURL = globalConfig.baseContext
// POST 请求头
axios.defaults.headers.post['Content-Type'] =
'application/x-www-form-urlencoded'
// 请求携带cookie
axios.defaults.withCredentials = true
// 请求拦截器
axios.interceptors.request.use(
(config) => {
config.headers['token'] = common.getCookies(globalConfig.tokenKeyName)
return config
},
(error) => {
console.log(error)
return Promise.reject(error)
}
)
// 响应拦截器
axios.interceptors.response.use(
(response) => {
if (response.status === 200) {
return Promise.resolve(response)
}
},
// 服务器状态码不是200的情况
(error) => {
if (error.response.status) {
console.log(error.response)
switch (error.response.status) {
case 404:
Message.warning('接口不存在,请刷新重试或联系管理员')
break
case 401:
loginTip()
break
case 500:
Message.error('服务异常,请稍后刷新重试或联系管理员')
break
case 502:
Message.error('服务异常,请稍后刷新重试或联系管理员')
break
default:
Message.warning(error.response.data.message)
return Promise.reject(error.response)
}
}
}
)
/**
* 封装 get方法 对应 GET 请求
* @param {string} url 请求url
* @param {object} params 查询参数
* @returns {Promise}
*/
export function get(url, params) {
return new Promise((resolve, reject) => {
axios
.get(url, {
params: params
})
.then((res) => {
resolve(res.data)
})
.catch((err) => {
reject(err.data)
})
})
}
/**
* 封装 post 方法,对应 POST 请求
* @param {string} url 请求url
* @param {object} data 请求体
* @param {boolean | undefined} info 请求体是否为 FormData 格式
* @returns {Promise}
*/
export function post(url, data = {}, info) {
return new Promise((resolve, reject) => {
let newData = data
if (info) {
// 转formData格式
newData = new FormData()
for (let i in data) {
newData.append(i, data[i])
}
}
axios
.post(url, newData)
.then((res) => {
resolve(res.data)
})
.catch((err) => {
reject(err.data)
})
})
}
/**
* 封装 put 方法,对应 PUT 请求
* @param {string} url 请求url
* @param {object} params 请求体
* @returns {Promise}
*/
export function put(url, params = {}) {
return new Promise((resolve, reject) => {
axios.put(url, params).then(
(res) => {
resolve(res.data)
},
(err) => {
reject(err.data)
}
)
})
}
/**
* 封装 axiosDelete 方法,对应 DELETE 请求
* @param {string} url 请求url
* @param {object} params 请求体
* @returns {Promise}
*/
export function axiosDelete(url, params = {}) {
return new Promise((resolve, reject) => {
axios
.delete(url, params)
.then((res) => {
resolve(res.data)
})
.catch((err) => {
reject(err.data)
})
})
}
// onlyoffice 相关接口
import { post } from './http'
// 创建文档
export const createOfficeFile = (p) => post('/file/createFile', p)
// 编辑文档
export const editOfficeFile = (p) => post('/office/editofficefile', p)
// 查看文档
export const previewOfficeFile = (p) => post('/office/previewofficefile', p)
// 用户信息相关接口
import { get, post } from './http'
/**
* 以登录接口为例
* export const login = p => get('/user/login', p);
*
* login ---------- 接口名称
* p -------------- 传参,若需要在url中拼接其他信息,传参可以改为(p, other)
* get ------------ 接口调用的方法,来自 http.js 中封装好的四个axios方法 get/post/put/axiosDelete
* '/user/login' -- 接口url,若需要在url中拼接其他信息:
* 首先需要在传参处改为(p, other1, other2)
* 然后将url改为`/user/${other1}/login/${other2}`
* p -------------- 传递给 get/post/put/axiosDelete 中的查询参数/请求体
*
*
*
* 除此之外,POST 请求支持请求体格式为 FormData,那么就需要多传递一个参数,true,如下示例:
* export const example = p => post('/test/example', p, true);
*/
// 用户登录
export const login = (p) => get('/user/login', p)
// 获取登录状态及用户信息
export const checkUserLoginInfo = (p) => get('/user/checkuserlogininfo', p)
// 用户注册
export const addUser = (p) => post('/user/register', p)
// 获取微信订阅号认证状态
export const getWeChatAuthState = (p) => get('/user/checkWxAuth', p)
......@@ -5,7 +5,7 @@ Vue.use(Router)
/* Layout */
import Layout from '@/layout'
import { routers } from './staticRoute'
import { staticRouters } from './staticRoute'
/**
* Note: 路由配置项
......@@ -75,12 +75,7 @@ export const constantRoutes = [
// }
// ]
// },
...routers,
{
path: '/create',
component: () => import('@/views/create/index'),
hidden: true
},
...staticRouters,
{
path: '/user',
component: Layout,
......
import Layout from '@/layout'
export const routers = [
export const staticRouters = [
{
path: '/',
path: '',
component: Layout,
redirect: '/home',
name: 'Home',
meta: {},
redirect: 'index',
children: [
{
path: 'home',
component: () => import('@/views/home/index.vue'),
path: 'index',
component: () => import('@/views/home/index'),
name: 'Index',
meta: {
title: '最近文件',
icon: 'dashboard',
noCache: false,
affix: false
}
meta: { title: '首页', icon: 'dashboard', affix: false }
}
]
},
......@@ -135,5 +128,17 @@ export const routers = [
}
}
]
},
{
path: '/wpsReader',
name: 'WpsReader',
hidden: true,
component: () => import('@/views/read/wpsReader/index.vue'),
},
{
path: '/pdfReader',
name: 'PdfReader',
hidden: true,
component: () => import('@/views/read/pdfReader/index.vue'),
}
]
\ No newline at end of file
......@@ -12,8 +12,11 @@ const getters = {
roles: state => state.user.roles,
permissions: state => state.user.permissions,
permission_routes: state => state.permission.routes,
topbarRouters:state => state.permission.topbarRouters,
defaultRoutes:state => state.permission.defaultRoutes,
sidebarRouters:state => state.permission.sidebarRouters,
topbarRouters: state => state.permission.topbarRouters,
defaultRoutes: state => state.permission.defaultRoutes,
sidebarRouters: state => state.permission.sidebarRouters,
//奇文
fileModel: state => state.fileList.fileModel,
}
export default getters
import { getViewUrlDbPath } from '@/api/doc/index'
import { getViewUrlDbPath } from '@/api/wps'
/**
* 下载文件
......@@ -114,6 +114,7 @@ export function changeURLArg(url, arg, arg_val) {
* @return {void}
*/
export function openFile(file, $el, localStorage, flag = false) {
// debugger
const { id, docId, fileType, docSType, name, showType, url, contentType } = file
if (contentType == 'pdf' || showType == 'pdf' && url) {
let query = {
......@@ -124,7 +125,7 @@ export function openFile(file, $el, localStorage, flag = false) {
title: name
}
let resolve = $el.$router.resolve({
path: '/read',
path: '/pdfReader',
query: query
})
window.open(resolve.href, '_blank')
......@@ -142,7 +143,7 @@ export function openFile(file, $el, localStorage, flag = false) {
localStorage.wpsUrl = res.data.wpsUrl
localStorage.token = res.data.token
let resolve = $el.$router.resolve({
path: '/write',
path: '/wpsReader',
query: {
wpsUrl: res.data.wpsUrl,
token: res.data.token
......@@ -152,4 +153,5 @@ export function openFile(file, $el, localStorage, flag = false) {
}
})
}
}
\ No newline at end of file
}
/**
* 存放工程配置项
* @author 李雅婷
*/
const qwConfig = {
/**
* @description 域名
* 区分生产环境和开发环境,用来存放session及一些用户配置信息(左侧菜单栏是否收缩等)
* 冒号之前配置生产环境域名
* 冒号之后配置开发环境域名,开发环境域名默认使用主机名
*/
domain:
process.env.NODE_ENV === 'production'
? location.host.indexOf('.qiwenshare.com') !== -1
? '.qiwenshare.com'
: ''
: location.hostname,
/**
* 网站名称
*/
siteName:
process.env.NODE_ENV === 'production' &&
location.host.indexOf('.qiwenshare.com') !== -1
? '奇文网盘'
: '网盘名称',
/**
* 请求后台接口 URL 代理时的上下文
* @description 仅适用于本地开发环境代理时使用,
* 生产环境需要在 nginx 配置中将 /api/ 代理到生产环境后台地址
* 对应 vue.config.js 中配置的 devServer.proxy 中的代理之一
* 若修改了此值,请同步修改 vue.config.js 中 devServer.proxy 对应的值
*/
baseContext: '/api',
/**
* 存放 token 时的命名方式
*/
tokenKeyName: 'token'
}
export default qwConfig
<template>
<div>
<!-- <headers /> -->
<div>
<div id="viewFile"></div>
<div id="tool">
<div class="title">
<i class="el-icon-edit-outline"></i>
我的笔记
</div>
<div class="filter">
<el-input
@change="search"
clearable
placeholder="书名搜索"
prefix-icon="el-icon-search"
v-model="keyword"
>
</el-input>
</div>
<div class="bookList">
<el-tabs
v-model="activeName"
ref="tabs"
@tab-click="tabClick"
type="border-card"
class="myTags"
>
<el-tab-pane label="按文档归类" name="按文档归类">
<el-collapse
ref="collapse"
accordion
v-loading="isShowBookListLoading"
@change="getBookMark"
>
<el-collapse-item
class="collapseIcon"
v-loading="item.loading"
:name="i"
v-for="(item, i) in bookList"
:key="i"
>
<span slot="title" :title="item.name">
{{ item.name.split(".")[0] }}
</span>
<div class="content">
<list
:data="item.markList"
@removeMark="removeMark($event, i)"
@editMark="editMark($event, i)"
@redirect="redirect(item)"
@insert="jump($event)"
/>
<div
class="toTop"
@click="backTop($event)"
v-if="item.markList.length > 3"
>
返回顶部
</div>
</div>
</el-collapse-item>
</el-collapse>
</el-tab-pane>
<el-tab-pane label="按标签归类" name="按标签归类">
<el-collapse
v-if="this.activeName === '按标签归类'"
v-model="collapseTagActive"
ref="collapseTag"
accordion
v-loading="isShowBookListLoading"
@change="getBookMarkByTag"
>
<el-collapse-item
class="collapseIcon"
v-loading="item.loading"
:name="i"
v-for="(item, i) in tagList"
:key="i"
>
<span slot="title" :title="item.tagName">
<i class="el-icon-price-tag" />
{{ item.name }}
</span>
<div class="content">
<list
:data="item.markList"
@removeMark="removeMark($event, i)"
@addTags="addTags($event)"
@editMark="editMark($event, i)"
@redirect="redirect(item)"
@insert="jump($event)"
/>
<div
class="toTop"
@click="backTop($event)"
v-if="item.tagList && item.tagList.length > 3"
>
返回顶部
</div>
</div>
</el-collapse-item>
</el-collapse>
</el-tab-pane>
</el-tabs>
<h1
v-if="isShowBookListLoading === false && bookList.length === 0"
style="margin-top: 160px; text-align: center; color: #909399"
>
暂无数据
</h1>
<el-backtop target=".bookList" :visibility-height="1"></el-backtop>
</div>
<div class="Pagination">
<el-pagination
prev-text="上一页"
next-text="下一页"
@current-change="handleCurrentChange"
:current-page="page.index"
:page-size="page.size"
layout="total, prev, next, jumper"
:total="page.total"
>
</el-pagination>
</div>
</div>
</div>
<!--添加笔记窗口-->
<note-window
:dialogVisible="dialogVisible"
@addNode="updateMark"
v-if="dialogVisible"
/>
</div>
</template>
<script>
import {
getBookList,
getBookMark,
addOrUpdate,
removeMark,
tagPage,
getBookMarkByTag,
} from "@/api/doc/wpsApi";
import WebOfficeSDK from "/public/weboffice/web-office-sdk-v1.1.8.es.js";
import { openFile } from "@/utils/file";
export default {
name: "write",
components: {
// headers: () => import("../../src/components/header.vue"),
list: () => import("@/components/NoteList/index.vue"),
noteWindow: () => import("@/components/NoteWindow/index.vue"),
},
data() {
return {
collapseTagActive: [0],
activeName: "按文档归类",
dialogVisible: false,
markNode: "",
keyword: "",
isShowBookListLoading: true,
isSetMarkLoading: false, //判断笔记修改是否结束
page: {
size: 6,
total: 10, //总条数
index: 1,
},
node: {
docId: "",
id: undefined,
nodeId: "",
text: "",
keyword: "",
anchorOffset: 0,
icon: "node",
docIndex: 0,
markIndex: 0,
},
wps: null,
simpleMode: false,
bookList: [],
tagList: [],
};
},
methods: {
addTags(e) {
debugger;
},
async tabClick(e, event) {
this.page.index = 1;
if (event.currentTarget.innerText === "按文档归类") {
await this.getBookList();
} else {
await this.getTagList();
}
},
redirect(e) {
openFile(e, this, localStorage);
},
handleClose(done) {
this.$confirm("确认关闭?")
.then((_) => {
done();
})
.catch((_) => {});
},
handleCurrentChange(e) {
this.page.index = e;
this.getBookList();
},
removeMark(e, index) {
let formData = new FormData();
formData.append("id", e);
removeMark(formData).then((res) => {
if (res.code !== 200) {
return;
}
for (let i = this.bookList[index].markList.length - 1; i >= 0; i--) {
let item = this.bookList[index].markList[i];
if (item.id === e) {
this.bookList[index].markList.splice(i, 1);
if (this.bookList[index].markList.length === 0) {
this.bookList.splice(index, 1);
}
}
}
});
},
updateMark() {
let _this = this;
let formData = new FormData();
formData.append("bookmarkContent", this.node.keyword);
formData.append("docId", this.node.docId);
formData.append("id", this.node.id);
formData.append("noteContent", this.node.text);
formData.append("offset", this.node.anchorOffset);
formData.append("sectionId", this.node.nodeId);
formData.append("type", 1);
_this.isSetMarkLoading = true;
addOrUpdate(formData).then((res) => {
_this.$message.success(res.message);
_this.dialogVisible = false;
if (res.message === "操作成功!") {
_this.bookList[_this.node.docIndex].markList[
_this.node.markIndex
].detail[0].value = _this.node.text;
_this.isSetMarkLoading = false;
}
});
},
editMark(e, index) {
this.dialogVisible = true;
let _this = this;
let target = this.bookList[index];
target.markList.forEach((res, i) => {
if (res.id === e) {
_this.node.text = res.detail[0].value;
_this.node.keyword = res.detail[1].value;
_this.node.anchorOffset = res.anchorOffset;
_this.node.id = res.id;
_this.node.nodeId = res.nodeId;
_this.node.docId = _this.bookList[index].id;
_this.node.docIndex = index;
_this.node.markIndex = i;
}
});
},
backTop(e) {
e.target.parentElement.parentElement.parentElement.scrollTop = 0;
},
async openWps(url, token) {
this.wps = WebOfficeSDK.config({
wpsUrl: url, // 如果需要通过js-sdk传递token方式鉴权,则需要包含_w_tokentype=1参数
mount: document.querySelector("#viewFile"),
});
this.wps.setToken({ token });
this.wps.ready();
},
async jump(e) {
let txt = "";
if (e.detail[0].icon === "note") {
txt = e.detail[1].value;
} else {
txt = e.detail[0].value;
}
await this.wps
.WordApplication()
.ActiveDocument.ActiveWindow.Selection.InsertAfter(txt);
},
async search() {
if (this.$refs["tabs"].currentName === "按文档归类") {
await this.getBookList();
} else {
await this.getTagList();
}
},
async getBookList() {
this.$refs.collapse.setActiveNames(0);
this.isShowBookListLoading = true;
let params = {
keyword: this.keyword,
pageNo: this.page.index,
pageSize: this.page.size,
};
let _this = this;
await getBookList(params).then((res) => {
_this.bookList = [];
res.result.records.forEach((item) => {
if (item) {
let model = {
loading: false,
icon: item.showType,
showType: item.showType,
name: item.name,
id: item.id,
docSType: item.docSType,
collected: item.collected,
url: item.url,
markList: [],
};
_this.bookList.push(model);
}
});
if (_this.bookList.length !== 0) {
_this.getBookMark(0);
}
console.log("_this.bookList", _this.bookList);
_this.page.index = parseInt(res.result.pageNo);
_this.page.total = parseInt(res.result.totalElements);
_this.isShowBookListLoading = false;
});
},
getBookMark(e) {
if (e === "" || this.bookList.length === 0) {
return;
}
let _this = this;
let params = {
docId: this.bookList[e].id,
docSType: this.bookList[e].docSType,
};
if (this.bookList[e].markList.length === 0) {
this.bookList[e].loading = true;
getBookMark(params).then((res) => {
this.bookList[e].markList = this.resDataFormate(res.result.data);
_this.bookList[e].loading = false;
});
}
},
async getTagList() {
this.isShowBookListLoading = true;
this.collapseTagActive = 0;
let p = {
keyword: this.keyword,
pageNo: this.page.index,
pageSize: this.page.size,
};
await tagPage(p).then((res) => {
this.tagList = [];
res.result.records.forEach((item) => {
if (item) {
let model = {
name: item.tagName,
id: item.id,
loading: false,
docSType: item.docSType,
collected: item.collected,
url: item.url,
markList: [],
};
this.tagList.push(model);
}
});
this.getBookMarkByTag(0);
this.page.index = parseInt(res.result.pageNo);
this.page.total = parseInt(res.result.totalElements);
this.isShowBookListLoading = false;
});
},
resDataFormate(e) {
let res = [];
e.forEach((item) => {
let detail = [];
if (item.type === "note") {
detail = [
{
key: "笔记",
value: item.noteContent || "无",
icon: "note",
},
{
key: "原文",
value: item.bookmarkContent || "无",
icon: "read",
},
];
} else if (item.type === "highlight") {
detail = [
{
key: "高亮",
value: item.bookmarkContent,
icon: "heigh",
},
];
} else {
detail = [
{
key: "下划线",
value: item.bookmarkContent,
icon: "underline",
},
];
}
let model = {
id: item.id,
userName: this.$store.state.currentUser.userInfo.username,
time: item.updateTime,
anchorOffset: item.offset,
nodeId: item.sectionId,
detail: detail,
};
res.push(model);
});
return res;
},
getBookMarkByTag(e) {
if (e !== "") {
if (
this.tagList.length !== 0 &&
this.tagList[e].markList.length === 0
) {
this.isShowBookListLoading = true;
let p = {
tagName: this.tagList[e].name,
pageNo: this.page.index,
pageSize: 100,
};
getBookMarkByTag(p).then((res) => {
if (res?.result?.data) {
this.tagList[e].markList = this.resDataFormate(res.result.data);
}
this.isShowBookListLoading = false;
});
}
}
},
},
mounted() {
this.getBookList();
this.openWps(this.$route.query.wpsUrl, this.$route.query.token);
},
};
</script>
<style lang="scss">
/*滚动条样式*/
::-webkit-scrollbar {
height: 10px;
width: 8px;
}
::-webkit-scrollbar-thumb {
background-color: #c6c6c6;
background-clip: padding-box;
border-radius: 8px;
min-height: 24px;
}
::-webkit-scrollbar-track {
border: 2px solid #fff;
border-radius: 5px;
background: transparent;
}
.collapseIcon {
.el-collapse-item__header {
border-bottom: 1px solid #f2f4f7 !important;
background-color: #ffffff !important;
padding-left: 0 !important;
}
.el-collapse-item__wrap {
overflow-y: auto !important;
max-height: 480px !important;
}
}
.bookList {
.myTags {
margin-top: -1px;
.is-top {
border: 0;
}
.el-tabs__nav {
width: 100%;
}
.el-tabs__item {
text-align: center;
width: 50%;
}
.el-tabs__content {
padding: 0 !important;
}
.el-collapse-item__header {
margin-left: 15px;
}
}
.collapseIcon {
}
.tools {
i {
font-size: 19px !important;
}
}
}
#viewFile {
iframe {
width: 100% !important;
}
}
</style>
<style lang="scss" scoped>
#viewFile {
float: left;
width: 1508px;
height: calc(100vh - 70px);
overflow: hidden;
}
#tool {
width: 410px;
height: calc(100vh - 70px);
overflow: hidden;
& > .title {
line-height: 62px;
color: #409eff;
font-size: 20px;
width: 100%;
height: 62px;
text-align: center;
border-bottom: 1px solid #e2e6ed;
}
& > .bookList {
height: 738px;
overflow-y: auto;
}
& > .filter {
}
& > .Pagination {
text-align: center;
}
.collapseIcon {
span {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
font-weight: normal !important;
width: 320px;
font-size: 16px;
& > .fileIcon {
margin-left: 20px;
width: 20px;
height: 26px;
vertical-align: middle;
fill: currentColor;
overflow: hidden;
}
}
.content {
width: 374px;
margin: 10px 0 0 50%;
transform: translateX(-50%);
& > .toTop {
float: right;
cursor: pointer;
color: #46a3ff;
}
}
}
}
</style>
......@@ -42,10 +42,14 @@
<div class="title">最近编辑</div>
<el-card shadow="never">
<template #header>
<span class="card-more"> 更多 </span>
<span class="card-more" @click="handleToCreate"> 更多 </span>
</template>
<el-table :data="createList.records" size="small">
<el-table-column width="400px" label="名称" prop="name" />
<el-table-column width="400px" label="名称" prop="name">
<template slot-scope="scope">
<svg-icon icon-class="word"></svg-icon>
</template>
</el-table-column>
<el-table-column label="作者" prop="author" />
<el-table-column label="修改时间" prop="modifyTime" />
</el-table>
......@@ -55,19 +59,20 @@
<div class="title">最近浏览</div>
<el-card shadow="never">
<template #header>
<span class="card-more"> 更多 </span>
<span class="card-more" @click="handleToRead"> 更多 </span>
</template>
<el-table
:data="readList.records"
size="small"
@row-click="handleRowClick"
>
<el-table-column
width="400px"
label="名称"
show-overflow-tooltip
prop="name"
/>
<el-table :data="readList.records" size="small">
<el-table-column width="400px" label="名称">
<template slot-scope="{ row }">
<span class="name" @click="handleClickName(row)"
><svg-icon
style="margin-right: 4px"
:icon-class="getIcon(row)"
></svg-icon>
{{ row.name }}</span
>
</template>
</el-table-column>
<el-table-column label="作者" prop="author" />
<el-table-column label="创建时间" prop="createTime" />
</el-table>
......@@ -78,12 +83,8 @@
</div>
</template>
<script>
import {
getNearRead,
getNearCreation,
newfile,
newfileTemplate,
} from "@/api/doc/index";
import { getNearRead, getNearCreation } from "@/api/home";
import { newfile, newfileTemplate } from "@/api/wps";
import { fileTypes } from "./constants";
import { openFile } from "@/utils/file";
export default {
......@@ -102,6 +103,18 @@ export default {
loading: false,
};
},
computed: {
getIcon(row) {
return (row) => {
const { showType } = row;
if (["doc", "docx", "word"].includes(row.showType)) {
return "word";
} else if (["pdf"].includes(row.showType)) {
return "pdf-color";
}
};
},
},
mounted() {
this.loadNearRead();
this.loadNearCreation();
......@@ -201,11 +214,17 @@ export default {
// });
// }
},
// 点击某一行
handleRowClick(row) {
// 点击表格某一行
handleClickName(row) {
console.log("row", row);
openFile(row, this, localStorage);
},
handleToCreate() {
this.$router.push("/mine/myCreate");
},
handleToRead() {
this.$router.push("/resource/internal");
},
},
};
</script>
......@@ -236,6 +255,12 @@ export default {
justify-content: flex-end;
cursor: pointer;
}
.name {
cursor: pointer;
&:hover {
color: $theme-blue;
}
}
.content {
display: flex;
.svg-icon {
......
export const mockNote = {
"data": [
{
"bookmarkContent": "青霞写自己的故事《窗里窗外》\n文 /林 皓",
"color": "#E44234",
"coords": "99.8938,657.0830000000001,299.02735,657.0830000000001,99.8938,642.143,299.02735,642.143,266.17,633.609,303.627,633.609,266.17,625.641,303.627,625.641",
"createTime": "2023-07-10 19:40:56",
"docId": "2c98e4068479d17c018479d2300d03bb",
"docName": "江湖一窗隔——读林青霞写自己的故事《窗里窗外》",
"docSType": "s_type_kbase",
"flags": "print",
"id": "1678368702654341121",
"isDelete": 0,
"mdate": "D:20230710194131+08'00'",
"page": 0,
"rect": "99.8938,625.641,303.627,657.0830000000001",
"showType": "pdf",
"subject": "下划线",
"title": "zys",
"type": "underline",
"uniqueId": "5740e065-7a7f-4415-4570-a3e17f8c0bdc",
"updateTime": "2023-07-10 19:40:56",
"userId": "1677150454842163202"
},
{
"bookmarkContent": "师眼里,她是不化妆就能直接上镜的女演\n员。息影18年,林青霞复出了,以一个作家身份。\n什么是大腕?大腕就是她不在江湖,江湖仍有她\n的传说。林青霞的新书《窗里窗外》一枝独秀,成为书展\n的最大热门,几乎横扫了国内媒体的重要版面。\n新书发布会上,名导徐克前",
"color": "#FFCD45",
"coords": "177.7397,603.3204999999999,324.2797,603.3204999999999,177.7397,593.7579999999999,324.2797,593.7579999999999,135.49554999999998,589.8905,302.07089999999994,589.8905,135.49554999999998,580.328,302.07089999999994,580.328,153.07100000000003,576.4604999999999,324.28225,576.4604999999999,153.07100000000003,566.8979999999999,324.28225,566.8979999999999,135.49555000000004,563.0305,324.28225000000003,563.0305,135.49555000000004,553.468,324.28225000000003,553.468,135.49555000000004,549.6004999999999,298.6377500000001,549.6004999999999,135.49555000000004,540.0379999999999,298.6377500000001,540.0379999999999,153.07015000000004,536.1705,249.03005000000002,536.1705,153.07015000000004,526.608,249.03005000000002,526.608",
"createTime": "2023-07-10 19:41:57",
"docId": "2c98e4068479d17c018479d2300d03bb",
"docName": "江湖一窗隔——读林青霞写自己的故事《窗里窗外》",
"docSType": "s_type_kbase",
"flags": "print",
"id": "1678368959962308609",
"isDelete": 0,
"mdate": "D:20230710194233+08'00'",
"page": 0,
"rect": "135.49554999999998,526.608,324.28225000000003,603.3204999999999",
"showType": "pdf",
"subject": "高亮",
"title": "zys",
"type": "highlight",
"uniqueId": "edb5c450-1823-df59-b635-14385ca14770",
"updateTime": "2023-07-10 19:41:57",
"userId": "1677150454842163202"
},
{
"bookmarkContent": "出道以来发生的难忘故事和不为人知的内心世界,还有\n200张珍贵照片。据悉,这部书编辑历经800多天,出版\n方和林青霞多次切磋琢磨,林青霞像是用文火煨出来的",
"color": "#E44234",
"coords": "346.96014999999994,563.03065,535.74685,563.03065,346.96014999999994,553.46815,535.74685,553.46815,346.96014999999994,549.6006500000001,535.7476999999999,549.6006500000001,346.96014999999994,540.0381500000001,535.7476999999999,540.0381500000001,346.961,536.17065,535.7494000000002,536.17065,346.961,526.60815,535.7494000000002,526.60815",
"createTime": "2023-07-19 11:15:57",
"docId": "2c98e4068479d17c018479d2300d03bb",
"docName": "江湖一窗隔——读林青霞写自己的故事《窗里窗外》",
"docSType": "s_type_kbase",
"flags": "print",
"id": "1681503111993643010",
"isDelete": 0,
"mdate": "D:20230719111557+08'00'",
"page": 0,
"rect": "346.96014999999994,526.60815,535.7494000000002,563.03065",
"showType": "pdf",
"subject": "下划线",
"title": "zys",
"type": "underline",
"uniqueId": "7c226c04-4fe2-4be3-6959-8b0dc67086de",
"updateTime": "2023-07-19 11:15:57",
"userId": "1677150454842163202"
},
{
"bookmarkContent": "曾有许多个凌晨深夜,香港著名作家马家辉被传真\n机呜呜响声吵醒,“不必查看即猜得到",
"color": "#E44234",
"coords": "364.53559999999993,321.29150000000027,535.7476999999999,321.29150000000027,364.53559999999993,311.72900000000027,535.7476999999999,311.72900000000027,346.96184999999997,307.86150000000026,475.35434999999995,307.86150000000026,346.96184999999997,298.29900000000026,475.35434999999995,298.29900000000026",
"createTime": "2023-07-19 11:21:23",
"docId": "2c98e4068479d17c018479d2300d03bb",
"docName": "江湖一窗隔——读林青霞写自己的故事《窗里窗外》",
"docSType": "s_type_kbase",
"flags": "print",
"id": "1681504477076017154",
"isDelete": 0,
"mdate": "D:20230719112121+08'00'",
"page": 0,
"rect": "346.96184999999997,298.29900000000026,535.7476999999999,321.29150000000027",
"showType": "pdf",
"subject": "下划线",
"title": "zys",
"type": "underline",
"uniqueId": "120e420f-12e7-0d9c-40cd-a33fafc83b3d",
"updateTime": "2023-07-19 11:21:23",
"userId": "1677150454842163202"
}
],
"xml": [
"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n<xfdf xmlns=\"http://ns.adobe.com/xfdf/\" xml:space=\"preserve\">\r\n<fields />\r\n<add><underline page=\"0\" rect=\"99.8938,625.641,303.627,657.0830000000001\" color=\"#E44234\" flags=\"print\" name=\"5740e065-7a7f-4415-4570-a3e17f8c0bdc\" title=\"zys\" subject=\"下划线\" date=\"D:20230710194131+08'00'\" creationdate=\"D:20230710194131+08'00'\" coords=\"99.8938,657.0830000000001,299.02735,657.0830000000001,99.8938,642.143,299.02735,642.143,266.17,633.609,303.627,633.609,266.17,625.641,303.627,625.641\"><contents>青霞写自己的故事《窗里窗外》\r\n文 /林 皓</contents></underline></add>\r\n<modify />\r\n<delete />\r\n</xfdf>",
"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n<xfdf xmlns=\"http://ns.adobe.com/xfdf/\" xml:space=\"preserve\">\r\n<fields />\r\n<add><highlight page=\"0\" rect=\"135.49554999999998,526.608,324.28225000000003,603.3204999999999\" color=\"#FFCD45\" flags=\"print\" name=\"edb5c450-1823-df59-b635-14385ca14770\" title=\"zys\" subject=\"高亮\" date=\"D:20230710194233+08'00'\" creationdate=\"D:20230710194233+08'00'\" coords=\"177.7397,603.3204999999999,324.2797,603.3204999999999,177.7397,593.7579999999999,324.2797,593.7579999999999,135.49554999999998,589.8905,302.07089999999994,589.8905,135.49554999999998,580.328,302.07089999999994,580.328,153.07100000000003,576.4604999999999,324.28225,576.4604999999999,153.07100000000003,566.8979999999999,324.28225,566.8979999999999,135.49555000000004,563.0305,324.28225000000003,563.0305,135.49555000000004,553.468,324.28225000000003,553.468,135.49555000000004,549.6004999999999,298.6377500000001,549.6004999999999,135.49555000000004,540.0379999999999,298.6377500000001,540.0379999999999,153.07015000000004,536.1705,249.03005000000002,536.1705,153.07015000000004,526.608,249.03005000000002,526.608\"><contents>师眼里,她是不化妆就能直接上镜的女演\r\n员。息影18年,林青霞复出了,以一个作家身份。\r\n什么是大腕?大腕就是她不在江湖,江湖仍有她\r\n的传说。林青霞的新书《窗里窗外》一枝独秀,成为书展\r\n的最大热门,几乎横扫了国内媒体的重要版面。\r\n新书发布会上,名导徐克前</contents></highlight></add>\r\n<modify />\r\n<delete />\r\n</xfdf>",
"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n<xfdf xmlns=\"http://ns.adobe.com/xfdf/\" xml:space=\"preserve\">\r\n<fields />\r\n<add><underline page=\"0\" rect=\"346.96014999999994,526.60815,535.7494000000002,563.03065\" color=\"#E44234\" flags=\"print\" name=\"7c226c04-4fe2-4be3-6959-8b0dc67086de\" title=\"zys\" subject=\"下划线\" date=\"D:20230719111557+08'00'\" creationdate=\"D:20230719111557+08'00'\" coords=\"346.96014999999994,563.03065,535.74685,563.03065,346.96014999999994,553.46815,535.74685,553.46815,346.96014999999994,549.6006500000001,535.7476999999999,549.6006500000001,346.96014999999994,540.0381500000001,535.7476999999999,540.0381500000001,346.961,536.17065,535.7494000000002,536.17065,346.961,526.60815,535.7494000000002,526.60815\"><contents>出道以来发生的难忘故事和不为人知的内心世界,还有\r\n200张珍贵照片。据悉,这部书编辑历经800多天,出版\r\n方和林青霞多次切磋琢磨,林青霞像是用文火煨出来的</contents></underline></add>\r\n<modify />\r\n<delete />\r\n</xfdf>",
"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n<xfdf xmlns=\"http://ns.adobe.com/xfdf/\" xml:space=\"preserve\">\r\n<fields />\r\n<add><underline page=\"0\" rect=\"346.96184999999997,298.29900000000026,535.7476999999999,321.29150000000027\" color=\"#E44234\" flags=\"print\" name=\"120e420f-12e7-0d9c-40cd-a33fafc83b3d\" title=\"zys\" subject=\"下划线\" date=\"D:20230719112121+08'00'\" creationdate=\"D:20230719112121+08'00'\" coords=\"364.53559999999993,321.29150000000027,535.7476999999999,321.29150000000027,364.53559999999993,311.72900000000027,535.7476999999999,311.72900000000027,346.96184999999997,307.86150000000026,475.35434999999995,307.86150000000026,346.96184999999997,298.29900000000026,475.35434999999995,298.29900000000026\"><contents>曾有许多个凌晨深夜,香港著名作家马家辉被传真\r\n机呜呜响声吵醒,“不必查看即猜得到</contents></underline></add>\r\n<modify />\r\n<delete />\r\n</xfdf>"
]
}
\ No newline at end of file
<template>
<div class="wrapper">
<div :span="5" class="left">
<el-input
placeholder="搜索文件"
suffix-icon="el-icon-search"
clearable
size="mini"
></el-input>
<div class="total">共计{{ markList.totalElements }}条数据</div>
<el-row class="list">
<el-col
v-for="(item, index) in markList.records"
:key="index"
@click.native="handleClickArticle(item)"
>
<div v-if="item" class="item">
<div class="item-left" :title="item.name">
<svg-icon
:icon-class="getIcon(item)"
style="margin-right: 4px"
></svg-icon>
<span>{{ item.name }}</span>
</div>
<div class="item-right">
<i class="el-icon-more"></i>
</div>
</div>
</el-col>
</el-row>
</div>
<div :span="19" class="right">
<div class="singleArticle" v-if="currentFile.name">
<el-row class="info">
<el-col :span="8" class="center">{{ currentFile.name }}</el-col>
<el-col :span="8" class="center">{{ currentFile.author }}</el-col>
<el-col :span="8" class="center"
><el-button type="text">查看原文</el-button></el-col
>
</el-row>
<div>
<el-card
class="info"
shadow="hover"
v-for="(item, index) in mockNote.data"
:key="index"
>
{{ item }}
</el-card>
</div>
</div>
</div>
</div>
</template>
<script>
import { getBookList, getBookMark } from "@/api/doc/bookMark";
import { mockNote } from "./mockNote";
export default {
data() {
return {
markList: {
records: [],
pageNo: 1,
pageSize: 10,
},
currentFile: {},
mockNote,
};
},
computed: {
getIcon(row) {
return (row) => {
const { showType } = row;
if (["doc", "docx", "word"].includes(row.showType)) {
return "word";
} else if (["pdf"].includes(row.showType)) {
return "pdf-color";
}
};
},
},
mounted() {
this.loadBookMarkList();
},
methods: {
async loadBookMarkList() {
let res = await getBookList();
console.log(res);
if (res.result) {
this.markList = res.result;
}
},
// 点击文章
async handleClickArticle(item) {
this.currentFile = item;
const { id, docSType } = this.currentFile;
const params = {
docId: id,
docSType,
};
const res = await getBookMark(params);
console.log(res);
},
},
};
</script>
<style lang="scss" scoped>
.wrapper,
.left,
.right {
height: 100%;
}
.wrapper {
display: flex;
}
.left {
width: 300px;
background-color: #f2f3f5;
border-right: #fefefe;
height: 100%;
overflow: auto;
padding: 16px 20px;
.total {
padding: 16px 0 0;
font-size: 14px;
}
.list {
font-size: 14px;
padding: 16px 0;
.item {
cursor: pointer;
padding: 8px;
color: #333;
display: flex;
.item-left {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
&:hover {
background-color: #eaebed;
}
}
.active {
color: $theme-blue;
background-color: #d6d8db;
}
}
}
.right {
flex: 1;
padding: 0 16px 16px;
.info {
padding: 16px;
border-bottom: 1px solid #e7e7e7;
margin-bottom: 8px;
.center {
display: flex;
justify-content: center;
}
}
}
</style>
<template>
<div>按标签分类</div>
</template>
<script>
export default {};
</script>
<style lang=""></style>
<template>
<div>测试</div>
<div class="container">
<el-tabs v-model="activeName">
<el-tab-pane name="byFile">
<span slot="label"><i class="el-icon-document"></i> 按文件分类</span>
<NoteByFile />
</el-tab-pane>
<el-tab-pane name="byTag">
<span slot="label"><i class="el-icon-price-tag"></i> 按标签分类</span>
<NoteByTag />
</el-tab-pane>
</el-tabs>
</div>
</template>
<script></script>
<style lang="scss"></style>
<script>
import NoteByFile from "./components/noteByFile.vue";
import NoteByTag from "./components/noteByTag.vue";
export default {
components: {
NoteByFile,
NoteByTag,
},
data() {
return {
activeName: "byFile",
};
},
};
</script>
<style lang="scss" scoped>
.container {
padding: 10px 0;
}
::v-deep .el-tabs__header {
padding: 0 20px;
}
::v-deep .el-tab-pane {
height: calc(100vh - 158px);
}
</style>
<template>
<div>测试</div>
<div>
<el-row v-show="list.length > 0" class="list" :gutter="16">
<el-col
:span="4"
:class="['item']"
v-for="(item, index) in list"
:key="index"
@mouseenter="handleMouseEnter(item)"
@mouseleave="handleMouseLeave()"
>
<div
:class="[
'item-container',
'cursor-pointer',
checkAll ? 'ischeckedAll' : '',
]"
>
<Icon :size="80" :icon="getIconType(item)" class="p-4 mr-4" />
<div class="text-sm text-gray-900">{{ item.name }}</div>
<div class="text-sm text-gray-500">
{{ fileUtil.getFileSize(item.size) }}
</div>
<div class="left-top" v-show="currentItem.id === item.id || checkAll">
<el-checkbox v-model="item.checked" size="large" />
</div>
<div class="right-top" v-show="currentItem.id === item.id">
<!-- <el-popconfirm title="确定分享吗?" @confirm="handleShare(item)" :teleported="false">
<template #reference>
<el-icon class="mr-2" title="分享"><Share /></el-icon>
</template>
</el-popconfirm> -->
<el-icon class="mr-2" title="下载" @click="handleDownload(item)"
><Download
/></el-icon>
<el-dropdown :teleported="false">
<span class="el-dropdown-link">
<el-icon class="more"><MoreFilled /></el-icon>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>
<el-icon><Delete /></el-icon>刪除
</el-dropdown-item>
<el-dropdown-item>
<el-icon><EditPen /></el-icon>编辑
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</div>
</el-col>
</el-row>
<el-empty v-show="list.length == 0"></el-empty>
</div>
<!-- <el-pagination
class="flex justify-end mt-10"
small
background
:current-page="list.pageNo"
:page-size="list.pageSize"
:page-sizes="[10, 20, 50]"
layout="total, sizes, prev, pager, next, jumper"
:total="list.totalElements"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/> -->
</template>
<script></script>
<style lang="scss"></style>
<script>
import { getTemplateList } from "@/api/wps";
export default {
data() {
return {
checkAll: false,
list: [],
currentItem: {
id: "",
name: "",
},
};
},
mounted() {
this.loadData();
},
methods: {
async loadData() {
const params = {};
const res = await getTemplateList(params);
const { w_list } = res;
this.list = w_list;
},
getIconType(item) {
let type = fileUtil.getFileType(item.name);
return `svg-icon:${type}`;
},
handleMouseEnter(item) {
this.currentItem = item;
},
handleMouseLeave() {
this.currentItem = {
id: "",
name: "",
};
},
handleDownload(row) {
const url = fileUtil.getPdfUrl(row.downloadUrl);
const fileName = row.name;
fileUtil.downloadFile(url, fileName);
},
},
};
</script>
<style lang="scss" scoped>
.add {
margin-bottom: 8px;
border-radius: 4px;
.container {
height: 100%;
border-radius: 4px;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
background-color: rgba($color: #1a5eff, $alpha: 4%);
cursor: pointer;
padding: 32px 8px;
.el-icon {
font-size: 38px;
color: var(--el-color-primary);
}
}
}
.item {
margin-bottom: 8px;
border-radius: 4px;
transition: all ease 0.3s;
.item-container {
position: relative;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
padding: 32px 8px;
&:hover {
background-color: rgba($color: #1a5eff, $alpha: 6%);
}
.left-top {
position: absolute;
left: 16px;
top: 0;
}
.right-top {
position: absolute;
right: 16px;
top: 10px;
font-size: 16px;
color: var(--el-color-primary);
.more {
color: var(--el-color-primary);
}
}
}
}
.ischeckedAll {
background-color: rgba($color: #1a5eff, $alpha: 6%);
}
</style>
<template>
<div class="catalogueRoot">
<el-row type="flex" class="title" justify="space-around">
<span>目录</span>
</el-row>
<el-row type="flex" class="tree" justify="space-around">
<el-tree
accordion
:highlight-current="true"
class="eltree"
:data="catalogue"
:props="defaultProps"
@node-click="handleNodeClick"
>
<span slot-scope="{ node, data }">
<span :title="node.label">{{ node.label }}</span>
</span>
</el-tree>
</el-row>
</div>
</template>
<script>
export default {
name: "catalogue",
props: ["catalogue", "pdfDocument"],
data() {
return {
defaultProps: {
children: "items",
label: "title",
},
};
},
methods: {
handleNodeClick(data) {
if (this.$route.query.fileType === "word") {
let dom = document.getElementById("detail");
for (let i = 0; i < dom.children.length; i++) {
this.getScrollTop(
dom.children[i],
data.title,
document.querySelector(".bg")
);
}
} else {
let model = {
gen: data.dest[0].gen,
num: data.dest[0].num,
};
this.pdfDocument.getPageIndex(model).then((res) => {
let target = document.getElementById("page" + (res + 1));
let scrollTop = target.offsetTop;
document.getElementsByClassName("bg")[0].scrollTop = scrollTop;
});
}
this.$emit("titleClick", data);
},
getScrollTop(e, t, d) {
if (e.children.length > 0) {
for (let i = 0; i < e.children.length; i++) {
let dom = e.children[i];
this.getScrollTop(dom, t, d);
}
} else {
if (e.innerText === t) {
if (e.offsetTop === 0) {
d.scrollTop = e.parentElement.offsetTop;
} else {
d.scrollTop = e.offsetTop;
}
}
}
},
},
};
</script>
<style lang="scss">
.el-tree-node__content {
& > span {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
word-break: break-all;
}
}
.el-tree {
color: #000000 !important;
}
.el-tree-node__expand-icon {
color: #000000 !important;
}
.el-tree-node__expand-icon.is-leaf {
color: transparent !important;
cursor: default !important;
}
.eltree {
.is-current > .el-tree-node__content {
color: #247aeb !important;
font-weight: bolder;
}
.el-tree-node__label {
}
}
</style>
<style lang="scss" scoped>
.catalogueRoot {
& > .title {
text-align: center;
height: 62px;
border-bottom: 1px solid #a4a9bd;
& > span {
letter-spacing: 40px;
font-size: 20px;
line-height: 60px;
color: #969b9f;
}
}
& > .tree {
& > .eltree {
height: 814px;
width: 280px;
background-color: transparent;
overflow-x: hidden;
overflow-y: auto;
}
}
}
</style>
<template>
<div class="compareItem" v-loading="loading">
<div class="title">{{ article.name }}</div>
<ul class="tool-bar">
<li title="目录" @click="toolbarClick(1)">
<i class="el-icon-tickets" />
</li>
<li title="笔记" @click="toolbarClick(2)">
<i class="el-icon-notebook-1" />
</li>
</ul>
<!-- <html-content v-if="article.showType !== 'pdf'" @complete="complete" :id="id" @loading="setLoading($event)"
:detail="htmlContent"/> -->
<!-- <readPdf v-else :article="article"/> -->
<readPdf :article="article" />
<el-dialog
width="50vw"
:modal="false"
:append-to-body="true"
:visible.sync="catalogueFlag"
:class="id === 'detailLeft' ? 'catalogueOriginal' : 'catalogueCompare'"
>
<catalogue :catalogue="catalogue" @titleClick="titleClick($event)" />
</el-dialog>
<!--添加笔记窗口-->
<note-window
:dialogVisible="dialogVisible"
@addNode="addNode"
v-if="dialogVisible"
/>
</div>
</template>
<script>
import { addOrUpdate, getBookMark, removeMark } from "@/api/doc/bookMark";
import { catlog, detail } from "@/api/doc/index";
import EasyMarker from "easy-marker";
// import Mark from "../../../node_modules/mark.js/dist/mark";
export default {
name: "compareItem",
props: ["article", "id", "compareWindowFlag"],
components: {
// htmlContent: () => import('./htmlContent'),
catalogue: () => import("./catalogue"),
noteWindow: () => import("./noteWindow"),
readPdf: () => import("./readPdf"),
},
data() {
return {
dialogVisible: false,
loading: false,
catalogue: [],
catalogueFlag: false,
htmlContent: undefined,
notes: [],
markIndex: 0,
node: {
flag: true, // 判断是否是新增笔记
text: "",
keyword: "",
anchorOffset: "",
id: undefined,
icon: "note",
},
};
},
watch: {
compareWindowFlag(c, o) {
if (c) {
this.getNotes();
this.getContent();
}
},
},
methods: {
addNode() {
let keyword = this.node.keyword;
let anchorOffset = this.node.anchorOffset;
let id = this.node.id;
let index = 0;
this.markList.forEach((item, i) => {
if (item.id === id) {
index = i;
}
});
if (this.node.flag) {
this.setNode(keyword, anchorOffset, id);
} else {
let formData = new FormData();
formData.append("id", this.markList[index].uid);
formData.append("noteContent", this.node.text);
addOrUpdate(formData).then((res) => {
if (res.code === 200) {
this.markList[index].detail[0].value = this.node.text;
this.$message.success("修改成功!");
}
});
}
this.dialogVisible = false;
},
setLoading(e) {
this.loading = e;
},
toolbarClick(e) {
//1:目录,2:笔记
if (e === 1) {
this.catalogueFlag = true;
this.setCatalogue();
} else {
}
},
setCatalogue() {
if (this.catalogue.length !== 0) {
return;
}
let p = {
id: this.article.id,
};
catlog(p).then((res) => {
if (res.code === 200) {
this.catalogue = res.result.catalog;
}
});
},
complete() {
this.playLine();
this.markInit();
},
playLine() {
let root = this;
let em = new EasyMarker({
menuTopOffset: "0.12rem",
scrollSpeedLevel: 1,
scrollOffsetBottom: "1.5rem",
mask: {
color: "#407ff2",
// color: 'transparent'
},
highlight: {
color: "red",
},
menuStyle: {
menu: {
backgroundColor: "#545454",
padding: "0px 0.05rem",
borderRadius: "0.05rem",
},
item: {
fontSize: "15px",
padding: "0px 10px",
lineHeight: "30px",
backgroundColor: "#545454",
cursor: "pointer",
},
triangle: {
borderTop: "0.1rem solid rgb(84 84 84)",
},
},
menuItems: [
{
text: "划线",
id: "1",
},
{
text: "高亮",
id: "2",
},
{
text: "笔记",
id: "3",
},
{
text: "复制",
id: "4",
},
],
});
em.onMenuClick(function (id, data) {
if (root.$store.state.currentUser === null) {
root.$message.error("用户未登录或者登录过期,请重新登录!");
return;
}
let keyword = data.anchorNode.textContent.slice(
data.anchorOffset,
data.focusOffset
);
let index = 0;
if (data.anchorNode.parentNode.childNodes.length === 1) {
index = 0;
} else {
for (
let i = 0;
i < data.anchorNode.parentNode.childNodes.length;
i++
) {
let item = data.anchorNode.parentNode.childNodes[i];
if (item.textContent === data.anchorNode.textContent) {
break;
}
index += item.textContent.length;
}
}
if (id === "1") {
root.setUnderine(
keyword,
data.anchorOffset + index,
data.anchorNode.parentElement.getAttribute("id")
);
} else if (id === "2") {
root.setHighlight(
keyword,
data.anchorOffset + index,
data.anchorNode.parentElement.getAttribute("id")
);
} else if (id === "3") {
root.node.anchorOffset = data.anchorOffset + index;
root.node.keyword = keyword;
root.node.id = data.anchorNode.parentElement.getAttribute("id");
root.node.text = "";
root.dialogVisible = true;
} else if (id === "4") {
const input = document.createElement("INPUT");
input.style.opacity = "0";
input.style.position = "absolute";
document.body.appendChild(input);
if (data.anchorNode === data.focusNode) {
input.value = keyword;
} else {
input.value =
data.anchorNode.textContent.slice(data.anchorOffset) +
data.focusNode.textContent.slice(0, data.focusOffset);
}
input.select();
if (root.flag) {
root.flag = false;
document.execCommand("copy");
document.body.removeChild(input);
root.$message.success("复制成功");
}
} else {
root.$message.success("纠错");
}
});
em.onSelectStatusChange((val) => {
if (val === "finish") {
root.flag = true;
}
});
em.create(document.querySelector("#" + this.id), null);
document.getElementById(this.id).setAttribute("style", "");
document.querySelector("#" + this.id).onclick = (e) => {
let points = document
.querySelector("#" + this.id + " svg")
.children[0].getAttribute("points");
let style = document
.querySelector("#" + this.id + " svg")
.getAttribute("style");
if (points !== "") {
document
.querySelector("#" + this.id + " svg")
.setAttribute("style", style.replace(/display:none;/g, ""));
} else {
document
.querySelector("#" + this.id + " svg")
.setAttribute("style", style + "display:none;");
}
};
},
markInit() {
this.notes.forEach((item) => {
item.detail.forEach((target) => {
if (target.icon === "underline") {
this.setUnderine(
target.value,
parseInt(item.anchorOffset),
item.nodeId,
false
);
} else if (target.icon === "highlight") {
this.setHighlight(
target.value,
parseInt(item.anchorOffset),
item.nodeId,
false
);
} else if (target.icon === "read") {
this.setNode(
target.value,
parseInt(item.anchorOffset),
item.nodeId,
false
);
}
});
});
},
titleClick(e) {
this.catalogueFlag = false;
let dom = document.getElementById(this.id);
for (let i = 0; i < dom.children.length; i++) {
if (this.id === "detailLeft") {
this.getScrollTop(
dom.children[i],
e.title,
document.querySelector(".left")
);
} else {
this.getScrollTop(
dom.children[i],
e.title,
document.querySelector(".right")
);
}
}
},
getScrollTop(e, t, d) {
if (e.children.length > 0) {
for (let i = 0; i < e.children.length; i++) {
let dom = e.children[i];
this.getScrollTop(dom, t, d);
}
} else {
if (e.innerText === t) {
if (e.offsetTop === 0) {
d.scrollTop = e.parentElement.offsetTop + 120;
} else {
d.scrollTop = e.offsetTop + 120;
}
}
}
},
async getNotes() {
this.notes = [];
let p = {
docId: this.article.id,
docSType: this.article.docSType,
};
await getBookMark(p).then((res) => {
if (res.code === 200) {
let result = this.NotesListFormater(res.result.data);
this.notes = result;
} else {
this.$message.error(res.message);
}
});
},
NotesListFormater(e) {
let result = [];
e.forEach((item, i) => {
let detail = [];
if (item.type === "underline") {
detail = [
{
key: "下划线",
value: item.bookmarkContent,
icon: "underline",
},
];
} else if (item.type === "highlight") {
detail = [
{
key: "高亮",
value: item.bookmarkContent,
icon: "highlight",
},
];
} else {
detail = [
{
key: "笔记",
value: item.noteContent,
icon: "note",
},
{
key: "原文",
value: item.bookmarkContent,
icon: "read",
},
];
}
let model = {
id: "mark" + i,
userName: this.$store.state.currentUser.userInfo.username,
time: item.updateTime,
anchorOffset: item.offset,
nodeId: item.sectionId,
detail: detail,
uid: item.id,
};
result.push(model);
});
return result;
},
getOption(className, anchorOffset, node) {
let root = this;
let options = {
node: node,
anchorOffset: anchorOffset,
element: "marker",
className: className,
exclude: [],
separateWordSearch: false,
accuracy: "partially",
diacritics: true,
synonyms: {},
iframes: false,
iframesTimeout: 5000,
acrossElements: false,
caseSensitive: false,
ignoreJoiners: false,
ignorePunctuation: [],
wildcards: "disabled",
each: (e) => {
let index = "mark" + root.markIndex++;
e.setAttribute("id", index);
let icon = document.createElement("mycon");
if (className !== "marknode") {
icon.setAttribute("class", "note-co-o");
e.addEventListener("click", (e) => {
root.iconClick(e);
});
} else {
icon.setAttribute("class", "note-co-b");
}
e.setAttribute("style", "cursor:pointer");
e.addEventListener("mouseover", (e) => {
root.markMouseOver(e);
});
icon.setAttribute("name", index);
icon.addEventListener("click", (e) => {
root.iconClick(e);
});
let parent = e.parentNode;
if (parent.lastChild === e) {
// 如果最后的节点是目标元素,则直接添加。因为默认是最后
parent.appendChild(icon);
} else {
// 如果不是,则插入在目标元素的下一个兄弟节点 的前面。也就是目标元素的后面
parent.insertBefore(icon, e.nextSibling);
}
},
filter: function (textNode, foundTerm, totalCounter, counter) {
let current = root.findStr(
this.node.textContent,
foundTerm.toString(),
++this.index
);
if (current === this.anchorOffset) {
if (textNode.parentNode.localName === "marker") {
return false;
}
return true; // must return either true or false
} else {
return false;
}
},
noMatch: function (term) {
// term is the not found term
},
done: function (counter) {},
debug: false,
log: window.console,
};
return options;
},
markMouseOver(e) {
let target = e.currentTarget.getAttribute("id");
let menuBg = document.createElement("div");
let item = document.createElement("div");
if (e.isTrusted && e.currentTarget.getAttribute("class") === "marknode") {
menuBg.innerHTML = this.notes.find(
(n) => n.id === target
).detail[0].value;
menuBg.appendChild(item);
menuBg.style.width = "160px";
menuBg.style.left =
(e.target.offsetLeft + e.target.offsetWidth / 2) * 0.01 + "rem";
menuBg.style.top = (e.target.offsetTop - 6) * 0.01 + "rem";
menuBg.id = "tooltip";
document.getElementById(this.id).appendChild(menuBg);
e.stopPropagation();
}
e.target.onmouseleave = (a) => {
if (a.isTrusted) {
let dom = document.getElementById("tooltip");
if (dom !== null) {
dom.remove();
document.onclick = null;
}
}
};
},
iconClick(e) {
if (e.isTrusted) {
let dom = document.getElementById("menu");
if (dom !== null) {
dom.remove();
document.onclick = null;
}
let root = this;
let target =
e.currentTarget.getAttribute("name") === null
? e.currentTarget.getAttribute("id")
: e.currentTarget.getAttribute("name");
let menuBg = document.createElement("div");
let menu = document.createElement("div");
let bg = document.createElement("div");
let item = document.createElement("span");
let height = 0;
if (this.id === "detailLeft") {
height = document.getElementsByClassName("left")[0].scrollTop;
} else {
height = document.getElementsByClassName("right")[0].scrollTop;
}
item.innerText = "删除";
item.addEventListener("click", (p) => {
if (p.isTrusted) {
let targetMenu = p.currentTarget.parentElement.parentElement;
root
.$confirm("此操作将永久删除该记录, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
targetMenu.remove();
root.removeMark(target);
})
.catch(() => {
this.$message({
type: "info",
message: "已取消删除",
});
});
}
});
menu.appendChild(item);
let left = 96;
let offsetLetf = 14;
let top = 110;
let offsetTop = 28;
menu.style.left = (e.clientX - left - offsetLetf) * 0.01 + "rem";
menu.style.top = (e.clientY - top - offsetTop + height) * 0.01 + "rem";
bg.style.left = (e.clientX - left) * 0.01 + "rem";
bg.style.top = (e.clientY - top + height) * 0.01 + "rem";
menuBg.id = "menu";
menuBg.appendChild(menu);
menuBg.appendChild(bg);
document.getElementById(this.id).appendChild(menuBg);
e.stopPropagation();
document.onclick = (a) => {
if (a.isTrusted) {
let dom = document.getElementById("menu");
if (dom !== null) {
dom.remove();
document.onclick = null;
}
}
};
}
},
removeMark(e) {
let target = undefined;
let index = 0;
for (let i = 0; i < this.notes.length; i++) {
let item = this.notes[i];
if (item.id === e) {
index = i;
target = item;
break;
}
}
let formData = new FormData();
formData.append("id", target.uid);
removeMark(formData).then((res) => {
if (res.code === 200) {
this.notes.splice(index, 1);
let node = document.getElementById(e);
// let instance = new Mark(node);
document.getElementsByName(e)[0].remove();
instance.unmark();
this.$message.success("删除成功!");
}
});
},
async setHighlight(keyword, anchorOffset, id, flag = true) {
if (flag && id.indexOf("mark") === -1) {
await this.addMarkList(keyword, anchorOffset, id, "highlight");
} else if (flag && id.indexOf("mark") !== -1) {
this.$message.error("不能重复操作");
}
let dom = document.querySelector("#" + this.id + " #" + id);
// let instance = new Mark(dom);
instance.mark(
keyword,
this.getOption("markhigh", parseInt(anchorOffset), dom)
);
},
async setUnderine(keyword, anchorOffset, id, flag = true) {
if (flag && id.indexOf("mark") === -1) {
await this.addMarkList(keyword, anchorOffset, id, "underline");
} else if (flag && id.indexOf("mark") !== -1) {
this.$message.error("不能重复操作");
}
let dom = document.querySelector("#" + this.id + " #" + id);
// let instance = new Mark(dom);
instance.mark(
keyword,
this.getOption("markline", parseInt(anchorOffset), dom)
);
},
async setNode(keyword, anchorOffset, id, flag = true) {
if (flag && id.indexOf("mark") === -1) {
await this.addMarkList(keyword, anchorOffset, id, "note");
} else if (flag && id.indexOf("mark") !== -1) {
this.$message.error("不能重复操作");
}
let dom = document.querySelector("#" + this.id + " #" + id);
// let instance = new Mark(dom);
instance.mark(
keyword,
this.getOption("marknode", parseInt(anchorOffset), dom)
);
},
async addMarkList(keyword, anchorOffset, id, icon) {
let details = {};
let model = {};
model.id = "mark" + this.markIndex;
model.userName = this.$store.state.currentUser.userInfo.username;
model.time = new Date().toLocaleString();
model.anchorOffset = anchorOffset;
model.nodeId = id;
model.detail = [];
let formData = new FormData();
formData.append("bookmarkContent", keyword);
formData.append("docId", this.article.id);
formData.append("noteContent", this.node.text);
formData.append("docSType", this.article.docSType);
formData.append("offset", anchorOffset);
formData.append("sectionId", id);
formData.append("type", icon);
await addOrUpdate(formData).then((res) => {
if (res.code === 200) {
if (icon !== "note") {
details.key = icon === "underline" ? "下划线" : "高亮";
details.value = keyword;
details.icon = icon;
model.detail.push(details);
} else {
details.key = "笔记";
details.value = this.node.text;
details.icon = icon;
model.detail.push(details);
let target = {};
target.key = "原文";
target.value = keyword;
target.icon = "read";
model.detail.push(target);
}
model.uid = res.result;
model.id = "mark" + this.markIndex;
this.notes.push(model);
this.$message.success("笔记添加成功!");
} else {
this.$message.error(res.message);
}
});
},
getContent() {
let p = {
docId: this.article.id,
docSType: this.article.docSType,
};
detail(p).then((res) => {
if (res?.code === 200) {
this.htmlContent = res;
}
});
},
findStr(str, cha, num) {
let times = num === 0 ? 1 : num;
let x = str.indexOf(cha);
for (let i = 0; i < times - 1; i++) {
x = str.indexOf(cha, x + 1);
}
return x;
},
},
async mounted() {
await this.getNotes();
this.getContent();
},
};
</script>
<style lang="scss">
.catalogueOriginal {
width: 46vw !important;
margin-left: 62px !important;
overflow: hidden;
.el-dialog {
width: 44vw !important;
height: 600px !important;
box-shadow: 0 0 8px 1px !important;
overflow: auto;
}
.el-row--flex {
display: block !important;
width: 100% !important;
font-size: 20px !important;
}
.el-tree-node {
margin-bottom: 8px !important;
}
.el-tree--highlight-current {
width: 100% !important;
}
}
.catalogueCompare {
z-index: 0 !important;
width: 46vw !important;
margin-left: 1012px !important;
overflow: hidden;
.el-dialog {
width: 44vw !important;
height: 600px !important;
box-shadow: 0 0 8px 1px !important;
overflow-y: auto;
}
}
</style>
<style lang="scss" scoped>
.compareItem {
& > .title {
padding-top: 20px;
text-align: center;
font-size: 30px;
font-weight: bold;
font-family: cursive;
}
& > .tool-bar {
margin-top: 50px;
position: absolute;
& > li {
transition: all 0.5s ease;
cursor: pointer;
background-color: #2eb4ff;
display: block;
& > i {
color: #ffffff;
border: 1px solid #004b71;
font-size: 26px;
padding: 10px;
}
}
& > li:hover {
background-color: #0085cd;
}
& > li:first-child {
border-top-right-radius: 6px;
& > i:first-child {
border-top-right-radius: 6px;
}
}
& > li:last-child {
border-bottom-right-radius: 6px;
& > i:last-child {
border-bottom-right-radius: 6px;
}
}
}
}
</style>
<template>
<div class="searchWindow">
<el-input
placeholder="请输入内容"
v-model="searchTypeValue"
class="input-with-select"
@keyup.enter.native="search"
style="
width: 400px;
margin-left: 860px;
margin-top: -30px;
margin-bottom: 20px;
"
>
<el-select
v-model="searchType"
slot="prepend"
placeholder="请选择"
style="width: 120px"
>
<el-option label="全部文档" value=""></el-option>
<el-option label="外部资源" value="s_type_kbase"></el-option>
<el-option label="报刊" value="s_type_journal"></el-option>
<el-option label="入库文档" value="s_type_digit"></el-option>
<el-option label="分享文档" value="s_type_creation"></el-option>
</el-select>
<el-button
slot="append"
icon="el-icon-search"
@click="search"
></el-button>
</el-input>
<el-table
ref="compareTable"
v-loading="tableLoading"
@current-change="compareTableCurrentChange"
:data="compareTableData"
highlight-current-row
border
class="compareTableData"
header-row-class-name="compareTableHeader"
style="width: 100%"
>
<el-table-column type="index" align="center" width="50" label="行号">
</el-table-column>
<el-table-column show-overflow-tooltip prop="name" label="篇名">
</el-table-column>
<el-table-column show-overflow-tooltip prop="author" label="作者">
</el-table-column>
<el-table-column
width="100"
align="center"
show-overflow-tooltip
:formatter="docSTypeFormatter"
prop="docSType"
label="来源"
>
</el-table-column>
<el-table-column
align="center"
width="150"
prop="createTime"
label="时间"
>
</el-table-column>
</el-table>
<el-pagination
class="pagination"
@current-change="handleCurrentChange"
:current-page="page.index"
:page-size="page.size"
layout="total, prev, pager, next, jumper"
:total="page.total"
>
</el-pagination>
</div>
</template>
<script>
import { search } from "@/api/home";
export default {
name: "compareSearch",
data() {
return {
tableLoading: false,
searchType: "",
searchTypeValue: "",
page: {
index: 1,
size: 10,
total: 0,
count: 0,
},
compareTableData: [],
};
},
watch: {
"$parent.$parent.CompareSearch"(c, o) {
if (c === false) {
this.$refs["compareTable"].setCurrentRow();
}
},
},
methods: {
compareTableCurrentChange(e) {
this.$emit("changeRow", e);
},
handleCurrentChange(val) {
this.page.index = val;
this.search(false);
},
search(flag = true) {
this.tableLoading = true;
if (flag) {
this.page.index = 1;
}
let p = {
docSType: this.searchType,
keyword: this.searchTypeValue,
pageNo: this.page.index,
pageSize: this.page.size,
};
search(p).then((res) => {
if (res.code === 200) {
this.compareTableData = res.result.records;
this.tableLoading = false;
this.page.total = parseInt(res.result.totalElements);
this.page.count = parseInt(res.result.totalPages);
}
});
},
docSTypeFormatter(row) {
switch (row.docSType) {
case "s_type_kbase":
return "外部资源";
case "s_type_journal":
return "报刊";
case "s_type_digit":
return "入库文档";
case "s_type_creation":
return "分享文档";
}
},
},
mounted() {
this.search();
},
};
</script>
<style lang="scss">
.compareTableData {
.compareTableHeader {
& > th {
background-color: #f5f7fa !important;
text-align: center !important;
}
}
.current-row {
& > td {
background-color: #b5dbff !important;
}
}
}
</style>
<style lang="scss" scoped>
.pagination {
margin: 30px 0 0 0;
text-align: center;
}
</style>
<template>
<div class="compareWindow">
<div class="left window">
<compare-item v-if="articleOriginal.showType!=='pdf'" :id="'detailLeft'" :article="articleOriginal"
:compareWindowFlag="compareWindowFlag"/>
<readPdf v-if="articleOriginal.showType==='pdf'" :article="articleOriginal"/>
</div>
<div class="right window" v-if="articleCompare">
<compare-item v-if="articleCompare.showType!=='pdf'" :id="'detailRight'" :article="articleCompare"
:compareWindowFlag="compareWindowFlag"/>
<readPdf v-if="articleCompare.showType==='pdf'" :article="articleCompare"/>
</div>
</div>
</template>
<script>
export default {
name: "compareWindow",
props: {
articleCompare: Object,
compareWindowFlag: Boolean
},
components: {
compareItem: () => import('./compareItem'),
readPdf: () => import('./readPdf')
},
data() {
return {
articleOriginal: {
id: this.$route.query.id,
docSType: this.$route.query.docSType,
name: this.$route.query.title,
showType: this.$route.query.fileType,
url: this.$route.query.pdfSrc
},
htmlContentOriginal: undefined,
htmlContentCompare: undefined,
catalogueOriginalFlag: false,
catalogueCompareFlag: false,
noteFlag: false,
catalogueOriginal: undefined,
catalogueCompare: undefined,
noteOriginal: [],
noteCompare: []
}
},
watch: {
'$route.query'(c, o) {
this.articleOriginal = {
id: c.id,
docSType: c.docSType,
name: c.title
}
}
},
methods: {},
mounted() {
debugger
}
}
</script>
<style lang="scss" scoped>
.compareWindow {
& > .window {
background-color: #FFFFFF;
height: calc(100vh - 30px);
width: 49.7%;
margin-top: -40px;
overflow-x: hidden;
overflow-y: auto;
}
& > .left {
float: left;
}
& > .right {
float: right;
}
}
</style>
......@@ -51,7 +51,7 @@
<script>
import E from "wangeditor";
import { tagSuggest } from "@/api/doc/index";
import { tagSuggest } from "@/api/doc/tag";
export default {
name: "NoteWindow",
......
<template>
<div class="pdfExpress">
<div class="title">
<svg class="icon" @click="showCompareSearch" v-if="compareFlag">
<title>对比阅读</title>
<use :xlink:href="`#icon-compare`"></use>
</svg>
<p :title="article.name">{{ article.name }}</p>
</div>
<div ref="viewer" class="content"></div>
<el-dialog
width="1300px"
title="文档搜索"
top="5vh"
:visible.sync="compareSearch"
class="CompareSearch"
:close-on-click-modal="false"
v-dialog-drag
>
<compare-search @changeRow="changeRow($event)" />
<div slot="footer" class="dialog-footer">
<el-button @click="closeComparSearch">取 消</el-button>
<el-button type="primary" @click="openCompareWindow">确 定</el-button>
</div>
</el-dialog>
<el-dialog
:append-to-body="true"
v-if="compareWindowFlag"
fullscreen
:visible.sync="compareWindowFlag"
class="CompareWindow"
:close-on-click-modal="false"
>
<compare-window
:articleCompare="compareSearchCurrentRow"
:compareWindowFlag="compareWindowFlag"
/>
</el-dialog>
</div>
</template>
<script>
import WebViewer from "@pdftron/webviewer";
import { pdfAddOrUpdate, getBookMark, pdfRemoveMark } from "@/api/doc/bookMark";
export default {
name: "readPdf",
props: ["article"],
components: {
compareSearch: () => import("./compareSearch.vue"),
compareWindow: () => import("./compareWindow.vue"),
},
watch: {
"$store.state.currentUser"(c, o) {
this.isReadOnly = c === null;
if (this.instance) {
this.instance.dispose();
document.querySelector("#webviewer-1").remove();
}
this.WebViewerInit();
},
},
data() {
return {
noteArray: [],
instance: undefined,
isReadOnly:
this.$store.state.currentUser?.userInfo?.username === undefined,
compareSearch: false,
compareSearchCurrentRow: undefined,
compareWindowFlag: false,
compareFlag: document.querySelector(".compareWindow") === null,
};
},
methods: {
openCompareWindow() {
if (this.compareSearchCurrentRow !== undefined) {
this.compareSearch = false;
this.compareWindowFlag = true;
}
},
closeComparSearch() {
this.compareSearch = false;
this.compareSearchCurrentRow = undefined;
},
changeRow(e) {
this.compareSearchCurrentRow = e;
},
showCompareSearch() {
this.compareSearch = true;
},
getBookMark() {
let p = {
docId: this.article.id,
docSType: this.article.docSType,
};
getBookMark(p).then((res) => {
if (res?.result?.xml) {
for (let i = 0; i < res.result.xml.length; i++) {
let tag = res.result.xml[i];
this.instance.annotManager
.importAnnotCommand(tag)
.then((res) => {});
}
}
});
},
documentLoaded() {
this.instance.docViewer.on("documentLoaded", () => {
setTimeout(() => {
this.getBookMark();
this.instance.docViewer.refreshAll();
this.instance.docViewer.updateView();
}, 1000);
this.instance.setCurrentPageNumber(1);
this.instance.setZoomLevel(1.2);
this.instance.setNoteDateFormat("YYYY-MM-DD HH:mm");
if (this.article.showMenu) {
this.instance.toggleElement("leftPanel");
this.instance.toggleElement("notesPanel");
}
let userName =
this.$store.state.currentUser?.userInfo?.username || "游客";
this.instance.setAnnotationUser(userName);
});
},
annotationChanged() {
this.instance.annotManager.on(
"annotationChanged",
(annotations, action, info) => {
if (
[
"highlight",
"underline",
"squiggly",
"strikeout",
"text",
].includes(annotations[0].elementName)
) {
if (info.imported === false || info.imported === undefined) {
this.instance.annotManager.getAnnotCommand().then((res) => {
if (action === "add" || action === "modify") {
this.addOrUpdateMark(res);
} else {
this.deleteMark(annotations[0]);
}
});
}
}
}
);
},
updateReply() {},
deleteReply() {
this.instance.annotManager.on(
"deleteReply",
(annotation, parent, root) => {}
);
},
addReply() {
this.instance.annotManager.on("addReply", (annotation, root) => {});
},
addOrUpdateMark(e) {
let p = new FormData();
p.append("docId", this.article.id);
p.append("docSType", this.article.docSType);
p.append("xmlParams", e);
// zwj p.append('xmlParams', e) 标签(多个用逗号分割)
p.append("tags", "问题");
pdfAddOrUpdate(p).then((res) => {
if (res.code === 500) {
this.$message.error(res.message);
} else {
this.$message.success("操作成功");
}
});
},
deleteMark(e) {
let p = new FormData();
p.append("uniqueId", e.Id);
pdfRemoveMark(p).then((res) => {
if (res.code === 200) {
this.$message.success("删除成功");
} else {
this.$message.error("删除失败,请重试");
}
});
},
updateMark() {},
setWatermark() {
this.instance.docViewer.setWatermark({
// Draw diagonal watermark in middle of the document
diagonal: {
fontSize: 60, // or even smaller size
fontFamily: "sans-serif",
color: "#67c3e0",
opacity: 50, // from 0 to 100
text: "CNKI",
},
});
this.instance.docViewer.getWatermark().then((res) => {
debugger;
});
},
contextMenuPopup() {
this.instance.contextMenuPopup.add({
type: "actionButton",
label: "some-label",
onClick: (e, a) => {},
});
},
setHeaderItems() {
this.instance.setHeaderItems((header) => {
header.push({
type: "toggleElementButton",
img: "ic_left_sidebar_black_24px",
element: "leftPanel",
});
});
},
WebViewerInit() {
let _this = this;
// debugger
WebViewer(
{
path: "/static/webviewer",
// initialDoc: '/static/webviewer/demo.pdf', // replace with your own PDF file
initialDoc: this.article.url, // replace with your own PDF file
fullAPI: true,
config: "/static/webviewer/ui/webViewerConfig.js",
isReadOnly:
this.isReadOnly || this.$route.query.isReadOnly === "true",
},
this.$refs.viewer
).then((instance) => {
this.instance = instance;
instance.setLanguage("zh_cn");
this.documentLoaded();
this.annotationChanged();
this.deleteReply();
this.addReply();
this.contextMenuPopup();
this.instance.annotManager.on(
"setNoteText",
(annotation, parent, root) => {}
);
this.instance.annotManager.on(
"fieldChanged",
(annotation, parent, root) => {}
);
});
},
},
mounted() {
this.WebViewerInit();
},
};
</script>
<style lang="scss">
.CompareSearch {
& > .el-dialog {
border-radius: 8px !important;
}
.el-dialog__header {
border-bottom: 1px solid #e6e6e6;
}
}
.CompareWindow {
& > .el-dialog {
background-color: rgba(0, 0, 0, 0.5) !important;
& > .el-dialog__header {
.el-dialog__headerbtn {
width: 40px;
height: 40px;
margin-top: 6px;
margin-right: 10px;
border-radius: 30px;
background-color: rgba(0, 0, 0, 0.5);
font-size: 40px !important;
transition: all 1s ease;
.el-icon-close {
color: #ffffff;
}
}
.el-dialog__headerbtn:hover {
transform: rotate(180deg);
}
}
}
}
</style>
<style lang="scss" scoped>
.pdfExpress {
width: 100%;
height: calc(100vh - 70px);
& > .title {
width: 100%;
height: 50px;
background-color: #f1f3f5;
line-height: 50px;
font-size: 30px;
font-family: cursive;
& > .icon {
cursor: pointer;
margin-top: 6px;
margin-left: 10px;
float: left;
border-radius: 6px;
font-weight: bold;
background-color: #dde6ee;
padding: 6px;
width: 22px;
height: 22px;
}
& > p {
margin: 0 auto;
width: 50%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: #185db7;
font-weight: bold;
text-align: center;
}
}
& > .content {
height: 100%;
}
}
</style>
<template>
<div class="pdfExpress">
<div class="title">
<svg class="icon" @click="showCompareSearch" v-if="compareFlag">
<title>对比阅读</title>
<use :xlink:href="`#icon-compare`"></use>
</svg>
<p :title="article.name">{{ article.name }}</p>
</div>
<div ref="viewer" class="content"></div>
<el-dialog
width="1300px"
title="文档搜索"
top="5vh"
:visible.sync="compareSearch"
class="CompareSearch"
:close-on-click-modal="false"
v-dialog-drag
>
<compare-search @changeRow="changeRow($event)" />
<div slot="footer" class="dialog-footer">
<el-button @click="closeComparSearch">取 消</el-button>
<el-button type="primary" @click="openCompareWindow">确 定</el-button>
</div>
</el-dialog>
<el-dialog
:append-to-body="true"
v-if="compareWindowFlag"
fullscreen
:visible.sync="compareWindowFlag"
class="CompareWindow"
:close-on-click-modal="false"
>
<compare-window
:articleCompare="compareSearchCurrentRow"
:compareWindowFlag="compareWindowFlag"
/>
</el-dialog>
</div>
</template>
<script>
import WebViewer from "@pdftron/webviewer";
import { pdfAddOrUpdate, getBookMark, pdfRemoveMark } from "@/api/doc/bookMark";
export default {
name: "readPdf",
// props: ["article"],
components: {
// compareSearch: () => import("./components/compareSearch.vue"),
// compareWindow: () => import("./components/compareWindow.vue"),
},
watch: {
"$store.state.currentUser"(c, o) {
console.log("c", c);
this.isReadOnly = c === null;
if (this.instance) {
this.instance.dispose();
document.querySelector("#webviewer-1").remove();
}
this.WebViewerInit();
},
},
data() {
return {
noteArray: [],
instance: undefined,
isReadOnly:
this.$store.state.currentUser?.userInfo?.username === undefined,
compareSearch: false,
compareSearchCurrentRow: undefined,
compareWindowFlag: false,
compareFlag: document.querySelector(".compareWindow") === null,
article: {}, //文章信息
};
},
methods: {
openCompareWindow() {
if (this.compareSearchCurrentRow !== undefined) {
this.compareSearch = false;
this.compareWindowFlag = true;
}
},
closeComparSearch() {
this.compareSearch = false;
this.compareSearchCurrentRow = undefined;
},
changeRow(e) {
this.compareSearchCurrentRow = e;
},
showCompareSearch() {
this.compareSearch = true;
},
getBookMark() {
let p = {
docId: this.article.id,
docSType: this.article.docSType,
};
getBookMark(p).then((res) => {
if (res?.result?.xml) {
for (let i = 0; i < res.result.xml.length; i++) {
let tag = res.result.xml[i];
this.instance.annotManager
.importAnnotCommand(tag)
.then((res) => {});
}
}
});
},
documentLoaded() {
this.instance.docViewer.on("documentLoaded", () => {
setTimeout(() => {
this.getBookMark();
this.instance.docViewer.refreshAll();
this.instance.docViewer.updateView();
}, 1000);
this.instance.setCurrentPageNumber(1);
this.instance.setZoomLevel(1.2);
this.instance.setNoteDateFormat("YYYY-MM-DD HH:mm");
if (this.article.showMenu) {
this.instance.toggleElement("leftPanel");
this.instance.toggleElement("notesPanel");
}
let userName =
this.$store.state.currentUser?.userInfo?.username || "游客";
this.instance.setAnnotationUser(userName);
});
},
annotationChanged() {
this.instance.annotManager.on(
"annotationChanged",
(annotations, action, info) => {
if (
[
"highlight",
"underline",
"squiggly",
"strikeout",
"text",
].includes(annotations[0].elementName)
) {
if (info.imported === false || info.imported === undefined) {
this.instance.annotManager.getAnnotCommand().then((res) => {
if (action === "add" || action === "modify") {
this.addOrUpdateMark(res);
} else {
this.deleteMark(annotations[0]);
}
});
}
}
}
);
},
updateReply() {},
deleteReply() {
this.instance.annotManager.on(
"deleteReply",
(annotation, parent, root) => {}
);
},
addReply() {
this.instance.annotManager.on("addReply", (annotation, root) => {});
},
addOrUpdateMark(e) {
let p = new FormData();
p.append("docId", this.article.id);
p.append("docSType", this.article.docSType);
p.append("xmlParams", e);
// zwj p.append('xmlParams', e) 标签(多个用逗号分割)
p.append("tags", "问题");
pdfAddOrUpdate(p).then((res) => {
if (res.code === 500) {
this.$message.error(res.message);
} else {
this.$message.success("操作成功");
}
});
},
deleteMark(e) {
let p = new FormData();
p.append("uniqueId", e.Id);
pdfRemoveMark(p).then((res) => {
if (res.code === 200) {
this.$message.success("删除成功");
} else {
this.$message.error("删除失败,请重试");
}
});
},
updateMark() {},
setWatermark() {
this.instance.docViewer.setWatermark({
// Draw diagonal watermark in middle of the document
diagonal: {
fontSize: 60, // or even smaller size
fontFamily: "sans-serif",
color: "#67c3e0",
opacity: 50, // from 0 to 100
text: "CNKI",
},
});
this.instance.docViewer.getWatermark().then((res) => {
debugger;
});
},
contextMenuPopup() {
this.instance.contextMenuPopup.add({
type: "actionButton",
label: "some-label",
onClick: (e, a) => {},
});
},
setHeaderItems() {
this.instance.setHeaderItems((header) => {
header.push({
type: "toggleElementButton",
img: "ic_left_sidebar_black_24px",
element: "leftPanel",
});
});
},
WebViewerInit() {
let _this = this;
console.log("article", this.article);
WebViewer(
{
path: "/static/webviewer",
// initialDoc: '/static/webviewer/demo.pdf', // replace with your own PDF file
initialDoc: this.article.url, // replace with your own PDF file
fullAPI: true,
config: "/static/webviewer/ui/webViewerConfig.js",
isReadOnly:
this.isReadOnly || this.$route.query.isReadOnly === "true",
},
this.$refs.viewer
).then((instance) => {
this.instance = instance;
instance.setLanguage("zh_cn");
this.documentLoaded();
this.annotationChanged();
this.deleteReply();
this.addReply();
this.contextMenuPopup();
this.instance.annotManager.on(
"setNoteText",
(annotation, parent, root) => {}
);
this.instance.annotManager.on(
"fieldChanged",
(annotation, parent, root) => {}
);
});
},
// 获取文章信息
getArticleInfo() {
this.article = {
name: this.$route.query.title,
id: this.$route.query.id,
docSType: this.$route.query.docSType,
url: this.$route.query.pdfSrc,
showMenu: true,
};
this.WebViewerInit();
},
},
mounted() {
this.getArticleInfo();
},
};
</script>
<style lang="scss">
.CompareSearch {
& > .el-dialog {
border-radius: 8px !important;
}
.el-dialog__header {
border-bottom: 1px solid #e6e6e6;
}
}
.CompareWindow {
& > .el-dialog {
background-color: rgba(0, 0, 0, 0.5) !important;
& > .el-dialog__header {
.el-dialog__headerbtn {
width: 40px;
height: 40px;
margin-top: 6px;
margin-right: 10px;
border-radius: 30px;
background-color: rgba(0, 0, 0, 0.5);
font-size: 40px !important;
transition: all 1s ease;
.el-icon-close {
color: #ffffff;
}
}
.el-dialog__headerbtn:hover {
transform: rotate(180deg);
}
}
}
}
</style>
<style lang="scss" scoped>
.pdfExpress {
width: 100%;
height: calc(100vh - 70px);
& > .title {
width: 100%;
height: 50px;
background-color: #f1f3f5;
line-height: 50px;
font-size: 30px;
font-family: cursive;
& > .icon {
cursor: pointer;
margin-top: 6px;
margin-left: 10px;
float: left;
border-radius: 6px;
font-weight: bold;
background-color: #dde6ee;
padding: 6px;
width: 22px;
height: 22px;
}
& > p {
margin: 0 auto;
width: 50%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: #185db7;
font-weight: bold;
text-align: center;
}
}
& > .content {
height: 100%;
}
}
</style>
<template>
<div>阅读wps</div>
</template>
<script>
export default {};
</script>
<style lang=""></style>
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论