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>

posted @   丁少华  阅读(515)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示