xinglie / report-designer

⚡打印设计、可视化、标签打印、编辑器、设计器、数据分析、报表设计、组件化、表单设计、h5页面、调查问卷、pdf生成、流程图、试卷、SVG、图形元素、物联网、标签纸
https://xinglie.github.io/report-designer/
902 stars 232 forks source link

接口及配置说明 #27

Open xinglie opened 3 years ago

xinglie commented 3 years ago

部分可设计元素支持通过接口与数据源绑定,方便展示或打印,这里介绍下相关的数据格式和绑定思路

接口统一格式

项目中所有用到的接口均按以下统一格式返回

{
    "data":any, //根据接口的具体作用,返回相应的如数组、对象等结构的数据
    "success": boolean,//接口状态,成功为true,失败为false,当失败时,最好在"message"中提供相应的失败信息
    "message": "" //当接口异常时可提供的信息
}

如果您购买了源码,则设计器中所有接口统一由designer/service.ts中发出,而状态success及数据data均可以在这里适配成其它现有接口的格式,无须按这里描述的格式进行处理。

另外一种适配方案是,通过提供的配置项response进行适配,返回上述格式即可,设计器并不要求您一定修改现有接口为上述结构,如果您还是不明白,可以联系作者。您只需要知道上述提到的格式只是设计器默认的数据格式而已,并且可以很方便的适配成其它结构。

全部数据源接口

该接口为设计器数据源面板中,显示的树形列表,如下图所示

image

该接口返回后端都有哪些数据接口可供使用,可查看当前项目中使用的一份写死的格式:https://github.com/xinglie/report-designer/blob/master/apis/fields.json

说明一下data中的格式

{
    "data":[{//数组格式,可设置多个数据源
            "name": "地区测试",//数据源名称,必须设置
            "tag": "apis/area.json",//数据源接口地址、参数或其它标识,非必须
            "id": 1,//数据源id,必须且唯一
            "fields":[{//数据源中包含的可使用的字段
                    "name": "河北",//字段名称,必须
                    "key": "area_13"//字段key,必须
             }]
     }]
    "success": true,
    "message": "" 
}

如上述示例中的”地区测试“数据源,需要配合相应的”地区测试“这个数据接口来看:https://github.com/xinglie/report-designer/blob/master/apis/area.json

其中最关键的是”fields“这个对象,该对象需要列出 https://github.com/xinglie/report-designer/blob/master/apis/area.json 接口中可供使用的字段集合,这是绑定数据源的关键。

对于tag字段,因为开发和发布最终的请求地址会不一样,因此tag可以只存放一个标识字符串,而在最终请求时,report-designer会交由统一的数据模块进行处理,可在这个数据模块里根据一定的规则,把tag存储的标识字符串转换成真实的url。

点击这里查看如何通过tagid在打印或预览时转换成真实的url

元素绑定数据源

所有元素均支持数据源的绑定,任意一个元素只要出现在属性面板中的属性也支持数据绑定。目前做了常用元素如文本、图片、条形码、二维码以及“数据”元素分组下的列表格、数据表格等的数据绑定,如果您需要定制元素或调整某些元素的某些属性成数据绑定的形式,请联系作者

元素在绑定时,内部会记录相应的接口地址或标识以及绑定的字段,在展示或打印时,由展示或打印页面根据元素绑定的接口,把数据设置到绑定信息上,而元素仅根据绑定的字段key把相应的数据取出来展示

自动分页

目前只有“数据”元素分组下的列表格、数据表格等能根据数据源的数据多少在打印时自动分页

根据可设计元素的不同,需要绑定的数据源是数组还是对象也不同。比如“数据”元素分组下的列表格、数据表格等要求数组。文本、图片等要求返回单个对象,即使返回数组也只会使用第一个。

更多规则

以上是个人根据以往的经验总结的格式,非必须按照执行的最终格式。包括元素绑定数据源时,到底使用对象还是数组,并非最终定论,可根据具体需求调整。

xinglie commented 2 years ago

图片库和模板数据接口

在入口文件,如index.html中,启动设计器的入口配置相应的接口地址

designer.setup({
    getImageUrl:'./apis/images.json',
    getFieldUrl:'./apis/fields.json',
    getTemplateUrl:'./apis/example.json'
});

可到apis目录自行查看相应的接口数据:https://github.com/xinglie/report-designer/tree/master/apis

设计器初始化配置对象

/**
 * 设计器支持的初始化对象
 */
interface DesignerOptions {
    /**
     * 站点名称,需要授权
     */
    siteName?: string
    /**
     * 站点logo,需要授权
     */
    siteLogo?: string
    /**
     * 主题色配置,需要授权
     */
    themeBrand?: string
    /**
     * 主题反差色配置,需要授权
     */
    themeContrast?: string
    /**
     * 版权信息,支持html,需要授权
     */
    copyright?: string
    /**
     * 版本号,哪天打包的代码
     */
    version?: string
    /**
     * 使用哪个view做为入口
     */
    use?: string, 
    /**
     * 应用根节点id
     */
    rootId?: string,
    /**
     * 是否mini模式
     */
    mini?: boolean
    /**
     * 拆分模式
     */
    split?: boolean
    /**
     * 元素插件集合
     */
    plugins?: string[]
    /**
     * 面板配置
     */
    panels?: Report.OuterPanelsConfig
    /**
     * 工具栏控制
     */
    toolbar?: Report.OuterViewConfig
    /**
     * 头部控制
     */
    header?: Report.OuterViewConfig
    /**
     * 第三方地址配置
     */
    providers?: Report.ProviderURLConfig
    /**
     * 预览页url
     */
    viewerUrl?: string
    /**
     * 设计器自己的服务地址,打印页面使用
     */
    rdsUrl?: string
    /**
     * 图片源接口地址
     */
    getImageUrl?: string
    /**
     * 自定义字体接口地址
     */
    getFontFaceUrl?: string
    /**
     * 数据源接口地址
     */
    getFieldUrl?: string
    /**
     * 示例接口
     */
    getTemplateUrl?: string
    /**
     * 获取示例内容接口
     */
    getTemplateContentUrl?: string
    /**
     * 保存内容接口
     */
    saveContentUrl?: string
    /**
     * 获取内容接口
     */
    getContentUrl?: string
    /**
     * 图片上传接口
     */
    imageUploadUrl?: string
    /**
     * 错误上报接口
     */
    errorReportUrl?: string
    /**
     * 预设内容接口,进入设计器后,可通过该接口返回随机内容,填充设计区
     */
    presetUrl?: string
    /**
     * 保存主题接口
     */
    saveThemeUrl?: string
    /**
     * 解析绑定元素的url请求地址
     */
    getBindUrl?: (bind: object) => string
   /**
    * 拦截所有接口请求,如果提供该配置则要在该配置内完成相应的接口请求
    * @param url 请求地址
    * @param options 请求配置信息
    */
 io?:(url,options)=>object
  /**
     * 对接口响应内容做处理。该配置仅在你的接口无法返回{"data":object,"success":boolean,"message":string}这种格式时,
     * 使用该配置来适配。通过该函数返回{"data":object,"success":boolean,"message":string}的数据结构
     * 来让你现在的接口和设计器都无需修改代码即可配合工作
     * @param response 响应数据
     * @param url 哪个接口
     * @returns 返回{"data":object,"success":boolean,"message":string}的结构对象
     */
    response?: (response, url) => { success: boolean, data?: object, message?: string }
    /**
      * 对接口请求参数做处理
      * @param request 请求对象
      * @param url 哪个接口
      * @returns 返回{ options, body, query }结构的数据
      */
   request?: (request, url) => ({ options, body, query })
}
xinglie commented 2 years ago

保存和编辑数据接口

在入口文件,如index.html中,启动设计器的入口配置相应的接口地址

designer.setup({
  getImageUrl:'./apis/images.json',//图片库接口
  getFieldUrl:'./apis/fields.json',//数据源接口
  getTemplateUrl:'./apis/example.json',//获取模板接口
  saveContentUrl:'./apis/save.json',//保存内容接口
  getContentUrl:'./apis/getcontent.json',//获取内容接口
  presetUrl:'.apis/content.json',//预设内容接口
});

当保存内容时,以post的形式向saveContentUrl提交数据,保存keystage,保存的内容是JSON字符串 当需要编辑时,进入设计器页面时,需要自己处理相应的参数,并传给getContentUrl配置的接口。可按提供的index.html进行处理,

思考

如果是以新建的模式进入设计器时,此时反复保存,后端是否会反复创建新的数据?

这里建议进入设计器时,始终携带一个类似id的标识,把该标识传给getContentUrl配置的接口。

后端根据数据库里是否有类似该id的标识决定是否新建还是修改。

设计器保存时提交什么数据,则编辑时返回什么样的数据

xinglie commented 2 years ago

接口配置与界面关系

以上接口配置与未配置界面上展示会不一样。

如果未配置getImageUrl则所有与选择图片相关的均自动隐藏不展示

如果未配置getFieldUrl则与数据绑定的相关操作自动隐藏不展示

如果未配置getTemplateUrl则右上角模板功能自动隐藏

如果未配置saveContentUrl则点保存的时候,展示保存内容对话框,如果配置,则直接保存,不出对话框。

xinglie commented 2 years ago

API

可视化编辑器,designer除了提供setup安装,和destroy销毁外,还提供get():Promise<string>获取内容以及set(content:string|JSONObject)设置内容。

您也可以不使用上述内置的接口,自己通过setget方法在外部进行设置和获取设计器的内容

可视化编辑器自带的打印预览页面viewer.js提供getHTML等常用方法,请参考:https://github.com/xinglie/report-designer/issues/38

xinglie commented 2 years ago

元素与接口的绑定

image

项目中元素与接口绑定后,会统一走数据中心模块(tmpl/provider/datacenter.ts)进行请求。

即上图中的文本、图片等会通过datacenter拿到绑定的数据。因此可以在datacenter中进行再次组织,比如转换接口的请求地址,向多个接口请求获取数据等(其中后文提到的getBindUrl函数调用就是在这里进行处理的)

report-designer项目中所有跟接口有关的请求均会走(tmpl/designer/service.ts),您可以在该处进行统一的请求处理,比如添加统一的参数或对返回的数据结构进行预处理等。

xinglie commented 2 years ago

接口的参数控制

假如进入设计器时url带上了其它参数,如http://localhost/report-designer/index.html?id=x&from=y&source=z

有时候我们想把地址栏中的其它参数如from继续透传给设计器中其它如数据源或图片源等接口,我们可以这样做:

因为数据源或图片源接口地址均是配置化的,我们只需要在初始化的时候,从地址栏获取参数,并透传给配置接口即可,示例如下

<script type="module">
let parsedUrl = new URL(location.href);
let from = parsedUrl.searchParams.get('from');
let postfix = from ? `?from=${from}` : '';
designer.setup({
    //以下是相关配置接口,如果地址栏有from参数,拼接上即可
    getImageUrl: './apis/images.json' + postfix,
    getFieldUrl: './apis/fields.json' + postfix,
    getTemplateUrl: './apis/example.json' + postfix,
    saveContentUrl: './apis/save.json' + postfix,
    getContentUrl: './apis/content.json' + postfix,
    imageUploadUrl: './apis/save-image.json' + postfix,
});
</script>

打开设计器带的参数,在设计器里面调用预览页面时,参数会自动透传给预览页面(需授权),独立使用预览页面需要自己处理(无须授权)

元素数据绑定接口

部分元素如文本提供和数据源进行绑定,绑定对象如下。

{
    //...以下是存储绑定的数据源和对应字段的对象
    bind: {
        tag: 'user.info',//数据源请求标识符
        id: 'source1',//唯一id
        fields: []//绑定了哪些字段
    },
}

在打印页面,如果需要根据bind对象来决定如何请求具体的接口地址,则可以使用配置getBindUrl进行配置,示例如下


<script>
    viewer.setup({
        rdsUrl: '//localhost:9988/',
        getBindUrl(bind) {
            if(bind.tag=='user.info'){
                return 'apis/person.json?bindId='+bind.id;
            }
            return 'apis/default.json?bindId='+bind.id;
        },
    });
</script>

getBindUrl回调参数bind即是元素的bind对象,所以在绑定时,可以把url设置为一个标识,只要在这个getBindUrl方法中,根据bind对象中的tagid返回真实的数据请求地址即可。

这样我们就可以在设计阶段只存放绑定标识,而在打印页面通过getBindUrl给出最终的请求地址。

当然,如果打印页面这种绑定数据的接口也需要地址栏中的参数,只需要像设计页面那样处理即可,示例如下

<script>
let parsedUrl = new URL(location.href);
let from = parsedUrl.searchParams.get('from');
let postfix = from ? `&from=${from}` : '';
viewer.setup({
    rdsUrl: '//localhost:9988/',
    getBindUrl(bind) {
        return bind.url + '?bindId=' + bind.id + postfix;
    },
});
</script>
xinglie commented 2 years ago

授权配置

以下配置需源码或定制授权

history.max.count

number 历史记录最大值,多出的历史记录会删除。

hisotry.save.continous.delay

number 相同类型的历史记录间断多少毫秒后记录,比如通过键盘移动元素,并非每次移动均记录,只有松开按键超过配置的ms后才记录

random.examples

boolean true 进入设计器在配置模板的情况下,是否随机显示一个示例,未授权则处于打开状态

show.help.and.ow.links

boolean true 是否展示相关的帮助链接,未授权则处于打开状态

save.can.use.native.file

boolean true 保存菜单是否支持从本机保存和读取文件,未授权则处于打开状态

save.can.show.stage.content

boolean true 保存菜单是否支持显示设计区内容,未授权则处于打开状态

support.help

boolean true 能否使用快捷键对话框和帮助链接

support.theme

boolean 是否支持主题功能

support.axis.help.line

boolean 是否支持标尺的辅助线功能

clear.copy.list.when.cut.action

boolean true 使用剪切时,每次剪切、粘贴完成后,是否清除剪切板中的复制元素

stage.scale

number 1 默认编辑区的缩放,配置的数值为0.5-4之间(包含),且为0.5的倍数

stage.padding

array 设计区外围灰色区域,上、右、下、左,px单位

stage.auto.center

boolean 设计区是否自动滚动到页面中间

stage.auto.scale.when.change

boolean 换示例或加载内容时,是否自动计算缩放比例

stage.wheel.zoom

boolean 是否支持按下ctrl+鼠标滚轮缩放设计区

stage.hook.wheel.event

boolean 是否拦截设计区wheel事件

page.width

number 默认编辑区的宽度,px单位

page.height

number 默认编辑区的高度,px单位

page.max.width

number 最大宽度,px单位

page.max.height

number 最大高度,px单位

page.min.width

number 最小宽度,px单位

page.min.height

number 最小高度,px单位

move.near.side.area

number 拖动时,四边边框响应贴边滚动的尺寸,px单位

move.near.step

number 拖动时,自动滚动步辐,px单位

page.enable.snap.align.elements

boolean true 是否启用拖动对齐功能

page.follow.snap.align.elements

boolean true 拖动多个元素时,非鼠标下的元素是否启用跟随吸附对齐

align.points

number 拖动元素吸附对齐时,哪些点参与对齐

align.svg.points

boolean 是否开启svg点对齐

align.svg.self.points

boolean 是否开启svg自身点对齐

contextmenu.paste.exactly.source.position

boolean false 右键粘贴时,是否强制粘贴的位置和鼠标复制时的位置一致

page.grid.width

number 网格宽,像素单位

page.grid.height

number 网格高,像素单位

page.grid.max.width

number 网格最大宽,像素单位

page.grid.max.height

number 网格最大高,像素单位

page.grid.min.width

number 网格最小宽,像素单位

page.grid.min.height

number 网格最小高,像素单位

wheel.delay.time

number 通过按下ctrl加鼠标滚轮缩放设计区时延迟时间,越小越灵敏

axis.size

number 标尺尺寸,即宽和高,px单位

axis.show.shadow

boolean true 标尺上是否显示选中元素的投影

scale.max

number 最大缩放值

scale.min

number 最小缩放值

scale.step

number 每次缩放步长

scale.fast.increase

number 快速发大步长

scale.slow.decrease

number 较慢缩小步长

support.snapshot

boolean 是否支持设计区快照

auto.save

boolean false 保存菜单是否展示自动保存

auto.save.debouce.duration

number 自动保存时,多少时间内的保存忽略,避免频繁保存

new.tab.viewer

boolean false 预览时,是否新开浏览器tab页展示打印页面

keyboard.move.step

number 使用键盘每次移动的距离,px单位

keyboard.with.shift.move.step

number 按下shift时,每次移动的距离,px单位

keyboard.rotate.step

number 使用键盘旋转角度,每次旋转多少

keyboard.with.shift.rotate.step

number 按下shift时,每次旋转角度

drag.snap.to.other.element.offset

number 拖动时,距离其它元素的吸附线小于该值时,则进行吸附,px单位

drag.snap.degree

number 拖动旋转时,在多少倍数附近进行吸附

drag.snap.degree.offset

number 拖动旋转,在倍数角度附近多少时,自动调整到倍数的角度上

support.readonly.element

boolean true 是否支持只读元素,如果对性能有要求且不需要只读元素,则可以关闭该项

support.panels.hide.when.nearside

boolean true 面板是否支持贴边隐藏

element.same.position.offset

number 元素粘贴,同位置时偏移量,防止重叠在一起,px单位

element.min.px.size

number 元素对齐时最小尺寸,比如宽度小于配置项时,则只进行左侧对齐

element.dblclick.interval.ms.time

number 元素双击间隔毫秒时间

panels.prop.show.group

boolean false 属性面板是否对属性进行分组展示

panels.tree.show.icon

boolean true 组件树面板是否展示icon

element.auto.show.icon.less.than

number 小于多少像素时元素自动展示icon

element.show.normal.outline

boolean 设计元素普通状态下是否展示边框线

element.svg.modify.point.min.factor

number svg修改点最小比率

element.svg.modify.point.max.factor

number svg修改点最大比率

element.svg.modify.point.step

number svg修改点步长

element.svg.modify.point.shift.step

number svg修改点按下shift的步长

element.svg.modify.point.fixed

number svg修改点小数位

font.family

array 字体设置项集合

font.default.family

string 默认字体

border.types

array 边框设置项集合

unit

string 设计器默认使用的单位

unit.allow.change

boolean 是否支持转换成其它单位

xinglie commented 1 year ago

接口适配

假设您现在使用的接口返回如下的格式

{
    "data":"array | object",
    "info": {
        "ok": true,
        "message":""
    }
}

可使用前面提到的response在初始化时,做如下适配

designer.setup({
    //...其它初始化配置项
    response(response, url) {
        console.log('current url', url, 'current response', response);
        return {
            success: response.info.ok,
            message: response.info.message,
            data: response.data
        };
    }
});