扩展功能:记录生成
什么是记录填写?
允许用户自定义表单填写记录,并对填写的记录进行管理。比如,用户需要管理员工信息,就可以使用记录填写功能。
该功能支持自定义数据处理。在数据提交前、提交后,可以自定义代码进行数据处理。
基础术语
- 表单:用户自定义的表单,包含多个字段。
- 记录:用户填写的表单记录。
- 字段:表单中的每个字段,包含字段名、字段类型、字段值等信息。
- 字段类型:字段的类型,包括文本、数字、日期、单选、多选、附加文件等。
- 方案:记录填写的方案,包含表单、记录、字段等信息。
创建方案
系统支持创建多种方案,实现对不同业务的处理。后续可以对方案进行授权管理。
创建方案步骤
-
点击左侧导航栏的“记录填写”,进入记录填写页面。
-
填写方案信息。包括名称、方案描述、表单、记录、字段等信息。
- 点击“保存”按钮,保存方案。
方案信息字段说明如下:
属性名称 | 属性说明 |
---|---|
方案名称 | 方案名称,必填。 |
方案描述 | 方案描述,选填。 |
数据表单 | 必填,用户通过该表单填写数据。从表单列表中选择。 |
业务配置表 | 必填,用户配置该业务时用到的表单。从表单列表中选择。 |
页面模板 | 可以自定义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": "", # 错误信息
}
后处理中的变量和函数
-
USER 变量 当前用户信息,字典类型
-
DB 变量 数据库操作对象,utils.db.MysqlDatabase类型
-
RECORD 变量
文档数据,字典类型, 包括vars和基础数据,下文的DATA=RECORD["vars"],基础数据包括sys_ctime_at, sys_deleted_at, plan_id, summary
- PLAN 变量
记录填写方案的信息,字典类型,包括name(名称)、category(分类)、upsert_tmpl(默认upsert界面的模板),sortno(顺序号)action_links(操作链接)
-
USERSETUP 变量 用户配置信息, 业务配置表 对应的信息,词典类型。
-
DOC_ID 变量 当前文档的id,整数类型
-
PLAN_ID 变量 当前文档生成方案的id, 整数类型
-
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
- EDIT(did, **kwds) 函数 更新文档数据的函数
EDIT(12, {"vars": {"name": "张三", "age": 18})
-
REQUEST 变量 当前请求的对象,werkzeug.wrappers.BaseRequest类型
-
DATA 变量
当前文档的数据,字典类型,和SAVED类似,不同的是SAVED更原始,DATA添加 form表单的label作为key,文件字段添加了local_path字段,返回本地路径。
比如,录入表单 {"key":"name", "label": "姓名"},如果填写 DATA["name"] = "张三" 那么 DATA["姓名"] = "张三"
-
LOGGER 类 日志对象,提供debug、error\info\warning方法
-
SIGN({uploaded}, plan_id, is_pdf=False, old_input_id=0) 函数 签署文件的函数,函数参数为({upload}, plan_id签署方案id, old_input_id=0) old_input_id:在防伪系统中的编号,防止重新添加新的签署文件
-
DOCXRENDER 类 docx文档渲染类,初始化参数为模板路径,提供save2upload方法,用于保存docx文件,并返回上传的文件信息。
-
EXCEL 模块 提供读取excel文件读取函数
get_cols_by_headers
get_cols_by_col_index
-
FILLED 变量
用户填写的数据. 该变量在预处理程序中表示已经保存到数据库的数据,在后处理程序中表示用户在表单中填写的数据。
-
STEP变量 STEP: 当前步骤,{"stepname": "步骤名称"},后处理所在的步骤信息。
-
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, "年龄") }}