在實際的Word文檔開發中,經常需要自動填充數據到Word模板中,以生成動態的Word文檔,那麼應該如何編輯製作Word模板呢?
方法一:直接打開Word文件插入書籤
假如使用數據區域(DataRegion)來定義模板中動態填充數據的位置,那麼直接打開一個Word文件,在其中添加“PO_”開頭的書籤即可製作word模板。例如,打開一個Word文件後,可以通過選中需要標記爲書籤的文字,例如“[姓名]”,然後點擊Word菜單中的“插入”-“書籤”來添加書籤,在彈出的“書籤”對話框中,輸入新書籤的名稱PO_userName,並點擊右側的“添加”按鈕,即可完成一個數據區域的定義。效果如下圖所示:
注意
書籤名必須以“PO_”開頭,並由字母和數字組成,但中間不能有空格。
Word模板中需要多少個動態填充數據的位置,就在Word文件中相應的位置插入多少個“PO_”開頭的書籤即可,這種製作word模板的方法操作簡單,但是常常用於新項目開發中開發人員定義Word模板。開發人員知道在Word模板的哪個位置要插入哪個數據,就比如上面所說的“姓名”的位置需要插入系統裏的數據UserName,所以就定義了一個PO_userName的書籤,然後就可以編程調用PageOffice接口,把web系統裏的UserName賦值給數據區域PO_userName,其他的數據區域也是相同的處理方式。但是項目發佈後用戶需求變動,希望修改Word模板或創建新的Word模板,用戶怎麼知道如何製作word模板呢?如何插入書籤?如何命名書籤?哪些名字的書籤與哪些系統數據是對應的呢?
方法二:給用戶提供自定義模板功能
開發人員可以給系統增加一個模板管理的模塊,擁有模板管理權限的用戶可以查看系統中的模板列表,可以新增、刪除和在線編輯模板,開發人員通過程序定義好編輯某種模板時可能用到的所有數據區域,用戶自定義編輯Word模板時可以把全部數據區域插入到模板的相應位置,也可以根據實際需求只使用部分數據區域,但Word模板中數據區域的數量總是開發人員定義的數據區域集合的子集,這樣一來就能實現開發人員與用戶的分工合作。
比如說web系統中合同模板的製作,合同模板中可能會用到的數據有:合同編號、購貨單位、供貨單位、產品名稱、購貨單位地址、供貨單位地址、擔保人、擔保人手機,那麼開發人員可以編寫代碼定義好這些數據區域,讓用戶在線打開編輯模板時,只能在Word模板中插入這些系統定義好的數據區域,這樣做不但實現了開發人員與用戶的一種約定,而且規範了用戶的操作。
- 開發人員編寫代碼定義好編輯模板時所有可用的數據區域:
開發人員調用PageOffice提供的defineDataRegion方法定義用戶編輯模板時所有可用的數據區域,第一個參數是數據區域名稱,也就是word書籤的名稱,第二個參數是數據區域在Word文件中顯示的文字內容,格式沒有特殊要求。下面示例代碼中顯示的文字內容都使用了中括號(也可以使用其他符號),僅僅是爲了便於用戶直觀的查看Word模板中哪些位置是插入的數據區域。
WordDocument doc = new WordDocument();
doc.getTemplate().defineDataRegion("PO_Guarantor", "[擔保人]");
doc.getTemplate().defineDataRegion("PO_SupplierAddress", "[供貨單位地址]");
doc.getTemplate().defineDataRegion("PO_BuyerAddress", "[購貨單位地址]");
doc.getTemplate().defineDataRegion("PO_No", "[合同編號]");
doc.getTemplate().defineDataRegion("PO_GuarantorPhone", "[擔保人手機]");
doc.getTemplate().defineDataRegion("PO_ProductName", "[產品名稱]");
doc.getTemplate().defineDataRegion("PO_Buyer", "[購貨單位]");
doc.getTemplate().defineDataRegion("PO_Supplier", "[供貨單位]");
- 用戶編輯模板時,直接使用開發人員定義好的數據區域來製作模板:
由於用戶操作習慣和Web系統界面風格的不同,開發人員可以根據實際需求在自己的Web項目中選擇實現下面的一種編輯模板效果。
用戶在線編輯模板效果1: 把數據區域列表和Word文件編輯界面,一左一右放到同一個頁面窗口中,用戶在右側Word文件中點擊定位光標到需要插入數據的位置,然後在左側選擇相應的數據區域,添加到當前位置即可。比如下圖所示:在Word中需要插入“合同編號”的位置點擊一下鼠標,然後在左側“待添加區域”中點擊數據區域“PO_No”的添加按鈕,數據區域“PO_No”就被插入到了Word光標所在位置,且“待添加區域”列表中的數據區域“PO_No”被移動到“已添加區域”的列表中。
此效果所用到的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: 300px;
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 type="text/javascript">
//控件中的一些常用方法都在這裏調用,比如保存,打印等等
function OnPageOfficeCtrlInit() {
pageofficectrl.AddCustomToolButton("保存", "Save", 1);
}
function Save() {
pageofficectrl.WebSave();
}
//加載數據
function loadData() {
var kWord1 = document.getElementById("inputKey1").value;
var kWord2 = document.getElementById("inputKey2").value;
var definedDataRegionJson = pageofficectrl.word.DataRegionsDefinedAsJson;
var dataRegionJson = pageofficectrl.word.DataRegionsAsJson;
searchDataRegion(definedDataRegionJson, dataRegionJson, kWord1);
searchDataRegion2(dataRegionJson, kWord2);
}
//加載上方數據列表
function searchDataRegion(drDefinedJson, drJson, s){
var tb1 = document.getElementById("bkmkTable");
var rCount = tb1.rows.length;
for (var i = 1; i < rCount; i++) {
tb1.deleteRow(1);
}
if('' == drDefinedJson) drDefinedJson = '[]';
let definedDataRegionObj = JSON.parse(drDefinedJson);
let dataRegionsJson = drJson;
if('' == dataRegionsJson) dataRegionsJson = '[]';
let dataRegionsObj = JSON.parse(dataRegionsJson);
var oTable = document.getElementById("bkmkTable");
var tbodyObj = oTable.tBodies[0];
for(let key in definedDataRegionObj ){
let drName = definedDataRegionObj[key].name;
let drCaption = definedDataRegionObj[key].caption;
//alert("數據區域:"+drName+"; 值:"+drValue);
let bFind = false;
for(let k in dataRegionsObj){
if(dataRegionsObj[k].name == drName){
bFind = true;
break;
}
}
if(bFind) continue;
if (drName.toLocaleLowerCase().indexOf(s.toLocaleLowerCase()) > -1) {
var oTr = tbodyObj.insertRow();
var oTd = oTr.insertCell();
oTd.innerHTML = drName;
oTd = oTr.insertCell();
oTd.innerHTML = drCaption;
oTd = oTr.insertCell();
oTd.innerHTML = '<button class="normal-button" onclick="addDataRegion(\''+drName+'\',\''+drCaption+'\');loadData();">添加</button>';
}
}
}
//加載下方數據列表
function searchDataRegion2(drJson, s) {
//刪除所有行
var tb1 = document.getElementById("bkmkTable2");
var rCount = tb1.rows.length;
for (var i = 1; i < rCount; i++) {
tb1.deleteRow(1);
}
let dataRegionsJson = drJson;
if('' == dataRegionsJson) dataRegionsJson = '[]';
let dataRegionsObj = JSON.parse(dataRegionsJson);
var oTable = document.getElementById("bkmkTable2");
var tbodyObj = oTable.tBodies[0];
for(let key in dataRegionsObj ){
let drName = dataRegionsObj[key].name;
if (drName.toLocaleLowerCase().indexOf(s.toLocaleLowerCase()) > -1) {
var oTr = tbodyObj.insertRow();
var oTd = oTr.insertCell();
oTd.innerHTML = drName;
oTd = oTr.insertCell();
oTd.innerHTML = '<button class="delete-button" onclick="deleteDataRegion(\''+ drName +'\');loadData();">刪除</button> <button class="locate-button" onclick="locateDataRegion(\''+ drName +'\');">定位</button>';
}
}
}
function locateDataRegion(drName) {
pageofficectrl.word.LocateDataRegion(drName);
}
function deleteDataRegion(drName){
pageofficectrl.word.DeleteDataRegion(drName);
}
function addDataRegion(drName, drValue){
pageofficectrl.word.AddDataRegion(drName, drValue);
}
function AfterDocumentOpened() {
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="inputKey1" oninput="loadData();" placeholder="請輸入數據區域關鍵字搜索">
</div>
<div class="container">
<table id="bkmkTable">
<thead>
<tr>
<th>數據區域</th>
<th>顯示文字</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<!-- 數據行 -->
</tbody>
</table>
</div>
<div class="input-group" style="margin-top: 20px">
<span style="font-size: 14px;">已添加區域:</span><input type="text" id="inputKey2" oninput="loadData();" placeholder="請輸入數據區域關鍵字搜索">
</div>
<div class="container">
<table id="bkmkTable2">
<thead>
<tr>
<th>數據區域</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<!-- 數據行 -->
</tbody>
</table>
</div>
</div>
用戶在線編輯模板效果2: 編輯模板的界面只顯示Word文件,添加數據區域時,彈出一個非模態的數據區域選擇框,然後用戶就可以在Word文件中點擊定位光標到需要插入數據的位置,再點擊數據區域選擇框中未使用過的數據區域進行添加。比如下圖所示:點擊“定義數據區域”按鈕,彈出數據區域選擇框,然後定位光標到Word中需要插入“購貨單位”的位置,然後在數據區域選擇框左側“待添加區域”中點擊數據區域“PO_Buyer”的添加按鈕,數據區域“PO_Buyer”就被插入到了Word光標所在位置,且“待添加區域”列表中的數據區域“PO_Buyer”被移動到“已添加區域”的列表中。
此效果所用到的數據區域選擇框DataRegionDlg.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 {
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;
}
/* 容器樣式 */
.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;
}
</style>
</head>
<body>
<div class="container">
<div class="left">
<h5>待添加區域:</h5>
<input type="text" id="inputKey1" oninput="loadData();" placeholder="請輸入數據區域關鍵字搜索" />
<div class="tbcontainer">
<table id="bkmkTable">
<thead>
<tr>
<th>數據區域</th>
<th>顯示文字</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<!-- 數據行 -->
</tbody>
</table>
</div>
</div>
<div class="right">
<h5>已添加區域:</h5>
<input type="text" id="inputKey2" oninput="loadData();" placeholder="請輸入數據區域關鍵字搜索" />
<div class="tbcontainer">
<table id="bkmkTable2">
<thead>
<tr>
<th>數據區域</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<!-- 數據行 -->
</tbody>
</table>
</div>
</div>
</div>
<script>
let definedDataRegionJson = window.external.UserParams;
//加載數據
function loadData() {
var kWord1 = document.getElementById("inputKey1").value;
var kWord2 = document.getElementById("inputKey2").value;
var dataRegionJson = pageofficectrl.word.DataRegionsAsJson;
searchDataRegion(definedDataRegionJson, dataRegionJson, kWord1);
searchDataRegion2(dataRegionJson, kWord2);
}
//加載待添加區域列表
function searchDataRegion(drDefinedJson, drJson, s){
var tb1 = document.getElementById("bkmkTable");
var rCount = tb1.rows.length;
for (var i = 1; i < rCount; i++) {
tb1.deleteRow(1);
}
if('' == drDefinedJson) drDefinedJson = '[]';
var definedDataRegionObj = JSON.parse(drDefinedJson);
var dataRegionsJson = drJson;
if('' == dataRegionsJson) dataRegionsJson = '[]';
var dataRegionsObj = JSON.parse(dataRegionsJson);
var oTable = document.getElementById("bkmkTable");
var tbodyObj = oTable.tBodies[0];
for(let key in definedDataRegionObj ){
let drName = definedDataRegionObj[key].name;
let drCaption = definedDataRegionObj[key].caption;
//alert("數據區域:"+drName+"; 值:"+drValue);
let bFind = false;
for(let k in dataRegionsObj){
if(dataRegionsObj[k].name == drName){
bFind = true;
break;
}
}
if(bFind) continue;
if (drName.toLocaleLowerCase().indexOf(s.toLocaleLowerCase()) > -1) {
var oTr = tbodyObj.insertRow();
var oTd = oTr.insertCell();
oTd.innerHTML = drName;
oTd = oTr.insertCell();
oTd.innerHTML = drCaption;
oTd = oTr.insertCell();
oTd.innerHTML = '<button class="normal-button" onclick="addDataRegion(\''+drName+'\',\''+drCaption+'\');loadData();">添加</button>';
}
}
}
//加載已添加區域列表
function searchDataRegion2(drJson, s) {
//刪除所有行
var tb1 = document.getElementById("bkmkTable2");
var rCount = tb1.rows.length;
for (var i = 1; i < rCount; i++) {
tb1.deleteRow(1);
}
let dataRegionsJson = drJson;
if('' == dataRegionsJson) dataRegionsJson = '[]';
let dataRegionsObj = JSON.parse(dataRegionsJson);
var oTable = document.getElementById("bkmkTable2");
var tbodyObj = oTable.tBodies[0];
for(let key in dataRegionsObj ){
let drName = dataRegionsObj[key].name;
if (drName.toLocaleLowerCase().indexOf(s.toLocaleLowerCase()) > -1) {
var oTr = tbodyObj.insertRow();
var oTd = oTr.insertCell();
oTd.innerHTML = drName;
oTd = oTr.insertCell();
oTd.innerHTML = '<button class="delete-button" onclick="deleteDataRegion(\''+ drName +'\');loadData();">刪除</button> <button class="locate-button" onclick="locateDataRegion(\''+ drName +'\');">定位</button>';
}
}
}
function locateDataRegion(drName) {
pageofficectrl.word.LocateDataRegion(drName);
}
function deleteDataRegion(drName){
pageofficectrl.word.DeleteDataRegion(drName);
}
function addDataRegion(drName, drValue){
pageofficectrl.word.AddDataRegion(drName, drValue);
}
loadData();
</script>
</body>
</html>
自定義工具欄“定義數據區域”按鈕的相關代碼:
function Save() {
pageofficectrl.WebSave();
}
function ShowDefineDataRegions() {
var drDefinedJson = pageofficectrl.word.DataRegionsDefinedAsJson;
pageofficectrl.ShowHtmlModelessDialog("DataRegionDlg.htm", drDefinedJson, "left=300px;top=390px;width=560px;height=410px;frame:no;");
}
function OnPageOfficeCtrlInit() {
pageofficectrl.AddCustomToolButton("保存", "Save", 1);
pageofficectrl.AddCustomToolButton("定義數據區域", "ShowDefineDataRegions", 10);
}
在最終需要動態填充數據到word模板中生成正式合同文件時,開發人員只管編寫代碼給所有的數據區域賦值即可,無需關心用戶自定義的word模板中到底使用了哪些數據區域,因爲那些沒有使用的數據區域會被PageOffice自動忽略掉;而最終用戶也可以根據自己的實際需要定義好word模板中各項數據及其位置,無需關心數據從哪裏來,也不用事事都與開發人員溝通,當業務需求發生簡單的變化時,可以自主修改word模板來滿足新的需求。這樣一來,不管是用戶還是開發人員,都在一定程度上從這種紛雜多變的業務需求中解脫出來。
參考鏈接:用戶自定義模板中數據區域