• 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 {
         70%;
      }
      .right {
         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>
    
    
  • 相关阅读:
    斐波那契数列 的两种实现方式(Java)
    单链表反转
    单链表合并
    两个有序list合并
    list去重 转载
    RemoveAll 要重写equals方法
    Java for LeetCode 138 Copy List with Random Pointer
    Java for LeetCode 137 Single Number II
    Java for LeetCode 136 Single Number
    Java for LeetCode 135 Candy
  • 原文地址:https://www.cnblogs.com/dingshaohua/p/16409733.html
Copyright © 2020-2023  润新知