wps office定制化 自定义右侧面板 关联批注
效果

核心思想
监听onWindowSelectionChange事件,获取当前光标位置,然后对比高连位置 判断是否选在区域内。
若是则激活右侧对应的高亮面板
核心代码
index.vue
<script setup lang="ts">
import RightPanel from './right-panel.vue';
import WpsPanel from './wps-panel.vue';
import emitter from '../../utils/emitter';
import { ref, onBeforeMount } from 'vue';
const props = defineProps<{ fileId: string }>();
onBeforeMount(() => {
emitter.on('wpsReady', (params) => {
jssdk.value = params;
});
});
const jssdk = ref<any>(null);
</script>
<template>
<div class="wps-render">
<div class="wps">
<wps-panel :fileId="props.fileId" />
</div>
<div class="right" v-if="jssdk">
<right-panel :fileId="props.fileId" :jssdk="jssdk" />
</div>
</div>
</template>
<style lang="less">
.wps-render {
height: 100vh;
display: flex;
.wps {
width: 70%;
}
.right {
width: 30%;
}
}
</style>
right-panel.vue
<script setup lang="ts">
import { ref, onBeforeMount, computed } from 'vue';
import axios from 'axios';
import _ from 'lodash';
const props = defineProps<{ fileId: string; jssdk: any }>();
onBeforeMount(async () => {
await synncCheckData();
props.jssdk.on('WindowSelectionChange', _.debounce(onWindowSelectionChange, 500));
});
/*
* 监听光标移动
*/
const onWindowSelectionChange = async (event: any) => {
console.log(event);
for (const iterator of checkData.value) {
for (const risk of iterator.risks) {
for (const hlight of risk.highlight_list) {
const atBegin = event.begin >= hlight.begin && event.begin <= hlight.end;
const atEnd = event.end >= hlight.begin && event.end <= hlight.end;
// 假设目标光标or所选区域 在高亮范围内,则匹配的上
if (atBegin || atEnd) {
hlight.active = true;
} else {
hlight.active = false;
}
}
}
}
};
//定义计算属性,返回wpsApp
const wpsApp: any = computed(() => {
return props.jssdk.Application;
});
// 审核结果
const checkData = ref<any>([]);
/*
* 获取审查结果new
*/
const synncCheckData = async () => {
const url = 'primaryApi/api/contract_review/v1/parse_result';
const res = await axios.post(url, { id: props.fileId, role: '甲方' });
// 获取审查结果 高亮里补充坐标信息
for (const iterator of res.data.data.danger_list) {
for (const risk of iterator.risks) {
for (const hlight of risk.highlight_list) {
if (hlight.text) {
const res = await findByText(hlight.text);
if (res) {
hlight.begin = res.begin;
hlight.end = res.end;
}
}
}
}
}
checkData.value = res.data.data.danger_list;
};
/*
* 根据文本查找内容位置坐标
*/
const findByText = async (text: string) => {
// 1. 搜索
const findResult: Array<any> = await wpsApp.value.ActiveDocument.Find.Execute(text, false);
// 2. 获取位置信息
if (findResult.length === 0) {
return false;
}
const { pos: begin, len } = findResult[0];
const end = begin + len;
return { begin, end };
};
/*
* 点击右侧面板
*/
const onClick = async (item: any) => {
const res = await findByText(item.text);
if (!res) {
return false;
}
console.log('res', res);
// // 1. 获取选中区域 https://wwo.wps.cn/docs/front-end/API/Word/Range
// const range = await wpsApp.value.ActiveDocument.Range(res.begin, res.end);
// // 2. 选中区域设置高亮
// range.HighlightColorIndex = 7;
// 3. 获取区域对象
const range = await wpsApp.value.ActiveDocument.Range.SetRange(res.begin, res.end);
// 4. 滚动文档窗口, 显示指定的区域
await wpsApp.value.ActiveDocument.ActiveWindow.ScrollIntoView(range);
};
</script>
<template>
<div class="right-panel">
<div v-for="item in checkData" :key="item.danger_num" class="item">
<div class="label">{{ item.label }} ({{ item.danger_num }})</div>
<div class="content">
<div v-for="risk in item.risks" class="risk">
<div class="rlabel">{{ risk.label }}</div>
<div class="rcontent">
<div v-for="hlight in risk.highlight_list" class="hlight" @click="onClick(hlight)" :class="{ active: hlight.active }">
{{ hlight.text }}
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<style lang="less">
.right-panel {
height: 100vh;
overflow: auto;
.item {
border: red solid 2px;
margin-top: 10px;
border-radius: 4px;
min-height: 100px;
.label {
background-color: aliceblue;
padding: 10px;
}
.content {
padding: 10px;
.risk {
background-color: bisque;
margin-bottom: 10px;
padding: 10px;
.rcontent {
.hlight {
color: red;
cursor: pointer;
border: greenyellow solid 2px;
margin-bottom: 10px;
padding: 10px;
}
.active {
background-color: red;
color: white;
}
}
}
}
}
}
</style>
wps-panel.vue
<script setup lang="ts">
import { ref, onBeforeMount } from 'vue';
import WebOfficeSDK from 'web-office-sdk';
import axios from 'axios';
import emitter from '../../utils/emitter';
const props = defineProps<{ fileId: string }>();
onBeforeMount(() => {
init();
});
const init = async () => {
// 获取wps中url与token get_url_token:,
const {
data: { wpsUrl: url, token }
} = await axios.get('/wpsApi/getUrlAndToken', {
params: { fileid: props.fileId }
});
const jssdk = WebOfficeSDK.config({
url,
mount: document.querySelector('.wps-box') as any // 挂载到div
});
// 设置 token
jssdk.setToken({
token: token,
hasRefreshTokenConfig: false
});
// 打开文档结果
jssdk.on('fileOpen', (data) => {
// console.log(123, data.success);
});
// 等待加载完毕
jssdk.ready().then(() => {
emitter.emit('wpsReady', jssdk);
});
// 如果需要对 iframe 进行特殊的处理,可以通过以下方式拿到 iframe 的 dom 对象
// console.log(jssdk.iframe);
};
</script>
<template>
<div class="hello-world">
<div class="wps-box"></div>
</div>
</template>
<style lang="less">
.hello-world {
.wps-box {
height: 100vh;
}
}
</style>
wps office定制化 自定义右侧面板 关联批注的更多相关文章
- strapi系列--如何自定义非界面化的接口,定制化自己的业务逻辑
为什么要进行后端定制呢? 在实际开发过程中,项目中有些需求是不需要创建界面化接口的,需要我们定制化自己的业务逻辑,那么我们该如何处理这个需求呢?本文以图文并茂的形式,定制一个我们自己的业务逻辑接口. ...
- Django 2.0 学习(10):Django 定制化
定制化admin表单 通过使用admin.site.register(Question)注册Question模型,Django可以构造默认的表单.通常,可以通过对象的注册机制来告诉Django我们想要 ...
- python 全栈开发,Day114(装饰器,排序规则,显示列,添加按钮,定制ModelForm,自定义列表页面,自定制URL)
一.装饰器 装饰器本质上就是一个python函数,他可以让其他函数在不需要做任何代码变动的前提下,增加额外的功能,装饰器的返回值也是一个函数对象. 装饰器的应用场景:比如插入日志,性能测试,事务处理, ...
- Oceanus:美团HTTP流量定制化路由的实践
背景简述 Oceanus是美团基础架构部研发的统一HTTP服务治理框架,基于Nginx和ngx_lua扩展,主要提供服务注册与发现.动态负载均衡.可视化管理.定制化路由.安全反扒.session ID ...
- solr特点三: 基于Solr实现排序定制化参考
排序实现有N种形式,最低成本.最快响应时间是目标 一份索引,支持N种排序策略并且在线互不干扰是要考虑的每一种实现,处理的场景是不同的,不要千篇一律 020排序,从索引到效果,有不少坑,这篇文章没有细说 ...
- Centos7.5的定制化安装
一.前言 关于定制化centos7.5的镜像真的是历经波折,前前后后.来来回回尝试了不少于20次,上网找了各种关于定制7系统的方法,都没有成功... 但最终功夫不负有心人终于解决了,O(∩_∩)O哈哈 ...
- Gradle 实现 Android 多渠道定制化打包
Gradle 实现 Android 多渠道定制化打包 版权声明:本文为博主原创文章,未经博主允许不得转载. 最近在项目中遇到需要实现 Apk 多渠道.定制化打包, Google .百度查找了一些资料, ...
- Oracle Sales Cloud:管理沙盒(定制化)小细节1——利用公式创建字段并显示在前端页面
Oracle Sales Cloud(Oracle 销售云)是一套基于Oracle云端的CRM管理系统.由于 Oracle 销售云是基于 Oracle 云环境的,它与传统的管理系统相比,显著特点之一便 ...
- cobbler重装、web、定制化
cobbler重装 根据此文已自动化安装centos 7的版本http://www.cnblogs.com/shhnwangjian/p/5858900.html 在cobbler-test主机上重装 ...
- WPS Office文档未保存怎么恢复
有时候用WPS Office时,文档还没保存,因为电脑卡死或者关机,再次打开时编辑的内容都不见了,这个时候可以利用WPS自带的备份功能来恢复文档,表格.幻灯片.文档都是可以的. 首先单击WPS左上角的 ...
随机推荐
- 学习Linux命令的正确姿势
大家好,我是良许. 大家应该注意到了,最近我的公众号文章末尾都挂着自己录制的<Linux命令从小白到大神>课程. 这个课程我从开始录制到制作完成,足足花了一个半月.如果加上前期的资料收集与 ...
- Flowable快速入门
flowable官方文档 官网:https://tkjohn.github.io/flowable-userguide/#_getting_started 工作流(Workflow),是& ...
- PriorityBlockingQueue 的put方法底层源码
一.PriorityBlockingQueue 的put方法底层源码 PriorityBlockingQueue 的 put 方法用于将元素插入队列.由于 PriorityBlockingQueue ...
- VScode设置用户代码片段快捷方式
一.创建步骤 a. b. 二.创建模板 { "生成vue模板": { "prefix": "vue", "body": ...
- 华为od机考2025A卷真题 -查找接口成功率最优时间段
题目描述与示例 题目描述 服务之间交换的接口成功率作为服务调用关键质量特性,某个时间段内的接口失败率使用一个数组表示,数组中每个元素都是单位时间内失败率数值,数组中的数值为 0~100 的整数,给定一 ...
- JWT Token解析
参照:c#中token的使用方法实例_C#教程_脚本之家 (jb51.net) (7条消息) JWT 算法_み旋律的博客-CSDN博客_jwt算法
- MySQL开启general_log
General_log 详解 1.介绍 开启 general log 将所有到达MySQL Server的SQL语句记录下来. 一般不会开启开功能,因为log的量会非常庞大.但个别情况下可能会临时的开 ...
- 【BUG】vite build、Flask运行后报错Failed to load module script. Strict MIME type checking is enforced
解决方案来源于Stack Overflow. 翻译来源于javascript - Python Flask - 错误 : "Failed to load module script. Str ...
- css_初阶
s10.html <!DOCTYPE html> <html lang="en"> <head> <meta charset=&q ...
- vue3 基础-常用模板语法
一个 vue 的单文件 SAP ( single page web application ) 即在一个 .vue 为后缀的文件中, 会包含3个部分. 模板: html 逻辑: javascript ...