报表助手
1.简介
- 该应用适用于网页打印场景
- 支持直接打印、预览报表,模板设计,生成文档
- 支持开机自启和
URL Protocol
唤醒 - 支持多指令、多任务、多线程、多模式
- 支持ws与wss双协议
- 软件下载地址:点击下载
2.架构
开发语言:
C#
应用框架:
.NET FrameWork 4.8
依赖组件:
Fleck 1.2
Newtonsoft.Json 13.0
FastReport 2023.2.4
通信协议:
WebStock
通信端口:
3676
3.文件说明
- 安装目录
\ReportHelper.exe
为主应用 - 安装目录
\ReportDesign.exe
为设计应用 - 安装目录
\config.ini
为配置文件
4.界面介绍
- 服务
- 启动服务:程序将开启端口监听与相关服务
- 停止服务:程序将停止端口监听与停止服务
- 地址
- 默认显示本机IP地址
- 支持
127.0.0.1
与localhost
- 点击可复制到剪切板
- 端口
- 监听端口号为
3676
- 请确保端口未占用
- 点击可复制到剪切板
- 监听端口号为
- 模式
- 应用模式:需人工自行开启与启动服务
- 服务模式:开启自启并启动服务且最小化运行
- 托盘
- 托盘区内可操作显示界面
- 应用的退出操作在托盘区内操作
5.配置介绍
配置文件名称:config.ini
配置项 | 默认值 | 说明 |
---|---|---|
schem | ws | 协议类型(ws或wss) |
server | 0.0.0.0 | 监听地址 |
port | 3676 | 监听端口 |
path | certificate.pfx | 证书路径(wss模式下必填) |
password | 000000 | 证书密码(wss模式下必填) |
6.功能介绍
数据交互
- 采用
JSON
作为交互格式。 - 编码统一使用
UTF-8
- 采用
指令字段
- 字段名称:
Instruct
- 类型:
String
- 描述:指令内容
- 场景:通用
- 可选项:
print
:直接打印view
:预览报表design
:设计模板document
:输出文档
- 类型:
- 字段名称:
name
- 类型:
String
- 描述:报表名称
- 场景:通用
- 类型:
- 字段名称:
templates
- 类型:
Array
- 描述:报表名称
- 场景:直接打印、预览报表、输出文档
- 内容项
source
:- 类型:
String
- 描述:数据源
- 格式:
Json=Str;Encoding=utf-8
- 内容:Str为数据对象JSON编码后Base64编码
- 类型:
template
- 类型:
String
- 描述:模板编码
- 编码:
Base64
- 类型:
- 类型:
- 字段名称:
id
- 类型:
String
- 描述:模板ID
- 场景:设计模板
- 类型:
- 字段名称:
source
- 类型:
String
- 描述:数据源
- 场景:设计模板
- 内容:同Templates下source
- 类型:
- 字段名称:
template
- 类型:
String
- 描述:数据源
- 场景:设计模板
- 内容:同templates下template
- 类型:
- 字段名称:
token
- 类型:
String
- 描述:授权码
- 场景:直接打印
- 内容:可为空
- 类型:
- 字段名称:
回传字段
- 字段名称:
state
- 类型:
String
- 描述:任务状态
- 场景:通用
- 内容项:
success
:处理成功error
:处理失败
- 类型:
- 字段名称:
instruct
- 类型:
String
- 描述:任务名称
- 场景:通用
- 内容项:
print
:已发送到打印机document
:输出文档viewOpen
:预览打开designLoad
:设计打开designClose
:设计关闭designSave
:设计保存
- 类型:
- 字段名称:
name
- 类型:
String
- 描述:报表名称
- 场景:通用
- 类型:
- 字段名称:
id
- 类型:
String
- 描述:报表ID
- 场景:设计模板
- 类型:
- 字段名称:
template
- 类型:
String
- 描述:模板内容
- 场景:设计模板
- 编码:
Base64
- 类型:
- 字段名称:
mime
- 类型:
String
- 描述:文档类型
- 场景:输出文档
- 类型:
- 字段名称:
str
- 类型:
String
- 描述:文档类型
- 场景:输出文档
- 编码:
Base64Blob
- 类型:
- 字段名称:
交互须知
- 采用数据源与模板分离模式
- 在指令下发时数据源与模板应分开传输
- 指令下发时应用将自动组合数据与模板
- 设计模式下模板回传将自动剔除数据源区块
- 模板内容在交互过程中均采用Base64编码
- 文档模式下将输出Base64编码后的Blob内容
7.交互示例
指令内容
{"instruct":"print","name":"Test","templates":[{"source":"Json=eyJjbGFzcyI6eyJ0aXRsZSI6IlJlcG9ydEhlbHBlcjAiLCJsaXN0IjpbMSwyLDNdfX0=;Encoding=utf-8","template":"PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48UmVwb3J0IFNjcmlwdExhbmd1YWdlPSJDU2hhcnAiIFJlcG9ydEluZm8uQ3JlYXRlZD0iMTAvMTYvMjAyMiAxNjoxMTozMCIgUmVwb3J0SW5mby5Nb2RpZmllZD0iMTAvMjAvMjAyMiAxNjozMjo0MCIgUmVwb3J0SW5mby5DcmVhdG9yVmVyc2lvbj0iMjAyMi4zLjkuMCI+PFJlcG9ydFBhZ2UgTmFtZT0iUGFnZTEiIFdhdGVybWFyay5Gb250PSLlrovkvZMsIDYwcHQiPjxSZXBvcnRUaXRsZUJhbmQgTmFtZT0iUmVwb3J0VGl0bGUxIiBXaWR0aD0iNzE4LjIiIEhlaWdodD0iMzcuOCI+PFRleHRPYmplY3QgTmFtZT0iVGV4dDEiIExlZnQ9IjE1MS4yIiBUb3A9IjkuNDUiIFdpZHRoPSIxODkiIEhlaWdodD0iMTguOSIgVGV4dD0i5rWL6K+VLVtKU09OLml0ZW0uY2xhc3MudGl0bGVdIiBGb250PSLlrovkvZMsIDlwdCIvPjwvUmVwb3J0VGl0bGVCYW5kPjxEYXRhQmFuZCBOYW1lPSJEYXRhMSIgVG9wPSI0MS44IiBXaWR0aD0iNzE4LjIiIEhlaWdodD0iMzcuOCIgU3RhcnROZXdQYWdlPSJ0cnVlIiBEYXRhU291cmNlPSJsaXN0Ij48VGV4dE9iamVjdCBOYW1lPSJUZXh0MiIgTGVmdD0iMTUxLjIiIFRvcD0iOS40NSIgV2lkdGg9IjIxNy4zNSIgSGVpZ2h0PSIxOC45IiBUZXh0PSJbSlNPTi5pdGVtLmNsYXNzLmxpc3QuaXRlbV0iIEZvcm1hdD0iTnVtYmVyIiBGb3JtYXQuVXNlTG9jYWxlPSJ0cnVlIiBGb3JtYXQuRGVjaW1hbERpZ2l0cz0iMiIgSG9yekFsaWduPSJDZW50ZXIiIFdvcmRXcmFwPSJmYWxzZSIgRm9udD0i5a6L5L2TLCA5cHQiIFRyaW1taW5nPSJFbGxpcHNpc0NoYXJhY3RlciIvPjwvRGF0YUJhbmQ+PC9SZXBvcnRQYWdlPjwvUmVwb3J0Pg0K"}]}
指令内容
{"state":"success","instruct":"print","name":"Test"}
指令内容
{"instruct":"view","name":"Test","templates":[{"source":"Json=eyJjbGFzcyI6eyJ0aXRsZSI6IlJlcG9ydEhlbHBlcjAiLCJsaXN0IjpbMSwyLDNdfX0=;Encoding=utf-8","template":"PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48UmVwb3J0IFNjcmlwdExhbmd1YWdlPSJDU2hhcnAiIFJlcG9ydEluZm8uQ3JlYXRlZD0iMTAvMTYvMjAyMiAxNjoxMTozMCIgUmVwb3J0SW5mby5Nb2RpZmllZD0iMTAvMjAvMjAyMiAxNjozMjo0MCIgUmVwb3J0SW5mby5DcmVhdG9yVmVyc2lvbj0iMjAyMi4zLjkuMCI+PFJlcG9ydFBhZ2UgTmFtZT0iUGFnZTEiIFdhdGVybWFyay5Gb250PSLlrovkvZMsIDYwcHQiPjxSZXBvcnRUaXRsZUJhbmQgTmFtZT0iUmVwb3J0VGl0bGUxIiBXaWR0aD0iNzE4LjIiIEhlaWdodD0iMzcuOCI+PFRleHRPYmplY3QgTmFtZT0iVGV4dDEiIExlZnQ9IjE1MS4yIiBUb3A9IjkuNDUiIFdpZHRoPSIxODkiIEhlaWdodD0iMTguOSIgVGV4dD0i5rWL6K+VLVtKU09OLml0ZW0uY2xhc3MudGl0bGVdIiBGb250PSLlrovkvZMsIDlwdCIvPjwvUmVwb3J0VGl0bGVCYW5kPjxEYXRhQmFuZCBOYW1lPSJEYXRhMSIgVG9wPSI0MS44IiBXaWR0aD0iNzE4LjIiIEhlaWdodD0iMzcuOCIgU3RhcnROZXdQYWdlPSJ0cnVlIiBEYXRhU291cmNlPSJsaXN0Ij48VGV4dE9iamVjdCBOYW1lPSJUZXh0MiIgTGVmdD0iMTUxLjIiIFRvcD0iOS40NSIgV2lkdGg9IjIxNy4zNSIgSGVpZ2h0PSIxOC45IiBUZXh0PSJbSlNPTi5pdGVtLmNsYXNzLmxpc3QuaXRlbV0iIEZvcm1hdD0iTnVtYmVyIiBGb3JtYXQuVXNlTG9jYWxlPSJ0cnVlIiBGb3JtYXQuRGVjaW1hbERpZ2l0cz0iMiIgSG9yekFsaWduPSJDZW50ZXIiIFdvcmRXcmFwPSJmYWxzZSIgRm9udD0i5a6L5L2TLCA5cHQiIFRyaW1taW5nPSJFbGxpcHNpc0NoYXJhY3RlciIvPjwvRGF0YUJhbmQ+PC9SZXBvcnRQYWdlPjwvUmVwb3J0Pg0K"}]}
回传内容
{"state":"success","instruct":"viewOpen","name":"Test"}
设计模板
指令内容
{"instruct":"design","id":2,"name":"Test","source":"Json=eyJjbGFzcyI6eyJ0aXRsZSI6IlJlcG9ydEhlbHBlcjAiLCJsaXN0IjpbMSwyLDNdfX0=;Encoding=utf-8","template":"PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48UmVwb3J0IFNjcmlwdExhbmd1YWdlPSJDU2hhcnAiIFJlcG9ydEluZm8uQ3JlYXRlZD0iMTAvMTYvMjAyMiAxNjoxMTozMCIgUmVwb3J0SW5mby5Nb2RpZmllZD0iMTAvMjAvMjAyMiAxNjozMjo0MCIgUmVwb3J0SW5mby5DcmVhdG9yVmVyc2lvbj0iMjAyMi4zLjkuMCI+PFJlcG9ydFBhZ2UgTmFtZT0iUGFnZTEiIFdhdGVybWFyay5Gb250PSLlrovkvZMsIDYwcHQiPjxSZXBvcnRUaXRsZUJhbmQgTmFtZT0iUmVwb3J0VGl0bGUxIiBXaWR0aD0iNzE4LjIiIEhlaWdodD0iMzcuOCI+PFRleHRPYmplY3QgTmFtZT0iVGV4dDEiIExlZnQ9IjE1MS4yIiBUb3A9IjkuNDUiIFdpZHRoPSIxODkiIEhlaWdodD0iMTguOSIgVGV4dD0i5rWL6K+VLVtKU09OLml0ZW0uY2xhc3MudGl0bGVdIiBGb250PSLlrovkvZMsIDlwdCIvPjwvUmVwb3J0VGl0bGVCYW5kPjxEYXRhQmFuZCBOYW1lPSJEYXRhMSIgVG9wPSI0MS44IiBXaWR0aD0iNzE4LjIiIEhlaWdodD0iMzcuOCIgU3RhcnROZXdQYWdlPSJ0cnVlIiBEYXRhU291cmNlPSJsaXN0Ij48VGV4dE9iamVjdCBOYW1lPSJUZXh0MiIgTGVmdD0iMTUxLjIiIFRvcD0iOS40NSIgV2lkdGg9IjIxNy4zNSIgSGVpZ2h0PSIxOC45IiBUZXh0PSJbSlNPTi5pdGVtLmNsYXNzLmxpc3QuaXRlbV0iIEZvcm1hdD0iTnVtYmVyIiBGb3JtYXQuVXNlTG9jYWxlPSJ0cnVlIiBGb3JtYXQuRGVjaW1hbERpZ2l0cz0iMiIgSG9yekFsaWduPSJDZW50ZXIiIFdvcmRXcmFwPSJmYWxzZSIgRm9udD0i5a6L5L2TLCA5cHQiIFRyaW1taW5nPSJFbGxpcHNpc0NoYXJhY3RlciIvPjwvRGF0YUJhbmQ+PC9SZXBvcnRQYWdlPjwvUmVwb3J0Pg0K"}
- 回传内容
设计打开
{"state":"success","instruct":"designLoad","id":"2","name":"Test"}
模板回传
{"state":"success","instruct":"designSave","id":"2","name":"Test","template":"PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48UmVwb3J0IFNjcmlwdExhbmd1YWdlPSJDU2hhcnAiIFJlcG9ydEluZm8uQ3JlYXRlZD0iMTAvMTYvMjAyMiAxNjoxMTozMCIgUmVwb3J0SW5mby5Nb2RpZmllZD0iMTAvMjAvMjAyMiAxNzoyNjowOSIgUmVwb3J0SW5mby5DcmVhdG9yVmVyc2lvbj0iMjAyMi4zLjkuMCI+PFJlcG9ydFBhZ2UgTmFtZT0iUGFnZTEiIFdhdGVybWFyay5Gb250PSLlrovkvZMsIDYwcHQiPjxSZXBvcnRUaXRsZUJhbmQgTmFtZT0iUmVwb3J0VGl0bGUxIiBXaWR0aD0iNzE4LjIiIEhlaWdodD0iMzcuOCI+PFRleHRPYmplY3QgTmFtZT0iVGV4dDEiIExlZnQ9IjE4OSIgVG9wPSI5LjQ1IiBXaWR0aD0iMTg5IiBIZWlnaHQ9IjE4LjkiIFRleHQ9Iua1i+ivlS1bSlNPTi5pdGVtLmNsYXNzLnRpdGxlXSIgRm9udD0i5a6L5L2TLCA5cHQiLz48L1JlcG9ydFRpdGxlQmFuZD48RGF0YUJhbmQgTmFtZT0iRGF0YTEiIFRvcD0iNDEuOCIgV2lkdGg9IjcxOC4yIiBIZWlnaHQ9IjM3LjgiIFN0YXJ0TmV3UGFnZT0idHJ1ZSIgRGF0YVNvdXJjZT0ibGlzdCI+PFRleHRPYmplY3QgTmFtZT0iVGV4dDIiIExlZnQ9IjE1MS4yIiBUb3A9IjkuNDUiIFdpZHRoPSIyMTcuMzUiIEhlaWdodD0iMTguOSIgVGV4dD0iW0pTT04uaXRlbS5jbGFzcy5saXN0Lml0ZW1dIiBGb3JtYXQ9Ik51bWJlciIgRm9ybWF0LlVzZUxvY2FsZT0idHJ1ZSIgRm9ybWF0LkRlY2ltYWxEaWdpdHM9IjIiIEhvcnpBbGlnbj0iQ2VudGVyIiBXb3JkV3JhcD0iZmFsc2UiIEZvbnQ9IuWui+S9kywgOXB0IiBUcmltbWluZz0iRWxsaXBzaXNDaGFyYWN0ZXIiLz48L0RhdGFCYW5kPjwvUmVwb3J0UGFnZT48L1JlcG9ydD4NCg=="}
设计关闭
{"state":"success","instruct":"designClose","id":"2","name":"Test"}
指令内容
{"instruct":"document","name":"Test","templates":[{"source":"Json=eyJjbGFzcyI6eyJ0aXRsZSI6IlJlcG9ydEhlbHBlcjAiLCJsaXN0IjpbMSwyLDNdfX0=;Encoding=utf-8","template":"PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48UmVwb3J0IFNjcmlwdExhbmd1YWdlPSJDU2hhcnAiIFJlcG9ydEluZm8uQ3JlYXRlZD0iMTAvMTYvMjAyMiAxNjoxMTozMCIgUmVwb3J0SW5mby5Nb2RpZmllZD0iMTAvMjAvMjAyMiAxNzoyNjowOSIgUmVwb3J0SW5mby5DcmVhdG9yVmVyc2lvbj0iMjAyMi4zLjkuMCI+PFJlcG9ydFBhZ2UgTmFtZT0iUGFnZTEiIFdhdGVybWFyay5Gb250PSLlrovkvZMsIDYwcHQiPjxSZXBvcnRUaXRsZUJhbmQgTmFtZT0iUmVwb3J0VGl0bGUxIiBXaWR0aD0iNzE4LjIiIEhlaWdodD0iMzcuOCI+PFRleHRPYmplY3QgTmFtZT0iVGV4dDEiIExlZnQ9IjE4OSIgVG9wPSI5LjQ1IiBXaWR0aD0iMTg5IiBIZWlnaHQ9IjE4LjkiIFRleHQ9Iua1i+ivlS1bSlNPTi5pdGVtLmNsYXNzLnRpdGxlXSIgRm9udD0i5a6L5L2TLCA5cHQiLz48L1JlcG9ydFRpdGxlQmFuZD48RGF0YUJhbmQgTmFtZT0iRGF0YTEiIFRvcD0iNDEuOCIgV2lkdGg9IjcxOC4yIiBIZWlnaHQ9IjM3LjgiIFN0YXJ0TmV3UGFnZT0idHJ1ZSIgRGF0YVNvdXJjZT0ibGlzdCI+PFRleHRPYmplY3QgTmFtZT0iVGV4dDIiIExlZnQ9IjE1MS4yIiBUb3A9IjkuNDUiIFdpZHRoPSIyMTcuMzUiIEhlaWdodD0iMTguOSIgVGV4dD0iW0pTT04uaXRlbS5jbGFzcy5saXN0Lml0ZW1dIiBGb3JtYXQ9Ik51bWJlciIgRm9ybWF0LlVzZUxvY2FsZT0idHJ1ZSIgRm9ybWF0LkRlY2ltYWxEaWdpdHM9IjIiIEhvcnpBbGlnbj0iQ2VudGVyIiBXb3JkV3JhcD0iZmFsc2UiIEZvbnQ9IuWui+S9kywgOXB0IiBUcmltbWluZz0iRWxsaXBzaXNDaGFyYWN0ZXIiLz48L0RhdGFCYW5kPjwvUmVwb3J0UGFnZT48L1JlcG9ydD4NCg=="}]}
回传内容
{{"state":"success","instruct":"document","name":"Test","mime":"application/pdf","str":"base64..."}
8.JavaScript 示例
import { Base64 } from 'js-base64';
//报表助手
const helper = {
token:'',
ver: '1.3.2.4',
ip: '127.0.0.1',
port: '3676',
ws: null,
task: {},
//创建连接
connect() {
return new Promise((resolve, reject) => {
if (this.ws && this.ws.readyState == WebSocket.OPEN) {
resolve();
} else {
try {
this.ws = new WebSocket('ws://' + this.ip + ':' + this.port);
this.ws.onmessage = (e) => this.message(e);
this.ws.onopen = () => resolve();
this.ws.onerror = () => reject();
this.ws.onclose = () => {
this.ws = null;
this.task = {};
};
} catch {
reject();
}
}
});
},
//直接打印
print(name, templates) {
if (this.ws && this.ws.readyState == WebSocket.OPEN) {
let msg = {
instruct: 'print',
name: name,
token:this.token,
templates: templates.map((row) => {
return {
source: 'Json=' + Base64.encode(JSON.`string`ify(row.source)) + ';Encoding=utf-8',
template: row.template
};
})
};
this.ws.send(JSON.stringify(msg));
} else {
throw Error('ReportHelper Not connected');
}
},
//预览打印
view(name, templates) {
if (this.ws && this.ws.readyState == WebSocket.OPEN) {
let msg = {
instruct: 'view',
name: name,
templates: templates.map((row) => {
return {
source: 'Json=' + Base64.encode(JSON.stringify(row.source)) + ';Encoding=utf-8',
template: row.template
};
})
};
this.ws.send(JSON.stringify(msg));
} else {
throw Error('ReportHelper Not connected');
}
},
//文档预览
document(name, templates) {
if (this.ws && this.ws.readyState == WebSocket.OPEN) {
let msg = {
instruct: 'document',
name: name,
templates: templates.map((row) => {
return {
source: 'Json=' + Base64.encode(JSON.stringify(row.source)) + ';Encoding=utf-8',
template: row.template
};
})
};
this.ws.send(JSON.stringify(msg));
} else {
throw Error('ReportHelper Not connected');
}
},
//模板设计
design(id, name, param, template, fun) {
if (this.ws && this.ws.readyState == WebSocket.OPEN) {
let msg = {
instruct: 'design',
id: id,
name: name,
source: 'Json=' + Base64.encode(JSON.stringify(param)) + ';Encoding=utf-8',
template: template
};
this.task['design_' + id] = fun;
this.ws.send(JSON.stringify(msg));
} else {
throw Error('ReportHelper Not connected');
}
},
//消息处理
message(e) {
try {
let result = JSON.parse(e.data);
if (result.state == 'success') {
//设计保存
result.instruct == 'designSave' && this.task['design_' + result.id](result.id, result.name, result.template);
//设计关闭
result.instruct == 'designClose' && delete this.task['design_' + result.id];
//输出文档
if (result.instruct == 'document') {
let ua = Base64.toUint8Array(result.str);
let blob = new Blob([ua], { type: result.mime });
window.open(URL.createObjectURL(blob));
}
} else {
//错误回调
alert(result.message);
}
} catch (e) {
alert(e);
}
},
//错误处理
error: () => {
console.log('ReportHelper Connect Error');
}
};
export default helper;
直接打印
helper.token="";
helper.connect().then(() => {
helper.print("Test", [{ source:{title: "ReportHelper" },template:"str"}]);
}).catch(()=>{});
预览报表
helper.connect().then(() => {
helper.view("Test", [{ source:{title: "ReportHelper" },template:"str"}]);
}).catch(()=>{});
设计模板
helper.connect().then(() => {
helper.design("1", "Test", {title: "ReportHelper" }, template, (id, name, template) => {
console.log(id, name, template);
});
}).catch(()=>{});
输出文档
helper.connect().then(() => {
helper.document("Test", [{ source:{title: "ReportHelper" },template:"str"}]);
}).catch(()=>{});
9.杂项
- URL Protocol唤醒:
ReportHelper://run
- 命令参数
run
开启服务serve
开启服务并最小化