报表助手
简介
- 该应用适用于网页打印场景
- 支持直接打印、预览报表,模板设计,生成文档
- 支持开机自启和URL Protocol唤醒
- 支持多指令、多任务、多线程、多模式
- 支持ws与wss双协议
- 软件下载地址:点击下载
架构
开发语言:
C#
应用框架:
.NET FrameWork 4.8
依赖组件:
Fleck 1.2
Newtonsoft.Json 13.0
FastReport 2023.2.4
通信协议:
WebStock
通信端口:
3676
文件说明
- 安装目录
\ReportHelper.exe
为主应用 - 安装目录
\ReportDesign.exe
为设计应用 - 安装目录
\config.ini
为配置文件
界面介绍
- 服务
- 启动服务:程序将开启端口监听与相关服务
- 停止服务:程序将停止端口监听与停止服务
- 地址
- 默认显示本机IP地址
- 支持127.0.0.1与localhost
- 点击可复制到剪切板
- 端口
- 监听端口号为3676
- 请确保端口未占用
- 点击可复制到剪切板
- 模式
- 应用模式:需人工自行开启与启动服务
- 服务模式:开启自启并启动服务且最小化运行
- 托盘
- 托盘区内可操作显示界面
- 应用的退出操作在托盘区内操作
配置介绍
配置文件名称:config.ini
配置项 | 默认值 | 说明 |
---|---|---|
schem | ws | 协议类型(ws或wss) |
server | 0.0.0.0 | 监听地址 |
port | 3676 | 监听端口 |
path | certificate.pfx | 证书路径(wss模式下必填) |
password | 000000 | 证书密码(wss模式下必填) |
功能介绍
数据交互
- 采用
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内容
交互示例
直接打印
指令内容
{"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..."}
JavaScript 示例
示例代码
- SDK依赖于js-base64,下载地址:点击下载
- SDK实际使用应参考示例完成业务逻辑
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(()=>{});
杂项
- URL Protocol唤醒:
ReportHelper://run
- 命令参数
run
开启服务serve
开启服务并最小化