feat: restore source parity and harden agent runtime
This commit is contained in:
@@ -0,0 +1,386 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
内置文档模板
|
||||
"""
|
||||
import json
|
||||
from typing import Dict, Any, List
|
||||
|
||||
|
||||
# 请假申请单模板
|
||||
LEAVE_APPLICATION_TEMPLATE = {
|
||||
"version": "1.0",
|
||||
"pageConfig": {
|
||||
"size": "A4",
|
||||
"orientation": "portrait",
|
||||
"margin": {"top": 25, "right": 20, "bottom": 25, "left": 20}
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"id": "title",
|
||||
"type": "text",
|
||||
"content": "请假申请单",
|
||||
"position": {"x": 0, "y": 10, "width": 170},
|
||||
"style": {"fontSize": 22, "fontWeight": "bold", "textAlign": "center"}
|
||||
},
|
||||
{
|
||||
"id": "doc_no",
|
||||
"type": "field",
|
||||
"fieldName": "_instance.instance_no",
|
||||
"label": "单据编号:",
|
||||
"position": {"x": 120, "y": 25},
|
||||
"style": {"fontSize": 10, "color": "#666"}
|
||||
},
|
||||
{
|
||||
"id": "applicant_section",
|
||||
"type": "container",
|
||||
"position": {"x": 0, "y": 35, "width": 170},
|
||||
"children": [
|
||||
{
|
||||
"id": "applicant_name",
|
||||
"type": "field",
|
||||
"fieldName": "applicant_name",
|
||||
"label": "申请人:",
|
||||
"position": {"x": 0, "y": 0},
|
||||
"style": {"fontSize": 12}
|
||||
},
|
||||
{
|
||||
"id": "department",
|
||||
"type": "field",
|
||||
"fieldName": "department_name",
|
||||
"label": "部门:",
|
||||
"position": {"x": 60, "y": 0},
|
||||
"style": {"fontSize": 12}
|
||||
},
|
||||
{
|
||||
"id": "apply_date",
|
||||
"type": "field",
|
||||
"fieldName": "apply_date",
|
||||
"label": "申请日期:",
|
||||
"format": "date",
|
||||
"position": {"x": 120, "y": 0},
|
||||
"style": {"fontSize": 12}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "leave_info",
|
||||
"type": "container",
|
||||
"position": {"x": 0, "y": 50, "width": 170},
|
||||
"style": {"border": "1px solid #333", "padding": "10"},
|
||||
"children": [
|
||||
{
|
||||
"id": "leave_type",
|
||||
"type": "field",
|
||||
"fieldName": "leave_type_name",
|
||||
"label": "请假类型:",
|
||||
"position": {"x": 5, "y": 5},
|
||||
"style": {"fontSize": 12}
|
||||
},
|
||||
{
|
||||
"id": "start_time",
|
||||
"type": "field",
|
||||
"fieldName": "start_time",
|
||||
"label": "开始时间:",
|
||||
"format": "datetime",
|
||||
"position": {"x": 5, "y": 15},
|
||||
"style": {"fontSize": 12}
|
||||
},
|
||||
{
|
||||
"id": "end_time",
|
||||
"type": "field",
|
||||
"fieldName": "end_time",
|
||||
"label": "结束时间:",
|
||||
"format": "datetime",
|
||||
"position": {"x": 90, "y": 15},
|
||||
"style": {"fontSize": 12}
|
||||
},
|
||||
{
|
||||
"id": "duration",
|
||||
"type": "field",
|
||||
"fieldName": "duration",
|
||||
"label": "请假时长:",
|
||||
"position": {"x": 5, "y": 25},
|
||||
"style": {"fontSize": 12}
|
||||
},
|
||||
{
|
||||
"id": "reason_label",
|
||||
"type": "text",
|
||||
"content": "请假事由:",
|
||||
"position": {"x": 5, "y": 40},
|
||||
"style": {"fontSize": 12}
|
||||
},
|
||||
{
|
||||
"id": "reason",
|
||||
"type": "field",
|
||||
"fieldName": "reason",
|
||||
"position": {"x": 5, "y": 50, "width": 160, "height": 30},
|
||||
"style": {"fontSize": 12}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "approval_section",
|
||||
"type": "text",
|
||||
"content": "审批记录",
|
||||
"position": {"x": 0, "y": 145},
|
||||
"style": {"fontSize": 14, "fontWeight": "bold"}
|
||||
},
|
||||
{
|
||||
"id": "approval_table",
|
||||
"type": "table",
|
||||
"dataSource": "_logs",
|
||||
"columns": [
|
||||
{"field": "node_name", "label": "审批节点", "width": "60"},
|
||||
{"field": "action", "label": "操作", "width": "30"},
|
||||
{"field": "comment", "label": "审批意见", "width": "60"},
|
||||
{"field": "created_at", "label": "时间", "width": "40"}
|
||||
],
|
||||
"position": {"x": 0, "y": 155, "width": 170}
|
||||
},
|
||||
{
|
||||
"id": "signature_section",
|
||||
"type": "container",
|
||||
"position": {"x": 0, "y": 220, "width": 170},
|
||||
"children": [
|
||||
{
|
||||
"id": "applicant_sign_label",
|
||||
"type": "text",
|
||||
"content": "申请人签名:",
|
||||
"position": {"x": 0, "y": 0},
|
||||
"style": {"fontSize": 12}
|
||||
},
|
||||
{
|
||||
"id": "applicant_signature",
|
||||
"type": "signature",
|
||||
"fieldName": "applicant_signature",
|
||||
"position": {"x": 30, "y": 0},
|
||||
"size": {"width": 40, "height": 20}
|
||||
},
|
||||
{
|
||||
"id": "approver_sign_label",
|
||||
"type": "text",
|
||||
"content": "审批人签名:",
|
||||
"position": {"x": 100, "y": 0},
|
||||
"style": {"fontSize": 12}
|
||||
},
|
||||
{
|
||||
"id": "approver_signature",
|
||||
"type": "signature",
|
||||
"fieldName": "approver_signature",
|
||||
"position": {"x": 130, "y": 0},
|
||||
"size": {"width": 40, "height": 20}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "seal_placeholder",
|
||||
"type": "seal",
|
||||
"sealType": "company",
|
||||
"position": {"x": 130, "y": 200},
|
||||
"size": {"width": 40, "height": 40}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
# 报销单模板
|
||||
EXPENSE_REPORT_TEMPLATE = {
|
||||
"version": "1.0",
|
||||
"pageConfig": {
|
||||
"size": "A4",
|
||||
"orientation": "portrait",
|
||||
"margin": {"top": 25, "right": 20, "bottom": 25, "left": 20}
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"id": "title",
|
||||
"type": "text",
|
||||
"content": "费用报销单",
|
||||
"position": {"x": 0, "y": 10, "width": 170},
|
||||
"style": {"fontSize": 22, "fontWeight": "bold", "textAlign": "center"}
|
||||
},
|
||||
{
|
||||
"id": "doc_no",
|
||||
"type": "field",
|
||||
"fieldName": "_instance.instance_no",
|
||||
"label": "单据编号:",
|
||||
"position": {"x": 120, "y": 25},
|
||||
"style": {"fontSize": 10, "color": "#666"}
|
||||
},
|
||||
{
|
||||
"id": "basic_info",
|
||||
"type": "container",
|
||||
"position": {"x": 0, "y": 35, "width": 170},
|
||||
"children": [
|
||||
{
|
||||
"id": "applicant",
|
||||
"type": "field",
|
||||
"fieldName": "applicant_name",
|
||||
"label": "报销人:",
|
||||
"position": {"x": 0, "y": 0},
|
||||
"style": {"fontSize": 12}
|
||||
},
|
||||
{
|
||||
"id": "department",
|
||||
"type": "field",
|
||||
"fieldName": "department_name",
|
||||
"label": "部门:",
|
||||
"position": {"x": 60, "y": 0},
|
||||
"style": {"fontSize": 12}
|
||||
},
|
||||
{
|
||||
"id": "apply_date",
|
||||
"type": "field",
|
||||
"fieldName": "apply_date",
|
||||
"label": "申请日期:",
|
||||
"format": "date",
|
||||
"position": {"x": 120, "y": 0},
|
||||
"style": {"fontSize": 12}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "expense_table_label",
|
||||
"type": "text",
|
||||
"content": "报销明细",
|
||||
"position": {"x": 0, "y": 50},
|
||||
"style": {"fontSize": 14, "fontWeight": "bold"}
|
||||
},
|
||||
{
|
||||
"id": "expense_table",
|
||||
"type": "table",
|
||||
"dataSource": "expense_items",
|
||||
"columns": [
|
||||
{"field": "expense_date", "label": "日期", "width": "30"},
|
||||
{"field": "expense_type", "label": "费用类型", "width": "35"},
|
||||
{"field": "description", "label": "说明", "width": "60"},
|
||||
{"field": "amount", "label": "金额(元)", "width": "30"}
|
||||
],
|
||||
"position": {"x": 0, "y": 60, "width": 170}
|
||||
},
|
||||
{
|
||||
"id": "total_section",
|
||||
"type": "container",
|
||||
"position": {"x": 0, "y": 130, "width": 170},
|
||||
"children": [
|
||||
{
|
||||
"id": "total_label",
|
||||
"type": "text",
|
||||
"content": "合计金额:",
|
||||
"position": {"x": 100, "y": 0},
|
||||
"style": {"fontSize": 14, "fontWeight": "bold"}
|
||||
},
|
||||
{
|
||||
"id": "total_amount",
|
||||
"type": "field",
|
||||
"fieldName": "total_amount",
|
||||
"format": "money",
|
||||
"position": {"x": 130, "y": 0},
|
||||
"style": {"fontSize": 14, "fontWeight": "bold", "color": "#c00"}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "approval_section",
|
||||
"type": "text",
|
||||
"content": "审批记录",
|
||||
"position": {"x": 0, "y": 150},
|
||||
"style": {"fontSize": 14, "fontWeight": "bold"}
|
||||
},
|
||||
{
|
||||
"id": "approval_table",
|
||||
"type": "table",
|
||||
"dataSource": "_logs",
|
||||
"columns": [
|
||||
{"field": "node_name", "label": "审批节点", "width": "60"},
|
||||
{"field": "action", "label": "操作", "width": "30"},
|
||||
{"field": "comment", "label": "审批意见", "width": "60"},
|
||||
{"field": "created_at", "label": "时间", "width": "40"}
|
||||
],
|
||||
"position": {"x": 0, "y": 160, "width": 170}
|
||||
},
|
||||
{
|
||||
"id": "seal_placeholder",
|
||||
"type": "seal",
|
||||
"sealType": "finance",
|
||||
"position": {"x": 130, "y": 220},
|
||||
"size": {"width": 40, "height": 40}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
# 通用模板
|
||||
GENERAL_TEMPLATE = {
|
||||
"version": "1.0",
|
||||
"pageConfig": {
|
||||
"size": "A4",
|
||||
"orientation": "portrait",
|
||||
"margin": {"top": 25, "right": 20, "bottom": 25, "left": 20}
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"id": "title",
|
||||
"type": "text",
|
||||
"content": "{{_instance.title}}",
|
||||
"position": {"x": 0, "y": 10, "width": 170},
|
||||
"style": {"fontSize": 22, "fontWeight": "bold", "textAlign": "center"}
|
||||
},
|
||||
{
|
||||
"id": "doc_no",
|
||||
"type": "field",
|
||||
"fieldName": "_instance.instance_no",
|
||||
"label": "单据编号:",
|
||||
"position": {"x": 120, "y": 25},
|
||||
"style": {"fontSize": 10, "color": "#666"}
|
||||
},
|
||||
{
|
||||
"id": "content_placeholder",
|
||||
"type": "text",
|
||||
"content": "(请在模板设计器中添加表单字段)",
|
||||
"position": {"x": 0, "y": 50, "width": 170},
|
||||
"style": {"fontSize": 12, "textAlign": "center", "color": "#999"}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
# 内置模板列表
|
||||
BUILTIN_TEMPLATES: List[Dict[str, Any]] = [
|
||||
{
|
||||
"code": "builtin_leave_application",
|
||||
"name": "请假申请单",
|
||||
"category": "leave",
|
||||
"description": "标准请假申请单模板,包含请假信息、审批记录和签章位置",
|
||||
"template_type": "designer",
|
||||
"template_content": json.dumps(LEAVE_APPLICATION_TEMPLATE, ensure_ascii=False),
|
||||
"is_builtin": True,
|
||||
"status": "published",
|
||||
},
|
||||
{
|
||||
"code": "builtin_expense_report",
|
||||
"name": "费用报销单",
|
||||
"category": "expense",
|
||||
"description": "标准费用报销单模板,包含报销明细、合计金额和审批记录",
|
||||
"template_type": "designer",
|
||||
"template_content": json.dumps(EXPENSE_REPORT_TEMPLATE, ensure_ascii=False),
|
||||
"is_builtin": True,
|
||||
"status": "published",
|
||||
},
|
||||
{
|
||||
"code": "builtin_general",
|
||||
"name": "通用模板",
|
||||
"category": "other",
|
||||
"description": "通用文档模板,可根据需要自定义内容",
|
||||
"template_type": "designer",
|
||||
"template_content": json.dumps(GENERAL_TEMPLATE, ensure_ascii=False),
|
||||
"is_builtin": True,
|
||||
"status": "published",
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def get_builtin_templates() -> List[Dict[str, Any]]:
|
||||
"""获取内置模板列表"""
|
||||
return BUILTIN_TEMPLATES
|
||||
@@ -0,0 +1,96 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<style>
|
||||
@page {
|
||||
size: {{ page_width }} {{ page_height }};
|
||||
margin: {{ margin_top }}px {{ margin_right }}px {{ margin_bottom }}px {{ margin_left }}px;
|
||||
{{ page_number_css|safe }}
|
||||
}
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
body {
|
||||
font-family: {{ font_family|safe }};
|
||||
font-size: 12pt;
|
||||
line-height: 1.6;
|
||||
color: #333;
|
||||
}
|
||||
.document-body {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
.element {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.element-text {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
.element-field {
|
||||
display: inline-block;
|
||||
}
|
||||
.element-field .label {
|
||||
font-weight: normal;
|
||||
}
|
||||
.element-field .value {
|
||||
border-bottom: 1px solid #333;
|
||||
min-width: 100px;
|
||||
display: inline-block;
|
||||
padding: 0 5px;
|
||||
}
|
||||
.element-table, .info-table, .detail-table, .info-row {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
.element-table th,
|
||||
.element-table td {
|
||||
border: 1px solid #333;
|
||||
padding: 8px;
|
||||
text-align: left;
|
||||
}
|
||||
.element-table th {
|
||||
background-color: #f5f5f5;
|
||||
font-weight: bold;
|
||||
}
|
||||
.element-image {
|
||||
max-width: 100%;
|
||||
}
|
||||
.element-signature {
|
||||
max-width: 150px;
|
||||
max-height: 60px;
|
||||
}
|
||||
.element-qrcode,
|
||||
.element-barcode,
|
||||
.element-image {
|
||||
width: 100%;
|
||||
}
|
||||
.element-divider {
|
||||
border-top: 1px solid #333;
|
||||
margin: 10px 0;
|
||||
}
|
||||
h1 {
|
||||
margin: 15px 0;
|
||||
}
|
||||
.doc-header {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.doc-footer {
|
||||
margin-top: 30px;
|
||||
padding-top: 10px;
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
.approval-area {
|
||||
margin: 20px 0;
|
||||
}
|
||||
{{ custom_css|safe }}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="document-body">
|
||||
{{ content }}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,28 @@
|
||||
{% set label_font_size = labelFontSize|default(14) %}
|
||||
{% set label_color = labelColor|default('#333333') %}
|
||||
{% set label_font_weight = labelFontWeight|default('normal') %}
|
||||
{% set label_position = labelPosition|default('bottom') %}
|
||||
{% set align_map = {'left': 'flex-start', 'center': 'center', 'right': 'flex-end'} %}
|
||||
{% set justify = align_map.get(textAlign|default('center'), 'center') %}
|
||||
<div style="display: flex; justify-content: {{ justify }}; width: 100%; box-sizing: border-box; line-height: 0;">
|
||||
<div style="display: inline-flex; flex-direction: {% if label_position == 'top' %}column-reverse{% elif label_position == 'left' %}row-reverse{% elif label_position == 'right' %}row{% else %}column{% endif %}; align-items: center; gap: 4px; line-height: normal;">
|
||||
{% if barcode_image %}
|
||||
<img src="{{ barcode_image }}" style="width: {{ width }}; height: {{ height }}; display: block;" />
|
||||
{% else %}
|
||||
<div style="width: {{ width }}; height: {{ height }}; display: inline-flex; border: 2px dashed #dcdfe6; background-color: #f5f7fa; align-items: center; justify-content: center; flex-direction: column; gap: 8px; color: #909399; font-size: 12px;">
|
||||
<div style="display: flex; align-items: center; gap: 2px;">
|
||||
<div style="width: 2px; height: 16px; background-color: #909399;"></div>
|
||||
<div style="width: 2px; height: 16px; background-color: #909399;"></div>
|
||||
<div style="width: 2px; height: 16px; background-color: #909399;"></div>
|
||||
<div style="width: 2px; height: 16px; background-color: #909399;"></div>
|
||||
<div style="width: 2px; height: 16px; background-color: #909399;"></div>
|
||||
<div style="width: 2px; height: 16px; background-color: #909399;"></div>
|
||||
<div style="width: 2px; height: 16px; background-color: #909399;"></div>
|
||||
<div style="width: 2px; height: 16px; background-color: #909399;"></div>
|
||||
</div>
|
||||
<span>{{ width }} × {{ height }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if label %}<span style="font-size: {{ label_font_size }}px; color: {{ label_color }}; font-weight: {{ label_font_weight }};">{{ label }}</span>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1 @@
|
||||
{% for child in children %}{{ child|safe }}{% endfor %}
|
||||
@@ -0,0 +1,33 @@
|
||||
{% set header_font_size = header_font_size|default(14) %}
|
||||
{% set header_color = header_color|default('#333333') %}
|
||||
{% set header_font_weight = header_font_weight|default('bold') %}
|
||||
{% set content_font_size = content_font_size|default(14) %}
|
||||
{% set content_color = content_color|default('#333333') %}
|
||||
<table class="detail-table" style="width: 100%; border-collapse: collapse; margin: 10px 0;">
|
||||
{% if show_header %}
|
||||
<thead><tr>
|
||||
{% if show_index %}<th style="border: 1px solid #333; padding: 8px; font-size: {{ header_font_size }}px; color: {{ header_color }}; font-weight: {{ header_font_weight }};{% if header_bg_color %} background-color: {{ header_bg_color }};{% endif %} width: {{ index_width|default('40') }}px;">序号</th>{% endif %}
|
||||
{% for col in columns %}
|
||||
<th style="border: 1px solid #333; padding: 8px; font-size: {{ header_font_size }}px; color: {{ header_color }}; font-weight: {{ header_font_weight }};{% if header_bg_color %} background-color: {{ header_bg_color }};{% endif %}{% if col.width %} width: {{ col.width }};{% endif %} text-align: {{ col.align|default('left') }};">{{ col.label }}</th>
|
||||
{% endfor %}
|
||||
</tr></thead>
|
||||
{% endif %}
|
||||
<tbody>
|
||||
{% for row in rows %}
|
||||
<tr>
|
||||
{% if show_index %}<td style="border: 1px solid #333; padding: 8px; font-size: {{ content_font_size }}px; color: {{ content_color }}; text-align: center;">{{ loop.index }}</td>{% endif %}
|
||||
{% for col in columns %}
|
||||
<td style="border: 1px solid #333; padding: 8px; font-size: {{ content_font_size }}px; color: {{ content_color }}; text-align: {{ col.align|default('left') }};">{{ row[col.field]|default('') }}</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% if show_summary and rows %}
|
||||
<tr>
|
||||
{% if show_index %}<td style="border: 1px solid #333; padding: 8px; font-size: {{ content_font_size }}px; color: {{ content_color }}; text-align: center; font-weight: bold;">合计</td>{% endif %}
|
||||
{% for col in columns %}
|
||||
<td style="border: 1px solid #333; padding: 8px; font-size: {{ content_font_size }}px; color: {{ content_color }}; text-align: {{ col.align|default('left') }}; font-weight: bold;">{{ summary_values[col.field]|default('') }}</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -0,0 +1 @@
|
||||
<hr style="border: none; border-top: {{ line_width }}px {{ line_style }} {{ line_color }}; margin: 10px 0;" />
|
||||
@@ -0,0 +1,8 @@
|
||||
{% set label_font_size = label_font_size|default(font_size|default(12)) %}
|
||||
{% set label_color = label_color|default('#333333') %}
|
||||
{% set label_font_weight = label_font_weight|default('normal') %}
|
||||
{% set value_font_size = value_font_size|default(font_size|default(12)) %}
|
||||
{% set value_color = value_color|default('#333333') %}
|
||||
<div style="text-align: {{ text_align }}; margin: 10px 0;">
|
||||
{% for field in fields %}{% if not loop.first %} {% endif %}<span style="font-size: {{ label_font_size }}pt; color: {{ label_color }}; font-weight: {{ label_font_weight }};">{{ field.label }}:</span><span style="font-size: {{ value_font_size }}pt; color: {{ value_color }};{% if show_underline %} border-bottom: 1px solid #333; padding-bottom: 2px; display: inline-block; min-width: 50px;{% endif %}">{{ field.value if field.value else '' }}</span>{% endfor %}
|
||||
</div>
|
||||
@@ -0,0 +1 @@
|
||||
{% if label %}<span class="label">{{ label }}</span>{% endif %}<span class="value">{{ value }}</span>
|
||||
@@ -0,0 +1,5 @@
|
||||
{% set color = color|default('#666666') %}
|
||||
<div class="doc-footer" style="text-align: {{ text_align }}; font-size: {{ font_size }}pt; color: {{ color }}; margin-top: 30px; padding-top: 10px; border-top: 1px solid #ddd;">
|
||||
{% if content %}<div>{{ content }}</div>{% endif %}
|
||||
{% if footer_parts %}<div style="margin-top: 5px;">{{ footer_parts|join(' | ') }}</div>{% endif %}
|
||||
</div>
|
||||
@@ -0,0 +1,13 @@
|
||||
{% set header_font_size = header_font_size|default(14) %}
|
||||
{% set header_color = header_color|default('#333333') %}
|
||||
{% set header_font_weight = header_font_weight|default('bold') %}
|
||||
<table class="doc-header" style="width: 100%; border: none;">
|
||||
<tr>
|
||||
{% if header_type in ['logo', 'logo-text'] and logo_src %}
|
||||
<td style="width: 80px; border: none;"><img src="{{ logo_src }}" style="max-height: 50px;" /></td>
|
||||
{% endif %}
|
||||
{% if header_type in ['text', 'logo-text'] %}
|
||||
<td style="text-align: {{ text_align }}; border: none; font-size: {{ header_font_size }}pt; font-weight: {{ header_font_weight }}; color: {{ header_color }};">{{ company_name }}</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
</table>
|
||||
@@ -0,0 +1,27 @@
|
||||
{% set label_font_size = labelFontSize|default(14) %}
|
||||
{% set label_color = labelColor|default('#333333') %}
|
||||
{% set label_font_weight = labelFontWeight|default('normal') %}
|
||||
{% set align_map = {'left': 'flex-start', 'center': 'center', 'right': 'flex-end'} %}
|
||||
{% set justify = align_map.get(textAlign|default('center'), 'center') %}
|
||||
{% set is_float = position_mode|default('inline') == 'float' %}
|
||||
{% if is_float %}
|
||||
<div style="position: absolute; left: {{ float_x|default(0) }}px; top: {{ float_y|default(0) }}px; z-index: {{ float_z_index|default(100) }};">
|
||||
{% else %}
|
||||
<div style="display: flex; justify-content: {{ justify }}; width: 100%; box-sizing: border-box;">
|
||||
{% endif %}
|
||||
<div style="display: inline-flex; flex-direction: {% if labelPosition == 'top' %}column-reverse{% elif labelPosition == 'left' %}row-reverse{% elif labelPosition == 'right' %}row{% else %}column{% endif %}; align-items: center; gap: 4px;">
|
||||
{% if src %}
|
||||
<img src="{{ src }}" style="width: {{ width }}; height: {{ height }}; display: block;" />
|
||||
{% else %}
|
||||
<div style="width: {{ width }}; height: {{ height }}; display: flex; border: 2px dashed #dcdfe6; background-color: #f5f7fa; align-items: center; justify-content: center; flex-direction: column; gap: 8px; color: #909399; font-size: 12px;">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
|
||||
<circle cx="8.5" cy="8.5" r="1.5"></circle>
|
||||
<polyline points="21 15 16 10 5 21"></polyline>
|
||||
</svg>
|
||||
<span>{{ width }} × {{ height }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if label %}<span style="font-size: {{ label_font_size }}px; color: {{ label_color }}; font-weight: {{ label_font_weight }};">{{ label }}</span>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,12 @@
|
||||
{% set label_font_size = label_font_size|default(font_size|default(12)) %}
|
||||
{% set label_color = label_color|default('#333333') %}
|
||||
{% set label_font_weight = label_font_weight|default('normal') %}
|
||||
{% set value_font_size = value_font_size|default(font_size|default(12)) %}
|
||||
{% set value_color = value_color|default('#333333') %}
|
||||
<table class="info-row" style="width: 100%; border: none; margin: 8px 0;">
|
||||
<tr>
|
||||
{% for field in fields %}
|
||||
<td style="width: {{ field.width|default('auto') }}; border: none; padding: 4px 0;">{% if show_label %}<span style="font-size: {{ label_font_size }}pt; color: {{ label_color }}; font-weight: {{ label_font_weight }};">{{ field.label }}:</span>{% endif %}<span style="font-size: {{ value_font_size }}pt; color: {{ value_color }};{% if show_underline %} border-bottom: 1px solid #333; padding-bottom: 2px; display: inline-block; min-width: 50px;{% endif %}">{{ field.value if field.value else '' }}</span></td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</table>
|
||||
@@ -0,0 +1,14 @@
|
||||
{% set label_font_size = label_font_size|default(14) %}
|
||||
{% set label_color = label_color|default('#333333') %}
|
||||
{% set label_font_weight = label_font_weight|default('normal') %}
|
||||
{% set field_font_size = field_font_size|default(14) %}
|
||||
{% set field_color = field_color|default('#333333') %}
|
||||
<table class="info-table" style="width: 100%; border-collapse: collapse; margin: 10px 0;">
|
||||
{% for row in rows %}
|
||||
<tr>
|
||||
{% for cell in row.cells %}
|
||||
<td colspan="{{ cell.colspan|default(1) }}" rowspan="{{ cell.rowspan|default(1) }}" style="border: {{ border }}; padding: 8px; text-align: {{ cell.align|default('left') }};{% if cell.type == 'label' %} font-size: {{ label_font_size }}px; color: {{ label_color }}; font-weight: {{ label_font_weight }};{% if label_width %} width: {{ label_width }}px;{% endif %}{% if label_bg_color %} background-color: {{ label_bg_color }};{% elif cell.backgroundColor %} background-color: {{ cell.backgroundColor }};{% endif %}{% else %} font-size: {{ field_font_size }}px; color: {{ field_color }};{% if cell.bold %} font-weight: bold;{% endif %}{% if cell.backgroundColor %} background-color: {{ cell.backgroundColor }};{% endif %}{% endif %}">{% if cell.type == 'field' and show_underline %}<span style="border-bottom: 1px solid #333; padding-bottom: 2px; display: inline-block; min-width: 50px;">{{ cell.content if cell.content else '' }}</span>{% else %}{{ cell.content }}{% endif %}</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
@@ -0,0 +1,10 @@
|
||||
{% set label_font_size = label_font_size|default(font_size|default(12)) %}
|
||||
{% set label_color = label_color|default('#333333') %}
|
||||
{% set label_font_weight = label_font_weight|default('normal') %}
|
||||
{% set value_font_size = value_font_size|default(font_size|default(12)) %}
|
||||
{% set value_color = value_color|default('#333333') %}
|
||||
{% if show_label %}
|
||||
<p style="margin: 5px 0;"><span style="font-size: {{ label_font_size }}pt; color: {{ label_color }}; font-weight: {{ label_font_weight }};">{{ label }}:</span><span style="font-size: {{ value_font_size }}pt; color: {{ value_color }};{% if show_underline %} border-bottom: 1px solid #333; padding-bottom: 2px; display: inline-block; min-width: 50px;{% endif %}">{{ value if value else '' }}</span></p>
|
||||
{% else %}
|
||||
<p style="margin: 5px 0;"><span style="font-size: {{ value_font_size }}pt; color: {{ value_color }};{% if show_underline %} border-bottom: 1px solid #333; padding-bottom: 2px; display: inline-block; min-width: 50px;{% endif %}">{{ value if value else '' }}</span></p>
|
||||
{% endif %}
|
||||
@@ -0,0 +1,13 @@
|
||||
{% set color = color|default('#333333') %}
|
||||
<div style="font-size: {{ font_size }}pt; line-height: {{ line_height }}; text-align: {{ text_align }}; color: {{ color }}; margin: 10px 0; white-space: pre-wrap; word-wrap: break-word;">
|
||||
<style>
|
||||
.paragraph-content p { margin: 0.5em 0; }
|
||||
.paragraph-content p:first-child { margin-top: 0; }
|
||||
.paragraph-content p:last-child { margin-bottom: 0; }
|
||||
.paragraph-content br { display: block; content: ''; margin: 0.5em 0; }
|
||||
.paragraph-content table { border-collapse: collapse; width: 100%; margin: 1em 0; }
|
||||
.paragraph-content table td, .paragraph-content table th { border: 1px solid #ddd; padding: 8px; text-align: left; }
|
||||
.paragraph-content table th { font-weight: 500; }
|
||||
</style>
|
||||
<div class="paragraph-content">{{ content|safe }}</div>
|
||||
</div>
|
||||
@@ -0,0 +1,27 @@
|
||||
{% set label_font_size = labelFontSize|default(14) %}
|
||||
{% set label_color = labelColor|default('#333333') %}
|
||||
{% set label_font_weight = labelFontWeight|default('normal') %}
|
||||
{% set label_position = labelPosition|default('bottom') %}
|
||||
{% set align_map = {'left': 'flex-start', 'center': 'center', 'right': 'flex-end'} %}
|
||||
{% set justify = align_map.get(textAlign|default('center'), 'center') %}
|
||||
<div style="display: flex; justify-content: {{ justify }}; width: 100%; box-sizing: border-box; line-height: 0;">
|
||||
<div style="display: inline-flex; flex-direction: {% if label_position == 'top' %}column-reverse{% elif label_position == 'left' %}row-reverse{% elif label_position == 'right' %}row{% else %}column{% endif %}; align-items: center; gap: 4px; line-height: normal;">
|
||||
{% if qrcode_image %}
|
||||
<img src="{{ qrcode_image }}" style="width: {{ width }}; height: {{ height }}; display: block;" />
|
||||
{% else %}
|
||||
<div style="width: {{ width }}; height: {{ height }}; display: inline-flex; border: 2px dashed #dcdfe6; background-color: #f5f7fa; align-items: center; justify-content: center; flex-direction: column; gap: 8px; color: #909399; font-size: 12px;">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<rect x="3" y="3" width="7" height="7"></rect>
|
||||
<rect x="14" y="3" width="7" height="7"></rect>
|
||||
<rect x="3" y="14" width="7" height="7"></rect>
|
||||
<rect x="14" y="14" width="3" height="3"></rect>
|
||||
<rect x="18" y="14" width="3" height="3"></rect>
|
||||
<rect x="14" y="18" width="3" height="3"></rect>
|
||||
<rect x="18" y="18" width="3" height="3"></rect>
|
||||
</svg>
|
||||
<span>{{ width }} × {{ height }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if label %}<span style="font-size: {{ label_font_size }}px; color: {{ label_color }}; font-weight: {{ label_font_weight }};">{{ label }}</span>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1 @@
|
||||
<div class="rich-text" style="margin: 10px 0;">{{ content|safe }}</div>
|
||||
@@ -0,0 +1,7 @@
|
||||
<table style="width: 100%; border: none; border-collapse: separate; border-spacing: {{ gap }}px 0;">
|
||||
<tr>
|
||||
{% for child in children %}
|
||||
<td style="{% if child.width %}width: {{ child.width }};{% endif %} vertical-align: top; border: none; padding: 0;">{{ child.content|safe }}</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</table>
|
||||
@@ -0,0 +1,42 @@
|
||||
{% set align_map = {'left': 'flex-start', 'center': 'center', 'right': 'flex-end'} %}
|
||||
{% set justify = align_map.get(text_align, 'flex-end') %}
|
||||
{% set flex_direction = 'column' if label_position in ['top', 'bottom'] else 'row' %}
|
||||
{% set label_font_size = label_font_size|default(14) %}
|
||||
{% set label_color = label_color|default('#333333') %}
|
||||
{% set label_font_weight = label_font_weight|default('normal') %}
|
||||
{% set is_float = position_mode|default('inline') == 'float' %}
|
||||
{% set float_style = 'position: absolute; left: %spx; top: %spx; z-index: %s;'|format(float_x|default(0), float_y|default(0), float_z_index|default(100)) if is_float else 'display: flex; justify-content: %s; margin: 10px 0; width: 100%%; box-sizing: border-box;'|format(justify) %}
|
||||
{% if seal_image_data %}
|
||||
<div class="seal-container" style="{{ float_style }}">
|
||||
<div style="display: flex; flex-direction: {{ flex_direction }}; align-items: center; gap: 8px;">
|
||||
{% if label and label_position in ['top', 'left'] %}
|
||||
<span class="seal-label" style="font-size: {{ label_font_size }}px; color: {{ label_color }}; font-weight: {{ label_font_weight }}; white-space: nowrap;">{{ label }}</span>
|
||||
{% endif %}
|
||||
<img class="seal-image"
|
||||
src="{{ seal_image_data }}"
|
||||
data-seal-id="{{ seal_id }}"
|
||||
data-seal-image-id="{{ seal_image_id }}"
|
||||
style="width: {{ width }}px; height: {{ height }}px; object-fit: contain; flex-shrink: 0;"
|
||||
alt="{{ seal_name }}" />
|
||||
{% if label and label_position in ['bottom', 'right'] %}
|
||||
<span class="seal-label" style="font-size: {{ label_font_size }}px; color: {{ label_color }}; font-weight: {{ label_font_weight }}; white-space: nowrap;">{{ label }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="seal-placeholder" data-seal-type="{{ seal_type }}"
|
||||
style="{{ float_style }}">
|
||||
<div style="display: flex; flex-direction: {{ flex_direction }}; align-items: center; gap: 8px;">
|
||||
{% if label and label_position in ['top', 'left'] %}
|
||||
<span class="seal-label" style="font-size: {{ label_font_size }}px; color: {{ label_color }}; font-weight: {{ label_font_weight }}; white-space: nowrap;">{{ label }}</span>
|
||||
{% endif %}
|
||||
<div style="width: {{ width }}px; height: {{ height }}px; border: 2px dashed #ccc; border-radius: 50%;
|
||||
display: flex; align-items: center; justify-content: center; color: #999; flex-shrink: 0;">
|
||||
签章
|
||||
</div>
|
||||
{% if label and label_position in ['bottom', 'right'] %}
|
||||
<span class="seal-label" style="font-size: {{ label_font_size }}px; color: {{ label_color }}; font-weight: {{ label_font_weight }}; white-space: nowrap;">{{ label }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
@@ -0,0 +1,5 @@
|
||||
{% if src %}
|
||||
<img class="element-signature" src="{{ src }}" />
|
||||
{% else %}
|
||||
<div class="signature-placeholder"></div>
|
||||
{% endif %}
|
||||
@@ -0,0 +1,52 @@
|
||||
{% set table_font_size = table_font_size|default(14) %}
|
||||
{% set border_mode = border_mode|default('all') %}
|
||||
{% set border_color = border_color|default('#333') %}
|
||||
<table class="smart-table" style="width: 100%; border-collapse: collapse; margin: 10px 0; table-layout: fixed; font-size: {{ table_font_size }}px;">
|
||||
{% if col_widths %}
|
||||
<colgroup>
|
||||
{% for w in col_widths %}
|
||||
<col style="width: {{ w }}%;" />
|
||||
{% endfor %}
|
||||
</colgroup>
|
||||
{% endif %}
|
||||
{% for row in rows %}
|
||||
{% set row_idx = loop.index0 %}
|
||||
{% set is_first_row = loop.first %}
|
||||
{% set is_last_row = loop.last %}
|
||||
<tr>
|
||||
{% for cell in row.cells %}
|
||||
{% set col_idx = loop.index0 %}
|
||||
{% set is_first_col = loop.first %}
|
||||
{% set is_last_col = loop.last %}
|
||||
{% set solid_border = '1px solid ' ~ border_color %}
|
||||
{% set no_border = 'none' %}
|
||||
{% if border_mode == 'none' %}
|
||||
{% set b_top = no_border %}{% set b_right = no_border %}{% set b_bottom = no_border %}{% set b_left = no_border %}
|
||||
{% elif border_mode == 'outer' %}
|
||||
{% set b_top = solid_border if is_first_row else no_border %}
|
||||
{% set b_right = solid_border if is_last_col else no_border %}
|
||||
{% set b_bottom = solid_border if is_last_row else no_border %}
|
||||
{% set b_left = solid_border if is_first_col else no_border %}
|
||||
{% elif border_mode == 'inner' %}
|
||||
{% set b_top = no_border if is_first_row else solid_border %}
|
||||
{% set b_right = no_border if is_last_col else solid_border %}
|
||||
{% set b_bottom = no_border if is_last_row else solid_border %}
|
||||
{% set b_left = no_border if is_first_col else solid_border %}
|
||||
{% elif border_mode == 'horizontal' %}
|
||||
{% set b_top = no_border if is_first_row else solid_border %}
|
||||
{% set b_right = no_border %}
|
||||
{% set b_bottom = no_border if is_last_row else solid_border %}
|
||||
{% set b_left = no_border %}
|
||||
{% elif border_mode == 'vertical' %}
|
||||
{% set b_top = no_border %}
|
||||
{% set b_right = no_border if is_last_col else solid_border %}
|
||||
{% set b_bottom = no_border %}
|
||||
{% set b_left = no_border if is_first_col else solid_border %}
|
||||
{% else %}
|
||||
{% set b_top = solid_border %}{% set b_right = solid_border %}{% set b_bottom = solid_border %}{% set b_left = solid_border %}
|
||||
{% endif %}
|
||||
<td colspan="{{ cell.colspan|default(1) }}" rowspan="{{ cell.rowspan|default(1) }}" style="border-top: {{ b_top }}; border-right: {{ b_right }}; border-bottom: {{ b_bottom }}; border-left: {{ b_left }}; padding: 6px 8px; text-align: {{ cell.align|default('left') }};{% if cell.bold %} font-weight: bold;{% endif %}{% if cell.fontSize %} font-size: {{ cell.fontSize }}px;{% endif %}{% if cell.color %} color: {{ cell.color }};{% endif %}{% if cell.backgroundColor %} background-color: {{ cell.backgroundColor }};{% endif %} vertical-align: top; overflow-wrap: break-word;">{{ cell.content }}</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
@@ -0,0 +1,4 @@
|
||||
<div class="smart-text" style="margin: 8px 0; font-size: {{ font_size }}px; line-height: {{ line_height }}; text-align: {{ text_align }}; overflow-wrap: break-word;">{{ content|safe }}</div>
|
||||
{% if table_html %}
|
||||
<div class="smart-text-table" style="margin: 4px 0 8px 0;">{{ table_html|safe }}</div>
|
||||
{% endif %}
|
||||
@@ -0,0 +1 @@
|
||||
<div style="height: {{ height }}px;"></div>
|
||||
@@ -0,0 +1,16 @@
|
||||
<table class="element-table">
|
||||
<thead><tr>
|
||||
{% for col in columns %}
|
||||
<th style="width: {{ col.width|default('auto') }}">{{ col.label }}</th>
|
||||
{% endfor %}
|
||||
</tr></thead>
|
||||
<tbody>
|
||||
{% for row in rows %}
|
||||
<tr>
|
||||
{% for col in columns %}
|
||||
<td>{{ row[col.field]|default('') }}</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -0,0 +1 @@
|
||||
<span class="text-content">{{ content }}</span>
|
||||
@@ -0,0 +1,2 @@
|
||||
{% set color = color|default('#333333') %}
|
||||
<h1 style="font-size: {{ font_size }}pt; font-weight: {{ font_weight }}; text-align: {{ text_align }}; color: {{ color }}; margin: 15px 0;">{{ content }}</h1>
|
||||
@@ -0,0 +1,11 @@
|
||||
<div class="wysiwyg-content" style="font-size: 14px; line-height: 1.6;">
|
||||
{{ content }}
|
||||
</div>
|
||||
<style>
|
||||
.wysiwyg-content h1 { font-size: 28px; font-weight: bold; margin: 16px 0 8px; line-height: 1.3; }
|
||||
.wysiwyg-content h2 { font-size: 22px; font-weight: bold; margin: 14px 0 6px; line-height: 1.3; }
|
||||
.wysiwyg-content h3 { font-size: 18px; font-weight: bold; margin: 12px 0 4px; line-height: 1.4; }
|
||||
.wysiwyg-content p { margin: 4px 0; }
|
||||
.wysiwyg-content ul, .wysiwyg-content ol { padding-left: 24px; margin: 4px 0; }
|
||||
.wysiwyg-content img { max-width: 100%; height: auto; }
|
||||
</style>
|
||||
Reference in New Issue
Block a user