首页 > 其他分享 >自定义模板中数据标签

自定义模板中数据标签

时间:2024-01-26 11:02:30浏览次数:32  
标签:Word 自定义 数据 color 标签 border 模板

笔记
数据标签(DataTag)只是一种辨识度比较高的文本字符串,样式完全由开发人员自己说了算。比如这样的数据标签“【##日期$$】”,编写代码openDataTag("【##日期$$】")即可返回数据标签对象,进而可以对此数据标签填充数据或设置样式等操作。

在实际的Word文档开发中,经常需要自动填充数据到Word模板中,以生成动态的Word文档,那么应该如何使用PageOffice概念中的数据标签(DataTag)编辑制作Word模板呢?

方法一:直接打开Word文件插入数据标签

假如使用数据标签(DataTag)来定义模板中动态填充数据的位置,那么直接打开一个Word文件,在其中添加自定义特殊格式的文本即可制作word模板。例如,打开一个Word文件后,可以直接插入“{部门名}”、“{姓名}”、“【时间】”等类似的、辨识度很高的、特殊格式的文本。效果如下图所示:
image

Word模板中需要多少个动态填充数据的位置,就在Word文件中相应的位置插入多少数据标签即可。这种制作word模板的方法操作简单,但是常用于开发新项目时定义Word模板,开发人员知道在Word模板的哪个位置需要插入哪个数据,把所有需要动态填充数据的数据标签插入到Word中,就可以编程调用PageOffice接口给这些数据标签填充数据,就比如操作上面的“【时间】”,代码这样写openDataTag("【时间】").setvalue("当前时间"),就可以把当前时间赋值给数据标签。其他的数据标签也是相同的处理方式,但是项目发布后,如果用户的需求发生变动,希望修改Word模板或创建新的Word模板,用户怎么知道如何制作word模板呢?如何插入和命名数据标签?哪些数据标签与哪些系统数据是对应的呢?

方法二:给用户提供自定义模板功能

开发人员可以给系统增加一个模板管理的模块,拥有模板管理权限的用户可以查看系统中的模板列表,可以新增、删除和在线编辑模板,开发人员通过程序定义好编辑某种模板时可能用到的所有数据标签,用户自定义编辑Word模板时可以把全部数据标签插入到模板的相应位置,也可以根据实际需求只使用部分数据标签,但Word模板中用到的数据标签总是开发人员定义的数据标签集合的子集,这样一来就能实现开发人员与用户的分工合作。

比如说web系统中合同模板的制作,合同模板中可能会用到的数据有:甲方、乙方、担保人、合同编号、合同日期,那么开发人员可以编写代码定义好这些数据标签,让用户在线打开编辑模板时,只能在Word模板中插入这些系统定义好的数据标签,这样做不但实现了开发人员与用户的一种约定,而且规范了用户的操作。

1. 开发人员编写代码定义好编辑模板时所有可用的数据标签:
开发人员调用PageOffice提供的defineDataTag方法定义用户编辑模板时所有可用的数据标签。数据标签的格式没有特殊要求,下面示例代码中分别使用了英文中括号和中文中括号(也可以使用其他符号),是为了便于用户直观的查看Word模板中哪些位置是插入的数据标签,也是为了通过程序给数据标签动态赋值的时候与普通的正文内容做区别处理。

WordDocument doc = new WordDocument();
doc.getTemplate().defineDataTag("{ 甲方 }");
doc.getTemplate().defineDataTag("{ 乙方 }");
doc.getTemplate().defineDataTag("{ 担保人 }");
doc.getTemplate().defineDataTag("【 合同日期 】");
doc.getTemplate().defineDataTag("【 合同编号 】");

2. 用户编辑模板时,直接使用开发人员定义好的数据标签来制作模板:
由于用户操作习惯和Web系统界面风格的不同,开发人员可以根据实际需求在自己的Web项目中选择实现下面的一种编辑模板效果。

用户在线编辑模板效果1: 把数据标签列表和Word文件编辑界面,一左一右放到同一个页面窗口中,用户在右侧Word文件中点击定位光标到需要插入数据的位置,然后在左侧选择相应的数据标签,添加到当前位置即可。比如下图所示:在Word中需要插入“乙方”的位置点击一下鼠标,然后在左侧“待添加标签”中点击数据标签“{ 乙方 }”的添加按钮,“{ 乙方 }”标签就被插入到了Word光标所在位置。
image
此效果所用到的html、css和javascript代码:

    <style>
        body {
            margin: 0;
            padding: 0;
            display: flex;
        }
		div{
			 box-sizing: border-box; 
		}
        #left-container {
            width: 360px;
            display: flex;
            flex-direction: column;
            border-right: 2px solid #ccc;
            padding: 20px;
            overflow: auto;
            font-size: 12px;
            height: 90vh;
        }
        #right-container {
            flex: 1;
            padding: 0px;
            height: 95vh;
        }
        #podiv{
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
        }
        #left-title{
            text-align: center;
            font-size: 16px;
            padding-bottom: 10px;
            margin-bottom: 10px;
            border-bottom: solid 1px #ccc;
        }

        .input-group {
            margin-bottom: 20px;
            display: flex;
            align-items: center;
        }
        input[type="text"] {
            width: 70%;
            padding: 10px;
            margin-top: 5px;
            box-sizing: border-box;
            border: 1px solid #ccc;
            border-radius: 5px;
            font-size: 12px;
            outline: none;
        }

        input[type="submit"] {
            width: 80px;
            padding: 10px;
            margin-top: 5px;
            margin-left: 10px;
            box-sizing: border-box;
            border: none;
            border-radius: 5px;
            background-color: #4E6EF2;
            color: white;
            font-size: 12px;
            outline: none;
            cursor: pointer;
        }
        /* 表格样式 */
        table {
            border-collapse: collapse;
            width: 100%;
        }

        th, td {
            padding: 8px;
            text-align: left;
            border-bottom: 1px solid #ddd;
        }

        th {
            position: sticky;
            top: 0;
            background-color: #f2f2f2;
            z-index: 1;
        }

        /* 容器样式 */
        .container {
            height: 600px;
            overflow: auto;
            border: solid 1px #ccc;
            scrollbar-width: thin;
            scrollbar-color: #888 #f2f2f2;
        }

        /* 滚动条样式 */
        .container::-webkit-scrollbar {
            width: 8px;
        }

        .container::-webkit-scrollbar-track {
            background: #f2f2f2;
        }

        .container::-webkit-scrollbar-thumb {
            background-color: #888;
            border-radius: 4px;
        }

        .container::-webkit-scrollbar-thumb:hover {
            background-color: #555;
        }
        .delete-button {
            padding: 6px 6px;
            border: none;
            border-radius: 5px;
            background-color: #f44336;
            color: white;
            font-size: 12px;
            cursor: pointer;
        }
        .delete-button:hover {
            background-color: #d32f2f;
        }

        .normal-button {
            padding: 6px 6px;
            border: none;
            border-radius: 5px;
            background-color: #4E7EFF;
            color: white;
            font-size: 12px;
            cursor: pointer;
        }
        .normal-button:hover {
            background-color: #4E6EF2;
        }

        .locate-button {
            padding: 6px 6px;
            border: none;
            border-radius: 5px;
            background-color: #0abb87;
            color: white;
            font-size: 12px;
            cursor: pointer;
        }
        .locate-button:hover {
            background-color: #0a9966;
        }
    </style>
    <script>
        var definedDataTagJson = '';
        var isFromStart = false;
        var lastOpTag = '';

        function OnPageOfficeCtrlInit() {
            pageofficectrl.AddCustomToolButton("保存", "Save", 1);
        }
        function Save() {
            pageofficectrl.WebSave();
        }

        //加载数据
        function loadData() {
            var kWord = document.getElementById("inputKey").value;
            searchDataTag(definedDataTagJson, kWord);
            return;
        }

        //加载上方数据列表
        function searchDataTag(dtDefinedJson, s){
            var tb1 = document.getElementById("tagTable");
            var rCount = tb1.rows.length;
            for (var i = 1; i < rCount; i++) {
                tb1.deleteRow(1);
            }

            if('' == dtDefinedJson) dtDefinedJson = '[]';
            let definedDataTagObj = JSON.parse(dtDefinedJson);

            var oTable = document.getElementById("tagTable");
            var tbodyObj = oTable.tBodies[0];
            for(let key in definedDataTagObj ){
                let dtName = definedDataTagObj[key].name;
                if (dtName.toLocaleLowerCase().indexOf(s.toLocaleLowerCase()) > -1) {
                    var oTr = tbodyObj.insertRow();
                    var oTd = oTr.insertCell();
                    oTd.innerHTML = dtName;
                    oTd.title = dtName;
                    oTd = oTr.insertCell();
                    oTd.innerHTML = '<button class="delete-button" onclick="deleteTag(\''+ dtName +'\')">删除</button> <button class="locate-button" onclick="locateTag(\''+ dtName +'\')" >定位</button> <button class="normal-button" onclick="addTag(\''+ dtName +'\');">添加</button> ';
                }
            }
        }

        function addTag(tagName) {
            pageofficectrl.word.SetTextToSelection(tagName);
        }

        function locateTag(tagName){
            pageofficectrl.word.SelectionCollapse(0);

            if(isFromStart){
                if(lastOpTag == tagName){
                    pageofficectrl.word.HomeKey(6);
                }

                isFromStart = false;
            }

            if(!pageofficectrl.word.FindNextText(tagName)){
                alert('已经搜索到文档末尾。');
                isFromStart = true;
            }

            lastOpTag = tagName;
        }

        function deleteTag(tagName){
            let selectText = pageofficectrl.word.GetTextFromSelection();
            if(tagName != selectText){
                alert('请先执行‘'+tagName+'’的定位操作,然后再删除。');
            }else{
                pageofficectrl.word.SetTextToSelection('');
            }
        }

        function AfterDocumentOpened() {
            definedDataTagJson = pageofficectrl.word.DataTagsDefinedAsJson;
            loadData();
        }

    </script> 


    <div id="left-container">
        <div id="left-title">定义数据标签</div>
        <div class="input-group">
            <span style="font-size: 14px;">待添加标签:</span><input type="text" id="inputKey" oninput="loadData();" placeholder="请输入数据标签关键字搜索">
        </div>
        <div class="container">
            <table id="tagTable">
                <thead>
                <tr>
                    <th>数据标签</th>
                    <th style="width: 130px;">操作</th>
                </tr>
                </thead>
                <tbody>
                <!-- 数据行 -->
                </tbody>
            </table>
        </div>

    </div>

用户在线编辑模板效果2: 编辑模板的界面只显示Word文件,添加数据标签时,弹出一个非模态的数据标签选择框,然后用户就可以在Word文件中点击定位光标到需要插入数据的位置,再点击数据标签选择框中的数据标签进行添加。比如下图所示:点击“定义数据标签”按钮,弹出数据标签选择框,然后定位光标到Word中需要插入“乙方”的位置,然后点击数据标签“{ 乙方 }”的添加按钮,“{ 乙方 }”标签就被插入到了Word光标所在位置。
image
此效果所用到的数据标签选择框DataTagDlg.htm的页面代码:


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>定义数据标签</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            font-size:10px;
            margin: 0;
            padding: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100%;
            background-color: #f5f5f5;
        }

        .container {
            display: flex;
            width: 99%;
            max-width: 100%;
        }

        .left, .right {
            background-color: #fff;
            padding:0 10px;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
        }
        .left{
            flex-grow: 7;
        }
        .right {
            flex-grow: 3;
        }

        h5 {
            margin-bottom: 10px;
        }

        input[type="text"], textarea {
            width: 90%;
            padding: 10px;
            margin-bottom: 15px;
            border-radius: 5px;
            border: 1px solid #ccc;
        }

        /* 表格样式 */
        table {
            table-layout: fixed;/* 设置表格的布局为固定布局 */
            border-collapse: collapse;
            width: 100%;
        }

        th, td {
            padding: 8px;
            text-align: left;
            border-bottom: 1px solid #ddd;
            white-space: nowrap; /* 强制单元格内文字不换行 */
            overflow: hidden; /* 隐藏超出单元格的文字 */
            text-overflow: ellipsis; /* 显示省略号 */
        }

        th {
            position: sticky;
            top: 0;
            background-color: #f2f2f2;
            z-index: 1;
        }

        /* 容器样式 */
        .tbcontainer {
            height: 300px;
            overflow: auto;
            border: solid 1px #ccc;
            scrollbar-width: thin;
            scrollbar-color: #888 #f2f2f2;
        }

        /* 滚动条样式 */
        .tbcontainer::-webkit-scrollbar {
            width: 8px;
        }

        .tbcontainer::-webkit-scrollbar-track {
            background: #f2f2f2;
        }

        .tbcontainer::-webkit-scrollbar-thumb {
            background-color: #888;
            border-radius: 4px;
        }

        .tbcontainer::-webkit-scrollbar-thumb:hover {
            background-color: #555;
        }
        .delete-button {
            padding: 3px 3px;
            border: none;
            border-radius: 3px;
            background-color: #f44336;
            color: white;
            font-size: 10px;
            cursor: pointer;
        }
        .delete-button:hover {
            background-color: #d32f2f;
        }

        .normal-button {
            padding: 3px 3px;
            border: none;
            border-radius: 3px;
            background-color: #4E7EFF;
            color: white;
            font-size: 10px;
            cursor: pointer;
        }
        .normal-button:hover {
            background-color: #4E6EF2;
        }

        .locate-button {
            padding: 3px 3px;
            border: none;
            border-radius: 3px;
            background-color: #0abb87;
            color: white;
            font-size: 10px;
            cursor: pointer;
        }
        .locate-button:hover {
            background-color: #0a9966;
        }

        /* 定义信息提示条的样式 */
        .alert-container {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            z-index: 9999;
        }

        .alert-bar {
            padding: 10px;
            border-bottom: solid 1px #f8a2a6;
            background-color: #f8d7da;
            color: #721c24;
            font-weight: bold;
            text-align: center;
            margin-bottom: 1px;
            opacity: 1;
            transition: all 0.5s ease;
        }

        .alert-bar.hide {
            opacity: 0;
            transform: translateY(-50px);
        }
    </style>
</head>
<body>
<!-- 定义信息提示条的HTML结构 -->
<div id="alert-container" class="alert-container"></div>

<div class="container">
    <div class="left">
        <h5>待添加标签:</h5>
        <input type="text" id="inputKey" oninput="loadData();" placeholder="请输入数据标签关键字搜索" />
        <div class="tbcontainer">
            <table id="tagTable">
                <thead>
                <tr>
                    <th>数据标签</th>
                    <th style="width: 110px;">操作</th>
                </tr>
                </thead>
                <tbody>
                <!-- 大量的数据行 -->
                <!--<tr>-->
                <!--<td>AAA</td>-->
                <!--<td>BBB</td>-->
                <!--<td><button class="normal-button">添加</button></td>-->
                <!--</tr>-->

                </tbody>
            </table>
        </div>
    </div>

</div>

<script>
    let definedDataTagJson = window.external.UserParams;

    var isFromStart = false;
    var lastOpTag = '';

    //加载数据
    function loadData() {
        var kWord = document.getElementById("inputKey").value;
        searchDataTag(definedDataTagJson, kWord);
        return;
    }

    //加载上方数据列表
    function searchDataTag(dtDefinedJson, s){
        var tb1 = document.getElementById("tagTable");
        var rCount = tb1.rows.length;
        for (var i = 1; i < rCount; i++) {
            tb1.deleteRow(1);
        }

        if('' == dtDefinedJson) dtDefinedJson = '[]';
        let definedDataTagObj = JSON.parse(dtDefinedJson);

        var oTable = document.getElementById("tagTable");
        var tbodyObj = oTable.tBodies[0];
        for(let key in definedDataTagObj ){
            let dtName = definedDataTagObj[key].name;
            if (dtName.toLocaleLowerCase().indexOf(s.toLocaleLowerCase()) > -1) {
                var oTr = tbodyObj.insertRow();
                var oTd = oTr.insertCell();
                oTd.innerHTML = dtName;
                oTd.title = dtName;
                oTd = oTr.insertCell();
                oTd.innerHTML = '<button class="delete-button" onclick="deleteTag(\''+ dtName +'\')">删除</button> <button class="locate-button" onclick="locateTag(\''+ dtName +'\')" >定位</button> <button class="normal-button" onclick="addTag(\''+ dtName +'\');">添加</button> ';
            }
        }
    }

    function addTag(tagName) {
        pageofficectrl.word.SetTextToSelection(tagName);
    }

    function locateTag(tagName){
        pageofficectrl.word.SelectionCollapse(0);

        if(isFromStart){
            if(lastOpTag == tagName){
                pageofficectrl.word.HomeKey(6);
            }

            isFromStart = false;
        }

        if(!pageofficectrl.word.FindNextText(tagName)){
            showAlert('已经搜索到文档末尾。');
            isFromStart = true;
        }

        lastOpTag = tagName;
    }

    function deleteTag(tagName){
        let selectText = pageofficectrl.word.GetTextFromSelection();
        if(tagName != selectText){
            showAlert('请先执行‘'+tagName+'’的定位操作,然后再删除。');
        }else{
            pageofficectrl.word.SetTextToSelection('');
        }
    }

    // 自定义alert提示条
    function showAlert(message) {
        var alertBar = document.createElement('div');
        alertBar.className = 'alert-bar';
        alertBar.textContent = message;

        var alertContainer = document.getElementById('alert-container');
        alertContainer.insertBefore(alertBar, alertContainer.firstChild);
        alertBar.style.animation = 'slideDown 0.5s ease-out';

        setTimeout(function() {
            alertBar.classList.add('hide');
            setTimeout(function() {
                alertContainer.removeChild(alertBar);
            }, 500);
        }, 2000);
    }

    loadData();
</script>
</body>
</html>

自定义工具栏“定义数据标签”按钮的相关代码:

function Save() {
    pageofficectrl.WebSave();
}

function ShowDefineDataTags() {
    var dtDefinedJson = pageofficectrl.word.DataTagsDefinedAsJson;
    pageofficectrl.ShowHtmlModelessDialog("DataTagDlg.jsp", dtDefinedJson, "left=300px;top=390px;width=400px;height=410px;frame:no;");
}

function OnPageOfficeCtrlInit() {
    pageofficectrl.AddCustomToolButton("保存", "Save", 1);
    pageofficectrl.AddCustomToolButton("定义数据标签", "ShowDefineDataTags", 20);
}

在最终需要动态填充数据到word模板中生成正式合同文件时,开发人员只管编写代码给所有的数据标签赋值即可,无需关心用户自定义的word模板中到底使用了哪些数据标签,因为那些没有使用的数据标签会被PageOffice自动忽略掉;而最终用户也可以根据自己的实际需要定义好word模板中各项数据及其位置,无需关心数据从哪里来,也不用事事都与开发人员沟通,当业务需求发生简单的变化时,可以自主修改word模板来满足新的需求。这样一来,不管是用户还是开发人员,都在一定程度上从这种纷杂多变的业务需求中解脱出来。

参考链接:用户自定义模板中数据标签

标签:Word,自定义,数据,color,标签,border,模板
From: https://www.cnblogs.com/qq742655/p/17988872

相关文章

  • Pseudo-Label伪标签
    1.Semi-SupervisedLearningSemi-SupervisedLearning(半监督学习)是监督学习和无监督学习的一种结合方法。半监督学习使用大量的未标记数据,以及同时使用标记数据,来进行模式识别工作。2.Pseudo-Label产生伪标签的步骤非常简单,可以用如下步骤概括:Step1:给定带标签数据和不带标......
  • 记windows自定义bat脚本自启动
    自定义Windows启动脚本简化版在本指南中,我们将使用一个简化的批处理文件(.bat)来演示如何创建自定义的Windows启动脚本。以下是一个基本的模板,您只需根据需要在:begin部分添加您的代码。@echooffif"%1"=="h"gotobeginrem获取脚本路径set"scriptPath=%~dp0"rem......
  • Auth模板
    Auth模板什么是Auth模块,有什么用?django的auth的模块的使用:auth是集合注册,登录,注销,session多个功能集合在一起的模块使用Auth组件的默认auth_user表常用操作fromdjango.contrib.auth.modelsimportUser#1、创建普通用户User.objects.create_user(username='......
  • P3374 【模板】树状数组 1(线段树)
    【模板】树状数组1题目描述如题,已知一个数列,你需要进行下面两种操作:将某一个数加上x求出某区间每一个数的和输入格式第一行包含两个正整数n,m,分别表示该数列数字的个数和操作的总个数。第二行包含n个用空格分隔的整数,其中第i个数字表示数列第i项的初始值......
  • springBoot自定义参数注解
    springBoot自定义参数注解前置条件:新建一个springboot项目1.新建一个标记注解@Authimportjava.lang.annotation.ElementType;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.lang.annotation.Target;/***@authorwa......
  • SSAS 利用Adomd 编程实现Cube的自定义配置
    利用Adomd执行Cube数据库的配置。 需要下载:Microsoft.AnalysisServices.AdomdClient,安装,再搜索到DLL的位置,在程序里引用下载地址 环境:SqlServer2022表格模型脚本内容存放在:s01.json文件里AdomdConnectionconn=newAdomdConnection("DataSourc......
  • 解决IE浏览器textarea标签placeholder不生效的问题
    IE10给textarea设置了placeholder,F12控制台打印document.getElementById(id).getAttribute('placeholder'),可以看到placeholder的值,但是浏览器不显示,可以再添加如下代码显示出来,不需要引用JQuery,前提是该元素已经设置了placeholder属性,并且浏览器支持placeholder,IE8和IE9不支持,参......
  • 【K8S】label标签常用命令
    node节点增加、修改、删除、查看、查找label标签单个node增加标签:kubectllabelnode<nodename>type=basic所有node增加标签:kubectllabelnode--alltype=basic修改:kubectllabelnode<nodename>type=special--overwrite删除单个标签:kubectllabelnode<nodename>type-......
  • 根据word模板动态导出word文档
    根据word模板动态导出word文档前置条件:新建一个springboot项目1.引jar包<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><group......
  • 【模板】并查集
    并查集是解决两元素是否属于同一集合,将一个集合合并另一集合的数据结构。具体来说,我们使用数字代替集合,比如集合1,集合2.使用数组f[i]维护元素i属于的集合,比如f[2]=4表示元素2属于集合4。具体我们有以下实现功能的代码1初始化表示集合的数组。cin>>n>>m;for(int......