跳转至

扩展功能:记录生成

什么是记录填写?

允许用户自定义表单填写记录,并对填写的记录进行管理。比如,用户需要管理员工信息,就可以使用记录填写功能。

该功能支持自定义数据处理。在数据提交前、提交后,可以自定义代码进行数据处理。

基础术语

  • 表单:用户自定义的表单,包含多个字段。
  • 记录:用户填写的表单记录。
  • 字段:表单中的每个字段,包含字段名、字段类型、字段值等信息。
  • 字段类型:字段的类型,包括文本、数字、日期、单选、多选、附加文件等。
  • 方案:记录填写的方案,包含表单、记录、字段等信息。

创建方案

系统支持创建多种方案,实现对不同业务的处理。后续可以对方案进行授权管理。

创建方案步骤

  1. 点击左侧导航栏的“记录填写”,进入记录填写页面。 alt text

  2. 填写方案信息。包括名称、方案描述、表单、记录、字段等信息。 alt text

  3. 点击“保存”按钮,保存方案。

方案信息字段说明如下:

属性名称 属性说明
方案名称 方案名称,必填。
方案描述 方案描述,选填。
数据表单 必填,用户通过该表单填写数据。从表单列表中选择。
业务配置表 必填,用户配置该业务时用到的表单。从表单列表中选择。
页面模板 可以自定义html模板,用于数据填写时的界面展示。
摘要模板 便于展示记录供用户浏览。此处填写记录的摘要模板, 使用 {{ 变量 }}这种语法进行书写。变量名称为数据表单的字段名称。
所属分类 为了便于管理,给表单设置分类信息,系统按照分类进行排序展示
预处理程序 用户填写表单前,系统按照这个预处理程序进行数据处理。处理后的数据展示到表单。具体语法见后文。
后处理程序 用户提交数据后,系统按照这个后处理程序进行数据处理。具体语法见后文。

数据处理

数据处理是记录填写的核心功能。数据处理分为预处理和后处理。

#coding: utf8
# 2025-03-10 17:35:00 by wanglinlin
# 文档填写前的预处理的示例文件

# 必须定义一个main函数,无参数,返回一个字典
# main中可以使用的变量
#     USER: 当前用户信息,字典类型
#     DB: 数据库操作对象,utils.db.MysqlDatabase类型
#     RECORD: 文档数据,字典类型, 包括vars和基础数据,下文的DATA=RECORD["vars"]
#     PLAN: 方案信息,字典类型
#     USERSETUP: 方案的setup字段,字典类型
#     DOC_ID: 当前文档的id
#     PLAN_ID: 当前文档生成方案的id
#     GETDOC: 获取文档数据的函数,函数参数为(plan_id, did, **kwds)
#     EDIT: 更新文档数据的函数,函数参数为(did, **kwds)
#     REQUEST: 当前请求的对象,werkzeug.wrappers.BaseRequest类型
#     DATA:当前文档的数据,字典类型,和SAVED类型,不同的是SAVED更原始,DATA添加
#           label作为key,文件字段添加了local_path字段,返回本地路径
#     LOGGER: 日志对象,提供debug、error\info\warning方法
#     SIGN: 签署文件的函数,函数参数为({upload}, plan_id签署方案id, old_input_id=0)
#     DOCXRENDER: docx文档渲染类,初始化参数为模板路径
#     EXCEL: 提供读取excel文件读取函数 get_cols_by_headers get_cols_by_col_index
#     FILLED:用户已经填写的数据。当
#     STEP: 当前步骤,{"stepname": "步骤名称"}

def regenerate():
    try:
        tmpl_file = USERSETUP["template"]
        tmpl_file = GETFILE(tmpl_file)["path"] # 成功获取模板文件
    except Exception as e:
        raise Exception("获取模板文件失败")
    docx = DOCXRENDER(tmpl_file)
    return docx.save2upload(filename="%s.docx" % DATA["name"])

# 预处理示例
def main():
    # 本实例说明如何初始化记录
    FILLED["regener"] = False  # 让regener这个变量始终为false
    return {
        "result": FILLED,  # 返回数据,该数据用于初始化表单
        "msg": "",      # 返回提示信息,用于显示在页面上
        "error": ""    # 返回错误信息,用于显示在页面上
    }  

# 后处理示例
def main():
    # 本实例说明如何生成文档
    # tmpl_file = USERSETUP["template"][0]["local_path"]
    # 获取模板路径
    uploaded_word = FILLED.get("report") # 用户上传的报告文件
    regener = FILLED.get("regener")    # 重新生成报告
    old_input_id = DATA.get("_fangwei_id", 0) or 0  # 在防伪系统中的编号,防止重新添加新的签署文件
    gener_ret = None
    doc = None
    msg = ""
    update_vars = {
        "regener": False,  # 重新生成报告一律置为False
        "signreport": False  # 签署报告一律置为False
    }
    if regener:
        # 重新签署
        doc = regenerate()
        msg = "重新生成报告文件"
        update_vars["report"] = [doc]
    elif uploaded_word:
        # 用户上传了报告文件文件
        doc = uploaded_word[0]
        msg = "使用上传的报告文件"
    if doc:
        if DATA.get("signreport"):            
            gener_ret = SIGN(doc, plan=26, is_pdf=False, old_input_id=old_input_id)
            msg += "并签署"
        if old_input_id == 0 and DATA.get("signreport"):
            # 第一次签署, 将签署后的文件id保存到数据库
            update_vars.update({
                "_fangwei_id": gener_ret["report_id"], 
                "_fangwei_sn": gener_ret["sn"]
            })
        EDIT(DOC_ID, vars=update_vars)
    return {
        "msg": msg,
        "error": "", # 错误信息
    }

后处理中的变量和函数

  1. USER 变量 当前用户信息,字典类型

  2. DB 变量 数据库操作对象,utils.db.MysqlDatabase类型

  3. RECORD 变量

文档数据,字典类型, 包括vars和基础数据,下文的DATA=RECORD["vars"],基础数据包括sys_ctime_at, sys_deleted_at, plan_id, summary

  1. PLAN 变量

记录填写方案的信息,字典类型,包括name(名称)、category(分类)、upsert_tmpl(默认upsert界面的模板),sortno(顺序号)action_links(操作链接)

  1. USERSETUP 变量 用户配置信息, 业务配置表 对应的信息,词典类型。

  2. DOC_ID 变量 当前文档的id,整数类型

  3. PLAN_ID 变量 当前文档生成方案的id, 整数类型

  4. GETDOC(plan_id, did, **kwds)

    获取文档数据, 返回的词典格式数据。

返回某个文档的内容,其中vars是这个文档的数据

Args:
    plan_id (_type_): 可以是整数或者字符串,如果是字符串,则表示方案名称
    did (int, optional): 文档id. Defaults to 0.
    kwds:文档额外的名称,比如,name="张三", age=18 找到name是张三的文档

Returns:
    词典格式, keys包括如下
    vars: 文档的数据,如果字段是文件格式,会额外添加local_path字段,指向本地的文件路径
            将label自动作为key添加到变量中,便于前端展示
    id: 文档id
    plan_id: 方案id    
  1. EDIT(did, **kwds) 函数 更新文档数据的函数
EDIT(12, {"vars": {"name": "张三", "age": 18})
  1. REQUEST 变量 当前请求的对象,werkzeug.wrappers.BaseRequest类型

  2. DATA 变量

    当前文档的数据,字典类型,和SAVED类似,不同的是SAVED更原始,DATA添加 form表单的label作为key,文件字段添加了local_path字段,返回本地路径。

    比如,录入表单 {"key":"name", "label": "姓名"},如果填写 DATA["name"] = "张三" 那么 DATA["姓名"] = "张三"

  3. LOGGER 类 日志对象,提供debug、error\info\warning方法

  4. SIGN({uploaded}, plan_id, is_pdf=False, old_input_id=0) 函数 签署文件的函数,函数参数为({upload}, plan_id签署方案id, old_input_id=0) old_input_id:在防伪系统中的编号,防止重新添加新的签署文件

  5. DOCXRENDER 类 docx文档渲染类,初始化参数为模板路径,提供save2upload方法,用于保存docx文件,并返回上传的文件信息。

  6. EXCEL 模块 提供读取excel文件读取函数 get_cols_by_headers get_cols_by_col_index

  7. FILLED 变量

    用户填写的数据. 该变量在预处理程序中表示已经保存到数据库的数据,在后处理程序中表示用户在表单中填写的数据。

  8. STEP变量 STEP: 当前步骤,{"stepname": "步骤名称"},后处理所在的步骤信息。

  9. GETFILE(uploaded_file) 函数

    获取文件的函数,函数参数为({"url": "", "filename": "文件名"}),返回的是文件在服务器硬盘的绝对路径。

方案中渲染word模板

DOCXRENDER 类

系统提供 DOCXRENDER 类,用于渲染word模板。

类初始化

DOCXRENDER 类的初始化参数为模板路径。

类方法

save2upload(word文件名称)

DOCXRENDER 类的 save2upload 方法用于保存word文件,并返回上传的文件信息,格式为 { "url": "下载渲染后文件的路径", "filename": "文件名", "_filepath": "本地文件路径", "_fileid": "文件id,对应于upload表的id" }

示例代码如下, 该代码可以放在后处理中执行。

tmpl_file = GETFILE(tmpl_file)["path"] # 成功获取模板文件
docx = DOCXRENDER(tmpl_file)
return docx.save2upload(filename="%s.docx" % DATA["name"])

word模板可用变量

USER 变量

当前用户信息,字典类型

直接使用DATA变量中的值

当前名称 {{ 姓名 }}

NOW 变量

当前时间,datetime.datetime类型 当前日期 {{ NOW.strftime("%Y-%m-%d") }}

FUNC.images(imagepath/fieldname, width=None, height=None)

插入图片的函数,函数参数为图片路径或者字段名称,返回的是图片的html代码。

{{ _FUNC_.images("头像", width=30)[0] }}

FUNC.excel(excelpath/fieldname) 类

{{ set rows = _FUNC_.excel("数据表").data(columns=["姓名", "年龄"]) }}

{{ set cellvalue = _FUNC_.excel("数据表").val("A3") }}

{{ set cellvalue = _FUNC_.excel("数据表").val(1, 2) }} 第一行第二列

{{ set cellvalue = _FUNC_.excel("数据表").val("定位数据", offsetx="1", offsety="!2") }} 找到”定位数据“所在的位置,然后偏移向上2行,向右1列

{{ set cellvalue = _FUNC_.excel("数据表").val("定位数据", offsetx="5~20", offsety="!2") }} 找到”定位数据“所在的位置,然后偏移向上2行,向右5列开始找数据,找到20列结束,找到为止。

SUMC(rows, "column") 函数

计算总和,函数参数为rows和字段名称,返回的是该列总和。

{{ SUMC(rows, "年龄") }}

AVGC(rows, "column") 函数

计算平均值,函数参数为rows和字段名称,返回的是字段的平均值。

{{ AVGC(rows, "年龄") }}

MIN、MAX、AVG、SUM、LEN 函数