fix: band-level windowed refine_layout + programmatic map_fields to prevent 91.5% content loss
Root cause: LLM receiving full 34k-char JRXML would regenerate from scratch
instead of modifying coordinates in-place, shrinking output to ~3k chars.
Solution (programmatic node control, not prompt engineering):
- New agent/jrxml_windower.py: decompose JRXML into header (never sent to
LLM) + individual bands. Split bands >4000 chars at element boundaries.
Reassemble with element count validation (>10% change = rollback).
- Rewrite refine_layout: per-band windowed LLM processing (~2-4k chars
each). LLM cannot "reimagine" the entire report.
- Rewrite map_fields: 100% programmatic regex $F{field_N} -> real name
replacement. Zero LLM calls, zero content loss.
- _sanitize_field_name: non-ASCII chars escaped to _uXXXX_ format for
valid JRXML identifiers.
- Tests: 48 new unit tests (windower 28 + map_fields 20). All passing.
Full suite 385 tests, zero regressions.
This commit is contained in:
@@ -44,12 +44,15 @@ cd frontend && npm run dev
|
||||
│ ├── api/client.ts SSE 客户端 + fetch 封装
|
||||
│ ├── stores/chat.ts Pinia: 消息/流式/节点进度
|
||||
│ ├── stores/session.ts Pinia: 会话管理
|
||||
│ ├── stores/kb.ts Pinia: KB 状态管理(多租户知识库)
|
||||
│ ├── components/
|
||||
│ │ ├── Sidebar.vue 会话列表 + 下载 + 历史版本
|
||||
│ │ ├── ChatMessages.vue 消息列表渲染
|
||||
│ │ ├── ProcessSection.vue 过程折叠区(替代 StreamingMessage + NodeProgress)
|
||||
│ │ ├── UnifiedInput.vue 统一输入框(文本+文件拖拽/粘贴/芯片)
|
||||
│ │ └── SummaryCard.vue 结果摘要卡片(含耗时)
|
||||
│ │ ├── UnifiedInput.vue 统一输入框(文本+文件拖拽/粘贴/芯片,含 .jrxml)
|
||||
│ │ ├── SummaryCard.vue 结果摘要卡片(含耗时)
|
||||
│ │ ├── KbSelector.vue KB 下拉选择器(对话中切换知识库)
|
||||
│ │ └── KbManager.vue KB 管理面板(创建/上传/构建/删除)
|
||||
│ └── utils/format.ts 工具函数
|
||||
│
|
||||
▼ HTTP + SSE (Server-Sent Events)
|
||||
@@ -87,9 +90,16 @@ validation_service/ (FastAPI, 端口 8001) — 不变
|
||||
| `backend/annotation_detector.py` | 批注检测: 圈选(cv2 HoughCircles) + 箭头(HoughLinesP聚类) + OCR关联 + LLM格式化 | 中 |
|
||||
| `backend/embeddings.py` | 嵌入模型工厂 (HuggingFace/OpenAI) | 低 |
|
||||
| `backend/validation.py` | 验证服务 HTTP 客户端 | 低 |
|
||||
| `backend/session.py` | 会话 JSON 文件 CRUD | 低 |
|
||||
| `backend/session.py` | 会话 JSON 文件 CRUD(含 kb_id) | 低 |
|
||||
| `backend/kb_manager.py` | 用户+知识库 CRUD(多租户,原子 JSON 持久化) | 中 |
|
||||
| `backend/kb_searcher.py` | 知识库隔离搜索 + 模板检索(per-KB ChromaDB) | 中 |
|
||||
| `backend/kb_parser.py` | KB 解析管道:文件解析→字段提取→chunk切割→向量嵌入 | 中 |
|
||||
| `backend/field_matcher.py` | OCR↔KB 字段匹配:Embedding 粗筛 + LLM 精确确认 | 中 |
|
||||
| `agent/datasource.py` | 数据源模式解析:$P{{xxx}} 参数 vs JDBC 直连 | 低 |
|
||||
| `agent/jrxml_windower.py` | JRXML Band 级窗口化引擎:拆解/切分/重组/元素计数校验 | 中 |
|
||||
| `validation_service/main.py` | FastAPI 验证服务 | 低 |
|
||||
| `scripts/init_kb.py` | 知识库初始化/模型下载 | 低 |
|
||||
| `scripts/init_kb.py` | 旧 RAG 知识库初始化/模型下载 | 低 |
|
||||
| `scripts/init_default_kb.py` | 多租户默认 KB 初始化(默认用户 + 预置 KB) | 低 |
|
||||
| `app.py` | ~~旧 Streamlit UI~~(已由 api_server.py + frontend/ 替代) | 废弃 |
|
||||
|
||||
## 关键约定
|
||||
@@ -427,3 +437,115 @@ cd frontend && npx playwright test
|
||||
### consult_answer 前端显示修复
|
||||
|
||||
- `api_server.py` — `agent_complete` SSE 事件新增 `consult_answer` 字段
|
||||
|
||||
## 更新 (v12 — 2026-05-23)
|
||||
|
||||
### 多租户知识库系统
|
||||
|
||||
**核心架构**:用户自行维护多套知识库,每套 KB 拥有独立的文件存储、JSON 元数据和 ChromaDB 向量集合。会话可绑定不同 KB,LLM 基于 KB 中的字段定义和 JRXML 模板生成报表。
|
||||
|
||||
**存储架构**:
|
||||
```
|
||||
kb_data/
|
||||
├── users.json # 用户注册表
|
||||
└── {user_id}/
|
||||
├── profile.json
|
||||
└── {kb_id}/
|
||||
├── meta.json # KB 元数据 + 字段定义 + 模板索引
|
||||
├── raw/ # 原始上传文件
|
||||
├── chunks.json # RAG chunks(含 JRXML 模板完整文本)
|
||||
└── chroma/ # KB 专属 ChromaDB
|
||||
```
|
||||
|
||||
**新增后端模块**:
|
||||
|
||||
| 文件 | 职责 |
|
||||
|------|------|
|
||||
| `backend/kb_manager.py` | 用户+KB CRUD:create_user/list_users/create_kb/list_kbs/get_kb/delete_kb/update_kb_meta/get_kb_raw_dir/get_kb_chroma_path。原子 JSON 写入(tempfile + os.replace) |
|
||||
| `backend/kb_parser.py` | KB 解析管道:`parse_jrxml_fields()` XML 提取参数/字段/查询 → `process_file_for_kb()` 处理多种格式(jrxml/zip/tar/pdf/docx/xlsx/md) → `chunk_file_results()` 切割 → `build_kb_from_files()` 全管线(parse→chunk→embed→update meta) |
|
||||
| `backend/kb_searcher.py` | `KBChromaSearcher` 类:per-KB ChromaDB 懒连接。`search()` 语义搜索、`search_templates()` 仅搜索 JRXML 模板 chunk、`add_chunks()` 向量写入。全局 searcher 缓存 `_searchers: dict` |
|
||||
| `backend/field_matcher.py` | OCR↔KB 字段匹配:1) Embedding 粗筛(余弦相似度 top-3)2) LLM 精确确认。返回 `{"工单号": "billNo", ...}` 映射 |
|
||||
| `agent/datasource.py` | 数据源模式:`resolve_datasource_mode()` 检测用户意图 → `"parameter"`(默认 $P{xxx})或 `"jdbc"`(SQL 直连)。未配置 DB 时生成反问消息 |
|
||||
| `scripts/init_default_kb.py` | 默认 KB 初始化:创建默认用户 → 解析 `rag/jrxml_source/` 下的 17 个 JRXML + 16 个 MD → chunk + embed → ChromaDB |
|
||||
|
||||
**新增 API 端点**(api_server.py):
|
||||
|
||||
```
|
||||
POST /api/users # 创建用户
|
||||
GET /api/users # 用户列表
|
||||
GET /api/users/{user_id} # 用户详情
|
||||
DELETE /api/users/{user_id} # 删除用户
|
||||
GET /api/users/{user_id}/kbs # KB 列表
|
||||
POST /api/users/{user_id}/kbs # 创建 KB
|
||||
GET /api/kbs/{kb_id} # KB 详情
|
||||
DELETE /api/kbs/{kb_id} # 删除 KB
|
||||
POST /api/kbs/{kb_id}/upload # 上传文件到 KB
|
||||
POST /api/kbs/{kb_id}/build # 构建 KB(chunk→embed)
|
||||
GET /api/kbs/{kb_id}/status # KB 状态
|
||||
GET /api/kbs/{kb_id}/fields # KB 字段+模板列表
|
||||
GET /api/kbs/{kb_id}/search?q=&type= # KB 语义搜索
|
||||
PUT /api/sessions/{session_id}/kb # 绑定会话-KB
|
||||
GET /api/sessions/{session_id}/kb # 获取会话绑定的 KB
|
||||
```
|
||||
|
||||
**三条模板获取路径**:
|
||||
|
||||
1. **管理页预上传**:用户上传文件到 KB → 解析管道 → chunks + ChromaDB → 对话选择 KB → retrieve 节点从 KB 检索
|
||||
2. **对话框即时上传**:用户拖入 `.jrxml` → `_parse_jrxml_file()` → 注入 `agent_state["uploaded_template_jrxml"]` → 生成节点直接使用该模板
|
||||
3. **口头引用模板**:用户说"根据标准结算单模板" → `_detect_template_intent()` 正则匹配 → `retrieve()` 在 KB 中搜索模板 → 注入 `kb_template_jrxml`
|
||||
|
||||
**模板上下文注入**:所有 6 个生成节点(generate/generate_skeleton/refine_layout/map_fields/modify_jrxml/correct_jrxml)通过 `_build_template_context(state)` 获取模板上下文,优先级:聊天上传 > KB 检索 > KB 字段定义。6 个 prompt 模板全部新增 `{template_context}` 占位符。
|
||||
|
||||
**前端新增**:
|
||||
|
||||
| 文件 | 职责 |
|
||||
|------|------|
|
||||
| `stores/kb.ts` | Pinia store:用户列表、KB 列表、当前选择、字段/模板缓存、CRUD 操作、会话绑定 |
|
||||
| `components/KbSelector.vue` | 对话顶部 KB 下拉选择器 + 管理按钮 |
|
||||
| `components/KbManager.vue` | 模态面板:创建 KB、上传文件(支持 .jrxml/.md/.xlsx/.docx/.pdf/.csv/.zip 等)、构建、删除 |
|
||||
|
||||
**API Server 增强**:
|
||||
- `_process_files()` 检测 `.jrxml` 文件 → 提取参数/字段/查询/页面尺寸 → 注入 `uploaded_template_jrxml` + `uploaded_template_params`
|
||||
- `agent/state.py` 新增 10 个字段:`kb_id`, `kb_fields`, `kb_field_mapping`, `uploaded_template_jrxml`, `uploaded_template_params`, `kb_template_jrxml`, `kb_template_name`, `datasource_mode`, `db_config`
|
||||
|
||||
**字段匹配管线**(`_match_ocr_to_kb` → 尚未集成到节点):OCR 提取中文字段名 → `match_ocr_to_kb()` 两阶段匹配 → 结果为 `{"工单号": "billNo"}` → `format_field_mapping_context()` 注入 prompt → LLM 使用 `$P{billNo}` 而非 `$P{工单号}`
|
||||
|
||||
## 更新 (v13 — 2026-05-24)
|
||||
|
||||
### 3 阶段管道内容丢失修复 — Band 级窗口化 + 程序化字段映射
|
||||
|
||||
**问题**:`generate_skeleton` 生成 34k 字符骨架 JRXML → `refine_layout` 将完整 34k 发给 LLM → LLM 重新生成简化版(~3k 字符,丢失 91.5%)。`map_fields` 同样存在字段映射时内容丢失问题。
|
||||
|
||||
**根因**:LLM 看到完整 JRXML 时倾向于"重新生成"而非"在原基础上修改坐标/字段名"。提示词调控无法可靠解决。
|
||||
|
||||
**修复方案**(按用户要求 — 程序化节点控制,不靠 LLM 提示词):
|
||||
|
||||
#### `refine_layout`:Band 级窗口化 LLM 精调
|
||||
|
||||
新增 `agent/jrxml_windower.py` — JRXML 拆解/切分/重组引擎:
|
||||
|
||||
| 函数 | 用途 |
|
||||
|------|------|
|
||||
| `decompose_jrxml()` | ET 安全解析 → 分离 header(field 声明/queryString 等,不发给 LLM)+ 所有 band |
|
||||
| `split_band_into_windows()` | 超过 4000 字符的 band 在元素闭合标签处切分为多个窗口 |
|
||||
| `reassemble_band_windows()` | 合并同一 band 的多个窗口结果 |
|
||||
| `reassemble_jrxml()` | header + 所有修改后 band + footer → 完整 JRXML |
|
||||
| `count_elements()` | 正则计数 textField/staticText/field(兼容命名空间前缀) |
|
||||
| `validate_element_count()` | 校验元素数变化,>10% 回退到前一版本 |
|
||||
|
||||
**LLM 每次只看到 ~2-4k 字符片段**,无法"重写整个报表"。header 部分完全不发给 LLM,原样保留。
|
||||
|
||||
#### `map_fields`:完全程序化替换(零 LLM 调用)
|
||||
|
||||
`_programmatic_map_fields()` — 纯正则替换 `$F{field_N}` → OCR 真实字段名,100% 确定性。
|
||||
|
||||
`_sanitize_field_name()` — 非 ASCII 字符(中文/日文)转义为 `_uXXXX_` Unicode 码点格式,确保 JRXML 合法。
|
||||
|
||||
#### 新增测试
|
||||
|
||||
| 文件 | 用例数 | 覆盖 |
|
||||
|------|--------|------|
|
||||
| `tests/test_jrxml_windower.py` | 28 | 拆解/往返重组/窗口切分/元素计数/命名空间/多 section 多 band |
|
||||
| `tests/test_programmatic_map_fields.py` | 20 | 字段声明替换/引用替换/中文转义/坐标保留/部分映射/空字段跳过 |
|
||||
|
||||
完整测试套件(385 项)无回归。
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
"""数据源模式解析模块。
|
||||
|
||||
默认使用 $P{xxx} 参数模式;用户可选择 JDBC 直连模式。
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
from typing import Optional
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from agent.state import AgentState
|
||||
|
||||
load_dotenv()
|
||||
|
||||
|
||||
def resolve_datasource_mode(state: AgentState) -> str:
|
||||
"""返回数据源模式: "parameter" 或 "jdbc"。
|
||||
|
||||
优先读取 state 中已设定的模式,否则根据用户输入检测。
|
||||
"""
|
||||
existing = state.get("datasource_mode", "")
|
||||
if existing in ("parameter", "jdbc"):
|
||||
return existing
|
||||
|
||||
user_input = state.get("user_input", "")
|
||||
if _detect_jdbc_intent(user_input):
|
||||
return "jdbc"
|
||||
return "parameter"
|
||||
|
||||
|
||||
def _detect_jdbc_intent(user_input: str) -> bool:
|
||||
"""检测用户是否想要 JDBC 直连数据库模式。"""
|
||||
patterns = [
|
||||
r"(直连|直连数据库|数据库直连)",
|
||||
r"(从|在)(数据库|DB|MySQL|PostgreSQL|Oracle|SQL Server)\w*",
|
||||
r"(jdbc|JDBC)",
|
||||
r"(连接|连)(数据库|DB)",
|
||||
r"(查询|select|SELECT)\s",
|
||||
]
|
||||
for pat in patterns:
|
||||
if re.search(pat, user_input):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _sanitize_url(url: str) -> str:
|
||||
"""剥离 JDBC URL 中的 user:password@ 片段,防止泄露到 LLM prompt。"""
|
||||
return re.sub(r"://[^@]*@", "://***:***@", url)
|
||||
|
||||
|
||||
def build_datasource_context(mode: str, kb_fields: list, db_config: Optional[dict] = None) -> str:
|
||||
"""构建数据源上下文字符串,注入生成 prompt。"""
|
||||
if mode == "jdbc":
|
||||
if not db_config or not db_config.get("url"):
|
||||
return (
|
||||
"[数据源模式: JDBC]\n"
|
||||
"⚠ 用户想要 JDBC 直连模式,但尚未配置数据库连接信息。\n"
|
||||
"请先生成带 $P{xxx} 参数占位符的 JRXML,并提醒用户配置 JDBC 连接。"
|
||||
)
|
||||
safe_url = _sanitize_url(db_config.get("url", ""))
|
||||
return (
|
||||
"[数据源模式: JDBC]\n"
|
||||
f"连接URL: {safe_url}\n"
|
||||
f"驱动: {db_config.get('driver', '')}\n"
|
||||
"请使用 <queryString><![CDATA[...]]></queryString> 中的 SQL 查询。"
|
||||
)
|
||||
|
||||
# parameter mode
|
||||
if kb_fields:
|
||||
field_list = "\n".join(
|
||||
f"| {f['name']} | {f.get('description', '')} | {f.get('type', 'java.lang.String')} |"
|
||||
for f in kb_fields
|
||||
)
|
||||
return (
|
||||
"[数据源模式: 参数]\n"
|
||||
"使用 $P{xxx} 参数模式,以下为可用参数:\n"
|
||||
f"| 参数名 | 含义 | 类型 |\n|---|---|---|\n{field_list}"
|
||||
)
|
||||
return "[数据源模式: 参数]\n使用 $P{xxx} 参数模式生成 JRXML。"
|
||||
|
||||
|
||||
def configure_jdbc(state: AgentState, url: str = "", driver: str = "",
|
||||
username: str = "", password: str = "") -> dict:
|
||||
"""配置 JDBC 连接并返回更新字段。
|
||||
|
||||
注意:db_config 会被存入 AgentState 并持久化到会话文件。
|
||||
生产环境应使用外部密钥管理服务,避免明文存储密码。
|
||||
"""
|
||||
return {
|
||||
"datasource_mode": "jdbc",
|
||||
"db_config": {
|
||||
"url": url,
|
||||
"driver": driver or "com.mysql.cj.jdbc.Driver",
|
||||
"username": username,
|
||||
"password": password,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def ask_db_config(state: AgentState) -> Optional[str]:
|
||||
"""如果用户选了 JDBC 模式但未配置 DB 连接,返回反问消息。"""
|
||||
mode = resolve_datasource_mode(state)
|
||||
if mode == "jdbc":
|
||||
db_config = state.get("db_config", {})
|
||||
if not db_config or not db_config.get("url"):
|
||||
return (
|
||||
"您选择了数据库直连模式,请提供以下信息:\n"
|
||||
"1. JDBC URL(如 jdbc:mysql://localhost:3306/dbname)\n"
|
||||
"2. 数据库用户名\n"
|
||||
"3. 数据库密码\n"
|
||||
"4. 驱动类名(可选,默认 com.mysql.cj.jdbc.Driver)"
|
||||
)
|
||||
return None
|
||||
@@ -0,0 +1,377 @@
|
||||
"""JRXML 窗口化拆解与重组工具。
|
||||
|
||||
用于 3 阶段生成管道的 refine_layout 和 map_fields 节点:
|
||||
- 将大段 JRXML 按 band 拆解为独立窗口
|
||||
- 每个窗口独立发送给 LLM 进行坐标精调
|
||||
- 重组所有窗口 + 校验元素完整性
|
||||
|
||||
调用者: agent/nodes.py (refine_layout, map_fields)
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from dataclasses import dataclass
|
||||
from typing import Optional
|
||||
|
||||
import defusedxml.ElementTree as ET
|
||||
|
||||
from backend.logger import get_logger
|
||||
|
||||
_windower_log = get_logger("jrxml.windower")
|
||||
|
||||
# 需要按 section 拆解的 band 容器标签
|
||||
_SECTION_TAGS = {
|
||||
"title", "pageHeader", "columnHeader", "detail", "columnFooter",
|
||||
"pageFooter", "lastPageFooter", "summary", "noData", "background",
|
||||
}
|
||||
|
||||
# 不发给 LLM 的 header 元素(原样保留)
|
||||
_HEADER_TAGS = {
|
||||
"property", "propertyExpression", "import", "template", "reportFont",
|
||||
"style", "subDataset", "scriptlet", "parameter", "queryString",
|
||||
"field", "sortField", "variable", "filterExpression", "group",
|
||||
}
|
||||
|
||||
|
||||
@dataclass
|
||||
class BandInfo:
|
||||
"""单个 band 的拆解信息。"""
|
||||
section_name: str # 所属 section 名,如 "title", "detail"
|
||||
band_index: int # 在该 section 中的序号(0-based)
|
||||
band_xml: str # 完整 <band ...>...</band> 原始 XML
|
||||
element_count: int # textField + staticText 数量
|
||||
char_length: int # 字符数
|
||||
|
||||
@property
|
||||
def label(self) -> str:
|
||||
"""用于日志和 prompt 的标识。"""
|
||||
if self.band_index > 0:
|
||||
return f"{self.section_name}_band{self.band_index}"
|
||||
return self.section_name
|
||||
|
||||
|
||||
@dataclass
|
||||
class JRXMLParts:
|
||||
"""JRXML 拆解结果。"""
|
||||
declaration: str # <?xml version="1.0"?>(如有)
|
||||
root_open: str # <jasperReport ...>
|
||||
header_xml: str # fields/params/queryString 等(不发给 LLM)
|
||||
bands: list[BandInfo] # 按出现顺序
|
||||
footer: str # </jasperReport>
|
||||
|
||||
@property
|
||||
def band_count(self) -> int:
|
||||
return len(self.bands)
|
||||
|
||||
@property
|
||||
def total_elements(self) -> int:
|
||||
return sum(b.element_count for b in self.bands)
|
||||
|
||||
|
||||
# ── 拆解 ──────────────────────────────────────────────────────────
|
||||
|
||||
def decompose_jrxml(jrxml: str) -> Optional[JRXMLParts]:
|
||||
"""将 JRXML 字符串拆解为 header + bands + footer 三部分。
|
||||
|
||||
使用 defusedxml.ElementTree 进行安全解析。
|
||||
返回 None 表示解析失败。
|
||||
"""
|
||||
try:
|
||||
root = ET.fromstring(jrxml)
|
||||
except ET.ParseError as e:
|
||||
_windower_log.error("JRXML 解析失败: %s", e)
|
||||
return None
|
||||
|
||||
tag = _local_tag(root.tag)
|
||||
if tag != "jasperReport":
|
||||
_windower_log.error("根元素不是 jasperReport: %s", tag)
|
||||
return None
|
||||
|
||||
# 提取 XML 声明
|
||||
declaration = ""
|
||||
if jrxml.strip().startswith("<?xml"):
|
||||
decl_end = jrxml.find("?>")
|
||||
if decl_end != -1:
|
||||
declaration = jrxml[:decl_end + 2]
|
||||
|
||||
# 提取根元素属性来重建 root_open
|
||||
root_open = _build_root_open(jrxml, root)
|
||||
|
||||
# 分离 header 子元素和 section 子元素
|
||||
header_children = []
|
||||
section_children = [] # (section_tag, child_elem)
|
||||
|
||||
for child in root:
|
||||
child_tag = _local_tag(child.tag)
|
||||
if child_tag in _HEADER_TAGS:
|
||||
header_children.append(child)
|
||||
elif child_tag in _SECTION_TAGS:
|
||||
section_children.append((child_tag, child))
|
||||
|
||||
# 构建 header_xml:序列化所有 header 子元素
|
||||
header_parts = []
|
||||
for child in header_children:
|
||||
header_parts.append(_elem_to_string(child))
|
||||
header_xml = "\n".join(header_parts)
|
||||
|
||||
# 提取 bands:每个 section 内可能有多个 <band>
|
||||
bands = []
|
||||
for sec_tag, sec_elem in section_children:
|
||||
for bi, band_elem in enumerate(sec_elem):
|
||||
band_local = _local_tag(band_elem.tag)
|
||||
if band_local != "band":
|
||||
continue
|
||||
band_xml = _elem_to_string(band_elem)
|
||||
ec = _count_elements_in_text(band_xml)
|
||||
bands.append(BandInfo(
|
||||
section_name=sec_tag,
|
||||
band_index=bi,
|
||||
band_xml=band_xml,
|
||||
element_count=ec,
|
||||
char_length=len(band_xml),
|
||||
))
|
||||
|
||||
# 提取 footer:</jasperReport> 闭合标签
|
||||
footer = _extract_footer(jrxml)
|
||||
|
||||
parts = JRXMLParts(
|
||||
declaration=declaration,
|
||||
root_open=root_open,
|
||||
header_xml=header_xml,
|
||||
bands=bands,
|
||||
footer=footer,
|
||||
)
|
||||
_windower_log.info(
|
||||
"JRXML 拆解完成: %d bands, %d 个元素, header %d 字符",
|
||||
len(bands), parts.total_elements, len(header_xml),
|
||||
)
|
||||
return parts
|
||||
|
||||
|
||||
# ── 窗口切分 ──────────────────────────────────────────────────────
|
||||
|
||||
# 安全的元素边界:在这些闭合标签后切分
|
||||
_SAFE_SPLIT_CLOSING = re.compile(
|
||||
r"</(?:[\w:]+:)?(?:textField|staticText|line|rectangle|ellipse|image|"
|
||||
r"frame|subreport|elementGroup|break|componentElement)>\s*"
|
||||
)
|
||||
|
||||
|
||||
def split_band_into_windows(band: BandInfo, max_chars: int = 4000) -> list[str]:
|
||||
"""将一个 band 的 XML 在元素边界处切分为多个窗口。
|
||||
|
||||
每个窗口是合法的 XML 片段(完整的 <band>...</band>),
|
||||
大小不超过 max_chars。
|
||||
"""
|
||||
if band.char_length <= max_chars:
|
||||
return [band.band_xml]
|
||||
|
||||
inner = _extract_band_inner(band.band_xml)
|
||||
if not inner:
|
||||
return [band.band_xml]
|
||||
|
||||
segments = _split_at_boundaries(inner, _SAFE_SPLIT_CLOSING)
|
||||
if len(segments) <= 1:
|
||||
return [band.band_xml]
|
||||
|
||||
windows = _greedy_aggregate(segments, band.band_xml, max_chars)
|
||||
return windows
|
||||
|
||||
|
||||
# ── 重组 ──────────────────────────────────────────────────────────
|
||||
|
||||
def reassemble_band_windows(modified_windows: list[str]) -> str:
|
||||
"""将多个窗口的修改结果重新合并为一个 band XML。
|
||||
|
||||
策略:取第一个窗口的开头(band 标签)和最后一个窗口的结尾(/band 标签),
|
||||
中间拼接所有窗口内部的元素内容。
|
||||
"""
|
||||
if len(modified_windows) == 1:
|
||||
return modified_windows[0]
|
||||
|
||||
first = modified_windows[0]
|
||||
band_open_end = first.find(">")
|
||||
if band_open_end == -1:
|
||||
return "\n".join(modified_windows)
|
||||
band_open = first[:band_open_end + 1]
|
||||
|
||||
last = modified_windows[-1]
|
||||
band_close = _extract_band_close(last)
|
||||
|
||||
inner_parts = []
|
||||
for win in modified_windows:
|
||||
inner = _extract_band_inner(win)
|
||||
if inner:
|
||||
inner_parts.append(inner)
|
||||
|
||||
return band_open + "\n" + "\n".join(inner_parts) + "\n" + band_close
|
||||
|
||||
|
||||
def reassemble_jrxml(parts: JRXMLParts, modified_bands: dict[str, str]) -> str:
|
||||
"""将修改后的 bands 与 header/footer 重新组装为完整 JRXML。
|
||||
|
||||
modified_bands 的 key 格式为 "{section_name}_band{index}" 或 "{section_name}"(index=0 时)。
|
||||
"""
|
||||
result = []
|
||||
if parts.declaration:
|
||||
result.append(parts.declaration)
|
||||
result.append(parts.root_open)
|
||||
if parts.header_xml.strip():
|
||||
result.append(parts.header_xml)
|
||||
|
||||
current_section = None
|
||||
for band in parts.bands:
|
||||
if band.section_name != current_section:
|
||||
if current_section is not None:
|
||||
result.append(f"</{current_section}>")
|
||||
current_section = band.section_name
|
||||
result.append(f"<{current_section}>")
|
||||
|
||||
modified = modified_bands.get(band.label, band.band_xml)
|
||||
result.append(modified)
|
||||
|
||||
if current_section is not None:
|
||||
result.append(f"</{current_section}>")
|
||||
|
||||
result.append(parts.footer)
|
||||
return "\n".join(result)
|
||||
|
||||
|
||||
# ── 元素计数与校验 ────────────────────────────────────────────────
|
||||
|
||||
_ELEMENT_RE = re.compile(r"<(?:[\w:]+:)?(textField|staticText|field)\b", re.IGNORECASE)
|
||||
|
||||
|
||||
def count_elements(jrxml: str) -> int:
|
||||
"""正则计数 JRXML 中的 textField + staticText + field 声明。"""
|
||||
return len(_ELEMENT_RE.findall(jrxml))
|
||||
|
||||
|
||||
def validate_element_count(original: str, modified: str, stage: str) -> dict:
|
||||
"""校验修改前后的元素数变化。
|
||||
|
||||
返回:
|
||||
{"ok": bool, "original": int, "modified": int, "change_pct": float}
|
||||
变化 > 10% 时 ok=False,调用方应回退。
|
||||
"""
|
||||
orig = count_elements(original)
|
||||
mod = count_elements(modified)
|
||||
if orig == 0:
|
||||
return {"ok": True, "original": 0, "modified": mod, "change_pct": 0}
|
||||
change = abs(mod - orig) / orig
|
||||
ok = change <= 0.10
|
||||
if not ok:
|
||||
_windower_log.error(
|
||||
"%s 元素数变化过大: %d → %d (%.1f%%)",
|
||||
stage, orig, mod, change * 100,
|
||||
)
|
||||
elif change > 0.05:
|
||||
_windower_log.warning(
|
||||
"%s 元素数有差异: %d → %d (%.1f%%)",
|
||||
stage, orig, mod, change * 100,
|
||||
)
|
||||
return {"ok": ok, "original": orig, "modified": mod, "change_pct": round(change, 4)}
|
||||
|
||||
|
||||
# ── 内部工具函数 ──────────────────────────────────────────────────
|
||||
|
||||
def _local_tag(tag: str) -> str:
|
||||
"""去除 XML 命名空间前缀。"""
|
||||
return tag.split("}")[-1] if "}" in tag else tag
|
||||
|
||||
|
||||
def _elem_to_string(elem: ET.Element) -> str:
|
||||
"""将 ElementTree 元素序列化为字符串(使用 defusedxml 的 tostring)。"""
|
||||
raw = ET.tostring(elem, encoding="unicode")
|
||||
return raw.strip()
|
||||
|
||||
|
||||
def _build_root_open(jrxml: str, root: ET.Element) -> str:
|
||||
"""从原始文本重建 <jasperReport ...> 开头标签。"""
|
||||
m = re.search(r"<jasperReport\b[^>]*>", jrxml, re.IGNORECASE)
|
||||
if m:
|
||||
return m.group(0)
|
||||
attrs = []
|
||||
for k, v in root.attrib.items():
|
||||
attrs.append(f'{k}="{v}"')
|
||||
return "<jasperReport " + " ".join(attrs) + ">"
|
||||
|
||||
|
||||
def _extract_footer(jrxml: str) -> str:
|
||||
"""提取 </jasperReport> 闭合标签。"""
|
||||
m = re.search(r"</(?:[\w:]+:)?jasperReport>\s*$", jrxml, re.IGNORECASE)
|
||||
if m:
|
||||
return m.group(0).rstrip()
|
||||
return "</jasperReport>"
|
||||
|
||||
|
||||
_BAND_CLOSE_RE = re.compile(r"</(?:[\w:]+:)?band>\s*$", re.IGNORECASE)
|
||||
|
||||
def _extract_band_close(band_xml: str) -> str:
|
||||
"""提取 band 的闭合标签(兼容命名空间前缀),如 '</ns0:band>' 或 '</band>'。"""
|
||||
m = _BAND_CLOSE_RE.search(band_xml)
|
||||
return m.group(0).rstrip() if m else "</band>"
|
||||
|
||||
def _extract_band_inner(band_xml: str) -> str:
|
||||
"""提取 <band ...> 和 </ns0:band> 之间的内容(兼容命名空间前缀)。"""
|
||||
tag_end = band_xml.find(">")
|
||||
if tag_end == -1:
|
||||
return ""
|
||||
close_m = _BAND_CLOSE_RE.search(band_xml)
|
||||
if not close_m:
|
||||
return band_xml[tag_end + 1:].strip()
|
||||
return band_xml[tag_end + 1:close_m.start()].strip()
|
||||
|
||||
|
||||
def _split_at_boundaries(text: str, boundary_re: re.Pattern) -> list[str]:
|
||||
"""在正则匹配的闭合标签处切分文本。
|
||||
|
||||
返回切分后的片段列表(分隔符附加到前一个片段末尾)。
|
||||
"""
|
||||
segments = []
|
||||
last_end = 0
|
||||
for m in boundary_re.finditer(text):
|
||||
end = m.end()
|
||||
segments.append(text[last_end:end])
|
||||
last_end = end
|
||||
if last_end < len(text):
|
||||
segments.append(text[last_end:])
|
||||
elif not segments:
|
||||
segments.append(text)
|
||||
return segments
|
||||
|
||||
|
||||
def _greedy_aggregate(segments: list[str], band_xml: str, max_chars: int) -> list[str]:
|
||||
"""贪心聚合:将片段组合成不超过 max_chars 的窗口。
|
||||
|
||||
每个窗口包上 <band ...> 和 </band> 标签。
|
||||
"""
|
||||
tag_end = band_xml.find(">")
|
||||
band_open = band_xml[:tag_end + 1] if tag_end != -1 else "<band>"
|
||||
band_close = _extract_band_close(band_xml)
|
||||
overhead = len(band_open) + len(band_close) + 1 # +1 for \n
|
||||
|
||||
windows = []
|
||||
current = []
|
||||
current_len = overhead
|
||||
|
||||
for seg in segments:
|
||||
seg_len = len(seg)
|
||||
if current and current_len + seg_len > max_chars:
|
||||
windows.append(band_open + "\n" + "".join(current) + "\n" + band_close)
|
||||
current = [seg]
|
||||
current_len = overhead + seg_len
|
||||
else:
|
||||
current.append(seg)
|
||||
current_len += seg_len
|
||||
|
||||
if current:
|
||||
windows.append(band_open + "\n" + "".join(current) + "\n" + band_close)
|
||||
|
||||
return windows
|
||||
|
||||
|
||||
def _count_elements_in_text(xml_text: str) -> int:
|
||||
"""统计 XML 文本中的 textField + staticText 数量。"""
|
||||
return len(_ELEMENT_RE.findall(xml_text))
|
||||
+307
-75
@@ -418,7 +418,8 @@ def load_session_node(state: AgentState) -> Dict:
|
||||
state["session_name"] = data.get("session_name", "")
|
||||
state["created_at"] = data.get("created_at", "")
|
||||
except Exception:
|
||||
pass
|
||||
_node_log.warning("会话加载失败,使用空状态",
|
||||
extra={"session_id": state.get("session_id", "")})
|
||||
return state
|
||||
|
||||
|
||||
@@ -454,7 +455,8 @@ def save_session_node(state: AgentState) -> Dict:
|
||||
state["session_name"] = session_name
|
||||
state["updated_at"] = persistable["updated_at"]
|
||||
except Exception:
|
||||
pass
|
||||
_node_log.exception("会话保存失败",
|
||||
extra={"session_id": state.get("session_id", "")})
|
||||
return state
|
||||
|
||||
|
||||
@@ -493,6 +495,90 @@ def _format_row_coordinates(row: dict) -> dict:
|
||||
return {"y_center": row.get("y_center", 0), "columns": cols}
|
||||
|
||||
|
||||
def _build_sampled_text(ocr_rows: list) -> str:
|
||||
"""从 OCR 行数据构建采样坐标 JSON 字符串。"""
|
||||
sampled = {}
|
||||
if isinstance(ocr_rows, list) and len(ocr_rows) >= 1:
|
||||
sampled["header_row"] = _format_row_coordinates(ocr_rows[0])
|
||||
if len(ocr_rows) > 1:
|
||||
sampled["first_data_row"] = _format_row_coordinates(ocr_rows[1])
|
||||
if len(ocr_rows) > 2:
|
||||
sampled["last_row"] = _format_row_coordinates(ocr_rows[-1])
|
||||
return json.dumps(sampled, ensure_ascii=False, indent=2)
|
||||
|
||||
|
||||
def _extract_band_height(band_xml: str) -> int:
|
||||
"""从 <band height="N"> 中提取高度值。"""
|
||||
m = re.search(r'<band\b[^>]*\sheight\s*=\s*"(\d+)"', band_xml)
|
||||
return int(m.group(1)) if m else 0
|
||||
|
||||
|
||||
def _extract_xml_fragment(text: str) -> str:
|
||||
"""从 LLM 响应中提取 XML 片段(去除 markdown 代码块和解释文本)。"""
|
||||
text = text.strip()
|
||||
# 尝试提取 markdown 代码块内的内容
|
||||
m = re.search(r"```(?:xml)?\s*([\s\S]*?)```", text, re.IGNORECASE)
|
||||
if m:
|
||||
content = m.group(1).strip()
|
||||
if content:
|
||||
return content
|
||||
# 尝试找到 <band ...>...</band> 片段
|
||||
m = re.search(r"(<band\b[\s\S]*?</band>)", text, re.IGNORECASE)
|
||||
if m:
|
||||
return m.group(1).strip()
|
||||
return text
|
||||
|
||||
|
||||
def _programmatic_map_fields(jrxml: str, ocr_fields: list[dict]) -> str:
|
||||
"""程序化字段映射:将 $F{{field_N}} 替换为 OCR 提取的真实字段名。
|
||||
|
||||
纯正则替换,不调 LLM。100% 确定性,零内容丢失。
|
||||
"""
|
||||
result = jrxml
|
||||
for i, f in enumerate(ocr_fields):
|
||||
placeholder = f"field_{i+1}"
|
||||
raw_name = f.get("field_name", "")
|
||||
if not raw_name:
|
||||
continue
|
||||
real_name = _sanitize_field_name(raw_name)
|
||||
if real_name == placeholder:
|
||||
continue
|
||||
# 替换 field 声明: <field name="field_1" → <field name="customer_name"
|
||||
result = re.sub(
|
||||
rf'(<field\b[^>]*\bname\s*=\s*"){re.escape(placeholder)}(")',
|
||||
rf'\g<1>{real_name}\g<2>', result,
|
||||
)
|
||||
# 替换所有引用: $F{{field_1}} → $F{{customer_name}}
|
||||
result = result.replace(f'$F{{{placeholder}}}', f'$F{{{real_name}}}')
|
||||
return result
|
||||
|
||||
|
||||
def _sanitize_field_name(name: str) -> str:
|
||||
"""将 OCR 字段名净化为合法的 JRXML field name(仅 ASCII 字母/数字/下划线)。
|
||||
|
||||
非 ASCII 字符会被替换为其 Unicode 码点,确保唯一且合法。
|
||||
"""
|
||||
result = []
|
||||
for ch in name:
|
||||
if ch.isascii() and (ch.isalnum() or ch == '_'):
|
||||
result.append(ch)
|
||||
elif ch.isascii():
|
||||
result.append('_')
|
||||
else:
|
||||
# 非 ASCII 转 _uXXXX_ 格式,保留可追溯性
|
||||
cp = ord(ch)
|
||||
result.append(f'_u{cp:04X}_')
|
||||
cleaned = ''.join(result)
|
||||
cleaned = cleaned.strip('_')
|
||||
if not cleaned:
|
||||
return "unnamed_field"
|
||||
if cleaned[0].isdigit():
|
||||
cleaned = 'f_' + cleaned
|
||||
# 压缩连续下划线
|
||||
cleaned = re.sub(r'_{2,}', '_', cleaned)
|
||||
return cleaned.lower()
|
||||
|
||||
|
||||
def _format_ocr_context(state: AgentState) -> str:
|
||||
"""将 OCR 提取结果格式化为 LLM 可用的上下文文本。"""
|
||||
ocr_result = state.get("ocr_extraction_result")
|
||||
@@ -619,27 +705,116 @@ def _log_ocr_layers(state: AgentState) -> None:
|
||||
|
||||
@log_node("retrieve")
|
||||
def retrieve(state: AgentState) -> Dict:
|
||||
"""在 ChromaDB + 错误知识库中搜索相关的 JRXML 模板和组件。"""
|
||||
"""在 ChromaDB + 错误知识库中搜索相关的 JRXML 模板和组件。
|
||||
支持按 KB 隔离搜索 + 模板意图检测。
|
||||
"""
|
||||
try:
|
||||
from backend.rag_adapter import search_chunks
|
||||
from backend.error_kb import search_error_cases
|
||||
|
||||
user_input = state.get("user_input", "")
|
||||
context = search_chunks(user_input, k=5)
|
||||
kb_id = state.get("kb_id", "")
|
||||
context = search_chunks(user_input, k=5, kb_id=kb_id)
|
||||
|
||||
# 如果有最近错误,同时搜索错误知识库
|
||||
# 错误知识库
|
||||
error_msg = state.get("error_msg", "")
|
||||
if error_msg:
|
||||
error_context = search_error_cases(error_msg, k=2)
|
||||
if error_context:
|
||||
context = f"{context}\n\n[历史错误修正案例]\n{error_context}"
|
||||
|
||||
# 模板意图检测:用户是否提到了模板名?
|
||||
template_keywords = _detect_template_intent(user_input)
|
||||
if template_keywords and kb_id:
|
||||
try:
|
||||
from backend.kb_searcher import search_templates_in_kb
|
||||
templates = search_templates_in_kb(kb_id, template_keywords, k=1)
|
||||
if templates:
|
||||
tmpl = templates[0]
|
||||
state["kb_template_jrxml"] = tmpl.get("content", "")
|
||||
state["kb_template_name"] = (
|
||||
tmpl.get("metadata", {}).get("report_name", "")
|
||||
)
|
||||
context += (
|
||||
f"\n\n[匹配到模板: {state['kb_template_name']}]\n"
|
||||
f"{state['kb_template_jrxml']}"
|
||||
)
|
||||
except Exception:
|
||||
_node_log.warning("模板检索失败", extra={"kb_id": kb_id})
|
||||
|
||||
state["retrieved_context"] = context
|
||||
except Exception:
|
||||
_node_log.exception("RAG 检索失败", extra={"user_input": user_input[:80]})
|
||||
state["retrieved_context"] = ""
|
||||
return state
|
||||
|
||||
|
||||
def _detect_template_intent(user_input: str) -> str:
|
||||
"""检测用户输入中是否包含模板引用意图,返回提取的搜索关键词。"""
|
||||
import re
|
||||
patterns = [
|
||||
r"根据(.+?)模板",
|
||||
r"基于(.+?)模板",
|
||||
r"参照(.+?)模板",
|
||||
r"用(.+?)模板",
|
||||
r"使用(.+?)模板",
|
||||
r"(.+单)模板",
|
||||
]
|
||||
for pat in patterns:
|
||||
m = re.search(pat, user_input)
|
||||
if m:
|
||||
kw = m.group(1).strip()
|
||||
if len(kw) >= 2:
|
||||
return kw
|
||||
return ""
|
||||
|
||||
|
||||
def _build_template_context(state: dict) -> str:
|
||||
"""构建模板上下文,用于注入生成 prompt。
|
||||
优先级:对话上传 > KB 检索 > KB 字段定义。
|
||||
"""
|
||||
parts = []
|
||||
|
||||
# 对话中上传的 JRXML 模板
|
||||
uploaded = state.get("uploaded_template_jrxml", "")
|
||||
if uploaded:
|
||||
params = state.get("uploaded_template_params", [])
|
||||
param_str = "\n".join(
|
||||
f" - {p['name']} ({p.get('type', 'String')})" for p in params
|
||||
) if params else "(参数列表未解析)"
|
||||
parts.append(
|
||||
"[对话上传的模板]\n"
|
||||
f"以下为用户上传的 JRXML 模板,请基于此模板进行修改:\n"
|
||||
f"模板参数:\n{param_str}\n"
|
||||
f"```xml\n{uploaded}\n```"
|
||||
)
|
||||
|
||||
# KB 检索到的模板
|
||||
kb_tmpl = state.get("kb_template_jrxml", "")
|
||||
kb_name = state.get("kb_template_name", "")
|
||||
if kb_tmpl and not uploaded:
|
||||
parts.append(
|
||||
f"[知识库模板: {kb_name}]\n"
|
||||
f"以下为从知识库检索到的 JRXML 模板,请作为结构参考:\n"
|
||||
f"```xml\n{kb_tmpl}\n```"
|
||||
)
|
||||
|
||||
# KB 字段定义
|
||||
kb_fields = state.get("kb_fields", [])
|
||||
if kb_fields:
|
||||
field_table = "\n".join(
|
||||
f"| {f['name']} | {f.get('description', '')} | {f.get('type', 'String')} |"
|
||||
for f in kb_fields
|
||||
)
|
||||
parts.append(
|
||||
"[可用数据字段]\n"
|
||||
"生成 JRXML 时请使用以下字段作为 $P{{xxx}} 参数:\n"
|
||||
f"| 字段名 | 含义 | 类型 |\n|---|---|---|\n{field_table}"
|
||||
)
|
||||
|
||||
return "\n\n".join(parts)
|
||||
|
||||
|
||||
@log_node("generate")
|
||||
def generate(state: AgentState) -> Dict:
|
||||
"""根据用户需求和检索到的上下文生成初始 JRXML。"""
|
||||
@@ -656,6 +831,7 @@ def generate(state: AgentState) -> Dict:
|
||||
prompt = load_prompt("initial_generation").format(
|
||||
context=state.get("retrieved_context", ""),
|
||||
user_request=user_request,
|
||||
template_context=_build_template_context(state),
|
||||
)
|
||||
full = []
|
||||
for chunk in llm.stream(prompt):
|
||||
@@ -683,6 +859,7 @@ def generate_skeleton(state: AgentState) -> Dict:
|
||||
layout_schema=schema_text,
|
||||
context=state.get("retrieved_context", ""),
|
||||
user_request=user_request,
|
||||
template_context=_build_template_context(state),
|
||||
)
|
||||
prev_jrxml = state.get("current_jrxml", "")
|
||||
full_text = _generate_with_continuation(llm, prompt, writer, "generate_skeleton")
|
||||
@@ -700,92 +877,145 @@ def generate_skeleton(state: AgentState) -> Dict:
|
||||
|
||||
@log_node("refine_layout")
|
||||
def refine_layout(state: AgentState) -> Dict:
|
||||
"""阶段二:使用采样坐标(表头 + 首行数据 + 最后一行)精确调整元素位置。"""
|
||||
"""阶段二:Band 级窗口化精调 — 拆解骨架 JRXML 为独立 band,逐窗口 LLM 调整坐标。
|
||||
|
||||
流程:
|
||||
1. decompose_jrxml() 拆解为 header + bands + footer
|
||||
2. 每个 band 作为一个(或多个,若 >4000 字符)窗口发给 LLM
|
||||
3. LLM 只修改该窗口内 reportElement 的 x/y/width/height
|
||||
4. reassemble_jrxml() 重组 + validate_element_count() 校验
|
||||
"""
|
||||
from langgraph.config import get_stream_writer
|
||||
from agent.jrxml_windower import (
|
||||
decompose_jrxml, split_band_into_windows, reassemble_band_windows,
|
||||
reassemble_jrxml, validate_element_count,
|
||||
)
|
||||
|
||||
writer = get_stream_writer()
|
||||
llm = get_llm(caller="refine_layout")
|
||||
|
||||
ocr_rows = state.get("ocr_elements", [])
|
||||
sampled = {}
|
||||
if isinstance(ocr_rows, list) and len(ocr_rows) >= 1:
|
||||
sampled["header_row"] = _format_row_coordinates(ocr_rows[0])
|
||||
if len(ocr_rows) > 1:
|
||||
sampled["first_data_row"] = _format_row_coordinates(ocr_rows[1])
|
||||
if len(ocr_rows) > 2:
|
||||
sampled["last_row"] = _format_row_coordinates(ocr_rows[-1])
|
||||
sampled_text = json.dumps(sampled, ensure_ascii=False, indent=2)
|
||||
|
||||
prompt = load_prompt("refine_layout").format(
|
||||
current_jrxml=state.get("current_jrxml", ""),
|
||||
sampled_coordinates=sampled_text,
|
||||
)
|
||||
prev_jrxml = state.get("current_jrxml", "")
|
||||
full_text = _generate_with_continuation(llm, prompt, writer, "refine_layout")
|
||||
if not full_text.strip():
|
||||
_node_log.error("refine_layout LLM 返回空响应,保留前一版本")
|
||||
if not prev_jrxml.strip():
|
||||
_node_log.warning("refine_layout 无输入 JRXML,跳过")
|
||||
return state
|
||||
jrxml = _extract_jrxml(full_text)
|
||||
if len(jrxml.strip()) < 200:
|
||||
_node_log.warning(f"refine_layout 输出过短({len(jrxml)} 字符),回退到前一版本")
|
||||
jrxml = prev_jrxml
|
||||
state["current_jrxml"] = jrxml
|
||||
state["conversation_history"].append({"role": "assistant", "content": jrxml})
|
||||
|
||||
# 拆解 JRXML
|
||||
parts = decompose_jrxml(prev_jrxml)
|
||||
if parts is None or parts.band_count == 0:
|
||||
_node_log.warning("refine_layout 拆解失败或无 band,跳过")
|
||||
return state
|
||||
|
||||
# 构建采样坐标
|
||||
ocr_rows = state.get("ocr_elements", [])
|
||||
sampled_text = _build_sampled_text(ocr_rows)
|
||||
template_ctx = _build_template_context(state)
|
||||
|
||||
# 逐 band 窗口化精调
|
||||
modified_bands: dict[str, str] = {}
|
||||
total_windows = 0
|
||||
for band in parts.bands:
|
||||
if band.element_count == 0:
|
||||
modified_bands[band.label] = band.band_xml
|
||||
continue
|
||||
|
||||
windows = split_band_into_windows(band, max_chars=4000)
|
||||
total_windows += len(windows)
|
||||
band_results: list[str] = []
|
||||
|
||||
for wi, win_xml in enumerate(windows):
|
||||
prompt = load_prompt("refine_layout").format(
|
||||
band_name=band.section_name,
|
||||
band_index=band.band_index,
|
||||
band_height=_extract_band_height(win_xml),
|
||||
window_index=wi + 1,
|
||||
total_windows=len(windows),
|
||||
xml_fragment=win_xml,
|
||||
sampled_coordinates=sampled_text,
|
||||
template_context=template_ctx,
|
||||
)
|
||||
try:
|
||||
response = llm.invoke(prompt)
|
||||
content = response.content if hasattr(response, "content") else str(response)
|
||||
fragment = _extract_xml_fragment(content)
|
||||
if fragment:
|
||||
band_results.append(fragment)
|
||||
writer({"type": "stream", "node": "refine_layout",
|
||||
"text": f"[{band.label} 窗口 {wi+1}/{len(windows)} 完成] "})
|
||||
else:
|
||||
_node_log.warning("refine_layout 窗口 %s/%d 返回空,使用原文",
|
||||
band.label, wi + 1)
|
||||
band_results.append(win_xml)
|
||||
except Exception as e:
|
||||
_node_log.warning("refine_layout 窗口 %s/%d LLM 失败: %s,使用原文",
|
||||
band.label, wi + 1, e)
|
||||
band_results.append(win_xml)
|
||||
|
||||
if len(band_results) == 1:
|
||||
modified_bands[band.label] = band_results[0]
|
||||
else:
|
||||
modified_bands[band.label] = reassemble_band_windows(band_results)
|
||||
|
||||
# 重组并校验
|
||||
result = reassemble_jrxml(parts, modified_bands)
|
||||
validation = validate_element_count(prev_jrxml, result, "refine_layout")
|
||||
_node_log.info(
|
||||
"refine_layout 窗口化完成: %d bands, %d 窗口, 元素 %d→%d (%.1f%%)",
|
||||
parts.band_count, total_windows,
|
||||
validation["original"], validation["modified"],
|
||||
validation["change_pct"] * 100,
|
||||
)
|
||||
|
||||
if not validation["ok"]:
|
||||
_node_log.error("refine_layout 元素丢失过多,回退到骨架版本")
|
||||
return state
|
||||
|
||||
state["current_jrxml"] = result
|
||||
state["conversation_history"].append({"role": "assistant", "content": result})
|
||||
return state
|
||||
|
||||
|
||||
@log_node("map_fields")
|
||||
def map_fields(state: AgentState) -> Dict:
|
||||
"""阶段三:将占位字段名替换为 OCR 提取的真实字段名。"""
|
||||
from langgraph.config import get_stream_writer
|
||||
"""阶段三:程序化字段映射 — 用正则将 $F{field_N} 替换为 OCR 字段名,不调 LLM。
|
||||
|
||||
writer = get_stream_writer()
|
||||
llm = get_llm(caller="map_fields")
|
||||
仅当 OCR 字段名包含中文等需要语义解释时才回退到 LLM。
|
||||
"""
|
||||
from agent.jrxml_windower import validate_element_count
|
||||
|
||||
ocr_result = state.get("ocr_extraction_result", {})
|
||||
fields_text = ""
|
||||
if isinstance(ocr_result, dict) and ocr_result.get("fields"):
|
||||
field_descs = []
|
||||
for f in ocr_result["fields"]:
|
||||
fname = f.get("field_name", "")
|
||||
fval = f.get("field_value", "")
|
||||
if fname:
|
||||
field_descs.append(f" - {fname}: {fval}")
|
||||
if field_descs:
|
||||
fields_text = "提取的字段:\n" + "\n".join(field_descs)
|
||||
if not fields_text:
|
||||
elements = ocr_result.get("elements", []) if isinstance(ocr_result, dict) else []
|
||||
if elements:
|
||||
texts = [e.get("text", "") for e in elements if e.get("text")]
|
||||
fields_text = "OCR 文本内容:\n" + "\n".join(f" - {t}" for t in texts[:50])
|
||||
|
||||
prompt = load_prompt("field_mapping").format(
|
||||
current_jrxml=state.get("current_jrxml", ""),
|
||||
ocr_fields=fields_text,
|
||||
)
|
||||
prev_jrxml = state.get("current_jrxml", "")
|
||||
full_text = _generate_with_continuation(llm, prompt, writer, "map_fields")
|
||||
# 空响应重试:有时 LLM 第一轮不输出,换个方式再试一次
|
||||
if not full_text.strip():
|
||||
_node_log.warning("map_fields 第一轮返回空响应,尝试简化 prompt 重试")
|
||||
retry_prompt = (
|
||||
"请将以下 JRXML 中的占位字段名 $F{field_1}, $F{field_2}, ... 替换为 OCR 提取的真实字段名。\n"
|
||||
"规则:根据列顺序映射——$F{field_1} 对应第1列,$F{field_2} 对应第2列,以此类推。\n"
|
||||
"同时更新 <field name=\"...\"> 声明和所有 $F{...} 引用。\n"
|
||||
"只输出完整 JRXML,不要解释。\n\n"
|
||||
f"OCR 字段:\n{fields_text}\n\n"
|
||||
f"JRXML:\n{prev_jrxml}"
|
||||
)
|
||||
full_text = _generate_with_continuation(llm, retry_prompt, writer, "map_fields")
|
||||
if not full_text.strip():
|
||||
_node_log.error("map_fields LLM 重试后仍返回空响应,保留占位字段版本")
|
||||
if not prev_jrxml.strip():
|
||||
_node_log.warning("map_fields 无输入 JRXML,跳过")
|
||||
return state
|
||||
jrxml = _extract_jrxml(full_text)
|
||||
if len(jrxml.strip()) < 200:
|
||||
_node_log.warning(f"map_fields 输出过短({len(jrxml)} 字符),回退到前一版本")
|
||||
jrxml = prev_jrxml
|
||||
state["current_jrxml"] = jrxml
|
||||
state["conversation_history"].append({"role": "assistant", "content": jrxml})
|
||||
|
||||
# 提取 OCR 字段列表
|
||||
ocr_result = state.get("ocr_extraction_result", {})
|
||||
ocr_fields: list[dict] = []
|
||||
if isinstance(ocr_result, dict) and ocr_result.get("fields"):
|
||||
ocr_fields = ocr_result["fields"]
|
||||
|
||||
if not ocr_fields:
|
||||
_node_log.info("map_fields 无 OCR 字段,保留占位字段名")
|
||||
state["conversation_history"].append({"role": "assistant", "content": prev_jrxml})
|
||||
return state
|
||||
|
||||
# 程序化替换(主路径)
|
||||
result = _programmatic_map_fields(prev_jrxml, ocr_fields)
|
||||
|
||||
# 校验
|
||||
validation = validate_element_count(prev_jrxml, result, "map_fields")
|
||||
_node_log.info(
|
||||
"map_fields 程序化完成: %d 个字段, 元素 %d→%d (%.1f%%)",
|
||||
len(ocr_fields),
|
||||
validation["original"], validation["modified"],
|
||||
validation["change_pct"] * 100,
|
||||
)
|
||||
|
||||
if not validation["ok"]:
|
||||
_node_log.error("map_fields 元素丢失过多,回退到前一版本")
|
||||
return state
|
||||
|
||||
state["current_jrxml"] = result
|
||||
state["conversation_history"].append({"role": "assistant", "content": result})
|
||||
return state
|
||||
|
||||
|
||||
@@ -810,6 +1040,7 @@ def modify_jrxml(state: AgentState) -> Dict:
|
||||
conversation_history=conv_text,
|
||||
modification_request=state.get("user_modification_request", ""),
|
||||
ocr_context=_format_ocr_context(state),
|
||||
template_context=_build_template_context(state),
|
||||
)
|
||||
prev_jrxml = state.get("current_jrxml", "")
|
||||
full_text = _generate_with_continuation(llm, prompt, writer, "modify_jrxml")
|
||||
@@ -1181,6 +1412,7 @@ def correct_jrxml(state: AgentState) -> Dict:
|
||||
ocr_context=ocr_context,
|
||||
layout_schema_text=layout_text,
|
||||
fidelity_context=fidelity_text,
|
||||
template_context=_build_template_context(state),
|
||||
)
|
||||
# 保存修正前状态(供 validate 判断是否写入错误知识库)
|
||||
state["last_error_case"] = {
|
||||
|
||||
@@ -51,3 +51,14 @@ class AgentState(TypedDict, total=False):
|
||||
# 需求9:分层精确生成
|
||||
layout_schema: dict # extract_layout_schema() 输出,列+区域结构
|
||||
ocr_elements: list # OCR 原始行数据(用于阶段二坐标采样)
|
||||
|
||||
# 需求10:多租户知识库
|
||||
kb_id: str # 当前会话绑定的知识库 ID
|
||||
kb_fields: list # KB 提取的字段定义 [{name, description, type, required}]
|
||||
kb_field_mapping: dict # OCR 字段 → KB 字段映射 {"工单号": "billNo", ...}
|
||||
uploaded_template_jrxml: str # 对话中上传的 JRXML 模板原文
|
||||
uploaded_template_params: list # 解析出的参数 [{name, type}]
|
||||
kb_template_jrxml: str # 从 KB 检索到的模板 JRXML
|
||||
kb_template_name: str # 检索到的模板名称
|
||||
datasource_mode: str # "parameter" 或 "jdbc"
|
||||
db_config: dict # JDBC 连接配置
|
||||
|
||||
+292
-8
@@ -30,7 +30,7 @@ from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
from dotenv import load_dotenv
|
||||
from fastapi import FastAPI, HTTPException, UploadFile, File
|
||||
from fastapi import FastAPI, HTTPException, UploadFile, File, Form, BackgroundTasks
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.responses import StreamingResponse, FileResponse
|
||||
|
||||
@@ -50,6 +50,13 @@ from backend.session import (
|
||||
)
|
||||
from backend.file_parser import parse_file
|
||||
from backend.layout_analyzer import analyze_layout, extract_layout_schema
|
||||
from backend.kb_manager import (
|
||||
create_user, list_users, get_user, delete_user,
|
||||
create_kb, list_kbs, get_kb, update_kb_meta, delete_kb,
|
||||
get_kb_raw_dir,
|
||||
)
|
||||
from backend.kb_parser import parse_jrxml_fields, build_kb_from_files
|
||||
from backend.kb_searcher import search_kb, search_templates_in_kb
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# 常量(从 app.py 迁移)
|
||||
@@ -97,6 +104,7 @@ SKIP_NODES = {"load_session", "process_input", "manage_context",
|
||||
|
||||
_api_log = get_logger("api")
|
||||
UPLOADS_DIR = Path(os.getenv("UPLOADS_DIR", "./uploads"))
|
||||
MAX_UPLOAD_SIZE = 50 * 1024 * 1024 # 50 MB
|
||||
|
||||
def _check_session_id(session_id: str) -> None:
|
||||
"""校验 session_id 合法性(防路径穿越),非法时抛出 HTTPException(400)。"""
|
||||
@@ -380,6 +388,218 @@ async def remove_session(session_id: str):
|
||||
return {"status": "deleted", "session_id": session_id}
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# 用户管理
|
||||
# ─────────────────────────────────────────────
|
||||
|
||||
@app.post("/api/users")
|
||||
async def create_new_user(payload: dict):
|
||||
name = payload.get("name", "").strip()
|
||||
if not name:
|
||||
raise HTTPException(status_code=400, detail="用户名不能为空")
|
||||
try:
|
||||
user = create_user(name)
|
||||
return user
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@app.get("/api/users")
|
||||
async def list_all_users():
|
||||
return {"users": list_users()}
|
||||
|
||||
|
||||
@app.get("/api/users/{user_id}")
|
||||
async def get_user_info(user_id: str):
|
||||
user = get_user(user_id)
|
||||
if user is None:
|
||||
raise HTTPException(status_code=404, detail="用户不存在")
|
||||
return user
|
||||
|
||||
|
||||
@app.delete("/api/users/{user_id}")
|
||||
async def remove_user(user_id: str):
|
||||
ok = delete_user(user_id)
|
||||
if not ok:
|
||||
raise HTTPException(status_code=404, detail="用户不存在")
|
||||
return {"status": "deleted", "user_id": user_id}
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# 知识库 CRUD
|
||||
# ─────────────────────────────────────────────
|
||||
|
||||
@app.get("/api/users/{user_id}/kbs")
|
||||
async def list_user_kbs(user_id: str):
|
||||
return {"kbs": list_kbs(user_id)}
|
||||
|
||||
|
||||
@app.post("/api/users/{user_id}/kbs")
|
||||
async def create_user_kb(user_id: str, payload: dict):
|
||||
name = payload.get("name", "").strip()
|
||||
description = payload.get("description", "")
|
||||
if not name:
|
||||
raise HTTPException(status_code=400, detail="知识库名称不能为空")
|
||||
try:
|
||||
kb = create_kb(user_id, name, description)
|
||||
return kb
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@app.get("/api/kbs/{kb_id}")
|
||||
async def get_kb_info(kb_id: str):
|
||||
kb = get_kb(kb_id)
|
||||
if kb is None:
|
||||
raise HTTPException(status_code=404, detail="知识库不存在")
|
||||
return kb
|
||||
|
||||
|
||||
@app.delete("/api/kbs/{kb_id}")
|
||||
async def remove_kb(kb_id: str):
|
||||
ok = delete_kb(kb_id)
|
||||
if not ok:
|
||||
raise HTTPException(status_code=404, detail="知识库不存在")
|
||||
return {"status": "deleted", "kb_id": kb_id}
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# 知识库文件上传
|
||||
# ─────────────────────────────────────────────
|
||||
|
||||
@app.post("/api/kbs/{kb_id}/upload")
|
||||
async def upload_to_kb(kb_id: str, file: UploadFile = File(...)):
|
||||
kb = get_kb(kb_id)
|
||||
if kb is None:
|
||||
raise HTTPException(status_code=404, detail="知识库不存在")
|
||||
|
||||
raw_dir = get_kb_raw_dir(kb_id)
|
||||
if raw_dir is None:
|
||||
raise HTTPException(status_code=500, detail="知识库存储目录不可用")
|
||||
|
||||
raw_dir.mkdir(parents=True, exist_ok=True)
|
||||
safe_name = Path(file.filename or "upload").name
|
||||
dest = raw_dir / safe_name
|
||||
|
||||
content = await file.read()
|
||||
if len(content) > MAX_UPLOAD_SIZE:
|
||||
raise HTTPException(status_code=413, detail="文件大小超过 50MB 上限")
|
||||
|
||||
dest.write_bytes(content)
|
||||
|
||||
from backend.kb_parser import process_file_for_kb
|
||||
result = process_file_for_kb(kb_id, str(dest), source_name=safe_name)
|
||||
|
||||
_api_log.info("KB文件上传", extra={
|
||||
"kb_id": kb_id, "file": safe_name, "type": result.get("type"),
|
||||
})
|
||||
|
||||
return {
|
||||
"filename": safe_name,
|
||||
"type": result.get("type", ""),
|
||||
"error": result.get("error"),
|
||||
}
|
||||
|
||||
|
||||
@app.post("/api/kbs/{kb_id}/build")
|
||||
async def build_kb(kb_id: str):
|
||||
"""构建知识库:对已上传的文件执行 chunk → embed 管线。"""
|
||||
from backend.kb_parser import build_kb_from_files as build_fn
|
||||
raw_dir = get_kb_raw_dir(kb_id)
|
||||
if raw_dir is None or not raw_dir.exists():
|
||||
raise HTTPException(status_code=404, detail="知识库无已上传文件")
|
||||
|
||||
files = [str(p) for p in raw_dir.iterdir() if p.is_file()]
|
||||
if not files:
|
||||
raise HTTPException(status_code=400, detail="知识库无文件,请先上传")
|
||||
|
||||
result = build_fn(kb_id, files)
|
||||
return result
|
||||
|
||||
|
||||
@app.get("/api/kbs/{kb_id}/status")
|
||||
async def kb_status(kb_id: str):
|
||||
kb = get_kb(kb_id)
|
||||
if kb is None:
|
||||
raise HTTPException(status_code=404, detail="知识库不存在")
|
||||
return {
|
||||
"kb_id": kb_id,
|
||||
"name": kb.get("name", ""),
|
||||
"field_count": len(kb.get("fields", [])),
|
||||
"template_count": len(kb.get("templates", [])),
|
||||
"file_count": kb.get("file_count", 0),
|
||||
"chunk_count": kb.get("chunk_count", 0),
|
||||
"parse_status": kb.get("parse_status", "empty"),
|
||||
"created_at": kb.get("created_at", ""),
|
||||
}
|
||||
|
||||
|
||||
@app.get("/api/kbs/{kb_id}/fields")
|
||||
async def kb_fields(kb_id: str):
|
||||
kb = get_kb(kb_id)
|
||||
if kb is None:
|
||||
raise HTTPException(status_code=404, detail="知识库不存在")
|
||||
return {"fields": kb.get("fields", []), "templates": kb.get("templates", [])}
|
||||
|
||||
|
||||
@app.get("/api/kbs/{kb_id}/search")
|
||||
async def kb_search(kb_id: str, q: str = "", type: str = ""):
|
||||
if not q:
|
||||
raise HTTPException(status_code=400, detail="查询参数 q 不能为空")
|
||||
if type == "template":
|
||||
results = search_templates_in_kb(kb_id, q, k=5)
|
||||
else:
|
||||
ctx = search_kb(kb_id, q, k=5)
|
||||
return {"query": q, "context": ctx}
|
||||
return {"query": q, "results": results}
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# 会话-知识库绑定
|
||||
# ─────────────────────────────────────────────
|
||||
|
||||
@app.put("/api/sessions/{session_id}/kb")
|
||||
async def bind_session_kb(session_id: str, payload: dict):
|
||||
_check_session_id(session_id)
|
||||
kb_id = payload.get("kb_id", "").strip()
|
||||
data = load_session(session_id)
|
||||
if data is None:
|
||||
raise HTTPException(status_code=404, detail="会话不存在")
|
||||
|
||||
agent_state = data.get("agent_state", {})
|
||||
if kb_id:
|
||||
kb = get_kb(kb_id)
|
||||
if kb is None:
|
||||
raise HTTPException(status_code=404, detail="知识库不存在")
|
||||
agent_state["kb_id"] = kb_id
|
||||
agent_state["kb_fields"] = kb.get("fields", [])
|
||||
else:
|
||||
agent_state.pop("kb_id", None)
|
||||
agent_state.pop("kb_fields", None)
|
||||
|
||||
save_session(session_id, agent_state)
|
||||
return {"session_id": session_id, "kb_id": kb_id or None}
|
||||
|
||||
|
||||
@app.get("/api/sessions/{session_id}/kb")
|
||||
async def get_session_kb(session_id: str):
|
||||
_check_session_id(session_id)
|
||||
data = load_session(session_id)
|
||||
if data is None:
|
||||
raise HTTPException(status_code=404, detail="会话不存在")
|
||||
agent_state = data.get("agent_state", {})
|
||||
kb_id = agent_state.get("kb_id", "")
|
||||
result = {"kb_id": kb_id, "kb_fields": agent_state.get("kb_fields", [])}
|
||||
if kb_id:
|
||||
kb = get_kb(kb_id)
|
||||
if kb:
|
||||
result["kb_name"] = kb.get("name", "")
|
||||
result["templates"] = kb.get("templates", [])
|
||||
return result
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# 文件上传
|
||||
# ─────────────────────────────────────────────
|
||||
@@ -396,6 +616,9 @@ async def upload_file(file: UploadFile = File(...), session_id: str = ""):
|
||||
dest = _ensure_upload_dir(session_id) / f"{file_id}_{safe_name}"
|
||||
|
||||
content = await file.read()
|
||||
if len(content) > MAX_UPLOAD_SIZE:
|
||||
raise HTTPException(status_code=413, detail="文件大小超过 50MB 上限")
|
||||
|
||||
dest.write_bytes(content)
|
||||
|
||||
content_type = file.content_type or mimetypes.guess_type(safe_name)[0] or "application/octet-stream"
|
||||
@@ -423,20 +646,47 @@ async def upload_file(file: UploadFile = File(...), session_id: str = ""):
|
||||
# 文件处理辅助
|
||||
# ─────────────────────────────────────────────
|
||||
|
||||
def _process_files(file_ids: list[str], session_id: str) -> dict:
|
||||
"""处理上传的文件:解析 → 布局分析 → 提取 schema 文本。
|
||||
def _parse_jrxml_file(file_path: str) -> dict:
|
||||
"""解析上传的 JRXML 文件,提取模板参数和字段。
|
||||
|
||||
Returns:
|
||||
{full_prompt_prefix, uploaded_paths, layout_schema, ocr_text}
|
||||
{jrxml_text, parameters: [{name, type}], fields: [{name, type}],
|
||||
query: str, report_name: str, page_width: str, page_height: str}
|
||||
"""
|
||||
jrxml_info = parse_jrxml_fields(file_path)
|
||||
try:
|
||||
raw_xml = Path(file_path).read_text(encoding="utf-8")
|
||||
except Exception:
|
||||
raw_xml = ""
|
||||
return {
|
||||
"jrxml_text": raw_xml,
|
||||
"parameters": jrxml_info.get("parameters", []),
|
||||
"fields": jrxml_info.get("fields", []),
|
||||
"query": jrxml_info.get("query", ""),
|
||||
"report_name": jrxml_info.get("report_name", ""),
|
||||
"page_width": jrxml_info.get("page_width", ""),
|
||||
"page_height": jrxml_info.get("page_height", ""),
|
||||
"error": jrxml_info.get("error"),
|
||||
}
|
||||
|
||||
|
||||
def _process_files(file_ids: list[str], session_id: str) -> dict:
|
||||
"""处理上传的文件:解析 → 布局分析 → 提取 schema 文本。
|
||||
JRXML 文件额外解析为模板上下文注入 agent_state。
|
||||
|
||||
Returns:
|
||||
{full_prompt_prefix, uploaded_paths, layout_schema, ocr_text,
|
||||
jrxml_template: dict | None}
|
||||
"""
|
||||
if not file_ids:
|
||||
return {"full_prompt_prefix": "", "uploaded_paths": [],
|
||||
"layout_schema": {}, "ocr_text": ""}
|
||||
"layout_schema": {}, "ocr_text": "", "jrxml_template": None}
|
||||
|
||||
parts = []
|
||||
uploaded_paths = []
|
||||
layout_schema = {}
|
||||
ocr_text = ""
|
||||
jrxml_template = None
|
||||
|
||||
for fid in file_ids:
|
||||
info = _file_registry.get(fid)
|
||||
@@ -446,8 +696,33 @@ def _process_files(file_ids: list[str], session_id: str) -> dict:
|
||||
|
||||
file_path = info["path"]
|
||||
uploaded_paths.append(file_path)
|
||||
suffix = Path(info["filename"]).suffix.lower()
|
||||
|
||||
parsed = parse_file(file_path, Path(info["filename"]).suffix)
|
||||
# JRXML 文件 → 解析为模板
|
||||
if suffix == ".jrxml":
|
||||
jrxml_template = _parse_jrxml_file(file_path)
|
||||
if jrxml_template.get("error"):
|
||||
parts.append(f"[JRXML 模板: {info['filename']}]\n解析失败: {jrxml_template['error']}")
|
||||
else:
|
||||
params = jrxml_template["parameters"]
|
||||
fields = jrxml_template["fields"]
|
||||
param_desc = "\n".join(
|
||||
f" - {p['name']} ({p.get('type', 'String')})" for p in params
|
||||
) if params else " (无参数)"
|
||||
field_desc = "\n".join(
|
||||
f" - {f['name']} ({f.get('type', 'String')})" for f in fields
|
||||
) if fields else " (无字段)"
|
||||
parts.append(
|
||||
f"[上传的 JRXML 模板: {jrxml_template['report_name'] or info['filename']}]\n"
|
||||
f"页面尺寸: {jrxml_template['page_width']}x{jrxml_template['page_height']}\n"
|
||||
f"参数列表:\n{param_desc}\n"
|
||||
f"字段列表:\n{field_desc}\n"
|
||||
f"SQL查询: {jrxml_template['query'] or '(无)'}\n"
|
||||
f"--- XML 内容 ---\n{jrxml_template['jrxml_text']}"
|
||||
)
|
||||
continue
|
||||
|
||||
parsed = parse_file(file_path, suffix)
|
||||
if parsed.get("error"):
|
||||
parts.append(f"[文件: {info['filename']}]\n解析失败: {parsed['error']}")
|
||||
continue
|
||||
@@ -490,6 +765,7 @@ def _process_files(file_ids: list[str], session_id: str) -> dict:
|
||||
"uploaded_paths": uploaded_paths,
|
||||
"layout_schema": layout_schema,
|
||||
"ocr_text": ocr_text,
|
||||
"jrxml_template": jrxml_template,
|
||||
}
|
||||
|
||||
|
||||
@@ -543,6 +819,12 @@ async def chat(session_id: str, payload: dict):
|
||||
if file_result.get("uploaded_paths"):
|
||||
agent_state["uploaded_file_path"] = file_result["uploaded_paths"][0]
|
||||
|
||||
# ── 注入 JRXML 模板(对话中上传的模板)──
|
||||
jrxml_tmpl = file_result.get("jrxml_template")
|
||||
if jrxml_tmpl and not jrxml_tmpl.get("error"):
|
||||
agent_state["uploaded_template_jrxml"] = jrxml_tmpl["jrxml_text"]
|
||||
agent_state["uploaded_template_params"] = jrxml_tmpl["parameters"]
|
||||
|
||||
# ── 设置本轮输入 ──
|
||||
if agent_state.get("current_jrxml"):
|
||||
agent_state["user_modification_request"] = full_prompt
|
||||
@@ -591,7 +873,7 @@ async def chat(session_id: str, payload: dict):
|
||||
# ─────────────────────────────────────────────
|
||||
|
||||
@app.get("/api/sessions/{session_id}/download/latest")
|
||||
async def download_latest(session_id: str):
|
||||
async def download_latest(session_id: str, background_tasks: BackgroundTasks):
|
||||
"""下载最新 JRXML 文件。"""
|
||||
_check_session_id(session_id)
|
||||
data = load_session(session_id)
|
||||
@@ -607,6 +889,7 @@ async def download_latest(session_id: str):
|
||||
encoding="utf-8")
|
||||
tmp.write(jrxml)
|
||||
tmp.close()
|
||||
background_tasks.add_task(os.unlink, tmp.name)
|
||||
|
||||
return FileResponse(
|
||||
tmp.name,
|
||||
@@ -616,7 +899,7 @@ async def download_latest(session_id: str):
|
||||
|
||||
|
||||
@app.get("/api/sessions/{session_id}/download/{version}")
|
||||
async def download_version(session_id: str, version: int):
|
||||
async def download_version(session_id: str, version: int, background_tasks: BackgroundTasks):
|
||||
"""下载指定版本的 JRXML 文件。"""
|
||||
_check_session_id(session_id)
|
||||
data = load_session(session_id)
|
||||
@@ -635,6 +918,7 @@ async def download_version(session_id: str, version: int):
|
||||
encoding="utf-8")
|
||||
tmp.write(jrxml)
|
||||
tmp.close()
|
||||
background_tasks.add_task(os.unlink, tmp.name)
|
||||
|
||||
return FileResponse(
|
||||
tmp.name,
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
"""OCR 字段 → KB 字段匹配模块。
|
||||
|
||||
两阶段匹配:
|
||||
1. Embedding 粗筛(相似度 top-3)
|
||||
2. LLM 精确确认
|
||||
|
||||
返回映射: {"工单号": "billNo", "客户名称": "customerName", ...}
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
from typing import Optional
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from backend.logger import get_logger
|
||||
|
||||
load_dotenv()
|
||||
|
||||
_match_log = get_logger("field_matcher")
|
||||
|
||||
|
||||
def _embed(text: str) -> list:
|
||||
"""获取文本的向量嵌入。"""
|
||||
from backend.rag_adapter import _get_searcher
|
||||
searcher = _get_searcher()
|
||||
if searcher._model is None:
|
||||
_ = searcher.model
|
||||
emb = searcher.model.encode(text, normalize_embeddings=True, show_progress_bar=False)
|
||||
return emb.tolist()
|
||||
|
||||
|
||||
def _cosine_similarity(a: list, b: list) -> float:
|
||||
"""余弦相似度(假设向量已归一化,点积即相似度)。"""
|
||||
return sum(x * y for x, y in zip(a, b))
|
||||
|
||||
|
||||
def match_ocr_to_kb(ocr_fields: list[str], kb_fields: list[dict],
|
||||
llm=None) -> dict[str, str]:
|
||||
"""将 OCR 提取的字段名匹配到 KB 字段定义。
|
||||
|
||||
Args:
|
||||
ocr_fields: OCR 提取的中文字段名列表
|
||||
kb_fields: KB 字段定义 [{"name": "billNo", "description": "工单号", ...}]
|
||||
llm: 可选的 LLM 实例,用于精确确认
|
||||
|
||||
Returns:
|
||||
{"工单号": "billNo", "客户": "customerName", ...}
|
||||
"""
|
||||
if not ocr_fields or not kb_fields:
|
||||
return {}
|
||||
|
||||
result = {}
|
||||
|
||||
# 阶段 1: Embedding 粗筛
|
||||
try:
|
||||
ocr_embs = {f: _embed(f) for f in ocr_fields}
|
||||
kb_embs = {f["name"]: _embed(f.get("description", f["name"])) for f in kb_fields}
|
||||
except Exception as e:
|
||||
_match_log.warning("Embedding 匹配失败,回退到 LLM: %s", e)
|
||||
return _match_via_llm(ocr_fields, kb_fields, llm)
|
||||
|
||||
candidates = {}
|
||||
for ocr_name, ocr_emb in ocr_embs.items():
|
||||
scored = []
|
||||
for kb_name, kb_emb in kb_embs.items():
|
||||
sim = _cosine_similarity(ocr_emb, kb_emb)
|
||||
scored.append((kb_name, sim))
|
||||
scored.sort(key=lambda x: x[1], reverse=True)
|
||||
candidates[ocr_name] = scored[:3]
|
||||
|
||||
# 阶段 2: LLM 精确确认
|
||||
if llm:
|
||||
confirmed = _match_via_llm(ocr_fields, kb_fields, llm, candidates)
|
||||
result.update(confirmed)
|
||||
else:
|
||||
for ocr_name, cands in candidates.items():
|
||||
if cands and cands[0][1] > 0.5:
|
||||
result[ocr_name] = cands[0][0]
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def _match_via_llm(ocr_fields: list[str], kb_fields: list[dict],
|
||||
llm, candidates: Optional[dict] = None) -> dict[str, str]:
|
||||
"""使用 LLM 精确确认字段映射。"""
|
||||
kb_desc = "\n".join(
|
||||
f"- {f['name']}: {f.get('description', '')} ({f.get('type', 'java.lang.String')})"
|
||||
for f in kb_fields
|
||||
)
|
||||
|
||||
candidates_hint = ""
|
||||
if candidates:
|
||||
cand_lines = []
|
||||
for ocr_name, cands in candidates.items():
|
||||
cand_str = ", ".join(f"{n}({s:.2f})" for n, s in cands)
|
||||
cand_lines.append(f" {ocr_name} -> 候选: {cand_str}")
|
||||
candidates_hint = (
|
||||
"向量相似度候选(仅供参考,请根据语义确认):\n"
|
||||
+ "\n".join(cand_lines)
|
||||
)
|
||||
|
||||
prompt = (
|
||||
"请将以下 OCR 识别的字段名匹配到知识库定义的字段。\n\n"
|
||||
f"OCR 字段: {json.dumps(ocr_fields, ensure_ascii=False)}\n\n"
|
||||
f"知识库字段:\n{kb_desc}\n\n"
|
||||
f"{candidates_hint}\n\n"
|
||||
"请以 JSON 对象格式输出映射关系,键为 OCR 字段名,值为 KB 字段名:\n"
|
||||
'{"工单号": "billNo", "客户名称": "customerName"}'
|
||||
)
|
||||
|
||||
try:
|
||||
response = llm.invoke(prompt)
|
||||
content = response.content if hasattr(response, "content") else str(response)
|
||||
start = content.find("{")
|
||||
end = content.rfind("}") + 1
|
||||
if start >= 0 and end > start:
|
||||
return json.loads(content[start:end])
|
||||
except Exception as e:
|
||||
_match_log.warning("LLM 字段匹配失败: %s", e)
|
||||
|
||||
return {}
|
||||
|
||||
|
||||
def format_field_mapping_context(mapping: dict[str, str]) -> str:
|
||||
"""将字段映射格式化为 prompt 上下文字符串。"""
|
||||
if not mapping:
|
||||
return ""
|
||||
|
||||
lines = ["[字段映射 — OCR -> KB]",
|
||||
"请在 JRXML 中使用以下参数名:",
|
||||
"| OCR 字段 | JRXML 参数 |",
|
||||
"|---|---|"]
|
||||
for ocr_name, kb_name in mapping.items():
|
||||
lines.append(f"| {ocr_name} | $P{{{kb_name}}} |")
|
||||
return "\n".join(lines)
|
||||
@@ -0,0 +1,227 @@
|
||||
"""多租户知识库管理模块。
|
||||
|
||||
用户 + 知识库 CRUD,持久化到 kb_data/ 目录。
|
||||
每个 KB 拥有独立的 JSON 元数据文件和文件存储目录。
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import uuid
|
||||
import tempfile
|
||||
import shutil
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
from dotenv import load_dotenv
|
||||
from backend.logger import get_logger
|
||||
|
||||
load_dotenv()
|
||||
|
||||
_kb_log = get_logger("kb_manager")
|
||||
|
||||
KB_DATA_DIR = Path(os.getenv("KB_DATA_DIR", "./kb_data"))
|
||||
_USERS_FILE = KB_DATA_DIR / "users.json"
|
||||
|
||||
_VALID_ID_RE = re.compile(r'^[a-fA-F0-9]{12,}$')
|
||||
|
||||
|
||||
def _validate_id(id_str: str, label: str = "id") -> None:
|
||||
if not _VALID_ID_RE.match(id_str):
|
||||
raise ValueError(f"Invalid {label}: {id_str!r}")
|
||||
|
||||
|
||||
def _now_iso() -> str:
|
||||
return datetime.now(timezone.utc).isoformat()
|
||||
|
||||
|
||||
def _ensure_dir(path: Path) -> None:
|
||||
path.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
|
||||
def _read_json(fp: Path) -> dict:
|
||||
with open(fp, "r", encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
|
||||
|
||||
def _write_json_atomic(fp: Path, data: dict) -> None:
|
||||
_ensure_dir(fp.parent)
|
||||
tmp = tempfile.NamedTemporaryFile(
|
||||
mode="w", suffix=".json", delete=False,
|
||||
dir=fp.parent, encoding="utf-8",
|
||||
)
|
||||
try:
|
||||
json.dump(data, tmp, ensure_ascii=False, indent=2)
|
||||
tmp.flush()
|
||||
os.fsync(tmp.fileno())
|
||||
tmp.close()
|
||||
os.replace(tmp.name, str(fp))
|
||||
except Exception:
|
||||
tmp.close()
|
||||
Path(tmp.name).unlink(missing_ok=True)
|
||||
raise
|
||||
|
||||
|
||||
# ── User CRUD ──────────────────────────────────────────────────────────────
|
||||
|
||||
def _load_users() -> list[dict]:
|
||||
_ensure_dir(KB_DATA_DIR)
|
||||
if _USERS_FILE.exists():
|
||||
return _read_json(_USERS_FILE)
|
||||
return []
|
||||
|
||||
|
||||
def _save_users(users: list[dict]) -> None:
|
||||
_write_json_atomic(_USERS_FILE, users)
|
||||
|
||||
|
||||
def create_user(name: str, user_id: Optional[str] = None) -> dict:
|
||||
uid = user_id or uuid.uuid4().hex
|
||||
users = _load_users()
|
||||
if any(u["user_id"] == uid for u in users):
|
||||
raise ValueError(f"User {uid} already exists")
|
||||
user = {"user_id": uid, "name": name, "created_at": _now_iso()}
|
||||
users.append(user)
|
||||
_save_users(users)
|
||||
_ensure_dir(KB_DATA_DIR / uid)
|
||||
_write_json_atomic(KB_DATA_DIR / uid / "profile.json", user)
|
||||
_kb_log.info("创建用户", extra={"user_id": uid, "user_name": name})
|
||||
return user
|
||||
|
||||
|
||||
def list_users() -> list[dict]:
|
||||
return _load_users()
|
||||
|
||||
|
||||
def get_user(user_id: str) -> Optional[dict]:
|
||||
_validate_id(user_id, "user_id")
|
||||
for u in _load_users():
|
||||
if u["user_id"] == user_id:
|
||||
return u
|
||||
return None
|
||||
|
||||
|
||||
def delete_user(user_id: str) -> bool:
|
||||
_validate_id(user_id, "user_id")
|
||||
users = _load_users()
|
||||
filtered = [u for u in users if u["user_id"] != user_id]
|
||||
if len(filtered) == len(users):
|
||||
return False
|
||||
_save_users(filtered)
|
||||
user_dir = KB_DATA_DIR / user_id
|
||||
if user_dir.exists():
|
||||
shutil.rmtree(user_dir)
|
||||
_kb_log.info("删除用户", extra={"user_id": user_id})
|
||||
return True
|
||||
|
||||
|
||||
# ── KB CRUD ────────────────────────────────────────────────────────────────
|
||||
|
||||
def _kb_dir(kb_id: str) -> Optional[Path]:
|
||||
_validate_id(kb_id, "kb_id")
|
||||
for user_dir in KB_DATA_DIR.iterdir():
|
||||
if user_dir.is_dir() and not user_dir.name.startswith("."):
|
||||
candidate = user_dir / kb_id
|
||||
if candidate.is_dir():
|
||||
return candidate
|
||||
return None
|
||||
|
||||
|
||||
def _ensure_user_dir(user_id: str) -> Path:
|
||||
_validate_id(user_id, "user_id")
|
||||
d = KB_DATA_DIR / user_id
|
||||
_ensure_dir(d)
|
||||
return d
|
||||
|
||||
|
||||
def create_kb(user_id: str, name: str, description: str = "",
|
||||
kb_id: Optional[str] = None) -> dict:
|
||||
user_dir = _ensure_user_dir(user_id)
|
||||
kid = kb_id or uuid.uuid4().hex
|
||||
kb_dir = user_dir / kid
|
||||
_ensure_dir(kb_dir)
|
||||
_ensure_dir(kb_dir / "raw")
|
||||
|
||||
now = _now_iso()
|
||||
meta = {
|
||||
"kb_id": kid, "user_id": user_id, "name": name,
|
||||
"description": description, "created_at": now, "updated_at": now,
|
||||
"fields": [], "templates": [], "file_count": 0,
|
||||
"chunk_count": 0, "parse_status": "empty",
|
||||
}
|
||||
_write_json_atomic(kb_dir / "meta.json", meta)
|
||||
_kb_log.info("创建知识库", extra={"kb_id": kid, "user_id": user_id, "kb_name": name})
|
||||
return meta
|
||||
|
||||
|
||||
def list_kbs(user_id: str) -> list[dict]:
|
||||
user_dir = _ensure_user_dir(user_id)
|
||||
kbs = []
|
||||
for kb_dir in sorted(user_dir.iterdir(), key=os.path.getmtime, reverse=True):
|
||||
if kb_dir.is_dir() and not kb_dir.name.startswith("."):
|
||||
meta_path = kb_dir / "meta.json"
|
||||
if meta_path.exists():
|
||||
meta = _read_json(meta_path)
|
||||
kbs.append({
|
||||
"kb_id": meta.get("kb_id", kb_dir.name),
|
||||
"name": meta.get("name", kb_dir.name),
|
||||
"description": meta.get("description", ""),
|
||||
"created_at": meta.get("created_at", ""),
|
||||
"updated_at": meta.get("updated_at", ""),
|
||||
"field_count": len(meta.get("fields", [])),
|
||||
"template_count": len(meta.get("templates", [])),
|
||||
"file_count": meta.get("file_count", 0),
|
||||
"chunk_count": meta.get("chunk_count", 0),
|
||||
"parse_status": meta.get("parse_status", "empty"),
|
||||
})
|
||||
return kbs
|
||||
|
||||
|
||||
def get_kb(kb_id: str) -> Optional[dict]:
|
||||
_validate_id(kb_id, "kb_id")
|
||||
kb_dir = _kb_dir(kb_id)
|
||||
if kb_dir is None:
|
||||
return None
|
||||
meta_path = kb_dir / "meta.json"
|
||||
return _read_json(meta_path) if meta_path.exists() else None
|
||||
|
||||
|
||||
def update_kb_meta(kb_id: str, updates: dict) -> Optional[dict]:
|
||||
kb_dir = _kb_dir(kb_id)
|
||||
if kb_dir is None:
|
||||
return None
|
||||
meta_path = kb_dir / "meta.json"
|
||||
meta = _read_json(meta_path)
|
||||
meta.update(updates)
|
||||
meta["updated_at"] = _now_iso()
|
||||
_write_json_atomic(meta_path, meta)
|
||||
return meta
|
||||
|
||||
|
||||
def delete_kb(kb_id: str) -> bool:
|
||||
kb_dir = _kb_dir(kb_id)
|
||||
if kb_dir is None:
|
||||
return False
|
||||
shutil.rmtree(kb_dir)
|
||||
_kb_log.info("删除知识库", extra={"kb_id": kb_id})
|
||||
return True
|
||||
|
||||
|
||||
def get_kb_raw_dir(kb_id: str) -> Optional[Path]:
|
||||
kb_dir = _kb_dir(kb_id)
|
||||
return kb_dir / "raw" if kb_dir else None
|
||||
|
||||
|
||||
def get_kb_chunks_path(kb_id: str) -> Optional[Path]:
|
||||
kb_dir = _kb_dir(kb_id)
|
||||
return kb_dir / "chunks.json" if kb_dir else None
|
||||
|
||||
|
||||
def get_kb_chroma_path(kb_id: str) -> Optional[Path]:
|
||||
kb_dir = _kb_dir(kb_id)
|
||||
if kb_dir is None:
|
||||
return None
|
||||
chroma_dir = kb_dir / "chroma"
|
||||
_ensure_dir(chroma_dir)
|
||||
return chroma_dir
|
||||
@@ -0,0 +1,336 @@
|
||||
"""KB 解析管道 — 文件提取→字段解析→chunk 切割→向量嵌入。
|
||||
|
||||
调用者: api_server.py (upload endpoint), scripts/init_default_kb.py
|
||||
"""
|
||||
|
||||
import os
|
||||
import json
|
||||
import shutil
|
||||
import zipfile
|
||||
import tarfile
|
||||
import tempfile
|
||||
import defusedxml.ElementTree as ET
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
from dotenv import load_dotenv
|
||||
from backend.logger import get_logger
|
||||
from backend.file_parser import parse_file
|
||||
|
||||
load_dotenv()
|
||||
|
||||
_kb_parse_log = get_logger("kb_parser")
|
||||
|
||||
|
||||
def _find_tag(elem, tag):
|
||||
for el in elem.iter():
|
||||
local = el.tag.split("}")[-1] if "}" in el.tag else el.tag
|
||||
if local == tag:
|
||||
return el
|
||||
return None
|
||||
|
||||
|
||||
def _find_all_tags(elem, tag):
|
||||
results = []
|
||||
for el in elem.iter():
|
||||
local = el.tag.split("}")[-1] if "}" in el.tag else el.tag
|
||||
if local == tag:
|
||||
results.append(el)
|
||||
return results
|
||||
|
||||
|
||||
def parse_jrxml_fields(jrxml_path: str) -> dict:
|
||||
"""解析 JRXML 文件,提取参数和字段定义。"""
|
||||
try:
|
||||
tree = ET.parse(jrxml_path)
|
||||
root = tree.getroot()
|
||||
except ET.ParseError as e:
|
||||
return {"error": f"JRXML 解析失败: {e}", "parameters": [], "fields": [],
|
||||
"report_name": ""}
|
||||
|
||||
report_name = root.attrib.get("name", "")
|
||||
page_width = root.attrib.get("pageWidth", "")
|
||||
page_height = root.attrib.get("pageHeight", "")
|
||||
|
||||
parameters = []
|
||||
for p in _find_all_tags(root, "parameter"):
|
||||
params = {"name": p.attrib.get("name", ""),
|
||||
"type": p.attrib.get("class", "java.lang.String"),
|
||||
"description": ""}
|
||||
desc = _find_tag(p, "parameterDescription")
|
||||
if desc is not None and desc.text:
|
||||
params["description"] = desc.text.strip()
|
||||
parameters.append(params)
|
||||
|
||||
fields = []
|
||||
for f in _find_all_tags(root, "field"):
|
||||
fields.append({"name": f.attrib.get("name", ""),
|
||||
"type": f.attrib.get("class", "java.lang.String"),
|
||||
"description": ""})
|
||||
|
||||
query_text = ""
|
||||
query = _find_tag(root, "queryString")
|
||||
if query is not None and query.text:
|
||||
query_text = query.text.strip()
|
||||
|
||||
return {"report_name": report_name, "page_width": page_width,
|
||||
"page_height": page_height, "parameters": parameters,
|
||||
"fields": fields, "query": query_text, "error": None}
|
||||
|
||||
|
||||
def _extract_archive(file_path: str, dest_dir: str) -> list[str]:
|
||||
extracted = []
|
||||
resolved_dest = os.path.realpath(dest_dir)
|
||||
|
||||
if zipfile.is_zipfile(file_path):
|
||||
with zipfile.ZipFile(file_path, "r") as zf:
|
||||
for member in zf.namelist():
|
||||
member_path = os.path.realpath(os.path.join(dest_dir, member))
|
||||
if not member_path.startswith(resolved_dest + os.sep):
|
||||
continue
|
||||
zf.extract(member, dest_dir)
|
||||
if not member.endswith("/"):
|
||||
extracted.append(member_path)
|
||||
elif tarfile.is_tarfile(file_path):
|
||||
with tarfile.open(file_path, "r:*") as tf:
|
||||
for member in tf.getmembers():
|
||||
member_path = os.path.realpath(os.path.join(dest_dir, member.name))
|
||||
if not member_path.startswith(resolved_dest + os.sep):
|
||||
continue
|
||||
tf.extract(member, dest_dir)
|
||||
if not member.name.endswith("/"):
|
||||
extracted.append(member_path)
|
||||
return extracted
|
||||
|
||||
|
||||
def process_file_for_kb(kb_id: str, file_path: str,
|
||||
source_name: str = "") -> dict:
|
||||
from backend.kb_manager import get_kb_raw_dir
|
||||
raw_dir = get_kb_raw_dir(kb_id)
|
||||
if raw_dir is None:
|
||||
return {"error": "KB 不存在"}
|
||||
|
||||
fname = source_name or os.path.basename(file_path)
|
||||
dest = raw_dir / fname
|
||||
shutil.copy2(file_path, dest)
|
||||
|
||||
suffix = Path(fname).suffix.lower()
|
||||
|
||||
if suffix == ".jrxml":
|
||||
jrxml_info = parse_jrxml_fields(file_path)
|
||||
text = f"[JRXML 模板: {jrxml_info['report_name']}]\n"
|
||||
text += f"页面: {jrxml_info['page_width']}x{jrxml_info['page_height']}\n"
|
||||
text += "参数:\n" + "\n".join(
|
||||
f" {p['name']} ({p['type']})" for p in jrxml_info["parameters"])
|
||||
text += "\n字段:\n" + "\n".join(
|
||||
f" {f['name']} ({f['type']})" for f in jrxml_info["fields"])
|
||||
if jrxml_info["query"]:
|
||||
text += f"\n查询:\n{jrxml_info['query']}"
|
||||
try:
|
||||
raw_xml = Path(file_path).read_text(encoding="utf-8")
|
||||
except Exception:
|
||||
raw_xml = ""
|
||||
return {"filename": fname, "type": "jrxml", "text": text,
|
||||
"raw_xml": raw_xml, "jrxml_info": jrxml_info, "error": None}
|
||||
|
||||
if suffix in (".zip", ".tar", ".gz", ".tgz"):
|
||||
tmpdir = tempfile.mkdtemp(prefix="kb_extract_")
|
||||
try:
|
||||
extracted = _extract_archive(file_path, tmpdir)
|
||||
sub_results = []
|
||||
for ep in extracted:
|
||||
sub = process_file_for_kb(
|
||||
kb_id, ep, source_name=os.path.basename(ep))
|
||||
sub_results.append(sub)
|
||||
return {"filename": fname, "type": "archive", "text": "",
|
||||
"archive_contents": sub_results, "error": None}
|
||||
finally:
|
||||
shutil.rmtree(tmpdir, ignore_errors=True)
|
||||
|
||||
parse_result = parse_file(str(dest))
|
||||
return {"filename": fname, "type": suffix.lstrip("."),
|
||||
"text": parse_result.get("text", ""),
|
||||
"error": parse_result.get("error")}
|
||||
|
||||
|
||||
def chunk_file_results(results: list[dict], kb_name: str = "") -> list[dict]:
|
||||
chunks = []
|
||||
chunk_idx = 0
|
||||
|
||||
for r in results:
|
||||
if r.get("type") == "archive":
|
||||
for sub in r.get("archive_contents", []):
|
||||
chunks.extend(chunk_file_results([sub], kb_name))
|
||||
continue
|
||||
|
||||
fname = r.get("filename", "")
|
||||
ftype = r.get("type", "")
|
||||
text = r.get("text", "")
|
||||
if not text.strip():
|
||||
continue
|
||||
|
||||
if ftype == "jrxml" and r.get("raw_xml"):
|
||||
jinfo = r.get("jrxml_info", {})
|
||||
report_name = jinfo.get("report_name", "")
|
||||
chunks.append({
|
||||
"id": f"chunk_{chunk_idx}",
|
||||
"content": f"[JRXML 模板: {report_name}]\n{r['text']}\n\n"
|
||||
f"<xml>\n{r['raw_xml']}\n</xml>",
|
||||
"metadata": {"chunk_type": "jrxml_template",
|
||||
"source_file": fname,
|
||||
"report_name": report_name,
|
||||
"kb_name": kb_name,
|
||||
"param_count": len(jinfo.get("parameters", [])),
|
||||
"field_count": len(jinfo.get("fields", []))},
|
||||
})
|
||||
chunk_idx += 1
|
||||
continue
|
||||
|
||||
paragraphs = [p.strip() for p in text.split("\n\n") if p.strip()]
|
||||
for para in paragraphs:
|
||||
if len(para) < 10:
|
||||
continue
|
||||
chunk_type = "md_section" if ftype in ("md", "") else f"{ftype}_text"
|
||||
chunks.append({
|
||||
"id": f"chunk_{chunk_idx}",
|
||||
"content": para,
|
||||
"metadata": {"chunk_type": chunk_type,
|
||||
"source_file": fname, "kb_name": kb_name},
|
||||
})
|
||||
chunk_idx += 1
|
||||
return chunks
|
||||
|
||||
|
||||
def extract_fields_with_llm(text: str, llm=None) -> list[dict]:
|
||||
if llm is None:
|
||||
return _extract_fields_from_table(text)
|
||||
prompt = (
|
||||
"请分析以下接口文档内容,提取所有字段定义。\n"
|
||||
"对每个字段,输出: 字段名, 含义, 类型, 是否必需。\n"
|
||||
"以 JSON 数组格式输出,每个元素为 {\"name\": \"...\", "
|
||||
"\"description\": \"...\", \"type\": \"...\", \"required\": false}。\n\n"
|
||||
f"{text}"
|
||||
)
|
||||
try:
|
||||
response = llm.invoke(prompt)
|
||||
content = response.content if hasattr(response, "content") else str(response)
|
||||
start = content.find("[")
|
||||
end = content.rfind("]") + 1
|
||||
if start >= 0 and end > start:
|
||||
return json.loads(content[start:end])
|
||||
except Exception as e:
|
||||
_kb_parse_log.warning("LLM 字段提取失败,使用表格回退: %s", e)
|
||||
return _extract_fields_from_table(text)
|
||||
|
||||
|
||||
def _extract_fields_from_table(text: str) -> list[dict]:
|
||||
fields = []
|
||||
lines = text.split("\n")
|
||||
header_found = False
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if not line.startswith("|"):
|
||||
continue
|
||||
cells = [c.strip() for c in line.split("|")[1:-1]]
|
||||
if not cells:
|
||||
continue
|
||||
if not header_found:
|
||||
if any(h in str(c) for c in cells
|
||||
for h in ["字段", "名称", "含义", "说明", "类型"]):
|
||||
header_found = True
|
||||
continue
|
||||
if all(c.replace("-", "").replace(":", "").replace(" ", "") == ""
|
||||
for c in cells):
|
||||
continue
|
||||
if len(cells) >= 2:
|
||||
name = cells[0].replace("**", "").replace("L ", "").replace("\\", "").strip()
|
||||
if not name or name in ("", "---"):
|
||||
continue
|
||||
field = {"name": name, "description": "", "type": "java.lang.String",
|
||||
"required": False}
|
||||
if len(cells) >= 2 and cells[1]:
|
||||
field["description"] = cells[1].replace("<br/>", " ").strip()
|
||||
if len(cells) >= 3 and cells[2]:
|
||||
field["required"] = cells[2].strip() in ("是", "Y", "y", "yes", "Yes", "必填")
|
||||
if len(cells) >= 4 and cells[3]:
|
||||
field["type"] = cells[3].strip()
|
||||
fields.append(field)
|
||||
return fields
|
||||
|
||||
|
||||
def build_kb_from_files(kb_id: str, file_paths: list[str],
|
||||
llm=None) -> dict:
|
||||
from backend.kb_manager import update_kb_meta, get_kb_chunks_path
|
||||
from backend.kb_searcher import get_kb_searcher
|
||||
|
||||
all_results = []
|
||||
errors = []
|
||||
for fp in file_paths:
|
||||
try:
|
||||
r = process_file_for_kb(kb_id, fp)
|
||||
all_results.append(r)
|
||||
if r.get("error"):
|
||||
errors.append({"file": os.path.basename(fp), "error": r["error"]})
|
||||
except Exception as e:
|
||||
errors.append({"file": os.path.basename(fp), "error": str(e)})
|
||||
|
||||
chunks = chunk_file_results(all_results)
|
||||
|
||||
chunks_path = get_kb_chunks_path(kb_id)
|
||||
if chunks_path:
|
||||
chunks_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
with open(chunks_path, "w", encoding="utf-8") as f:
|
||||
json.dump(chunks, f, ensure_ascii=False, indent=2)
|
||||
|
||||
searcher = get_kb_searcher(kb_id)
|
||||
if searcher and chunks:
|
||||
try:
|
||||
searcher.add_chunks(chunks)
|
||||
except Exception as e:
|
||||
errors.append({"file": "embedding", "error": str(e)})
|
||||
|
||||
all_fields = []
|
||||
template_names = []
|
||||
for r in all_results:
|
||||
_collect_from_result(r, all_fields, template_names)
|
||||
|
||||
for r in all_results:
|
||||
if r.get("type") in ("archive", "jrxml"):
|
||||
continue
|
||||
text = r.get("text", "")
|
||||
if text.strip():
|
||||
for ef in extract_fields_with_llm(text, llm):
|
||||
if not any(f["name"] == ef["name"] for f in all_fields):
|
||||
all_fields.append(ef)
|
||||
|
||||
update_kb_meta(kb_id, {
|
||||
"fields": all_fields, "templates": template_names,
|
||||
"file_count": len(file_paths), "chunk_count": len(chunks),
|
||||
"parse_status": "ready" if not errors else "partial",
|
||||
})
|
||||
|
||||
_kb_parse_log.info("KB 构建完成", extra={
|
||||
"kb_id": kb_id, "fields": len(all_fields),
|
||||
"templates": len(template_names), "chunks": len(chunks),
|
||||
})
|
||||
|
||||
return {"status": "ready" if not errors else "partial",
|
||||
"field_count": len(all_fields), "chunk_count": len(chunks),
|
||||
"template_count": len(template_names), "errors": errors}
|
||||
|
||||
|
||||
def _collect_from_result(r: dict, all_fields: list, template_names: list) -> None:
|
||||
jinfo = r.get("jrxml_info")
|
||||
if jinfo and jinfo.get("report_name"):
|
||||
template_names.append({"name": jinfo["report_name"],
|
||||
"file": r.get("filename", "")})
|
||||
for p in jinfo.get("parameters", []):
|
||||
field = {"name": p["name"], "description": p.get("description", ""),
|
||||
"type": p.get("type", "java.lang.String"), "required": False}
|
||||
if not any(f["name"] == field["name"] for f in all_fields):
|
||||
all_fields.append(field)
|
||||
for f in jinfo.get("fields", []):
|
||||
field = {"name": f["name"], "description": f.get("description", ""),
|
||||
"type": f.get("type", "java.lang.String"), "required": False}
|
||||
if not any(fi["name"] == field["name"] for fi in all_fields):
|
||||
all_fields.append(field)
|
||||
@@ -0,0 +1,170 @@
|
||||
"""KB 隔离的 ChromaDB 语义搜索适配器。
|
||||
|
||||
每个知识库拥有独立的 ChromaDB collection。
|
||||
调用者: backend/rag_adapter.py, agent/nodes.py, api_server.py
|
||||
"""
|
||||
|
||||
import os
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_PROJECT_ROOT = Path(__file__).resolve().parent.parent
|
||||
|
||||
|
||||
def _resolve(path: str) -> Path:
|
||||
p = Path(path)
|
||||
return p if p.is_absolute() else _PROJECT_ROOT / p
|
||||
|
||||
|
||||
class KBChromaSearcher:
|
||||
"""连接指定 KB 的 ChromaDB,提供语义搜索。"""
|
||||
|
||||
def __init__(self, chroma_path: str, collection_name: str = "kb_chunks",
|
||||
model_name: Optional[str] = None, use_gpu: Optional[bool] = None,
|
||||
use_fp16: Optional[bool] = None):
|
||||
self.chroma_path = str(_resolve(chroma_path))
|
||||
self.collection_name = collection_name
|
||||
model_path = model_name or os.getenv(
|
||||
"RAG_EMBED_MODEL", "./rag/models/paraphrase-multilingual-MiniLM-L12-v2")
|
||||
resolved = _resolve(model_path)
|
||||
self.model_name = str(resolved) if resolved.exists() else model_path
|
||||
self.use_gpu = (use_gpu if use_gpu is not None
|
||||
else os.getenv("RAG_USE_GPU", "true").lower() in ("true", "1"))
|
||||
self.use_fp16 = (use_fp16 if use_fp16 is not None
|
||||
else os.getenv("RAG_USE_FP16", "true").lower() in ("true", "1"))
|
||||
self._model = None
|
||||
self._client = None
|
||||
self._collection = None
|
||||
|
||||
@property
|
||||
def model(self):
|
||||
if self._model is None:
|
||||
import torch
|
||||
from sentence_transformers import SentenceTransformer
|
||||
device = "cuda" if (self.use_gpu and torch.cuda.is_available()) else "cpu"
|
||||
logger.info("加载嵌入模型: %s (device=%s)", self.model_name, device)
|
||||
model = SentenceTransformer(self.model_name, device=device)
|
||||
if device == "cuda" and self.use_fp16:
|
||||
model = model.half()
|
||||
self._model = model
|
||||
return self._model
|
||||
|
||||
@property
|
||||
def client(self):
|
||||
if self._client is None:
|
||||
import chromadb
|
||||
self._client = chromadb.PersistentClient(path=self.chroma_path)
|
||||
return self._client
|
||||
|
||||
@property
|
||||
def collection(self):
|
||||
if self._collection is None:
|
||||
try:
|
||||
self._collection = self.client.get_collection(self.collection_name)
|
||||
except Exception:
|
||||
self._collection = self.client.create_collection(
|
||||
self.collection_name, metadata={"hnsw:space": "cosine"})
|
||||
return self._collection
|
||||
|
||||
def is_ready(self) -> bool:
|
||||
try:
|
||||
self.client.get_collection(self.collection_name)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def search(self, query: str, k: int = 5, threshold: Optional[float] = None) -> list[dict]:
|
||||
if not self.is_ready():
|
||||
return []
|
||||
query_embedding = self.model.encode(
|
||||
query, normalize_embeddings=True, show_progress_bar=False)
|
||||
results = self.collection.query(
|
||||
query_embeddings=[query_embedding.tolist()],
|
||||
n_results=k, include=["documents", "metadatas", "distances"])
|
||||
output = []
|
||||
if not results["ids"] or not results["ids"][0]:
|
||||
return output
|
||||
for i, doc_id in enumerate(results["ids"][0]):
|
||||
dist = results["distances"][0][i]
|
||||
if threshold is not None and dist > threshold:
|
||||
continue
|
||||
output.append({
|
||||
"id": doc_id,
|
||||
"content": results["documents"][0][i],
|
||||
"metadata": results["metadatas"][0][i] or {},
|
||||
"distance": dist,
|
||||
})
|
||||
return output
|
||||
|
||||
def search_templates(self, query: str, k: int = 3) -> list[dict]:
|
||||
results = self.search(query, k=k * 2)
|
||||
templates = []
|
||||
for r in results:
|
||||
meta = r.get("metadata", {})
|
||||
chunk_type = meta.get("chunk_type", "")
|
||||
if "jrxml" in chunk_type.lower() or meta.get("report_name"):
|
||||
templates.append(r)
|
||||
if len(templates) >= k:
|
||||
break
|
||||
return templates
|
||||
|
||||
def search_as_context(self, query: str, k: int = 5) -> str:
|
||||
results = self.search(query, k=k)
|
||||
if not results:
|
||||
return ""
|
||||
parts = []
|
||||
for r in results:
|
||||
meta = r.get("metadata", {})
|
||||
header = f"[类型:{meta.get('chunk_type', 'N/A')}]"
|
||||
if meta.get("report_name"):
|
||||
header += f" [报表:{meta['report_name']}]"
|
||||
parts.append(f"{header}\n{r['content']}")
|
||||
return "\n\n---\n\n".join(parts)
|
||||
|
||||
def add_chunks(self, chunks: list[dict]) -> None:
|
||||
if not chunks:
|
||||
return
|
||||
ids = [c["id"] for c in chunks]
|
||||
docs = [c["content"] for c in chunks]
|
||||
metas = [c.get("metadata", {}) for c in chunks]
|
||||
embeddings = self.model.encode(
|
||||
docs, normalize_embeddings=True, show_progress_bar=True)
|
||||
self.collection.upsert(
|
||||
ids=ids, documents=docs, metadatas=metas,
|
||||
embeddings=embeddings.tolist())
|
||||
|
||||
|
||||
_searchers: dict = {}
|
||||
|
||||
|
||||
def get_kb_searcher(kb_id: str) -> Optional[KBChromaSearcher]:
|
||||
from backend.kb_manager import get_kb_chroma_path
|
||||
if kb_id in _searchers:
|
||||
return _searchers[kb_id]
|
||||
chroma_path = get_kb_chroma_path(kb_id)
|
||||
if chroma_path is None:
|
||||
return None
|
||||
searcher = KBChromaSearcher(str(chroma_path))
|
||||
_searchers[kb_id] = searcher
|
||||
return searcher
|
||||
|
||||
|
||||
def search_kb(kb_id: str, query: str, k: int = 5) -> str:
|
||||
searcher = get_kb_searcher(kb_id)
|
||||
if searcher is None:
|
||||
return ""
|
||||
return searcher.search_as_context(query, k=k)
|
||||
|
||||
|
||||
def search_templates_in_kb(kb_id: str, query: str, k: int = 3) -> list[dict]:
|
||||
searcher = get_kb_searcher(kb_id)
|
||||
if searcher is None:
|
||||
return []
|
||||
return searcher.search_templates(query, k=k)
|
||||
@@ -150,6 +150,12 @@ def _get_searcher() -> RAGSearcher:
|
||||
return _searcher
|
||||
|
||||
|
||||
def search_chunks(query: str, k: int = 5) -> str:
|
||||
"""搜索 JRXML 知识库并返回拼接后的上下文文本(便捷函数)。"""
|
||||
def search_chunks(query: str, k: int = 5, kb_id: str = "") -> str:
|
||||
"""搜索知识库并返回拼接后的上下文文本。
|
||||
|
||||
若指定 kb_id,使用该 KB 专属 ChromaDB;否则使用全局默认库。
|
||||
"""
|
||||
if kb_id:
|
||||
from backend.kb_searcher import search_kb
|
||||
return search_kb(kb_id, query, k=k)
|
||||
return _get_searcher().search_as_context(query, k=k)
|
||||
|
||||
@@ -56,6 +56,7 @@ def create_session(name: str = "", agent_state: Optional[dict] = None,
|
||||
"session_name": name or f"新建报表 {now[:10]}",
|
||||
"created_at": now,
|
||||
"updated_at": now,
|
||||
"kb_id": agent_state.get("kb_id", "") if agent_state else "",
|
||||
"agent_state": agent_state,
|
||||
}
|
||||
with open(_session_path(sid), "w", encoding="utf-8") as f:
|
||||
|
||||
+50
-3
@@ -1,5 +1,52 @@
|
||||
# Vue 3 + TypeScript + Vite
|
||||
# JRXML Agent 前端
|
||||
|
||||
This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
|
||||
Vue 3 + TypeScript + Vite + Pinia — JRXML 报表生成代理的 Web UI。
|
||||
|
||||
Learn more about the recommended Project Setup and IDE Support in the [Vue Docs TypeScript Guide](https://vuejs.org/guide/typescript/overview.html#project-setup).
|
||||
## 技术栈
|
||||
|
||||
- **Vue 3** (Composition API + `<script setup>`)
|
||||
- **TypeScript** 6.x
|
||||
- **Vite** 8.x
|
||||
- **Pinia** 3.x (状态管理)
|
||||
- **SSE** (Server-Sent Events) 流式响应
|
||||
|
||||
## 组件结构
|
||||
|
||||
```
|
||||
src/
|
||||
├── api/client.ts SSE 客户端 + fetch 封装
|
||||
├── stores/
|
||||
│ ├── chat.ts Pinia: 消息/流式/节点进度/文件
|
||||
│ ├── session.ts Pinia: 会话 CRUD
|
||||
│ └── kb.ts Pinia: 多租户知识库管理
|
||||
├── components/
|
||||
│ ├── Sidebar.vue 会话列表 + 下载 + 历史版本
|
||||
│ ├── ChatMessages.vue 消息列表渲染
|
||||
│ ├── ProcessSection.vue 处理过程折叠区
|
||||
│ ├── UnifiedInput.vue 统一输入框(文本+文件拖拽/粘贴)
|
||||
│ ├── SummaryCard.vue 结果摘要卡片
|
||||
│ ├── KbSelector.vue KB 下拉选择器
|
||||
│ └── KbManager.vue KB 管理面板(创建/上传/构建/删除)
|
||||
└── utils/format.ts 工具函数
|
||||
```
|
||||
|
||||
## 开发
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run dev # 启动开发服务器 (localhost:5173)
|
||||
npm run build # 生产构建
|
||||
npx playwright test # E2E 测试
|
||||
```
|
||||
|
||||
## SSE 事件流
|
||||
|
||||
前端通过 `api.chat()` 发起 POST 请求,后端返回 `text/event-stream`:
|
||||
|
||||
| 事件 | 说明 |
|
||||
|------|------|
|
||||
| `node_start` | 节点开始执行(含 node/label/step_index) |
|
||||
| `node_complete` | 节点执行完成(含 detail) |
|
||||
| `stream_token` | LLM 逐字输出 |
|
||||
| `agent_complete` | 全图执行完成(含 intent/status/jrxml_length/error 等) |
|
||||
| `agent_error` | 执行异常 |
|
||||
|
||||
@@ -8,9 +8,19 @@ import ChatMessages from './components/ChatMessages.vue'
|
||||
import ProcessSection from './components/ProcessSection.vue'
|
||||
import SummaryCard from './components/SummaryCard.vue'
|
||||
import UnifiedInput from './components/UnifiedInput.vue'
|
||||
import KbSelector from './components/KbSelector.vue'
|
||||
import KbManager from './components/KbManager.vue'
|
||||
import { useKbStore } from './stores/kb'
|
||||
|
||||
const chat = useChatStore()
|
||||
const session = useSessionStore()
|
||||
const kb = useKbStore()
|
||||
|
||||
function handleKbChange(kbId: string) {
|
||||
if (session.currentId) {
|
||||
kb.bindKbToSession(session.currentId, kbId)
|
||||
}
|
||||
}
|
||||
|
||||
const chatContainer = ref<HTMLElement | null>(null)
|
||||
|
||||
@@ -128,6 +138,7 @@ async function handleSend(text: string, files: File[]) {
|
||||
<Sidebar @quickAction="(text) => handleSend(text, [])" />
|
||||
|
||||
<main class="main-area">
|
||||
<KbSelector @change="handleKbChange" />
|
||||
<div class="chat-container" ref="chatContainer">
|
||||
<ChatMessages />
|
||||
<ProcessSection />
|
||||
@@ -139,6 +150,8 @@ async function handleSend(text: string, files: File[]) {
|
||||
@send="handleSend"
|
||||
/>
|
||||
</main>
|
||||
|
||||
<KbManager />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useKbStore } from '../stores/kb'
|
||||
|
||||
const kb = useKbStore()
|
||||
|
||||
const newKbName = ref('')
|
||||
const newKbDesc = ref('')
|
||||
const creating = ref(false)
|
||||
const uploading = ref<string | null>(null)
|
||||
const building = ref<string | null>(null)
|
||||
const fileInput = ref<HTMLInputElement | null>(null)
|
||||
|
||||
onMounted(() => { kb.init() })
|
||||
|
||||
async function handleCreate() {
|
||||
if (!newKbName.value.trim()) return
|
||||
creating.value = true
|
||||
await kb.createKb(newKbName.value.trim(), newKbDesc.value.trim())
|
||||
newKbName.value = ''
|
||||
newKbDesc.value = ''
|
||||
creating.value = false
|
||||
}
|
||||
|
||||
async function handleDelete(kbId: string) {
|
||||
if (confirm('确定删除此知识库?所有文件和数据将被永久删除。')) {
|
||||
await kb.deleteKb(kbId)
|
||||
}
|
||||
}
|
||||
|
||||
function triggerUpload(kbId: string) {
|
||||
uploading.value = kbId
|
||||
fileInput.value?.click()
|
||||
}
|
||||
|
||||
async function handleFileSelect(e: Event, kbId: string) {
|
||||
const input = e.target as HTMLInputElement
|
||||
if (input.files && input.files.length > 0) {
|
||||
for (const f of input.files) {
|
||||
await kb.uploadFileToKb(kbId, f)
|
||||
}
|
||||
await kb.buildKb(kbId)
|
||||
await kb.refreshKbs()
|
||||
}
|
||||
input.value = ''
|
||||
uploading.value = null
|
||||
}
|
||||
|
||||
async function handleBuild(kbId: string) {
|
||||
building.value = kbId
|
||||
await kb.buildKb(kbId)
|
||||
building.value = null
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Teleport to="body">
|
||||
<div v-if="kb.showManager" class="kb-manager-overlay" @click.self="kb.showManager = false">
|
||||
<div class="kb-manager">
|
||||
<h3>知识库管理</h3>
|
||||
|
||||
<div class="create-form">
|
||||
<input v-model="newKbName" class="kb-input" placeholder="知识库名称" :disabled="creating" />
|
||||
<input v-model="newKbDesc" class="kb-input" placeholder="描述(可选)" :disabled="creating" />
|
||||
<button class="kb-btn primary" :disabled="creating || !newKbName.trim()" @click="handleCreate">
|
||||
{{ creating ? '创建中...' : '创建' }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-if="kb.loading" class="empty">加载中...</div>
|
||||
<div v-else-if="kb.kbs.length === 0" class="empty">暂无知识库</div>
|
||||
|
||||
<div v-for="k in kb.kbs" :key="k.kb_id" class="kb-card">
|
||||
<div class="kb-card-header">
|
||||
<strong>{{ k.name }}</strong>
|
||||
<span class="kb-status" :class="k.parse_status">
|
||||
{{ k.parse_status === 'ready' ? '就绪' : k.parse_status === 'partial' ? '部分' : '空' }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="kb-meta">
|
||||
{{ k.field_count }}字段 · {{ k.template_count }}模板 ·
|
||||
{{ k.file_count }}文件 · {{ k.chunk_count }}块
|
||||
</div>
|
||||
<div class="kb-actions">
|
||||
<button class="kb-btn" @click="triggerUpload(k.kb_id)" :disabled="uploading === k.kb_id">
|
||||
{{ uploading === k.kb_id ? '上传中...' : '上传文件' }}
|
||||
</button>
|
||||
<button class="kb-btn" @click="handleBuild(k.kb_id)" :disabled="building === k.kb_id || k.file_count === 0">
|
||||
{{ building === k.kb_id ? '构建中...' : '构建' }}
|
||||
</button>
|
||||
<button class="kb-btn danger" @click="handleDelete(k.kb_id)">删除</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="kb-btn close-btn" @click="kb.showManager = false">关闭</button>
|
||||
|
||||
<input ref="fileInput" type="file" multiple
|
||||
accept=".jrxml,.md,.xlsx,.xls,.docx,.doc,.pdf,.csv,.txt,.json,.zip,.tar,.gz"
|
||||
style="display:none"
|
||||
@change="(e: Event) => { const kbId = uploading; if (kbId) handleFileSelect(e, kbId); }" />
|
||||
</div>
|
||||
</div>
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.kb-manager-overlay {
|
||||
position: fixed; inset: 0;
|
||||
background: rgba(0,0,0,0.6);
|
||||
z-index: 100;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
}
|
||||
.kb-manager {
|
||||
background: #1e1e2e;
|
||||
border: 1px solid #45475a;
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
width: 540px;
|
||||
max-height: 80vh;
|
||||
overflow-y: auto;
|
||||
color: #cdd6f4;
|
||||
}
|
||||
h3 { margin: 0 0 16px; font-size: 18px; }
|
||||
.create-form { display: flex; gap: 8px; margin-bottom: 16px; }
|
||||
.kb-input {
|
||||
flex: 1;
|
||||
background: #181825;
|
||||
border: 1px solid #45475a;
|
||||
border-radius: 6px;
|
||||
color: #cdd6f4;
|
||||
padding: 6px 10px;
|
||||
font-size: 13px;
|
||||
outline: none;
|
||||
}
|
||||
.kb-input:focus { border-color: #cba6f7; }
|
||||
.kb-btn {
|
||||
background: #313244; border: none; border-radius: 6px;
|
||||
color: #cdd6f4; padding: 6px 12px; font-size: 12px;
|
||||
cursor: pointer; white-space: nowrap;
|
||||
}
|
||||
.kb-btn:hover:not(:disabled) { background: #45475a; }
|
||||
.kb-btn:disabled { opacity: 0.5; cursor: not-allowed; }
|
||||
.kb-btn.primary { background: #cba6f7; color: #1e1e2e; }
|
||||
.kb-btn.primary:hover:not(:disabled) { background: #b4befe; }
|
||||
.kb-btn.danger { color: #f38ba8; }
|
||||
.kb-btn.danger:hover:not(:disabled) { background: #f38ba8; color: #1e1e2e; }
|
||||
.empty { text-align: center; color: #6c7086; padding: 24px 0; }
|
||||
.kb-card {
|
||||
background: #181825; border: 1px solid #313244;
|
||||
border-radius: 8px; padding: 12px; margin-bottom: 8px;
|
||||
}
|
||||
.kb-card-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px; }
|
||||
.kb-status { font-size: 11px; padding: 1px 6px; border-radius: 4px; }
|
||||
.kb-status.ready { background: #a6e3a1; color: #1e1e2e; }
|
||||
.kb-status.partial { background: #fab387; color: #1e1e2e; }
|
||||
.kb-status.empty { background: #45475a; color: #a6adc8; }
|
||||
.kb-meta { font-size: 11px; color: #6c7086; margin-bottom: 8px; }
|
||||
.kb-actions { display: flex; gap: 6px; }
|
||||
.close-btn { display: block; margin: 16px auto 0; }
|
||||
</style>
|
||||
@@ -0,0 +1,108 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted } from 'vue'
|
||||
import { useKbStore } from '../stores/kb'
|
||||
|
||||
const kb = useKbStore()
|
||||
|
||||
const emit = defineEmits<{
|
||||
change: [kbId: string]
|
||||
}>()
|
||||
|
||||
function handleChange(e: Event) {
|
||||
const kbId = (e.target as HTMLSelectElement).value
|
||||
kb.selectKb(kbId)
|
||||
if (kbId) {
|
||||
kb.fetchKbFields(kbId)
|
||||
}
|
||||
emit('change', kbId)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
kb.init()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="kb-selector">
|
||||
<label class="kb-label">知识库</label>
|
||||
<select
|
||||
class="kb-select"
|
||||
:value="kb.currentKbId"
|
||||
@change="handleChange"
|
||||
>
|
||||
<option value="">-- 不使用知识库 --</option>
|
||||
<option
|
||||
v-for="k in kb.kbs"
|
||||
:key="k.kb_id"
|
||||
:value="k.kb_id"
|
||||
>
|
||||
{{ k.name }} ({{ k.field_count }}字段, {{ k.template_count }}模板)
|
||||
</option>
|
||||
</select>
|
||||
<button class="kb-manage-btn" @click="kb.showManager = !kb.showManager" title="管理知识库">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<circle cx="12" cy="12" r="3"/>
|
||||
<path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/>
|
||||
</svg>
|
||||
</button>
|
||||
<span v-if="kb.currentKbName" class="kb-badge">当前: {{ kb.currentKbName }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.kb-selector {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 16px;
|
||||
background: #181825;
|
||||
border-bottom: 1px solid #313244;
|
||||
}
|
||||
|
||||
.kb-label {
|
||||
font-size: 12px;
|
||||
color: #6c7086;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.kb-select {
|
||||
flex: 1;
|
||||
background: #1e1e2e;
|
||||
border: 1px solid #45475a;
|
||||
border-radius: 6px;
|
||||
color: #cdd6f4;
|
||||
padding: 4px 8px;
|
||||
font-size: 13px;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.kb-select:focus {
|
||||
border-color: #cba6f7;
|
||||
}
|
||||
|
||||
.kb-manage-btn {
|
||||
background: #313244;
|
||||
border: none;
|
||||
color: #a6adc8;
|
||||
border-radius: 6px;
|
||||
padding: 4px 6px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.kb-manage-btn:hover {
|
||||
background: #45475a;
|
||||
color: #cdd6f4;
|
||||
}
|
||||
|
||||
.kb-badge {
|
||||
font-size: 11px;
|
||||
color: #a6e3a1;
|
||||
background: #1e1e2e;
|
||||
padding: 2px 8px;
|
||||
border-radius: 10px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
@@ -140,7 +140,7 @@ function handlePaste(e: ClipboardEvent) {
|
||||
ref="fileInputRef"
|
||||
type="file"
|
||||
multiple
|
||||
accept="image/*,.pdf,.docx,.doc,.xlsx,.xls,.txt,.csv"
|
||||
accept="image/*,.pdf,.docx,.doc,.xlsx,.xls,.txt,.csv,.jrxml"
|
||||
style="display:none"
|
||||
@change="handleFileSelect"
|
||||
/>
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
/** Pinia store — multi-tenant KB management. */
|
||||
|
||||
import { ref } from 'vue'
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
export interface KbSummary {
|
||||
kb_id: string
|
||||
name: string
|
||||
description: string
|
||||
created_at: string
|
||||
updated_at: string
|
||||
field_count: number
|
||||
template_count: number
|
||||
file_count: number
|
||||
chunk_count: number
|
||||
parse_status: string
|
||||
}
|
||||
|
||||
export interface UserInfo {
|
||||
user_id: string
|
||||
name: string
|
||||
created_at: string
|
||||
}
|
||||
|
||||
export interface KbTemplate {
|
||||
name: string
|
||||
file: string
|
||||
}
|
||||
|
||||
export interface KbField {
|
||||
name: string
|
||||
description: string
|
||||
type: string
|
||||
required: boolean
|
||||
}
|
||||
|
||||
export const useKbStore = defineStore('kb', () => {
|
||||
const users = ref<UserInfo[]>([])
|
||||
const currentUserId = ref('')
|
||||
const kbs = ref<KbSummary[]>([])
|
||||
const currentKbId = ref('')
|
||||
const currentKbName = ref('')
|
||||
const currentKbFields = ref<KbField[]>([])
|
||||
const currentKbTemplates = ref<KbTemplate[]>([])
|
||||
const loading = ref(false)
|
||||
const showManager = ref(false)
|
||||
|
||||
function setKbs(list: KbSummary[]) { kbs.value = list }
|
||||
|
||||
function selectKb(kbId: string) {
|
||||
currentKbId.value = kbId
|
||||
const kb = kbs.value.find(k => k.kb_id === kbId)
|
||||
if (kb) currentKbName.value = kb.name
|
||||
}
|
||||
|
||||
async function refreshUsers() {
|
||||
try {
|
||||
const r = await fetch('/api/users')
|
||||
const data = await r.json()
|
||||
users.value = data.users || []
|
||||
if (users.value.length > 0 && !currentUserId.value) {
|
||||
currentUserId.value = users.value[0].user_id
|
||||
}
|
||||
} catch (e) { console.error('获取用户列表失败:', e) }
|
||||
}
|
||||
|
||||
async function refreshKbs(userId?: string) {
|
||||
const uid = userId || currentUserId.value
|
||||
if (!uid) return
|
||||
loading.value = true
|
||||
try {
|
||||
const r = await fetch(`/api/users/${uid}/kbs`)
|
||||
const data = await r.json()
|
||||
kbs.value = data.kbs || []
|
||||
} catch (e) { console.error('获取知识库列表失败:', e) }
|
||||
finally { loading.value = false }
|
||||
}
|
||||
|
||||
async function createKb(name: string, description = ''): Promise<KbSummary | null> {
|
||||
if (!currentUserId.value) return null
|
||||
try {
|
||||
const r = await fetch(`/api/users/${currentUserId.value}/kbs`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ name, description }),
|
||||
})
|
||||
if (!r.ok) throw new Error('创建失败')
|
||||
const kb = await r.json()
|
||||
await refreshKbs()
|
||||
return kb
|
||||
} catch (e) { console.error('创建知识库失败:', e); return null }
|
||||
}
|
||||
|
||||
async function deleteKb(kbId: string): Promise<boolean> {
|
||||
try {
|
||||
const r = await fetch(`/api/kbs/${kbId}`, { method: 'DELETE' })
|
||||
if (!r.ok) throw new Error('删除失败')
|
||||
if (currentKbId.value === kbId) { currentKbId.value = ''; currentKbName.value = '' }
|
||||
await refreshKbs()
|
||||
return true
|
||||
} catch (e) { console.error('删除知识库失败:', e); return false }
|
||||
}
|
||||
|
||||
async function uploadFileToKb(kbId: string, file: File): Promise<boolean> {
|
||||
try {
|
||||
const form = new FormData()
|
||||
form.append('file', file)
|
||||
const r = await fetch(`/api/kbs/${kbId}/upload`, { method: 'POST', body: form })
|
||||
return r.ok
|
||||
} catch (e) { console.error('KB文件上传失败:', e); return false }
|
||||
}
|
||||
|
||||
async function buildKb(kbId: string): Promise<boolean> {
|
||||
try {
|
||||
const r = await fetch(`/api/kbs/${kbId}/build`, { method: 'POST' })
|
||||
if (!r.ok) throw new Error('构建失败')
|
||||
await refreshKbs()
|
||||
return true
|
||||
} catch (e) { console.error('KB构建失败:', e); return false }
|
||||
}
|
||||
|
||||
async function fetchKbFields(kbId: string) {
|
||||
try {
|
||||
const r = await fetch(`/api/kbs/${kbId}/fields`)
|
||||
const data = await r.json()
|
||||
currentKbFields.value = data.fields || []
|
||||
currentKbTemplates.value = data.templates || []
|
||||
} catch (e) { console.error('获取KB字段失败:', e) }
|
||||
}
|
||||
|
||||
async function bindKbToSession(sessionId: string, kbId: string) {
|
||||
try {
|
||||
await fetch(`/api/sessions/${sessionId}/kb`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ kb_id: kbId }),
|
||||
})
|
||||
} catch (e) { console.error('绑定KB失败:', e) }
|
||||
}
|
||||
|
||||
async function init() {
|
||||
await refreshUsers()
|
||||
if (currentUserId.value) await refreshKbs()
|
||||
}
|
||||
|
||||
return {
|
||||
users, currentUserId, kbs, currentKbId, currentKbName,
|
||||
currentKbFields, currentKbTemplates, loading, showManager,
|
||||
setKbs, selectKb, refreshUsers, refreshKbs, createKb, deleteKb,
|
||||
uploadFileToKb, buildKb, fetchKbFields, bindKbToSession, init,
|
||||
}
|
||||
})
|
||||
@@ -166,3 +166,155 @@ test.describe("Input UX", () => {
|
||||
await expect(page.locator(".send-btn")).toBeEnabled();
|
||||
});
|
||||
});
|
||||
|
||||
// ── KB (Knowledge Base) API mocks ───────────────────────────────
|
||||
|
||||
function mockKbApi(page: any) {
|
||||
mockApi(page);
|
||||
|
||||
page.route("**/api/users", (route: any) => {
|
||||
if (route.request().method() === "POST") {
|
||||
return route.fulfill({
|
||||
json: { user_id: "u_e2e_test_001", name: "E2E用户", created_at: "2026-05-23T00:00:00Z" },
|
||||
});
|
||||
}
|
||||
return route.fulfill({
|
||||
json: { users: [{ user_id: "u_e2e_test_001", name: "E2E用户", created_at: "2026-05-23T00:00:00Z" }] },
|
||||
});
|
||||
});
|
||||
|
||||
page.route("**/api/users/*/kbs", (route: any) => {
|
||||
if (route.request().method() === "POST") {
|
||||
return route.fulfill({
|
||||
json: {
|
||||
kb_id: "kb_e2e_001", user_id: "u_e2e_test_001",
|
||||
name: "E2E测试库", description: "",
|
||||
created_at: "2026-05-23T00:00:00Z", updated_at: "2026-05-23T00:00:00Z",
|
||||
fields: [], templates: [], file_count: 0, chunk_count: 0, parse_status: "empty",
|
||||
},
|
||||
});
|
||||
}
|
||||
return route.fulfill({
|
||||
json: {
|
||||
kbs: [{
|
||||
kb_id: "kb_e2e_001", name: "E2E测试库", description: "",
|
||||
created_at: "2026-05-23T00:00:00Z", updated_at: "2026-05-23T00:00:00Z",
|
||||
field_count: 10, template_count: 3, file_count: 2, chunk_count: 50, parse_status: "ready",
|
||||
}],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
page.route("**/api/kbs/*/status", (route: any) =>
|
||||
route.fulfill({ json: { parse_status: "ready", file_count: 2, chunk_count: 50 } })
|
||||
);
|
||||
page.route("**/api/kbs/*/fields", (route: any) =>
|
||||
route.fulfill({ json: {
|
||||
fields: [{ name: "billNo", description: "工单号", type: "String" }],
|
||||
templates: [{ name: "结算单", file: "结算单.jrxml" }],
|
||||
}})
|
||||
);
|
||||
page.route("**/api/kbs/*", (route: any) => {
|
||||
if (route.request().method() === "DELETE") {
|
||||
return route.fulfill({ json: { status: "deleted" } });
|
||||
}
|
||||
return route.fulfill({
|
||||
json: {
|
||||
kb_id: "kb_e2e_001", user_id: "u_e2e_test_001",
|
||||
name: "E2E测试库", description: "",
|
||||
fields: [], templates: [],
|
||||
file_count: 2, chunk_count: 50, parse_status: "ready",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
page.route("**/api/kbs/*/upload", (route: any) =>
|
||||
route.fulfill({ json: { filename: "test.jrxml", type: "jrxml", error: null } })
|
||||
);
|
||||
|
||||
page.route("**/api/sessions/*/kb", (route: any) => {
|
||||
if (route.request().method() === "PUT") {
|
||||
return route.fulfill({ json: { kb_id: "kb_e2e_001", kb_name: "E2E测试库" } });
|
||||
}
|
||||
return route.fulfill({ json: { kb_id: "kb_e2e_001", kb_name: "E2E测试库" } });
|
||||
});
|
||||
}
|
||||
|
||||
// ── KB feature tests ────────────────────────────────────────────
|
||||
|
||||
test.describe("KB selector", () => {
|
||||
test("KB selector renders in chat interface", async ({ page }) => {
|
||||
await mockKbApi(page);
|
||||
await page.goto("/");
|
||||
|
||||
await expect(page.locator(".kb-selector")).toBeVisible({ timeout: 5000 });
|
||||
await expect(page.locator(".kb-label")).toContainText("知识库");
|
||||
await expect(page.locator(".kb-select")).toBeVisible();
|
||||
await expect(page.locator(".kb-manage-btn")).toBeVisible();
|
||||
});
|
||||
|
||||
test("can select a KB from dropdown", async ({ page }) => {
|
||||
await mockKbApi(page);
|
||||
await page.goto("/");
|
||||
|
||||
const select = page.locator(".kb-select");
|
||||
await expect(select).toBeVisible({ timeout: 5000 });
|
||||
await select.selectOption({ label: "E2E测试库 (10字段, 3模板)" });
|
||||
await expect(page.locator(".kb-badge")).toContainText("E2E测试库");
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("KB manager", () => {
|
||||
test("opens KB manager overlay", async ({ page }) => {
|
||||
await mockKbApi(page);
|
||||
await page.goto("/");
|
||||
|
||||
await page.locator(".kb-manage-btn").click();
|
||||
await expect(page.locator(".kb-manager")).toBeVisible({ timeout: 3000 });
|
||||
await expect(page.locator(".kb-manager h3")).toContainText("知识库管理");
|
||||
});
|
||||
|
||||
test("can close KB manager", async ({ page }) => {
|
||||
await mockKbApi(page);
|
||||
await page.goto("/");
|
||||
|
||||
await page.locator(".kb-manage-btn").click();
|
||||
await expect(page.locator(".kb-manager")).toBeVisible({ timeout: 3000 });
|
||||
await page.locator(".close-btn").click();
|
||||
await expect(page.locator(".kb-manager")).not.toBeVisible({ timeout: 3000 });
|
||||
});
|
||||
|
||||
test("create form has name input and create button", async ({ page }) => {
|
||||
await mockKbApi(page);
|
||||
await page.goto("/");
|
||||
|
||||
await page.locator(".kb-manage-btn").click();
|
||||
await expect(page.locator(".kb-manager")).toBeVisible({ timeout: 3000 });
|
||||
|
||||
await expect(page.locator('.kb-manager .create-form .kb-input').first()).toBeVisible();
|
||||
await expect(page.locator('.kb-manager .create-form button.primary')).toBeVisible();
|
||||
});
|
||||
|
||||
test("KB cards show name, status, and actions", async ({ page }) => {
|
||||
await mockKbApi(page);
|
||||
await page.goto("/");
|
||||
|
||||
await page.locator(".kb-manage-btn").click();
|
||||
await expect(page.locator(".kb-manager")).toBeVisible({ timeout: 3000 });
|
||||
|
||||
await expect(page.locator(".kb-card")).toBeVisible({ timeout: 3000 });
|
||||
await expect(page.locator(".kb-card strong")).toContainText("E2E测试库");
|
||||
await expect(page.locator(".kb-status.ready")).toContainText("就绪");
|
||||
await expect(page.locator(".kb-actions button")).toHaveCount(3);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("JRXML upload in chat", () => {
|
||||
test("file input accepts .jrxml extension", async ({ page }) => {
|
||||
await mockKbApi(page);
|
||||
await page.goto("/");
|
||||
|
||||
const input = page.locator('.unified-input input[type="file"]');
|
||||
await expect(input).toHaveAttribute("accept", /\.jrxml/);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"kb_id": "49b972ec9e424f04aec34899c978f087",
|
||||
"user_id": "2db10c2ebbf6434aab28035026e196c3",
|
||||
"name": "smoke_kb",
|
||||
"description": "",
|
||||
"created_at": "2026-05-23T12:21:32.409028+00:00",
|
||||
"updated_at": "2026-05-23T12:21:32.409028+00:00",
|
||||
"fields": [],
|
||||
"templates": [],
|
||||
"file_count": 0,
|
||||
"chunk_count": 0,
|
||||
"parse_status": "empty"
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"user_id": "2db10c2ebbf6434aab28035026e196c3",
|
||||
"name": "SmokeTest",
|
||||
"created_at": "2026-05-23T12:21:32.399217+00:00"
|
||||
}
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
+3950
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
+1059
File diff suppressed because it is too large
Load Diff
+2382
File diff suppressed because it is too large
Load Diff
+2381
File diff suppressed because it is too large
Load Diff
+2381
File diff suppressed because it is too large
Load Diff
+2289
File diff suppressed because it is too large
Load Diff
+67
@@ -0,0 +1,67 @@
|
||||
# 保险单接口文档
|
||||
|
||||
# 保险单接口文档
|
||||
|
||||
打印平台模版分类:保险单
|
||||
|
||||
| 字段 | 含义 | 是否必有 | 类型 |
|
||||
| --- | --- | --- | --- |
|
||||
| companyTitle | 打印title | | String |
|
||||
| customerName | 客户姓名 | | String |
|
||||
| carNo | 车牌号 | | String |
|
||||
| vin | vin码 | | String |
|
||||
| carModel | 车型 | | String |
|
||||
| cellPhone | 手机号 | | String |
|
||||
| insureDate | 起保日期 | | String yyyy-MM-dd |
|
||||
| receivable | 应收金额 | | BigDecimal |
|
||||
| preferentialAmount | 优惠金额 | | BigDecimal |
|
||||
| receiveAmount | 实收金额 | | BigDecimal |
|
||||
| oweAmount | 未收金额 | | BigDecimal |
|
||||
| commissionAmountTotal | 手续费 | | BigDecimal |
|
||||
| companyRefundAmount | 保险公司返点 | | BigDecimal |
|
||||
| customerRefundAmount | 客户返点 | | BigDecimal |
|
||||
| insuranceCompanyName | 承保公司 | | String |
|
||||
| memo | 备注 | | String |
|
||||
| employeeName | 服务顾问 | | String |
|
||||
| contacts | 保险公司联系人 | | String |
|
||||
| contactMobile | 保险公司联系人手机号 | | String |
|
||||
| channelName | 来店途径 | | String |
|
||||
| startDate | 开始日期 | | String yyyy-MM-dd |
|
||||
| endDate | 结束日期 | | String yyyy-MM-dd |
|
||||
| renewal | 是否续保 0否/1是 | | Integer |
|
||||
| tsInsuranceDetailList | 保险单明细 | | List<TsInsuranceDetailPrintVo> |
|
||||
| | | | |
|
||||
| <br/><br/> | | | |
|
||||
|
||||
TsInsuranceDetailPrintVo:
|
||||
|
||||
| 字段 | 含义 | 是否必有 | 类型 |
|
||||
| --- | --- | --- | --- |
|
||||
| policyNo | 保单号 | | String |
|
||||
| insuranceType | 保险类型(0交强险/1商业险) | | Integer |
|
||||
| name | 险种名称 | | String |
|
||||
| amount | 保额 | | BigDecimal |
|
||||
| receivable | 应收金额(元) | | BigDecimal |
|
||||
| discount | 折扣 | | BigDecimal |
|
||||
| concessionary | 优惠金额(元) | | BigDecimal |
|
||||
| commissionRate | 手续费率 | | BigDecimal |
|
||||
| commissionAmount | 手续费 | | BigDecimal |
|
||||
| paid | 实收金额(元) | | BigDecimal |
|
||||
| memo | 备注 | | String |
|
||||
| companyRefundAmount | 保险公司返点 | | BigDecimal |
|
||||
| customerRefundAmount | 客户返点 | | BigDecimal |
|
||||
| | | | |
|
||||
| | | | |
|
||||
| | | | |
|
||||
| | | | |
|
||||
| | | | |
|
||||
| | | | |
|
||||
| | | | |
|
||||
| | | | |
|
||||
| | | | |
|
||||
| | | | |
|
||||
| | | | |
|
||||
| | | | |
|
||||
| <br/><br/> | | | |
|
||||
|
||||
> 更新: 2023-09-20 11:32:29 原文: <https://xcz.yuque.com/ombipo/rpc7ms/fpzmr5qph5mloy1x>
|
||||
+420
@@ -0,0 +1,420 @@
|
||||
# 出/入库单据打印
|
||||
|
||||
# 现状梳理
|
||||
|
||||
| **场景** | | 入口 | 打印效果 | **底层模版** | 接口 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 库存 | 出入库单据-出库单 |  |  |  | REST:/stock/stockInAndOutBill/stockOutPrint?idStock=XXX&isNew=true<br>底层接口:com.f6car.stock.service.impl.print.PrintServiceImpl#getStockOutPrintUrl<br>日志关键字:+"出库单打印参数:" (有 apollo 开关 log.stockInout.print.switch 默认true) |
|
||||
| | 领料出库(工单领料)-出库单 |  |  |
|
||||
| | 出入库单据-入库单 |  |  |  | REST:/stock/stockInAndOutBill/stockInPrint?idStock=XXX&isNew=true<br>底层接口:com.f6car.stock.service.impl.print.PrintServiceImpl#getStockInPrintUrl<br>日志关键字:+"入库单打印参数:" (有 apollo 开关 log.stockInout.print.switch 默认true) |
|
||||
| | 领料出库(工单领料)-退料单 | <br> |  |
|
||||
| | 手工出入库-出库单 |  |  |  | REST:/stock/manual/print?pkId=XXX&billType=0&isNew=true (type=0 表示入库单 type=1 表示出库单)<br>底层接口:com.f6car.stock.service.print.PrintService#getManualStorageStockInPrintUrl<br>日志关键字:+"手工出入库单据打印入参是:" |
|
||||
| | 手工出入库-入库单 |  |  |  |
|
||||
| | 领料详情-打印领料单 |  |  |  | REST:/stock/maintain/print?idSourceBill=XXX&hasPreview=true<br>底层接口:com.f6car.stock.service.impl.print.PrintServiceImpl#getMaintainPrintUrl<br>日志关键字:+"领料单打印参数:" (有 apollo 开关 log.stock.maintain.print.switch 默认false) |
|
||||
|
||||
# 出入库单据-出库单 && 领料出库-出库单打印模版参数说明
|
||||
|
||||
出库单据定制类需求模版分类(newStockOutMaintainCustomPrint)--20250925新增
|
||||
|
||||
打印模版参数
|
||||
|
||||
HashMap<String, Object> resultMap
|
||||
|
||||
| **字段** | **说明** | 备注 |
|
||||
| --- | --- | --- |
|
||||
| title | 门店名称+ "出库单" | |
|
||||
| billNo | 出库单号 | |
|
||||
| sourceBillNo | 来源单号 | |
|
||||
| showSourceBillNo | 显示来源单号 (boolean) | |
|
||||
| billStatus | 单据状态(制单、完成) | |
|
||||
| inOutDate | 出库日期 | |
|
||||
| showInOutDate | 是否显示出库日期(boolean) | |
|
||||
| objectName | 出入库对象 | |
|
||||
| objectNameGD | 出入库对象工单<br/>工单出库单:客户姓名+车牌号整体+车辆VIN码+车辆品牌车系车型全称 (拼接后取前 80 个字符)<br/>非工单出库单:"" | |
|
||||
| creatorName | 制单人 | |
|
||||
| billDate | 制单日期 (yyyy-MM-dd) | |
|
||||
| sumNumber | 材料总数量 | |
|
||||
| sumAmount | 总金额 <br>\--脱敏场景显示 _\*_\*_\*\*_ | |
|
||||
| chineseAmount | 总金额(中文大写)<br>\--脱敏场景显示 _\*_\*\*\* | |
|
||||
| nowDateTime | 打印当前时间 (yyyy-MM-dd HH:mm) | |
|
||||
| idOwnOrg | 门店ID | |
|
||||
| remark | 备注信息 | |
|
||||
| showRemark | 是否显示备注(boolean)<br>\-- 备注不为空时是 true | |
|
||||
| isGdType | 是否是工单类型单据出库(boolean)<br>\-- 工单出库单是 true | |
|
||||
| saName | 服务顾问姓名<br>\-- 工单出库单场景 | |
|
||||
| printCount | 打印次数 | |
|
||||
| showCustomCode | 配置出入库打印参数-是否显示材料编码(boolean) | |
|
||||
| showBusinessLabel | 配置出入库打印参数-是否显示材料业务分类(boolean) | |
|
||||
| showApplyModel | 配置出入库打印参数-是否显示材料适用车型(boolean) | |
|
||||
| showStorageName | 配置出入库打印参数-是否显示出库仓库(boolean) | |
|
||||
| showDefSeat | 配置出入库打印参数-是否显示出库货位(boolean) | |
|
||||
| showChineseAmount | 配置出入库打印参数-是否显示大写金额(boolean) | |
|
||||
| showChineseSubtotal | 配置出入库打印参数-是否显示大写行合计(boolean) | |
|
||||
| columnCount | 显示几列 | |
|
||||
| batchPrintConfig | 配置出入库打印参数-查询批次成本展示设置 0:都不展示,1:总成本(将批次成本合并),2和3:展示批次成本 | |
|
||||
| memo | 车主描述 | \--20250925 新增 |
|
||||
| partInfoDetailMapList | | |
|
||||
| sortNumber | 序号<br>**通用模版追加一行合计行,显示 合计** | |
|
||||
| partShowName | 材料组合名称 | |
|
||||
| partName | 材料名称 | |
|
||||
| partBrand | 材料品牌 | \-- 2025.02.27 新增 |
|
||||
| supplierCode | 零件号 | |
|
||||
| labelName | 业务分类 | |
|
||||
| applyModel | 适用车型 | |
|
||||
| customCode | 材料编码 | |
|
||||
| storageName | 仓库名称 | |
|
||||
| defSeat | 货位 | |
|
||||
| number | 数量<br>**\-- 通用模版追加一行合计行,显示 材料出库总数** | |
|
||||
| unit | 单位 | |
|
||||
| price | 单价<br>\--脱敏场景显示 _\*_\*\*\* | |
|
||||
| subtotal | 金额<br>\--脱敏场景显示 _\*_\*\*\* | |
|
||||
| employeeName | 出库人 | |
|
||||
| salesEmployeeNameList | 材料行销售人员 | \--20250925 新增 |
|
||||
| orderBatchList<br>\--List<Map<String, String>> | 材料行成本相关 | |
|
||||
| orderNo | 批次号<br>\-- batchPrintConfig = 1 场景下,显示 ""<br>\-- 均价模式下,显示 ""<br>**\-- 通用模版追加一行合计,追加行,显示 ""** | |
|
||||
| count | 批次出库几个<br>\-- batchPrintConfig = 1 场景下,显示 ""<br>\-- 均价模式下,显示 ""<br>**\-- 通用模版追加一行合计,追加行,显示总数** | |
|
||||
| price | 批次单位成本<br>\-- batchPrintConfig = 1 场景下,显示 ""<br>\-- 脱敏场景显示 **\*\*\*\***<br>**\-- 均价模式下,显示均价单位成本**<br>\-- 通用模版追加一行合计,追加行,显示 "" | |
|
||||
| priceNoTax | 批次单位除税成本<br>\-- batchPrintConfig = 1 场景下,显示 ""<br>\-- 脱敏场景显示 **\*\*\*\***<br>**\-- 均价模式下,显示均价单位成本**<br>\-- 通用模版追加一行合计,追加行,显示 "" | 2025.08.14 新增 |
|
||||
| totalPrice | 批次总成本<br>\-- batchPrintConfig = 1 场景下,显示合计总成本<br>\-- 脱敏场景显示 **\*\*\*\***<br>**\-- 均价模式下,显示均价总成本**<br>\-- 通用模版追加一行合计,追加行,显示总成本 | |
|
||||
| totalPriceNoTax | 批次除税总成本<br>\-- batchPrintConfig = 1 场景下,显示合计总成本<br>\-- 脱敏场景显示 **\*\*\*\***<br>**\-- 均价模式下,显示均价除税总成本**<br>\-- 通用模版追加一行合计,追加行,显示总成本 | 2025.08.14 新增 |
|
||||
|
||||
样列:
|
||||
|
||||

|
||||
|
||||
```plaintext
|
||||
{
|
||||
"saName":"xuetting",
|
||||
"objectNameGD":"18551638685【苏ABF358】 LFV2A21K6A3092399 大众 速腾 1.4T 双离合变速器(DSG) 2011 速腾",
|
||||
"creatorName":"cltest",
|
||||
"showStorageName":true,
|
||||
"remark":"",
|
||||
"title":"流程配置ES出库单",
|
||||
"showSourceBillNo":true,
|
||||
"sumAmount":"860.0",
|
||||
"showChineseAmount":true,
|
||||
"billStatus":"完成",
|
||||
"sumNumber":"1.0",
|
||||
"isGdType":true,
|
||||
"printCount":"3",
|
||||
"billNo":"CKD20250116001",
|
||||
"showDefSeat":true,
|
||||
"idOwnOrg":"15870306745529549109",
|
||||
"showApplyModel":true,
|
||||
"memo":"",
|
||||
"partInfoDetailMapList":[
|
||||
{
|
||||
"employeeName":"cltest",
|
||||
"sortNumber":"1",
|
||||
"partShowName":" 3M 燃油宝1号 PN6868 3M (PN6868)",
|
||||
"defSeat":"A",
|
||||
"orderBatchList":[
|
||||
{
|
||||
"orderNo":"20211213000001",
|
||||
"totalPrice":"0.0",
|
||||
"price":"0.0",
|
||||
"count":"1.0"
|
||||
}
|
||||
],
|
||||
"supplierCode":"PN6868",
|
||||
"partName":"3M 燃油宝1号 PN6868",
|
||||
"applyModel":"",
|
||||
"customCode":"CL0000015",
|
||||
"storageName":"主仓库",
|
||||
"number":"1.0",
|
||||
"unit":"瓶",
|
||||
"price":"860.0",
|
||||
"subtotal":"860.0",
|
||||
"labelName":"保养",
|
||||
"salesEmployeeNameList": "B2C一店新员工,B2C一店采购员"
|
||||
|
||||
},
|
||||
{
|
||||
"number":"1.0",
|
||||
"subtotal":"860.0",
|
||||
"sortNumber":"合计",
|
||||
"orderBatchList":[
|
||||
{
|
||||
"orderNo":"",
|
||||
"totalPrice":"0.0",
|
||||
"price":"",
|
||||
"count":"1.0"
|
||||
}
|
||||
]
|
||||
}],
|
||||
"sourceBillNo":"WXD20250103001",
|
||||
"billDate":"2025-01-16",
|
||||
"chineseAmount":"捌佰陆拾元整",
|
||||
"columnCount":"5",
|
||||
"showCustomCode":true,
|
||||
"showBusinessLabel":true,
|
||||
"batchPrintConfig":"3",
|
||||
"nowDateTime":"2025-02-18 10:04",
|
||||
"showInOutDate":true,
|
||||
"showChineseSubtotal":true,
|
||||
"objectName":"18551638685【苏ABF358】大众 速腾",
|
||||
"inOutDate":"2025-01-16",
|
||||
"showRemark":false
|
||||
}
|
||||
```
|
||||
|
||||
# 出入库单据-入库单 && 退料入库-入库单打印模版参数说明
|
||||
|
||||
入库单据定制类需求模版分类(newStockInMaintainCustomPrint)--20250925新增
|
||||
|
||||
打印模版参数
|
||||
|
||||
HashMap<String, Object> resultMap
|
||||
|
||||
| **字段** | **说明** | 备注 |
|
||||
| --- | --- | --- |
|
||||
| title | 门店名称+ "入库单" | |
|
||||
| billNo | 入库单号 | |
|
||||
| sourceBillNo | 来源单号 | |
|
||||
| showSourceBillNo | 显示来源单号 (boolean)<br>默认:true | |
|
||||
| billStatus | 单据状态(制单、完成) | |
|
||||
| inOutDate | 入库日期<br>\-- yyyy-MM-dd | |
|
||||
| showInOutDate | 是否显示入库日期(boolean)<br>\-制单是 false<br>\-完成是 true | |
|
||||
| objectName | 出入库对象 | |
|
||||
| creatorName | 制单人 | |
|
||||
| billDate | 制单日期 (yyyy-MM-dd) | |
|
||||
| sumNumber | 材料总数量 | |
|
||||
| sumAmount | 总金额 <br>\--脱敏场景显示 _\*_\*_\*\*_ | |
|
||||
| noTaxSumAmount | 除税总金额 <br>\--脱敏场景显示 _\*_\*_\*\*_ | |
|
||||
| chineseAmount | 总金额(中文大写)<br>\--脱敏场景显示 _\*_\*\*\* | |
|
||||
| chineseNoTaxSumAmount | 除税总金额(中文大写)<br>\--脱敏场景显示 _\*_\*\*\* | |
|
||||
| nowDateTime | 打印当前时间 (yyyy-MM-dd HH:mm) | |
|
||||
| idOwnOrg | 门店ID | |
|
||||
| remark | 备注信息 | |
|
||||
| showRemark | 是否显示备注(boolean)<br>\-- 备注不为空时是 true | |
|
||||
| isGdType | 是否是工单类型单据出库(boolean)<br>\-- 工单出库单是 true | |
|
||||
| saName | 服务顾问姓名<br>\-- 工单出库单场景 | |
|
||||
| printCount | 打印次数 | |
|
||||
| showCustomCode | 配置出入库打印参数-是否显示材料编码(boolean) | |
|
||||
| showBusinessLabel | 配置出入库打印参数-是否显示材料业务分类(boolean) | |
|
||||
| showApplyModel | 配置出入库打印参数-是否显示材料适用车型(boolean) | |
|
||||
| showStorageName | 配置出入库打印参数-是否显示出库仓库(boolean) | |
|
||||
| showDefSeat | 配置出入库打印参数-是否显示出库货位(boolean) | |
|
||||
| showChineseAmount | 配置出入库打印参数-是否显示大写金额(boolean) | |
|
||||
| showChineseSubtotal | 配置出入库打印参数-是否显示大写行合计(boolean) | |
|
||||
| sumSubtotal | 入库总金额<br>\-- 脱敏场景显示 \*\*\*\*<br>\-- 工单退-才有 | |
|
||||
| chineseSubtotal | 大写入库总金额<br>\-- 脱敏场景显示 \*\*\*\*<br>\-- 工单退-才有 | |
|
||||
| showReturnIn | 显示退料入库一行<br>\-- 工单退-true | |
|
||||
| showSign | 【仓管签字】显示的位置<br>工单退-2;其它场景1 | |
|
||||
| stockInType | 退料入库<br>\-- 工单退-才有 | |
|
||||
| columnCount | 显示几列 | |
|
||||
| memo | 车主描述 | \--20250925 新增 |
|
||||
| partInfoDetailMapList | | |
|
||||
| sortNumber | 序号 | |
|
||||
| partShowName | 材料组合名称 | |
|
||||
| partName | 材料名称 | |
|
||||
| partBrand | 材料品牌 | |
|
||||
| labelName | 业务分类 | |
|
||||
| applyModel | 适用车型 | |
|
||||
| customCode | 材料编码 | |
|
||||
| storageName | 仓库名称 | |
|
||||
| defSeat | 货位 | |
|
||||
| number | 数量<br>**\-- 通用模版追加一行合计行,显示 材料出库总数** | |
|
||||
| unit | 单位 | |
|
||||
| price | 单价<br>\--脱敏场景显示 _\*_\*\*\* | |
|
||||
| noTaxPrice | 除税单价<br>\--脱敏场景显示 _\*_\*\*\* | |
|
||||
| subtotal | 金额<br>\--脱敏场景显示 _\*_\*\*\* | |
|
||||
| noTaxSubtotal | 除税金额<br>\--脱敏场景显示 _\*_\*\*\* | |
|
||||
| employeeName | 入库人 | |
|
||||
| salesEmployeeNameList | 材料行销售人员 | \--20250925 新增 |
|
||||
|
||||
# 手工出入库-出/入库单
|
||||
|
||||
打印模版参数
|
||||
|
||||
HashMap<String, Object> resultMap
|
||||
|
||||
| **字段** | **说明** | **备注** |
|
||||
| --- | --- | --- |
|
||||
| title | 出库单:门店名称+ "出库单"<br>入库单:门店名称+ "入库单" | |
|
||||
| billNo | 出库单号/入库单号 | |
|
||||
| sourceBillNo | 来源单号 空 | |
|
||||
| showSourceBillNo | 显示来源单号 (boolean)false | |
|
||||
| billStatus | 单据状态(制单、完成) | |
|
||||
| inOutDate | 出库日期 (yyyy-MM-dd) | |
|
||||
| showInOutDate | 是否显示出库日期(boolean) | |
|
||||
| objectName | 出入库对象 | |
|
||||
| objectNameGD | 出入库对象 | |
|
||||
| creatorName | 制单人 | |
|
||||
| billDate | 制单日期 (yyyy-MM-dd) | |
|
||||
| sumNumber | 材料总数量 | |
|
||||
| sumAmount | 总金额 <br>\--脱敏场景显示 _\*_\*\*\* | |
|
||||
| chineseAmount | 总金额(中文大写)<br>\--脱敏场景显示 _\*_\*\*\* | |
|
||||
| nowDateTime | 打印当前时间 (yyyy-MM-dd HH:mm) | |
|
||||
| idOwnOrg | 门店ID | |
|
||||
| remark | 备注信息 | |
|
||||
| showRemark | 是否显示备注(boolean)<br/>-- 备注不为空时是 true | |
|
||||
| printCount | 打印次数 | |
|
||||
| showCustomCode | <br/>配置出入库打印参数-是否显示材料编码(boolean) | |
|
||||
| showBusinessLabel | 配置出入库打印参数-是否显示材料业务分类(boolean) | |
|
||||
| showApplyModel | 配置出入库打印参数-是否显示材料适用车型(boolean) | |
|
||||
| showStorageName | 配置出入库打印参数-是否显示出库仓库(boolean) | |
|
||||
| showDefSeat | 配置出入库打印参数-是否显示出库货位(boolean) | |
|
||||
| showChineseAmount | 配置出入库打印参数-是否显示大写金额(boolean) | |
|
||||
| showChineseSubtotal | 配置出入库打印参数-是否显示大写行合计(boolean) | |
|
||||
| columnCount | 显示几列 | |
|
||||
| batchPrintConfig | 配置出入库打印参数-查询批次成本展示设置 0:都不展示,1:总成本(将批次成本合并),2和3:展示批次成本 | |
|
||||
| partInfoDetailMapList | | |
|
||||
| sortNumber | 序号<br>**\-- 通用模版追加一行合计行,显示 合计** | |
|
||||
| partShowName | 材料组合名称 (材料名称 规格型号 材料品牌 零件号) | |
|
||||
| partName | 材料名称 | |
|
||||
| partBrand | 材料品牌 -- 2025.02.27 新增 | |
|
||||
| supplierCode | 零件号 | |
|
||||
| labelName | 业务分类 | |
|
||||
| applyModel | 适用车型 | |
|
||||
| customCode | 材料编码 | |
|
||||
| storageName | 仓库名称 | |
|
||||
| defSeat | 货位 | |
|
||||
| number | 数量<br>**\-- 通用模版追加一行合计行,显示 材料出库总数** | |
|
||||
| unit | 单位 | |
|
||||
| price | 单价<br>\--脱敏场景显示 _\*_\*\*\* | |
|
||||
| subtotal | 金额<br>\--脱敏场景显示 _\*_\*\*\* | |
|
||||
| employeeName | 出库人 | |
|
||||
| taxRate | 税率 | |
|
||||
| orderBatchList<br>\--List<Map<String, String>> | 材料行成本相关 | |
|
||||
| orderNo | 批次号<br>\- batchPrintConfig = 1 场景下,显示 ""<br>\-- 均价模式下,显示 ""<br>**\-- 通用模版追加一行合计,追加行,显示 ""** | |
|
||||
| count | 批次出库几个<br>\-- batchPrintConfig = 1 场景下,显示 ""<br>\-- 均价模式下,显示出库/入库个数<br>**\-- 通用模版追加一行合计,追加行,显示总数** | |
|
||||
| price | 批次单位成本<br>\-- batchPrintConfig = 1 场景下,显示 ""<br>\-- 脱敏场景显示 **\*\*\*\***<br>**\-- 均价模式下,显示均价单位成本**<br>\-- 通用模版追加一行合计,追加行,显示 ""\*\* | |
|
||||
| priceNoTax | 批次除税单位成本<br>\-- batchPrintConfig = 1 场景下,显示 ""<br>\-- 脱敏场景显示 **\*\*\*\***<br>**\-- 均价模式下,显示均价单位成本**<br>\-- 通用模版追加一行合计,追加行,显示 ""\*\* | 2025.08.14 追加 |
|
||||
| totalPrice | 批次总成本<br>\-- batchPrintConfig = 1 场景下,显示合计总成本<br>\-- 脱敏场景显示 **\*\*\*\***<br>**\-- 均价模式下,显示均价总成本**<br>\-- 通用模版追加一行合计,追加行,显示总成本\*\*\*\* | |
|
||||
| totalPriceNoTax | 批次除税总成本<br>\-- batchPrintConfig = 1 场景下,显示合计总成本<br>\-- 脱敏场景显示 **\*\*\*\***<br>**\-- 均价模式下,显示均价总成本**<br>\-- 通用模版追加一行合计,追加行,显示总成本\*\*\*\* | 2025.08.14 追加 |
|
||||
|
||||
样列:
|
||||
|
||||

|
||||
|
||||
日志关键字:+"手工出入库单据打印入参是"
|
||||
|
||||
```plaintext
|
||||
{
|
||||
"objectNameGD":"",
|
||||
"creatorName":"王◇龙",
|
||||
"showStorageName":true,
|
||||
"remark":"",
|
||||
"title":"ISC总店出库单",
|
||||
"showSourceBillNo":false,
|
||||
"sumAmount":"410.0",
|
||||
"showChineseAmount":true,
|
||||
"billStatus":"完成",
|
||||
"sumNumber":"2.0",
|
||||
"printCount":"5",
|
||||
"billNo":"SGC20240515001",
|
||||
"showDefSeat":true,
|
||||
"idOwnOrg":"4060685614490690260",
|
||||
"showApplyModel":true,
|
||||
"partInfoDetailMapList":[
|
||||
{
|
||||
"employeeName":"XN",
|
||||
"sortNumber":"1",
|
||||
"partShowName":" 材料09080112 123456 米其林 (1240)",
|
||||
"defSeat":"A-14-02",
|
||||
"orderBatchList":[
|
||||
{
|
||||
"orderNo":"20210909000128",
|
||||
"totalPrice":"400.0",
|
||||
"price":"400.0",
|
||||
"count":"1.0"
|
||||
}
|
||||
],
|
||||
"supplierCode":"1240",
|
||||
"partName":"材料09080112",
|
||||
"applyModel":"大众 途安",
|
||||
"customCode":"CL090800112",
|
||||
"storageName":"主仓库",
|
||||
"number":"1.0",
|
||||
"unit":"条",
|
||||
"price":"400.0",
|
||||
"subtotal":"400.0",
|
||||
"labelName":"轮胎"
|
||||
},
|
||||
{
|
||||
"employeeName":"XN",
|
||||
"sortNumber":"2",
|
||||
"partShowName":" fnst=>1 AC德科 (FNST>=1)",
|
||||
"defSeat":"",
|
||||
"orderBatchList":[
|
||||
{
|
||||
"orderNo":"20201104000002",
|
||||
"totalPrice":"4.0",
|
||||
"price":"4.0",
|
||||
"count":"1.0"
|
||||
}
|
||||
],
|
||||
"supplierCode":"FNST>=1",
|
||||
"partName":"fnst=>1",
|
||||
"applyModel":"江淮瑞风S52....",
|
||||
"customCode":"fnst>=1",
|
||||
"storageName":"总2仓",
|
||||
"number":"1.0",
|
||||
"unit":"个",
|
||||
"price":"10.0",
|
||||
"subtotal":"10.0",
|
||||
"labelName":"保养"
|
||||
},
|
||||
{
|
||||
"number":"2.0",
|
||||
"subtotal":"410.0",
|
||||
"sortNumber":"合计",
|
||||
"orderBatchList":[
|
||||
{
|
||||
"orderNo":"",
|
||||
"totalPrice":"404.0",
|
||||
"price":"",
|
||||
"count":"2.0"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"sourceBillNo":"",
|
||||
"billDate":"2024-05-15",
|
||||
"chineseAmount":"肆佰壹拾元整",
|
||||
"columnCount":"5",
|
||||
"showCustomCode":true,
|
||||
"showBusinessLabel":true,
|
||||
"batchPrintConfig":"3",
|
||||
"nowDateTime":"2025-02-18 09:33",
|
||||
"showInOutDate":true,
|
||||
"showChineseSubtotal":true,
|
||||
"objectName":"",
|
||||
"inOutDate":"2024-05-15",
|
||||
"showRemark":false
|
||||
}
|
||||
```
|
||||
|
||||
# 领料详情-打印领料单
|
||||
|
||||
打印模版参数
|
||||
|
||||
HashMap<String, Object> resultMap
|
||||
|
||||
| **字段** | **说明** | **备注** |
|
||||
| --- | --- | --- |
|
||||
| idOwnOrg | 门店ID | |
|
||||
| title | 门店名称+ "领料单" | |
|
||||
| billNo | 工单号 | |
|
||||
| nowDateTime | 打印当前时间 (yyyy-MM-dd HH:mm) | |
|
||||
| employeeName | 服务顾问 | |
|
||||
| carModel | 车型 | |
|
||||
| carNoWhole | 车牌号 | |
|
||||
| memo | 车主描述 | 2025.08.14 新增 |
|
||||
| printTimes | 打印次数 | |
|
||||
| columnCount | 显示几列 | |
|
||||
| batchPrintConfig | 配置出入库打印参数-查询批次成本展示设置 0:都不展示,1:总成本(将批次成本合并),2和3:展示批次成本 | |
|
||||
| stuffDetailVOList | | |
|
||||
| index | 序号<br>**\-- 通用模版追加一行合计行,显示 合计** | |
|
||||
| partName | 材料组合名称 (材料名称 规格型号 材料品牌 零件号) | |
|
||||
| unit | 单位 | |
|
||||
| defSeatList | 货位 | |
|
||||
| salesEmployeeNameList | 销售人员<br>List<String> | 8.14新增 |
|
||||
| orderBatchList<br>\--List<Map<String, String>> | 材料行成本相关 | |
|
||||
| orderNo | 批次号<br>\- batchPrintConfig = 1 场景下,显示 ""<br>\-- 均价模式下,显示 ""<br>**\-- 通用模版追加一行合计,追加行,显示 ""** | |
|
||||
| count | 批次出库几个<br>\-- batchPrintConfig = 1 场景下,显示 ""<br>\-- 均价模式下,显示出库/入库个数<br>**\-- 通用模版追加一行合计,追加行,显示总数** | |
|
||||
| price | 批次单位成本<br>\-- batchPrintConfig = 1 场景下,显示 ""<br>\-- 脱敏场景显示 **\*\*\*\***<br>**\-- 均价模式下,显示均价单位成本**<br>\-- 通用模版追加一行合计,追加行,显示 ""\*\* | |
|
||||
| priceNoTax | 批次除税单位成本<br>\-- batchPrintConfig = 1 场景下,显示 ""<br>\-- 脱敏场景显示 **\*\*\*\***<br>**\-- 均价模式下,显示均价单位成本**<br>\-- 通用模版追加一行合计,追加行,显示 ""\*\* | 2025.08.14 追加 |
|
||||
| totalPrice | 批次总成本<br>\-- batchPrintConfig = 1 场景下,显示合计总成本<br>\-- 脱敏场景显示 **\*\*\*\***<br>**\-- 均价模式下,显示均价总成本**<br>\-- 通用模版追加一行合计,追加行,显示总成本\*\*\*\* | |
|
||||
| totalPriceNoTax | 批次除税总成本<br>\-- batchPrintConfig = 1 场景下,显示合计总成本<br>\-- 脱敏场景显示 **\*\*\*\***<br>**\-- 均价模式下,显示均价总成本**<br>\-- 通用模版追加一行合计,追加行,显示总成本\*\*\*\* | 2025.08.14 追加 |
|
||||
+682
@@ -0,0 +1,682 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Created with Jaspersoft Studio version 6.3.1.final using JasperReports Library version 6.3.1 -->
|
||||
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="Blank_A4" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="3fa22123-efc4-4f3f-a186-6a8f692d17e6">
|
||||
<property name="com.jaspersoft.studio.data.defaultdataadapter" value="One Empty Record"/>
|
||||
<subDataset name="List1" uuid="7366c5be-288c-41c7-b295-b8d023ec81ae">
|
||||
<queryString>
|
||||
<![CDATA[]]>
|
||||
</queryString>
|
||||
<field name="index" class="java.lang.String"/>
|
||||
<field name="serviceName" class="java.lang.String"/>
|
||||
<field name="cooperationServiceName" class="java.lang.String"/>
|
||||
<field name="cooperationOrgName" class="java.lang.String"/>
|
||||
<field name="auditStatus" class="java.lang.String"/>
|
||||
<field name="cooperationCost" class="java.math.BigDecimal"/>
|
||||
</subDataset>
|
||||
<parameter name="title" class="java.lang.String"/>
|
||||
<parameter name="billNo" class="java.lang.String"/>
|
||||
<parameter name="creatorName" class="java.lang.String"/>
|
||||
<parameter name="printTime" class="java.lang.String"/>
|
||||
<parameter name="naEmployee" class="java.lang.String"/>
|
||||
<parameter name="billDate" class="java.lang.String"/>
|
||||
<parameter name="deliveryTime" class="java.lang.String"/>
|
||||
<parameter name="naCustomer" class="java.lang.String"/>
|
||||
<parameter name="carModel" class="java.lang.String"/>
|
||||
<parameter name="cellPhone" class="java.lang.String"/>
|
||||
<parameter name="carNoWhole" class="java.lang.String"/>
|
||||
<parameter name="vin" class="java.lang.String"/>
|
||||
<parameter name="serviceDetailVOList" class="net.sf.jasperreports.engine.data.JRMapCollectionDataSource"/>
|
||||
<parameter name="amountAll" class="java.math.BigDecimal"/>
|
||||
<queryString>
|
||||
<![CDATA[]]>
|
||||
</queryString>
|
||||
<detail>
|
||||
<band height="115" splitType="Stretch">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="0" y="0" width="555" height="40" uuid="7c3a0deb-dcb0-406e-ba9c-9f279e1518b0">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="16"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{title}!=null?$P{title}+"协作项目确认单":""]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="240" y="60" width="120" height="18" uuid="6849ccdb-a3a0-4d32-a556-7a8fd5a19cca">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{creatorName}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="420" y="60" width="135" height="18" uuid="b347e5b3-390c-44c3-b746-481aa6dc808e">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{printTime}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="60" y="60" width="120" height="18" uuid="92646184-6d70-4b6e-9f0e-23b4a7b15fb5">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{billNo}]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement key="" x="360" y="60" width="50" height="18" isRemoveLineWhenBlank="true" uuid="86735eee-0435-4238-9b93-c08d86ed318f">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[打印时间:]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="0" y="60" width="60" height="18" uuid="fef0343d-31f4-4b1c-a521-1a1b736aa485">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[工单号:]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="180" y="60" width="60" height="18" uuid="627d90fe-c235-45d8-9f4a-92f8d7ec0de7">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[制单人:]]></text>
|
||||
</staticText>
|
||||
<line>
|
||||
<reportElement x="0" y="78" width="555" height="1" uuid="329fa736-2c18-4d9d-8fab-f54846315633">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.4" lineStyle="Solid"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
<staticText>
|
||||
<reportElement x="180" y="96" width="60" height="18" uuid="ef411f00-dff2-400c-9e82-bbc2450553c0">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.4" lineStyle="Solid"/>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[车型]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="0" y="78" width="60" height="18" uuid="74602da5-9195-47dd-9416-9cb229aeccad">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.5" lineStyle="Solid"/>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[服务顾问]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="240" y="96" width="315" height="18" uuid="985f2bdc-723d-477e-9786-263a1d3ce58c">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.4"/>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{carModel}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="240" y="78" width="120" height="18" uuid="49312902-8cda-4fe3-a92f-d6ecbf9cb893">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.5"/>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{billDate}]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement x="180" y="78" width="60" height="18" uuid="65483940-e0c7-4713-9e9a-6a5a7294d248">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.5" lineStyle="Solid"/>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[进厂时间]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="60" y="78" width="120" height="18" uuid="e9c8328d-22ea-4e66-a23f-5015ffbd8248">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.5"/>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{naEmployee}]]></textFieldExpression>
|
||||
</textField>
|
||||
<line>
|
||||
<reportElement x="0" y="96" width="555" height="1" uuid="f6716829-054d-4fed-a12c-2f4d227724c7">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.4" lineStyle="Dotted"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
<line>
|
||||
<reportElement x="0" y="114" width="555" height="1" uuid="404f9e68-011f-4c55-88f6-f1231a22908b">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.4" lineStyle="Dotted"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
<line>
|
||||
<reportElement x="0" y="113" width="555" height="1" uuid="09d822fb-3735-4773-b954-9c83f3eefdef">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.4" lineStyle="Solid"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="420" y="78" width="135" height="18" uuid="09e44308-af9c-4bf2-b88d-b6c213fa2c43">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{vin}]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement x="360" y="78" width="60" height="18" uuid="180c43d9-ea5c-4074-9b9e-b1ffaa905250">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.5" lineStyle="Solid"/>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[VIN码]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="60" y="96" width="120" height="18" uuid="85a6bfa2-352f-4f7e-b690-625639120c96">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{carNoWhole}]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement x="0" y="96" width="60" height="18" uuid="fb4b2bbf-ccd0-4201-9e4b-d98ad63364ca">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.5" lineStyle="Solid"/>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[车牌号]]></text>
|
||||
</staticText>
|
||||
</band>
|
||||
<band height="56">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<componentElement>
|
||||
<reportElement x="0" y="20" width="555" height="36" uuid="dab34898-b275-4c88-8129-eefa0454fc8a">
|
||||
<property name="com.jaspersoft.studio.layout" value="com.jaspersoft.studio.editor.layout.VerticalRowLayout"/>
|
||||
<property name="com.jaspersoft.studio.table.style.table_header" value="Table 2_TH"/>
|
||||
<property name="com.jaspersoft.studio.table.style.column_header" value="Table 2_CH"/>
|
||||
<property name="com.jaspersoft.studio.table.style.detail" value="Table 2_TD"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<jr:table xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd">
|
||||
<datasetRun subDataset="List1" uuid="c97f7286-0f00-496d-af86-5689f8ef21e5">
|
||||
<dataSourceExpression><![CDATA[$P{serviceDetailVOList}]]></dataSourceExpression>
|
||||
</datasetRun>
|
||||
<jr:column width="20" uuid="2a312910-46b6-42d0-a6f9-5b10690854b7">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column1"/>
|
||||
<jr:columnHeader height="18" rowSpan="1">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="px"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="px"/>
|
||||
<box>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.4" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
</jr:columnHeader>
|
||||
<jr:detailCell height="18">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="px"/>
|
||||
<box>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<textField isBlankWhenNull="true">
|
||||
<reportElement x="0" y="0" width="20" height="18" uuid="c20bd145-2589-4e34-acd8-c52ecb01f627"/>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$V{COLUMN_COUNT}]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
<jr:column width="150" uuid="e296f490-d79c-4dc7-b064-4df5beea7f6a">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column2"/>
|
||||
<jr:columnHeader height="18" rowSpan="1">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="px"/>
|
||||
<box>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.4" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="150" height="18" uuid="2cf4018d-7073-47cd-ba69-6239dea208d5"/>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9" isBold="true"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[项目名称]]></text>
|
||||
</staticText>
|
||||
</jr:columnHeader>
|
||||
<jr:detailCell height="18">
|
||||
<box>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="0" y="0" width="150" height="18" uuid="6d5dabce-2317-4d34-b286-b035b0319c86"/>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$F{serviceName}]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
<jr:column width="125" uuid="901500f5-9ff9-42de-985e-5d31c114a41c">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column3"/>
|
||||
<jr:columnHeader height="18" rowSpan="1">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="px"/>
|
||||
<box>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.4" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="125" height="18" uuid="fda635b8-de40-4302-a86e-27d94d5977cf"/>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9" isBold="true"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[协作项目名称]]></text>
|
||||
</staticText>
|
||||
</jr:columnHeader>
|
||||
<jr:detailCell height="18">
|
||||
<box>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="0" y="0" width="125" height="18" uuid="776c62d8-14e6-4bd5-9548-ecc3f933440a"/>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$F{cooperationServiceName}]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
<jr:column width="120" uuid="cf002016-6b32-41b9-ad57-b813114477bf">
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column4"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<jr:columnHeader height="18" rowSpan="1">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="px"/>
|
||||
<box>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.4" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="120" height="18" uuid="04d9aca5-e6c0-4688-b7f4-93dcf012c025"/>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9" isBold="true"/>
|
||||
<paragraph leftIndent="0"/>
|
||||
</textElement>
|
||||
<text><![CDATA[协作门店]]></text>
|
||||
</staticText>
|
||||
</jr:columnHeader>
|
||||
<jr:detailCell height="18">
|
||||
<box>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="0" y="0" width="120" height="18" uuid="b7b12dc9-c060-47b9-8252-ad264faed596"/>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$F{cooperationOrgName}]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
<jr:column width="70" uuid="275bd3e2-9eb4-4274-8693-06306f525ed9">
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column5"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<jr:columnHeader height="18" rowSpan="1">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="px"/>
|
||||
<box>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.4" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="70" height="18" uuid="a8222aea-c4e9-47c4-9c88-4043e14b06bc"/>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9" isBold="true"/>
|
||||
<paragraph leftIndent="0" rightIndent="0"/>
|
||||
</textElement>
|
||||
<text><![CDATA[审核状态]]></text>
|
||||
</staticText>
|
||||
</jr:columnHeader>
|
||||
<jr:detailCell height="18">
|
||||
<box>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="0" y="0" width="70" height="18" uuid="afca6b83-a1d0-4752-8fdb-b977d5c29aad"/>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$F{auditStatus}.equals("0")?"未审核":"已审核"]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
<jr:column width="70" uuid="efa6775a-c855-4f28-9c4b-f2f940ca48ed">
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column6"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<jr:columnHeader height="18" rowSpan="1">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="px"/>
|
||||
<box>
|
||||
<pen lineWidth="0.4"/>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.4" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="70" height="18" uuid="bc6f3a7c-ae6f-48a8-abea-958935d8ee5c"/>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9" isBold="true"/>
|
||||
<paragraph leftIndent="0" rightIndent="0"/>
|
||||
</textElement>
|
||||
<text><![CDATA[协作成本]]></text>
|
||||
</staticText>
|
||||
</jr:columnHeader>
|
||||
<jr:detailCell height="18">
|
||||
<box>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="0" y="0" width="70" height="18" uuid="e473f232-b64b-4d97-a953-f8a62d80e2f0"/>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$F{cooperationCost}.setScale( 2, BigDecimal.ROUND_DOWN )]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
</jr:table>
|
||||
</componentElement>
|
||||
</band>
|
||||
<band height="19">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<staticText>
|
||||
<reportElement x="20" y="1" width="60" height="18" uuid="fc27cb3d-0e5d-4143-b83d-daf432fa56c8">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9" isBold="true"/>
|
||||
<paragraph leftIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[小计]]></text>
|
||||
</staticText>
|
||||
<line>
|
||||
<reportElement x="0" y="0" width="555" height="1" uuid="98b923f9-1e14-4cc5-b508-12141cefb96e">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.4" lineStyle="Solid"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="485" y="1" width="70" height="18" uuid="bac7389a-d2c8-4df5-9e2b-bd0fba391750">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9" isBold="true"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{amountAll}.setScale( 2, BigDecimal.ROUND_DOWN )]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
<band height="50">
|
||||
<staticText>
|
||||
<reportElement x="185" y="25" width="70" height="18" uuid="c9a9b702-c7eb-4be8-b07e-365064dee61f">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph firstLineIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[技师签名:]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="370" y="25" width="70" height="18" uuid="a35c01ab-c3e4-46ca-a47f-e24e82171c0e">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph firstLineIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[审核人签名:]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="0" y="25" width="70" height="18" uuid="fa883b7a-2acb-44e9-a646-e9e7c5f2aef8">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph firstLineIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[顾问签名:]]></text>
|
||||
</staticText>
|
||||
</band>
|
||||
</detail>
|
||||
</jasperReport>
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
# 协作单接口文档
|
||||
|
||||
# 协作单接口文档
|
||||
|
||||
| 字段 | 含义 | 是否必有 | 类型 |
|
||||
| --- | --- | --- | --- |
|
||||
| title | 打印抬头(门店简称) | | String |
|
||||
| billNo | 工单号 | | String |
|
||||
| creatorName | 制单人 | | String |
|
||||
| printTime | 打印时间 | | String |
|
||||
| naEmployee | 服务顾问 | | String |
|
||||
| billDate | 进厂日期 | | String |
|
||||
| deliveryTime | 交车时间(出厂时间) | | String |
|
||||
| naCustomer | 车主姓名 | | String |
|
||||
| cellPhone | 车主电话 | | String |
|
||||
| carModel | 车型 | | String |
|
||||
| carNoWhole | 车牌号 | | String |
|
||||
| vin | 车辆VIN码 | | String |
|
||||
| amountAll | 小计 | | BigDecimal |
|
||||
| serviceDetailVOList | 协作项目集合 | | List<CooperationServicePrintAttribute> |
|
||||
|
||||
## CooperationServicePrintAttribute
|
||||
|
||||
| 字段 | 含义 | 是否必有 | 类型 |
|
||||
| --- | --- | --- | --- |
|
||||
| serviceName | 工单项目名称 | | String |
|
||||
| cooperationServiceName | 协作项目名称 | | String |
|
||||
| cooperationOrgName | 协作门店 | | String |
|
||||
| auditStatus | 审核状态 | | String |
|
||||
| cooperationCost | 协作成本 | | BigDecimal |
|
||||
|
||||
> 更新: 2023-08-28 16:06:07 原文: <https://xcz.yuque.com/ombipo/rpc7ms/awq306g9g8fg78or>
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
# 增项单接口文档
|
||||
|
||||
# 增项单接口文档
|
||||
|
||||
| 字段 | 含义 | 是否必有 | 类型 |
|
||||
| --- | --- | --- | --- |
|
||||
| title | 打印抬头(门店名称+"新增项目确认单") | | String |
|
||||
| sourceBillNo | 关联工单号 | | String |
|
||||
| printTime | 打印时间 | | String |
|
||||
| naEmployee | 服务顾问 | | String |
|
||||
| arrivalTime | 进厂日期 | | String |
|
||||
| deliveryTime | 交车时间 | | String |
|
||||
| naCustomer | 车主姓名 | | String |
|
||||
| cellPhone | 车主电话 | | String |
|
||||
| repairPerson | 送修人 | | String |
|
||||
| repairPersonContact | 送修人联系方式 | | String |
|
||||
| carModel | 车型 | | String |
|
||||
| carNoWhole | 车牌号 | | String |
|
||||
| carColor | 车身颜色 | | String |
|
||||
| engineCode | 发动机号 | | String |
|
||||
| vin | 车辆VIN码 | | String |
|
||||
| mileage | 进厂里程 | | String |
|
||||
| oilCapacity | 进厂油量 | | String |
|
||||
| merchantAddress | 商家联系地址 | | String |
|
||||
| merchantTel | 商家联系方式(固定电话) | | String |
|
||||
| merchantPhone | 商家联系方式(手机) | | String |
|
||||
| workHourPriceSubtotal | 工时费(小计) | | String |
|
||||
| amountSubtotal | 材料费(小计) | | String |
|
||||
| attachedServiceVoList | 增项服务项目集合 | | List<ServicePrintAttribute> |
|
||||
| attachedStuffVoList | 增项配件材料集合 | | List<PartPrintAttribute> |
|
||||
|
||||
**ServicePrintAttribute**
|
||||
|
||||
| 字段 | 含义 | 是否必有 | 类型 |
|
||||
| --- | --- | --- | --- |
|
||||
| serviceName | 工单项目名称 | | String |
|
||||
| labelName | 业务分类名称 | | String |
|
||||
| customCode | 项目编码 | | String |
|
||||
| price | 工时单价 | | Double |
|
||||
| workHour | 工时 | | Double |
|
||||
| number | 项目数量 | | Integer |
|
||||
| discount | 折扣 | | Double |
|
||||
| discountedSubtotal | 折后金额 | | Double |
|
||||
| subtotal | 金额 | | Double |
|
||||
| serviceMemo | 项目备注 | | String |
|
||||
| isMember | 当前项目是否使用会员 | | Integer |
|
||||
| nameMember | 会员项目的来源名(如套餐代码) | | String |
|
||||
| empNameStr | 服务项目明细对应修理工名称组装字符串 | | String |
|
||||
|
||||
If you get gains,please give a like
|
||||
|
||||
**PartPrintAttribute**
|
||||
|
||||
| 字段 | 含义 | 是否必有 | 类型 |
|
||||
| --- | --- | --- | --- |
|
||||
| partName | 材料名称 | | String |
|
||||
| labelName | 业务分类名称 | | String |
|
||||
| partBrand | 配件品牌 | | String |
|
||||
| customCode | 材料编码 | | String |
|
||||
| price | 单价 | | Double |
|
||||
| number | 材料数量 | | Integer |
|
||||
| unit | 单位 | | String |
|
||||
| discount | 折扣 | | Double |
|
||||
| discountedSubtotal | 折后金额 | | Double |
|
||||
| subtotal | 金额 | | Double |
|
||||
| partMemo | 材料备注 | | String |
|
||||
| isMember | 当前项目是否使用会员 | | Integer |
|
||||
| nameMember | 会员项目的来源名(如套餐代码) | | String |
|
||||
| employeeName | 员工名称 | | String |
|
||||
| empNameStr | 材料明细对应修理工名称组装字符串 | | String |
|
||||
|
||||
> 更新: 2023-09-05 10:34:22 原文: <https://xcz.yuque.com/ombipo/rpc7ms/gpobrxn8mn5lzthk>
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
# 委托单接口文档
|
||||
|
||||
# 委托单接口文档
|
||||
|
||||
| 字段 | 含义 | 是否必有 | 类型 |
|
||||
| --- | --- | --- | --- |
|
||||
| printOrgName | 打印抬头 | | String |
|
||||
| orgName | 维修厂名称 | | String |
|
||||
| billNo | 工单号 | | String |
|
||||
| naEmployee | 服务顾问 | | String |
|
||||
| employeePhone | 服务顾问手机号 | | String |
|
||||
| naCustomer | 单位名称(客户姓名) | | String |
|
||||
| carNoWhole | 车牌号整体 = carPrefix + carNo | | String |
|
||||
| cellPhone | 联系电话(客户) | | String |
|
||||
| repairPerson | 送修人 | | String |
|
||||
| repairPersonContact | 送修人联系方式 | | String |
|
||||
| billDate | 进厂日期 | | String |
|
||||
| deliveryTime | 交车时间(出厂时间) | | String |
|
||||
| mileage | 出厂里程(进厂里程) | | BigDecimal |
|
||||
| oilCapacity | 当前油量 | | String |
|
||||
| vin | 车辆VIN码 | | String |
|
||||
| carModelShort | 车型简称 | | String |
|
||||
| signaturePhotoUrl | 签名图片 | | String |
|
||||
| orgContactNumber | 联系电话(维修厂) | | String |
|
||||
| orgDetailAddress | 联系地址(维修厂) | | String |
|
||||
| orgContactMobile | 联系电话(维修厂) | | String |
|
||||
| printContentEntrust | 委托单免责条款 | | String |
|
||||
| serviceSubtotalVip | 服务项目明细小计(会员项目) | | BigDecimal |
|
||||
| stuffSubtotalVip | 材料收入小计(会员项目) | | BigDecimal |
|
||||
| serviceSubtotalAll | 工时费小计 | | BigDecimal |
|
||||
| stuffSubtotalAll | 材料费小计 | | BigDecimal |
|
||||
| serviceList | 工单对应项目集合 | | List<ServicePrintAttribute> |
|
||||
| | | | |
|
||||
| | | | |
|
||||
| | | | |
|
||||
| | | | |
|
||||
| | | | |
|
||||
|
||||
## ServicePrintAttribute
|
||||
|
||||
| 字段 | 含义 | 是否必有 | 类型 |
|
||||
| --- | --- | --- | --- |
|
||||
| serviceName | 项目名称 | | String |
|
||||
| price | 工时单价 | | BigInteger |
|
||||
| workHour | 工时 | | BigInteger |
|
||||
| subtotal | 金额 | | BigInteger |
|
||||
| serviceMemo | 附加信息备注 | | String |
|
||||
| isMember | 当前项目是否使用会员 | | Integer |
|
||||
| empNameStr | 服务项目明细对应修理工名称组装字符串 | | String |
|
||||
| | | | |
|
||||
| | | | |
|
||||
|
||||
> 更新: 2022-11-30 15:56:54 原文: <https://xcz.yuque.com/ombipo/rpc7ms/eppwl9lml80qq2bi>
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
# 定金单打印接口文档
|
||||
|
||||
# 定金单打印接口文档
|
||||
|
||||
# 接口出参
|
||||
|
||||
| 字段 | 含义 | 类型 |
|
||||
| --- | --- | --- |
|
||||
| title | 标题(门店名称) | String |
|
||||
| abbreviation | 门店简称 | String |
|
||||
| billNO | 定金单号 | String |
|
||||
| printTime | 打印时间 | String |
|
||||
| customerName | 客户姓名 | String |
|
||||
| cellPhone | 手机号码 | String |
|
||||
| carNo | 适用车辆(顿号、隔开) | String |
|
||||
| orgName | 适用门店(顿号、隔开) | String |
|
||||
| balanceStatus | 结算状态 | String |
|
||||
| receivedAmount | 已收金额 | Double |
|
||||
| amount | 收款交易金额 | Double |
|
||||
| amountAll | 定金单收款小计 | Double |
|
||||
| preRefundBalance | 定金单退款前余额 | Double |
|
||||
| advancesReceivedBalance | 定金单收款后剩余面额 | Double |
|
||||
| memo | 定金备注 | String |
|
||||
| settlePerson | 结算人 | String |
|
||||
| employeeName | 收款人 | String |
|
||||
| businessDate | 收款时间 | String |
|
||||
| billDate | 交易时间 | String |
|
||||
| transactionDate | 交易时间 | String |
|
||||
| detailAddress | 联系地址 | String |
|
||||
| contactMobile | 联系方式(手机+固定电话) | String |
|
||||
| naServicePerson | 服务顾问 | String |
|
||||
| gatheringList | 收款方式 | List |
|
||||
| L paymentType | 支付方式 | String |
|
||||
| L amount | 金额 | BigDecimal |
|
||||
| relationServices | 适用项目列表 | List |
|
||||
| L infoId | 项目id | BigInteger |
|
||||
| L infoName | 项目名称 | String |
|
||||
| L labelName | 业务分类 | String |
|
||||
| relationParts | 适用材料列表 | List |
|
||||
| L infoId | 材料id | BigInteger |
|
||||
| L infoName | 材料名称 | String |
|
||||
| L labelName | 业务分类 | String |
|
||||
| relationCars | 适用车辆列表 | List |
|
||||
| L idCar | 车辆信息id | BigInteger |
|
||||
| L carNo | 车牌号 | String |
|
||||
| L vin | vin码 | String |
|
||||
|
||||
# 范例
|
||||
|
||||
```plaintext
|
||||
收款收款{
|
||||
"data": {
|
||||
"preRefundBalance": 20000,
|
||||
"memo": "我是备注。",
|
||||
"title": "演示主店",
|
||||
"carNo": "藏AVB2131",
|
||||
"naServicePerson": "唐铭远",
|
||||
"contactMobile": "15051779785",
|
||||
"employeeName": "刘思杰",
|
||||
"amount": 10000,
|
||||
"orgName": "演示主店测试、第一分店",
|
||||
"advancesReceivedBalance": 10000,
|
||||
"amountAll": 10000,
|
||||
"balanceStatus": "7100",
|
||||
"billDate": "2024-07-11 16:27:49",
|
||||
"businessDate": "2024-07-24 14:49:01",
|
||||
"receivedAmount": 10000,
|
||||
"abbreviation": "演示主店测试",
|
||||
"transactionDate": "2024-07-11 16:27:49",
|
||||
"relationServices": [
|
||||
{
|
||||
"infoName": "龙膜全车贴膜(不含撕膜)",
|
||||
"infoId": "10545055918005551735",
|
||||
"infoType": 1,
|
||||
"id": "239",
|
||||
"labelName": "其他",
|
||||
"idSubscription": "11159"
|
||||
}
|
||||
],
|
||||
"customerName": "牛洋",
|
||||
"gatheringList": [
|
||||
{
|
||||
"amount": 4000,
|
||||
"paymentType": "支付宝"
|
||||
},
|
||||
{
|
||||
"amount": 3000,
|
||||
"paymentType": "现金"
|
||||
},
|
||||
{
|
||||
"amount": 3000,
|
||||
"paymentType": "挂账"
|
||||
}
|
||||
],
|
||||
"detailAddress": "西藏自治区那曲市班戈县西藏自治区那曲市班戈县北拉镇邮政所",
|
||||
"billNO": "DJD20240711001",
|
||||
"cellPhone": "17625046227",
|
||||
"printTime": "2024-07-11 17:28:08",
|
||||
"relationParts": [
|
||||
{
|
||||
"infoName": "奔腾CI-4 15W40 4*4L 胜牌 (706650)",
|
||||
"infoId": "10545055918005692400",
|
||||
"infoType": 2,
|
||||
"id": "240",
|
||||
"labelName": "业务分类测试",
|
||||
"idSubscription": "11159"
|
||||
}
|
||||
],
|
||||
"relationCars": [
|
||||
{
|
||||
"carNo": "AV616E",
|
||||
"vin": "LSVAA49J132047371",
|
||||
"idCar": 15809106713748983890
|
||||
}
|
||||
],
|
||||
},
|
||||
"storeId": 4060685614487994527,
|
||||
"tempId": 41
|
||||
}
|
||||
```
|
||||
> 更新: 2024-07-25 20:54:41 原文: <https://xcz.yuque.com/ombipo/rpc7ms/io3q0kkop242geg6>
|
||||
+942
@@ -0,0 +1,942 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Created with Jaspersoft Studio version 6.3.1.final using JasperReports Library version 6.3.1 -->
|
||||
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="dingjin" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="ecb495fd-dade-4203-bf0d-1beb50748cbb">
|
||||
<property name="com.jaspersoft.studio.data.defaultdataadapter" value="One Empty Record"/>
|
||||
<subDataset name="Bean" uuid="c4b2280f-9d97-43a6-af41-df8e4c3837f1">
|
||||
<queryString>
|
||||
<![CDATA[]]>
|
||||
</queryString>
|
||||
<field name="index" class="java.lang.String"/>
|
||||
<field name="paymentType" class="java.lang.String"/>
|
||||
<field name="amount" class="java.math.BigDecimal"/>
|
||||
</subDataset>
|
||||
<subDataset name="SubscriptionInfoRelationBean" uuid="63a5d0a7-7ac9-4e14-b3f3-d03138dc8910">
|
||||
<property name="com.jaspersoft.studio.data.defaultdataadapter" value="One Empty Record"/>
|
||||
<queryString>
|
||||
<![CDATA[]]>
|
||||
</queryString>
|
||||
<field name="infoName" class="java.lang.String"/>
|
||||
<field name="labelName" class="java.lang.String"/>
|
||||
</subDataset>
|
||||
<parameter name="title" class="java.lang.String"/>
|
||||
<parameter name="billNO" class="java.lang.String"/>
|
||||
<parameter name="printTime" class="java.lang.String"/>
|
||||
<parameter name="customerName" class="java.lang.String"/>
|
||||
<parameter name="cellPhone" class="java.lang.String"/>
|
||||
<parameter name="carNo" class="java.lang.String"/>
|
||||
<parameter name="orgName" class="java.lang.String"/>
|
||||
<parameter name="amountAll" class="java.math.BigDecimal"/>
|
||||
<parameter name="memo" class="java.lang.String"/>
|
||||
<parameter name="settlePerson" class="java.lang.String"/>
|
||||
<parameter name="employeeName" class="java.lang.String"/>
|
||||
<parameter name="billDate" class="java.lang.String"/>
|
||||
<parameter name="detailAddress" class="java.lang.String"/>
|
||||
<parameter name="contactMobile" class="java.lang.String"/>
|
||||
<parameter name="gatheringList" class="net.sf.jasperreports.engine.data.JRMapCollectionDataSource"/>
|
||||
<parameter name="transactionDate" class="java.lang.String"/>
|
||||
<parameter name="naServicePerson" class="java.lang.String"/>
|
||||
<parameter name="relationServices" class="net.sf.jasperreports.engine.data.JRMapCollectionDataSource"/>
|
||||
<parameter name="relationParts" class="net.sf.jasperreports.engine.data.JRMapCollectionDataSource"/>
|
||||
<parameter name="balanceStatus" class="java.lang.String">
|
||||
<parameterDescription><![CDATA[]]></parameterDescription>
|
||||
</parameter>
|
||||
<queryString>
|
||||
<![CDATA[]]>
|
||||
</queryString>
|
||||
<detail>
|
||||
<band height="103" splitType="Stretch">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="0" y="1" width="555" height="30" uuid="6b893528-b46e-4a7d-b95d-62163a92812c">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="16"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{title}!=null?$P{title} + "定金收款单":""]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement x="0" y="40" width="50" height="18" uuid="df2d5fff-f94e-48ce-8327-d04b0ed8a8eb">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9" isBold="true"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[定金单号:]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="405" y="40" width="50" height="18" uuid="6100aced-372a-4449-91cf-1b49465ddce1">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[打印时间:]]></text>
|
||||
</staticText>
|
||||
<line>
|
||||
<reportElement x="0" y="68" width="555" height="1" uuid="6820699a-64e5-4110-aab9-059fcfa04956">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.5" lineStyle="Solid"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
<staticText>
|
||||
<reportElement x="0" y="68" width="50" height="15" uuid="2d6a570f-5cff-411e-a42d-5f3833a49674">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[客户姓名]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="150" y="68" width="50" height="15" uuid="e25f93dc-e5d5-4f43-bd78-20bbd337df95">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[手机号码]]></text>
|
||||
</staticText>
|
||||
<textField isBlankWhenNull="true">
|
||||
<reportElement x="50" y="68" width="100" height="15" uuid="ae838d08-7ea2-4a9f-9bcb-ad039eea0139">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{customerName}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isBlankWhenNull="true">
|
||||
<reportElement x="200" y="68" width="100" height="15" uuid="f1280a32-7f86-45b7-b15e-e16b88db6f69">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{cellPhone}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isBlankWhenNull="true">
|
||||
<reportElement x="50" y="40" width="100" height="18" uuid="f86834e1-12c3-4f52-ab27-921980da0a86">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{billNO}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isBlankWhenNull="true">
|
||||
<reportElement x="455" y="40" width="100" height="18" uuid="f01ca83f-cc02-4c16-8edf-1ef24a479592">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{printTime}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isBlankWhenNull="true">
|
||||
<reportElement x="300" y="69" width="150" height="15" uuid="28fd8ca7-cd61-45c9-a5de-ecf081f3623c">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{naServicePerson} != null ? "服务顾问 " + $P{naServicePerson} : null]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
<band height="15">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="50" y="0" width="505" height="15" isPrintWhenDetailOverflows="true" uuid="bc87056d-ec39-4fa8-bc1b-cf2475f0b712">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<box bottomPadding="1"/>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{carNo}!=null?$P{carNo}:""]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="50" height="15" uuid="be24a675-674a-4e69-904f-462adddebdf2">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[限定车辆]]></text>
|
||||
</staticText>
|
||||
<line>
|
||||
<reportElement x="0" y="0" width="555" height="1" uuid="e0b7e65f-b9cd-4f1d-9896-f7b35076c20f">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.5" lineStyle="Dashed"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
</band>
|
||||
<band height="15">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="50" height="15" uuid="c951994c-2dc6-4a82-835e-9c132409edd0">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[适用门店]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="50" y="0" width="505" height="15" isPrintWhenDetailOverflows="true" uuid="6450a724-3257-45c0-b5ac-d970e2608683">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<box bottomPadding="1"/>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{orgName}!=null?$P{orgName}:""]]></textFieldExpression>
|
||||
</textField>
|
||||
<line>
|
||||
<reportElement x="0" y="0" width="555" height="1" uuid="95190ceb-a559-4b6b-99ed-4d92568db2ce">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.5" lineStyle="Dashed"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
</band>
|
||||
<band height="15">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<textField isBlankWhenNull="true">
|
||||
<reportElement x="50" y="0" width="505" height="15" uuid="73423a33-419c-424a-bf28-1f278c95f6de">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{amountAll}.setScale( 2, BigDecimal.ROUND_DOWN )]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="50" height="15" uuid="bbfe6557-435b-4a06-89e7-68f5fa5f866e">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[定金金额]]></text>
|
||||
</staticText>
|
||||
<line>
|
||||
<reportElement x="0" y="0" width="555" height="1" uuid="34772527-56ed-496e-83e8-638d8f87a7d4">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.5" lineStyle="Dashed"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
</band>
|
||||
<band height="18">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<staticText>
|
||||
<reportElement stretchType="ContainerBottom" x="0" y="0" width="50" height="15" isRemoveLineWhenBlank="true" uuid="31b57e69-4dea-4593-84c4-5f6e5d7c5cad">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[定金备注]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement stretchType="ContainerBottom" x="50" y="0" width="505" height="15" isRemoveLineWhenBlank="true" isPrintWhenDetailOverflows="true" uuid="d8c6dc34-aedb-46ab-ab17-1b75d37cee18">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{memo}]]></textFieldExpression>
|
||||
</textField>
|
||||
<line>
|
||||
<reportElement x="0" y="0" width="555" height="1" uuid="024b26b4-5ca0-4d1a-a713-2b1a04e4facb">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.5" lineStyle="Dashed"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
</band>
|
||||
<band height="6">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$P{relationServices} != null]]></printWhenExpression>
|
||||
<line>
|
||||
<reportElement x="0" y="5" width="555" height="1" uuid="3286a86a-5ca6-42c8-8302-9412dd51255b">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.5" lineStyle="Solid"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
<line>
|
||||
<reportElement x="0" y="2" width="555" height="1" uuid="6e4f8003-b171-43ba-b3d1-1e863feaa14f">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.5" lineStyle="Dashed"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
</band>
|
||||
<band height="62">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$P{relationServices} != null]]></printWhenExpression>
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="555" height="18" uuid="186a3a0f-9415-48af-8fc5-f0b91f01c8dd">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9" isBold="true"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[限定项目条件]]></text>
|
||||
</staticText>
|
||||
<line>
|
||||
<reportElement x="0" y="18" width="555" height="1" uuid="784988f1-bab7-4893-b7b0-45b8c7d36113">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.5" lineStyle="Dashed"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
<staticText>
|
||||
<reportElement x="10" y="21" width="40" height="18" uuid="3581da6d-7736-4324-8d00-46a8101328b8">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[序号]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="60" y="21" width="260" height="18" uuid="729944a0-c591-4d3c-bd82-10852a27ddb5">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[项目名称]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="340" y="21" width="215" height="18" uuid="91d16827-3716-49bf-9589-fef01692e051">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[业务分类]]></text>
|
||||
</staticText>
|
||||
<componentElement>
|
||||
<reportElement x="10" y="43" width="530" height="15" uuid="70e14cdb-d3db-4143-a95b-06c79be594e9">
|
||||
<property name="com.jaspersoft.studio.layout" value="com.jaspersoft.studio.editor.layout.VerticalRowLayout"/>
|
||||
<property name="com.jaspersoft.studio.table.style.table_header" value="Table_TH"/>
|
||||
<property name="com.jaspersoft.studio.table.style.column_header" value="Table_CH"/>
|
||||
<property name="com.jaspersoft.studio.table.style.detail" value="Table_TD"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="net.sf.jasperreports.export.headertoolbar.table.name" value=""/>
|
||||
</reportElement>
|
||||
<jr:table xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd">
|
||||
<datasetRun subDataset="SubscriptionInfoRelationBean" uuid="65597dd8-2b18-4b8f-af59-9a14a8c656f9">
|
||||
<dataSourceExpression><![CDATA[$P{relationServices}]]></dataSourceExpression>
|
||||
</datasetRun>
|
||||
<jr:column width="20" uuid="9f5cb566-9a81-471e-83b7-eed0ae9a15cc">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column1"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<jr:detailCell height="15">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="px"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="px"/>
|
||||
<textField isBlankWhenNull="true">
|
||||
<reportElement x="0" y="0" width="20" height="15" uuid="5b2a2317-f511-4c5b-8146-7422aa7bb656"/>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$V{REPORT_COUNT}]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
<jr:column width="299" uuid="50b00464-f90b-4b48-8dc9-3d06ac503250">
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column2"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<jr:detailCell height="15">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="px"/>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement stretchType="RelativeToBandHeight" x="0" y="0" width="299" height="15" uuid="4d201729-3ee9-42c2-b659-49966309bb6a">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph lineSpacing="Single" leftIndent="33"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$F{infoName}]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
<jr:column width="211" uuid="9589926e-9fb0-432d-a202-7701e2654ee5">
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column3"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<jr:detailCell height="15">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="px"/>
|
||||
<textField isBlankWhenNull="true">
|
||||
<reportElement x="0" y="0" width="211" height="15" uuid="41413b43-582e-4a5e-9025-bbe735caf9f7">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Right" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph rightIndent="170"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$F{labelName}]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
</jr:table>
|
||||
</componentElement>
|
||||
</band>
|
||||
<band height="6">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$P{relationParts} != null]]></printWhenExpression>
|
||||
<line>
|
||||
<reportElement x="0" y="4" width="555" height="1" uuid="2f6ac67a-48f3-4ead-a04d-dc0a5ee9ec77">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.5" lineStyle="Solid"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
</band>
|
||||
<band height="59">
|
||||
<printWhenExpression><![CDATA[$P{relationParts} != null]]></printWhenExpression>
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="555" height="18" uuid="0cf72aee-23b8-46aa-a29f-cf3f3b5f60fa">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9" isBold="true"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[限定材料条件]]></text>
|
||||
</staticText>
|
||||
<line>
|
||||
<reportElement x="0" y="18" width="555" height="1" uuid="55b86547-d6ca-42e0-854e-2e08893a2b5f">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.5" lineStyle="Dashed"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
<staticText>
|
||||
<reportElement x="10" y="20" width="40" height="18" uuid="91997de4-2512-47f0-ab50-a9611a851818">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[序号]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="60" y="20" width="260" height="18" uuid="821e871f-4d45-4c6e-a153-bdb11222edfd">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[材料名称]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="340" y="20" width="215" height="18" uuid="cb6c5a3e-3605-4451-b6e6-57bbd3b20aaa">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[业务分类]]></text>
|
||||
</staticText>
|
||||
<componentElement>
|
||||
<reportElement x="10" y="40" width="530" height="15" uuid="d9989d91-ae8e-494b-99ae-e466e8480b93">
|
||||
<property name="com.jaspersoft.studio.layout" value="com.jaspersoft.studio.editor.layout.VerticalRowLayout"/>
|
||||
<property name="com.jaspersoft.studio.table.style.table_header" value="Table_TH"/>
|
||||
<property name="com.jaspersoft.studio.table.style.column_header" value="Table_CH"/>
|
||||
<property name="com.jaspersoft.studio.table.style.detail" value="Table_TD"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<jr:table xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd">
|
||||
<datasetRun subDataset="SubscriptionInfoRelationBean" uuid="2250db78-4f45-464b-afac-5c1fbe1c526a">
|
||||
<dataSourceExpression><![CDATA[$P{relationParts}]]></dataSourceExpression>
|
||||
</datasetRun>
|
||||
<jr:column width="20" uuid="a3a9ba5c-d15d-45a0-9529-905dd13d1bb3">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column1"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<jr:detailCell height="15">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="px"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="px"/>
|
||||
<textField isBlankWhenNull="true">
|
||||
<reportElement x="0" y="0" width="20" height="15" uuid="80a4d1e9-c964-49e0-9165-e83d7f53c955"/>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$V{REPORT_COUNT}]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
<jr:column width="299" uuid="5b5b73ee-6e45-440c-abcc-c47295a8f445">
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column2"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<jr:detailCell height="15">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="px"/>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement stretchType="RelativeToBandHeight" x="0" y="0" width="299" height="15" uuid="f344b148-d0c4-4f7e-9b21-1a350e385f04">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph lineSpacing="Single" leftIndent="33"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$F{infoName}]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
<jr:column width="211" uuid="bc6a0624-08f4-4831-b786-d96ecbad358f">
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column3"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<jr:detailCell height="15">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="px"/>
|
||||
<textField isBlankWhenNull="true">
|
||||
<reportElement x="0" y="0" width="211" height="15" uuid="43282bdc-4735-4173-b9be-1e34a4c7ecf1">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Right" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph rightIndent="170"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$F{labelName}]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
</jr:table>
|
||||
</componentElement>
|
||||
</band>
|
||||
<band height="6">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<line>
|
||||
<reportElement x="0" y="4" width="555" height="1" uuid="6020511d-2f28-4dc2-80f1-9176d218b3be">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.5" lineStyle="Solid"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
</band>
|
||||
<band height="19">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<printWhenExpression><![CDATA["7100".equals($P{balanceStatus})]]></printWhenExpression>
|
||||
<staticText>
|
||||
<reportElement x="20" y="0" width="50" height="18" uuid="3581da6d-7736-4324-8d00-46a8101328b8">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9" isBold="true"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[收款方式]]></text>
|
||||
</staticText>
|
||||
<line>
|
||||
<reportElement x="0" y="18" width="555" height="1" uuid="784988f1-bab7-4893-b7b0-45b8c7d36113">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.5" lineStyle="Solid"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
<staticText>
|
||||
<reportElement x="455" y="0" width="75" height="18" uuid="e5017d0f-3946-4dd0-8cdd-cc01396607c0">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Right" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9" isBold="true"/>
|
||||
<paragraph leftIndent="0" rightIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[金额]]></text>
|
||||
</staticText>
|
||||
</band>
|
||||
<band height="15">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<printWhenExpression><![CDATA["7100".equals($P{balanceStatus})]]></printWhenExpression>
|
||||
<componentElement>
|
||||
<reportElement x="0" y="0" width="530" height="15" uuid="e508f855-fa78-4d64-a6e4-a8a8a46aca77">
|
||||
<property name="com.jaspersoft.studio.layout" value="com.jaspersoft.studio.editor.layout.VerticalRowLayout"/>
|
||||
<property name="com.jaspersoft.studio.table.style.table_header" value="Table_TH"/>
|
||||
<property name="com.jaspersoft.studio.table.style.column_header" value="Table_CH"/>
|
||||
<property name="com.jaspersoft.studio.table.style.detail" value="Table_TD"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<jr:table xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd">
|
||||
<datasetRun subDataset="Bean" uuid="b65bc3e9-f219-4cb4-9e37-06389e44b27a">
|
||||
<dataSourceExpression><![CDATA[$P{gatheringList}]]></dataSourceExpression>
|
||||
</datasetRun>
|
||||
<jr:column width="20" uuid="ee067303-224b-4228-9945-59b00d0f5cab">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column1"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<jr:detailCell height="15">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="px"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="px"/>
|
||||
<textField isBlankWhenNull="true">
|
||||
<reportElement x="0" y="0" width="20" height="15" uuid="69411085-ae93-4494-a5be-5f1c08c669e6"/>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$V{REPORT_COUNT}]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
<jr:column width="435" uuid="c73b03e1-b451-4ba7-aa66-506770b0d16b">
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column2"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<jr:detailCell height="15">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="px"/>
|
||||
<textField isBlankWhenNull="true">
|
||||
<reportElement x="0" y="0" width="435" height="15" uuid="513d0744-5c1a-4cbc-9ab0-a494b491c01f"/>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$F{paymentType}]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
<jr:column width="75" uuid="e1f4c79b-33e8-46e3-8d01-2405584f90dc">
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column3"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<jr:detailCell height="15">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="px"/>
|
||||
<textField isBlankWhenNull="true">
|
||||
<reportElement x="0" y="0" width="75" height="15" uuid="41c011f0-5a98-40a5-96c5-27cad152cd7b"/>
|
||||
<textElement textAlignment="Right" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph rightIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$F{amount}.setScale( 2, BigDecimal.ROUND_DOWN )]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
</jr:table>
|
||||
</componentElement>
|
||||
</band>
|
||||
<band height="15">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<printWhenExpression><![CDATA["7100".equals($P{balanceStatus})]]></printWhenExpression>
|
||||
<line>
|
||||
<reportElement x="0" y="0" width="555" height="1" uuid="125ba998-bf5b-433a-9954-6043f153ff42">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.5" lineStyle="Solid"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
<staticText>
|
||||
<reportElement x="20" y="0" width="50" height="15" uuid="f6849ec7-9e15-47e5-b71e-dcd53f0b84e0">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[小计]]></text>
|
||||
</staticText>
|
||||
<textField isBlankWhenNull="true">
|
||||
<reportElement x="455" y="0" width="75" height="15" uuid="6fc715c5-3a85-4a39-8b51-ff75731aba06">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Right" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="0" rightIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{amountAll}.setScale( 2, BigDecimal.ROUND_DOWN )]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
<band height="25">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<printWhenExpression><![CDATA["7100".equals($P{balanceStatus})]]></printWhenExpression>
|
||||
<staticText>
|
||||
<reportElement x="0" y="10" width="50" height="15" uuid="97da61eb-2f1d-46a4-8ed4-c3172d371408">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[结算人:]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="200" y="10" width="50" height="15" uuid="319ada1b-ff86-4b3c-82d6-15bc9981b1d9">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[收款人:]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="405" y="10" width="50" height="15" uuid="01e213a0-948f-4a51-9b39-f3da64729c60">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[收款时间:]]></text>
|
||||
</staticText>
|
||||
<textField isBlankWhenNull="true">
|
||||
<reportElement x="50" y="10" width="100" height="15" uuid="92b95e36-c1a5-4311-94db-f615b29958f1">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{employeeName}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isBlankWhenNull="true">
|
||||
<reportElement x="250" y="10" width="100" height="15" uuid="389f723a-1618-48f7-8e25-890a4902b19b">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{employeeName}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isBlankWhenNull="true">
|
||||
<reportElement x="455" y="10" width="100" height="15" uuid="d8abcebc-b5b3-4c86-89b2-b45c218f353e">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{billDate}]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
<band height="109">
|
||||
<staticText>
|
||||
<reportElement x="0" y="25" width="50" height="15" uuid="55ff22be-c6bb-4bbb-bb41-8cefc91675e0">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[办理人签名]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="300" y="25" width="50" height="15" uuid="ff44db31-a42f-477e-9e52-378b94c34217">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[客户签名]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="0" y="55" width="50" height="15" uuid="9afa1f35-7bf2-4b9b-aa4d-9989db266bd5">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[联系地址:]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="0" y="70" width="50" height="15" uuid="a439d4d9-7268-40cb-8f44-41c75c328179">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[联系方式:]]></text>
|
||||
</staticText>
|
||||
<textField isBlankWhenNull="true">
|
||||
<reportElement x="50" y="55" width="505" height="15" uuid="0fd29c3e-c04b-4552-85b0-55b2720d57df">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{detailAddress}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isBlankWhenNull="true">
|
||||
<reportElement x="50" y="70" width="505" height="15" uuid="421732bc-d6d4-4f97-8480-565eaa109ffc">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{contactMobile}.split(" ")[1].length() == 5 ? $P{contactMobile}.split(" ")[0] : $P{contactMobile}]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
</detail>
|
||||
</jasperReport>
|
||||
+641
@@ -0,0 +1,641 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Created with Jaspersoft Studio version 6.3.1.final using JasperReports Library version 6.3.1 -->
|
||||
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="Blank_A4" pageWidth="223" pageHeight="842" whenNoDataType="NoPages" columnWidth="223" leftMargin="0" rightMargin="0" topMargin="0" bottomMargin="0" uuid="5195ed21-e8c1-4daf-ab55-5f5dc9c07b0a">
|
||||
<property name="com.jaspersoft.studio.unit." value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.topMargin" value="mm"/>
|
||||
<property name="com.jaspersoft.studio.unit.bottomMargin" value="mm"/>
|
||||
<property name="com.jaspersoft.studio.unit.leftMargin" value="mm"/>
|
||||
<property name="com.jaspersoft.studio.unit.rightMargin" value="mm"/>
|
||||
<property name="com.jaspersoft.studio.data.defaultdataadapter" value="One Empty Record"/>
|
||||
<property name="com.jaspersoft.studio.unit.pageWidth" value="mm"/>
|
||||
<property name="ireport.zoom" value="1.0"/>
|
||||
<property name="ireport.x" value="0"/>
|
||||
<property name="ireport.y" value="0"/>
|
||||
<subDataset name="Dataset1" uuid="7e6cf9c7-d927-4f84-a0f6-e84863998e11">
|
||||
<property name="com.jaspersoft.studio.data.defaultdataadapter" value="One Empty Record"/>
|
||||
<queryString>
|
||||
<![CDATA[]]>
|
||||
</queryString>
|
||||
<field name="paymentType" class="java.lang.String"/>
|
||||
<field name="amount" class="java.math.BigDecimal"/>
|
||||
</subDataset>
|
||||
<subDataset name="SubscriptionInfoRelationBean" uuid="63b98521-dd7d-419f-bae4-f6a776630dd5">
|
||||
<property name="com.jaspersoft.studio.data.defaultdataadapter" value="One Empty Record"/>
|
||||
<queryString>
|
||||
<![CDATA[]]>
|
||||
</queryString>
|
||||
<field name="infoName" class="java.lang.String"/>
|
||||
<field name="labelName" class="java.lang.String"/>
|
||||
</subDataset>
|
||||
<parameter name="title" class="java.lang.String"/>
|
||||
<parameter name="abbreviation" class="java.lang.String"/>
|
||||
<parameter name="billNO" class="java.lang.String"/>
|
||||
<parameter name="printTime" class="java.lang.String"/>
|
||||
<parameter name="customerName" class="java.lang.String"/>
|
||||
<parameter name="cellPhone" class="java.lang.String"/>
|
||||
<parameter name="carNo" class="java.lang.String"/>
|
||||
<parameter name="orgName" class="java.lang.String"/>
|
||||
<parameter name="amountAll" class="java.math.BigDecimal"/>
|
||||
<parameter name="memo" class="java.lang.String"/>
|
||||
<parameter name="settlePerson" class="java.lang.String"/>
|
||||
<parameter name="employeeName" class="java.lang.String"/>
|
||||
<parameter name="billDate" class="java.lang.String"/>
|
||||
<parameter name="detailAddress" class="java.lang.String"/>
|
||||
<parameter name="contactMobile" class="java.lang.String"/>
|
||||
<parameter name="gatheringList" class="net.sf.jasperreports.engine.data.JRMapCollectionDataSource"/>
|
||||
<parameter name="transactionDate" class="java.lang.String"/>
|
||||
<parameter name="naServicePerson" class="java.lang.String"/>
|
||||
<parameter name="relationServices" class="net.sf.jasperreports.engine.data.JRMapCollectionDataSource"/>
|
||||
<parameter name="relationParts" class="net.sf.jasperreports.engine.data.JRMapCollectionDataSource"/>
|
||||
<parameter name="balanceStatus" class="java.lang.String"/>
|
||||
<queryString>
|
||||
<![CDATA[]]>
|
||||
</queryString>
|
||||
<detail>
|
||||
<band height="20" splitType="Stretch">
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="0" y="0" width="222" height="20" isPrintWhenDetailOverflows="true" uuid="fdd7c75d-7f0c-42a3-afa1-9927522a4dd1">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="true"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{title}]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
<band height="22">
|
||||
<staticText>
|
||||
<reportElement x="0" y="1" width="222" height="15" uuid="2f71d4ac-e294-4763-a1ad-8e24fcb09055">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体"/>
|
||||
</textElement>
|
||||
<text><![CDATA[定金单]]></text>
|
||||
</staticText>
|
||||
<line>
|
||||
<reportElement x="15" y="16" width="195" height="1" uuid="1fac1b83-9a99-4059-94f8-705f03630c06">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.5" lineStyle="Dashed"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
</band>
|
||||
<band height="12">
|
||||
<printWhenExpression><![CDATA["7100".equals($P{balanceStatus})]]></printWhenExpression>
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="44" height="12" uuid="8210a1bf-fb5f-465d-8e13-15ee265db665">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[收款时间]]></text>
|
||||
</staticText>
|
||||
<textField isBlankWhenNull="true">
|
||||
<reportElement x="44" y="0" width="177" height="12" uuid="e79b3ef6-3727-46d0-8de1-035b71f358f4">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="15"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{transactionDate}]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
<band height="12">
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="44" height="12" uuid="924e0a29-acb7-4430-98fd-0dd08bf26d01">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[单号]]></text>
|
||||
</staticText>
|
||||
<textField isBlankWhenNull="true">
|
||||
<reportElement x="44" y="0" width="177" height="12" uuid="35315081-9a78-4f78-8df5-5ad786dd56b9">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="15"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{billNO}]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
<band height="12">
|
||||
<printWhenExpression><![CDATA["7100".equals($P{balanceStatus})]]></printWhenExpression>
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="44" height="12" uuid="af0870ec-d979-4c13-8743-c7a0c3621815">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[收款人]]></text>
|
||||
</staticText>
|
||||
<textField isBlankWhenNull="true">
|
||||
<reportElement x="44" y="0" width="177" height="12" uuid="3b66f5f5-f6d9-4d05-90e7-af9561373bb6">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="15"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{employeeName}]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
<band height="12">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$P{naServicePerson}!=null]]></printWhenExpression>
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="44" height="12" uuid="ccdb57d5-cdaf-4189-930f-fc1165c936ee">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[服务顾问]]></text>
|
||||
</staticText>
|
||||
<textField isBlankWhenNull="true">
|
||||
<reportElement x="44" y="-1" width="177" height="12" uuid="62146321-e5d6-4c36-b91c-db8c0a5653de">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体"/>
|
||||
<paragraph leftIndent="15"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{naServicePerson}]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
<band height="24">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<staticText>
|
||||
<reportElement x="0" y="-1" width="44" height="12" uuid="53391abc-4be2-40a8-8c2d-a770e6c13f18">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[车主姓名]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="0" y="11" width="44" height="12" uuid="e3b541a2-001d-4a3c-b67d-c687f923f78e">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[车主电话]]></text>
|
||||
</staticText>
|
||||
<textField isBlankWhenNull="true">
|
||||
<reportElement x="44" y="0" width="177" height="12" uuid="7f7dfe97-543c-4dae-8af6-d7113d7a438e">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="15"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{customerName}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="44" y="11" width="177" height="12" isPrintWhenDetailOverflows="true" uuid="b8c5fc03-800c-4e05-bfe1-e47ec4dfbcb8">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="15"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{cellPhone}]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
<band height="12">
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="44" height="12" uuid="92f7d079-701e-433b-80f4-54b2bffec66c">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[适用门店]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="44" y="0" width="177" height="12" isPrintWhenDetailOverflows="true" uuid="0e37d554-d28f-405d-8f0a-ea70b390ee9d">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="15"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{orgName}!=null?$P{orgName}:""]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
<band height="12">
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="44" height="12" uuid="a58d2826-ecce-4305-a937-880861b60320">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[限定车辆]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="44" y="0" width="177" height="12" isPrintWhenDetailOverflows="true" uuid="fb93e076-c62e-40f1-ad63-412181861bbb">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="15"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{carNo}!=null?$P{carNo}:""]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
<band height="12">
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="33" height="12" uuid="3776a7e6-1f34-4e6e-b685-28ea1beb953f">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[备注:]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="33" y="0" width="188" height="12" isPrintWhenDetailOverflows="true" uuid="49649536-e37f-4a5c-8fbf-35e71314c888"/>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="5"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{memo}]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
<band height="6">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$P{relationServices} != null]]></printWhenExpression>
|
||||
<line>
|
||||
<reportElement x="5" y="4" width="202" height="1" uuid="d13f3282-835d-4a3f-bfaf-de1bc0f02c6f">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.5" lineStyle="Solid"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
</band>
|
||||
<band height="42">
|
||||
<printWhenExpression><![CDATA[$P{relationServices} != null]]></printWhenExpression>
|
||||
<staticText>
|
||||
<reportElement x="5" y="6" width="64" height="12" uuid="b46dad1a-e4e2-4cbb-8078-8fadef5c2421">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[限定项目条件]]></text>
|
||||
</staticText>
|
||||
<componentElement>
|
||||
<reportElement x="12" y="21" width="200" height="12" uuid="7544bbec-c542-4d41-ae3c-a434b41bfc67">
|
||||
<property name="com.jaspersoft.studio.layout" value="com.jaspersoft.studio.editor.layout.VerticalRowLayout"/>
|
||||
<property name="com.jaspersoft.studio.table.style.table_header" value="Table_TH"/>
|
||||
<property name="com.jaspersoft.studio.table.style.column_header" value="Table_CH"/>
|
||||
<property name="com.jaspersoft.studio.table.style.detail" value="Table_TD"/>
|
||||
<property name="net.sf.jasperreports.export.headertoolbar.table.name" value=""/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<jr:table xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd" whenNoDataType="Blank">
|
||||
<datasetRun subDataset="SubscriptionInfoRelationBean" uuid="0c7af790-dee9-440a-9406-7ca725234db3">
|
||||
<dataSourceExpression><![CDATA[$P{relationServices}]]></dataSourceExpression>
|
||||
</datasetRun>
|
||||
<jr:column width="130" uuid="854655c8-8e29-4621-8d50-301a091b089c">
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column1"/>
|
||||
<jr:detailCell height="12">
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement stretchType="RelativeToBandHeight" x="0" y="0" width="130" height="12" uuid="17589590-fe21-4b4b-ac94-6c89446150af"/>
|
||||
<textElement>
|
||||
<font fontName="黑体"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$F{infoName}]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
<jr:column width="70" uuid="4a3d6479-0f51-4e1b-8499-f5e408b62814">
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column2"/>
|
||||
<jr:detailCell height="12">
|
||||
<textField isBlankWhenNull="true">
|
||||
<reportElement x="0" y="0" width="70" height="12" uuid="948b7821-5590-4c82-a0ba-540f0c14ea99"/>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体"/>
|
||||
<paragraph leftIndent="23"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$F{labelName}]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
</jr:table>
|
||||
</componentElement>
|
||||
</band>
|
||||
<band height="10">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$P{relationParts} != null]]></printWhenExpression>
|
||||
<line>
|
||||
<reportElement x="5" y="4" width="202" height="1" uuid="8e4022d7-288e-46d5-9e8b-322f809389b5">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.5" lineStyle="Solid"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
</band>
|
||||
<band height="42">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$P{relationParts} != null]]></printWhenExpression>
|
||||
<staticText>
|
||||
<reportElement x="5" y="6" width="64" height="12" uuid="3eb5fc85-6d1a-4e66-a6bb-90ffab0419bf">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[限定材料条件]]></text>
|
||||
</staticText>
|
||||
<componentElement>
|
||||
<reportElement x="12" y="21" width="200" height="12" uuid="0e8c9514-c83d-46bb-a398-df11b50450b3">
|
||||
<property name="com.jaspersoft.studio.layout" value="com.jaspersoft.studio.editor.layout.VerticalRowLayout"/>
|
||||
<property name="com.jaspersoft.studio.table.style.table_header" value="Table_TH"/>
|
||||
<property name="com.jaspersoft.studio.table.style.column_header" value="Table_CH"/>
|
||||
<property name="com.jaspersoft.studio.table.style.detail" value="Table_TD"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<jr:table xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd" whenNoDataType="Blank">
|
||||
<datasetRun subDataset="SubscriptionInfoRelationBean" uuid="a7ec5475-0753-496e-ba0c-821200ca3b09">
|
||||
<dataSourceExpression><![CDATA[$P{relationParts}]]></dataSourceExpression>
|
||||
</datasetRun>
|
||||
<jr:column width="130" uuid="521fa5b3-9477-4345-a4f1-22b89cd526b4">
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column1"/>
|
||||
<jr:detailCell height="12">
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement stretchType="RelativeToBandHeight" x="0" y="0" width="130" height="12" uuid="00aa7b2c-66f5-4b2a-86ef-e353042a169e"/>
|
||||
<textElement>
|
||||
<font fontName="黑体"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$F{infoName}]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
<jr:column width="70" uuid="7d0f5ffc-76f9-4f63-9218-1af7cb5a5fbd">
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column2"/>
|
||||
<jr:detailCell height="12">
|
||||
<textField isBlankWhenNull="true">
|
||||
<reportElement x="0" y="0" width="70" height="12" uuid="006c2c0f-2b11-4379-964b-6b7769307ee7"/>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体"/>
|
||||
<paragraph leftIndent="23"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$F{labelName}]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
</jr:table>
|
||||
</componentElement>
|
||||
</band>
|
||||
<band height="6">
|
||||
<line>
|
||||
<reportElement x="5" y="4" width="202" height="1" uuid="394e187e-5449-424f-807c-bb0c62e2d18d">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.5" lineStyle="Solid"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
</band>
|
||||
<band height="29">
|
||||
<textField isBlankWhenNull="true">
|
||||
<reportElement x="130" y="5" width="70" height="12" uuid="3d050094-7d49-4e3f-bca4-47d99321ed82">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{amountAll}.setScale( 2, BigDecimal.ROUND_DOWN )]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement x="0" y="5" width="130" height="12" uuid="4e9ec6ff-a558-48bb-a529-e94936a53b12">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[金额]]></text>
|
||||
</staticText>
|
||||
<line>
|
||||
<reportElement x="15" y="23" width="195" height="1" uuid="267b9040-1d0d-4050-8906-04ebcdfba7b0">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.5" lineStyle="Dashed"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
</band>
|
||||
<band height="18">
|
||||
<printWhenExpression><![CDATA["7100".equals($P{balanceStatus})]]></printWhenExpression>
|
||||
<componentElement>
|
||||
<reportElement x="0" y="5" width="200" height="12" uuid="9ba8d55a-8e43-4aee-af93-ffdb8f2ec5ce">
|
||||
<property name="com.jaspersoft.studio.layout" value="com.jaspersoft.studio.editor.layout.VerticalRowLayout"/>
|
||||
<property name="com.jaspersoft.studio.table.style.table_header" value="Table_TH"/>
|
||||
<property name="com.jaspersoft.studio.table.style.column_header" value="Table_CH"/>
|
||||
<property name="com.jaspersoft.studio.table.style.detail" value="Table_TD"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<jr:table xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd" whenNoDataType="Blank">
|
||||
<datasetRun subDataset="Dataset1" uuid="a4a70f4b-c3cb-4482-95ff-149fb66ea7f6">
|
||||
<dataSourceExpression><![CDATA[$P{gatheringList}]]></dataSourceExpression>
|
||||
</datasetRun>
|
||||
<jr:column width="130" uuid="3b60f38e-2a7c-43b7-b976-071e57aeadf1">
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column1"/>
|
||||
<jr:detailCell height="12">
|
||||
<textField isBlankWhenNull="true">
|
||||
<reportElement x="0" y="0" width="130" height="12" uuid="faf9cca2-d266-463d-91ee-cc7cc3575f24"/>
|
||||
<textElement>
|
||||
<font fontName="黑体"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$F{paymentType}]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
<jr:column width="70" uuid="56829dd0-7286-4bbf-825a-48d016b353bd">
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column2"/>
|
||||
<jr:detailCell height="12">
|
||||
<textField isBlankWhenNull="true">
|
||||
<reportElement x="0" y="0" width="70" height="12" uuid="f8450d4c-7ad6-4237-ba69-56862a2d9a6d"/>
|
||||
<textElement>
|
||||
<font fontName="黑体"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$F{amount}.setScale( 2, BigDecimal.ROUND_DOWN )]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
</jr:table>
|
||||
</componentElement>
|
||||
</band>
|
||||
<band height="44">
|
||||
<line>
|
||||
<reportElement x="15" y="5" width="195" height="1" uuid="425e895d-8b95-436e-bd82-55a6c4d4cbf8">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.5" lineStyle="Dashed"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
<staticText>
|
||||
<reportElement x="0" y="11" width="44" height="12" uuid="c3e05a21-6ba4-4708-991a-825a994a1b2f">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[客户签字]]></text>
|
||||
</staticText>
|
||||
<line>
|
||||
<reportElement x="15" y="28" width="195" height="1" uuid="b6bb8778-b57c-4fda-9e09-1a7eac4ca4e7">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.5" lineStyle="Dashed"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
<staticText>
|
||||
<reportElement x="0" y="32" width="222" height="12" uuid="8a83c68d-8555-4889-a063-2f78dce9af4a">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[请妥善保管购物凭证,谢谢惠顾!]]></text>
|
||||
</staticText>
|
||||
</band>
|
||||
<band height="12">
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="53" y="0" width="169" height="12" isPrintWhenDetailOverflows="true" uuid="429e5e34-e7cc-4b2e-a7ec-f9bdc72268ce">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="0"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{detailAddress}]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="53" height="12" uuid="91cf76df-ccf1-417b-8ad1-73b7e1be2306"/>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[门店地址:]]></text>
|
||||
</staticText>
|
||||
</band>
|
||||
<band height="24">
|
||||
<textField isBlankWhenNull="true">
|
||||
<reportElement x="53" y="12" width="169" height="12" uuid="bee0af12-b474-4e3a-8218-141663bc62f2">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="0"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{printTime}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isBlankWhenNull="true">
|
||||
<reportElement x="33" y="0" width="189" height="12" uuid="0f0d0893-f0ea-4221-b89f-b7a8ab6461be">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="0"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{contactMobile}.split(" ")[1].length() == 5 ? $P{contactMobile}.split(" ")[0] : $P{contactMobile}]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="33" height="12" uuid="d007cd43-b97e-4837-badf-79a6f4fad415">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[电话:]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="0" y="12" width="53" height="12" uuid="3bd289b6-ad7a-4e24-b8b0-cbf579a979f2">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[打印时间:]]></text>
|
||||
</staticText>
|
||||
</band>
|
||||
</detail>
|
||||
</jasperReport>
|
||||
+510
@@ -0,0 +1,510 @@
|
||||
# 工单结算单接口文档
|
||||
|
||||
# 打印单最新接口参数
|
||||
|
||||
#### maintain接口
|
||||
|
||||
**接口:/print/dispatchPrint/genUrl**
|
||||
|
||||
**方法:post**
|
||||
|
||||
支持场景:
|
||||
|
||||
各类结算单
|
||||
|
||||
不支持:上海结算单
|
||||
|
||||
**入参:**
|
||||
|
||||
```plaintext
|
||||
{
|
||||
"pkId": "14581820313319918809",
|
||||
"rowCode": "costSettlePrint",
|
||||
"rowId": "12"
|
||||
}
|
||||
```
|
||||
```plaintext
|
||||
{
|
||||
"code": 200,
|
||||
"data": {
|
||||
"url": "http://s1.f6yc.com/printserver/test/printFile/201912/191213154046701.pdf"
|
||||
},
|
||||
"message": "SUCCESS"
|
||||
}
|
||||
```
|
||||
|
||||
#### erp接口
|
||||
|
||||
**/print/getPrintPDFPath.do**
|
||||
|
||||
templateId=56&templateType=newSettlePrint&idSourceBill=10546443563897503197
|
||||
|
||||
**rest get**
|
||||
|
||||
**支持各种新版打印类型**
|
||||
|
||||
```plaintext
|
||||
{
|
||||
"code": 200,
|
||||
"data": "http://s1.f6yc.com/printserver/test/printFile/201912/191213154046701.pdf",
|
||||
"message": "SUCCESS"
|
||||
}
|
||||
```
|
||||
|
||||
#### jasper取参对照
|
||||
|
||||
```plaintext
|
||||
{
|
||||
"data": {
|
||||
"cellPhone": "15421562365", //联系电话
|
||||
"naCustomer": "0322新", //单位名称
|
||||
"repairPerson": "", //送修人
|
||||
"carOwnerName":"", // 车辆所有人
|
||||
"accountNumber": "", //账号
|
||||
"billNo": "GD20190517001", //工单号
|
||||
"carNoWhole": "苏1542", //车牌号
|
||||
""
|
||||
"carColor":"" //车身颜色
|
||||
"orgDetailAddress": "江苏省盐城市阜宁县豆豆",//联系地址
|
||||
"vin": "11111111111111111", //车辆VIN码
|
||||
"naEmployee": "员工1(旧1)", //服务顾问
|
||||
"billDate": "2019-05-17 11:49",//进厂日期
|
||||
"businessTypeName": "维修", //维修类别
|
||||
"deliveryTime": "2019-05-17 12:49",//交车时间(出厂时间)
|
||||
"email": "126544@qq.com", //组织邮件
|
||||
"maintainType": "GD", //工单类型
|
||||
"billStatus":"6300", //单据状态
|
||||
"orgContactMobile": "15315256232", //联系电话
|
||||
"memo": "", //工单备注
|
||||
"orgMemo":"", // 门店备注
|
||||
"carMemo":"", // 车辆备注
|
||||
"printCount": "1", //打印次数
|
||||
"orgContactNumber": "", //联系电话-承修方信息
|
||||
"carSeriesName": "商用车", //车系名称
|
||||
"carBrandName": "商用车", //品牌名称
|
||||
"balanceStatus": "7000", //结算状态
|
||||
"printTime": "2019-07-26 11:43:48",//打印时间
|
||||
"firstSettlementTime":"2019-07-26 11:43:48",//结算时间(第一次收款时间)
|
||||
"orgName": "新公司测试", //单位名称-承修方信息
|
||||
"abbreviation": "门店简称", //门店简称
|
||||
"engineNumber": "123", //发动机号
|
||||
"transmissionNo": "123", //变速箱号
|
||||
"creationtime": "2019-05-17 11:50:46.0",//创建时间
|
||||
"creatorName": "员工1(旧1)", //创建人名称
|
||||
"employeePhone":"18734033191", //服务顾问手机号
|
||||
"paymentTypeDetails":"记账", //支付方式(记账公司)汇总
|
||||
"bankAccount": "", //开户银行
|
||||
"naInsurer":"", //理赔公司名称
|
||||
"insurancepolicyNo":"", //理赔单理赔保险单号
|
||||
"mergePackageContent": "1", //套餐合并标识
|
||||
"totalStuffNum": 1.0, //材料数量合计
|
||||
"selfTotalStuffNum": 0.0, //自带材料数量合计
|
||||
"serviceNum": "1", //维修项目小计
|
||||
"spreadRate": 0.0, //进销差价率
|
||||
"managementCost": 0.0, //进销差价合计
|
||||
"amountAll": 160.0, //应收总计
|
||||
"serviceDisCountSubTotal": 100.0, //项目折后金额合计
|
||||
"stuffSubtotalAll": 60.0, //材料费小计
|
||||
"serviceSubtotalAll": 100.0, //工时费小计
|
||||
"receiptAmount": 160.0, //实收金额
|
||||
"chineseAmount": "壹佰陆拾元整", //实收金额(大写)
|
||||
"oweAmount": 160.0, //未收金额
|
||||
"remainAmount":1.0, //结算金额tsf
|
||||
"receivedAmount":1.0, //收款金额tsf
|
||||
"settleOweAmout":1.0, //结算单中用的待付金额(未收)
|
||||
"settleOweAmoutChinese":"壹", //待付金额大写
|
||||
"settleReceivedAmout":1.0, //实付金额
|
||||
"settleReceivedAmoutChinese":1.0, //实付金额大写
|
||||
"totalWorkHour": 1.0, //项目工时合计
|
||||
"serviceFavourableTotal": 52.0, //项目优惠金额合计
|
||||
"serviceFavourableCommonTotal": 52.0,//普通项目优惠金额合计
|
||||
"stuffSubtotalAll": 532.0, //材料费小计
|
||||
"partFavourableTotal": 102.0, //材料优惠金额合计
|
||||
"partFavourableCommonTotal": 92.0, //普通材料优惠金额合计
|
||||
"stuffDisCountTotal": 60.0, //材料折后金额合计
|
||||
"extraCostTotal": 0.0, //附加费小计
|
||||
"allOtherCost": 0.0, //附加费合计应收
|
||||
"packageFavourable": 0.0, //套餐优惠
|
||||
"czkExpense": 0.0, //储值卡消费金额
|
||||
"vipExpense": 0.0, //会员卡消费金额
|
||||
"czkExpenseFavourable": 0.0, //储值卡优惠金额
|
||||
"czkDiscountFavourable": 0.0, //储值卡办卡优惠金额
|
||||
"vipExpenseFavourable": 0.0, //计次卡/套餐卡优惠金额
|
||||
"partinfoDiscountFavourable": 0.0, //材料折扣优惠
|
||||
"partinfoFavourable": 0.0, //材料项目(非会员项目)客户等级优惠
|
||||
"couponFavourable": 0.0, //优惠券优惠
|
||||
"pointFavourable": 0.0, //积分优惠
|
||||
"discountFavourable": 0.0, //结算时设置的结清优惠
|
||||
"gatheringFavourable": 0.0, //收银时设置的收银优惠
|
||||
"customerLevelFavourable": 0.0, //客户级别优惠金额
|
||||
"serviceFavourable": 0.0, //服务项目(非会员项目)客户等级优惠
|
||||
"disCountAll": 0.0, //总优惠合计
|
||||
"disCountAllBak":0.0, //总优惠合计bak
|
||||
"printContent": "", //免责条款
|
||||
"printContentEntrust":"", //委托单免责条款
|
||||
"mainCostList": [ //维修结算费用集合
|
||||
{
|
||||
"subtotal": 60.0, //价格
|
||||
"sortNumber": "1", //序号
|
||||
"costName": "材料费" //名称
|
||||
},
|
||||
{
|
||||
"subtotal": 100.0,
|
||||
"sortNumber": "2",
|
||||
"costName": "工时费"
|
||||
},
|
||||
{
|
||||
"subtotal": 160.0,
|
||||
"sortNumber": "3",
|
||||
"costName": "合计"
|
||||
}
|
||||
],
|
||||
"partList": [ //工单对应配件材料集合
|
||||
{
|
||||
"unit": "个", //单位
|
||||
"isBring": 0, //是否自带,1表示自带,0表示非自带
|
||||
"discountedSubtotal": 60.0, //折后金额
|
||||
"price": 60.0, //价格
|
||||
"partName": "分全", //材料名称
|
||||
"number": 1.0, //数量
|
||||
"subtotal": 60.0, //金额
|
||||
"taxRateOutput": 0.13, //销项税率
|
||||
"singleFavourable":0.0, //优惠金额
|
||||
"partBrand":"", //配件品牌
|
||||
"spec":"", //规格型号
|
||||
"supplierCode":"", //供应商编码(零件号)
|
||||
"customCode":"", //材料编码
|
||||
"isMember":0, //是否是会员卡材料 1是
|
||||
"discount":0.5, //折扣
|
||||
"partMemo":"", //备注
|
||||
"employeeName":"", //员工名称(维修技师)
|
||||
"cargoSpace":"", //货位
|
||||
"outStockEmployeeName":"", //领料人
|
||||
"sortNumber": "1" //序号
|
||||
}
|
||||
],
|
||||
"serviceList": [ //工单对应项目集合
|
||||
{
|
||||
"discountedSubtotal": 100.0,//折后金额
|
||||
"price": 100.0, //工时单价
|
||||
"workHour": 1.0, //工时
|
||||
"subtotal": 100.0, //金额
|
||||
"taxRateOutput": 0.13, //销项税率
|
||||
"sortNumber": "1", //序号
|
||||
"discount":1, //折扣
|
||||
"singleFavourable":0.0, //优惠金额
|
||||
"isMember":1, //是否是会员卡项目 1是 0否
|
||||
"empNameStr":"", //修理工
|
||||
"unusedNumber":1, //会员卡项目-未使用次数
|
||||
"number":2, //会员卡项目-总次数
|
||||
"infiniteFlag":1, //是否无限,0:否,1:是
|
||||
"serviceName": "0322新" //项目名称
|
||||
}
|
||||
],
|
||||
"cardList": [ //会员卡列表
|
||||
{
|
||||
"favourable": 20, //优惠
|
||||
"amount": 2019799, //余额
|
||||
"consumeAmount":10, //本次消费金额
|
||||
"memberCardNo": "123232rg",//卡号
|
||||
"name": "测试洗车卡项目2" //卡名称
|
||||
}
|
||||
],
|
||||
"czkList": [ //储值卡列表
|
||||
{
|
||||
"favourable": 20, //优惠
|
||||
"amount": 2019799, //余额
|
||||
"consumeAmount":10, //本次消费金额
|
||||
"memberCardNo": "123232rg",//卡号
|
||||
"name": "测试洗车卡项目2" //卡名称
|
||||
}
|
||||
],
|
||||
"extraPrintVo": { //附加项目
|
||||
"processItemName": "加工", //加工条目名称
|
||||
"checkCustomName": "检测费", //检测费名称
|
||||
"diagnosisCustomName": "诊断费", //诊断费名称
|
||||
"diagnosisItemName": "维修诊断", //维修诊断项目
|
||||
"diagnosisMemo": "", //诊断费备注
|
||||
"diagnosisCost": 0.0, //诊断费
|
||||
"commissionCustomName": "代办费", //代办费名称
|
||||
"managementCustomName": "管理费", //管理费名称
|
||||
"commissionMemo": "", //代办费备注
|
||||
"processMemo": "", //加工费
|
||||
"commissionCost": 0.0, //代办费
|
||||
"checkCost": 0.0, //检测费
|
||||
"managementCost": 0.0, //管理费
|
||||
"processCustomName": "加工费", //加工费名称
|
||||
"processCost": 0.0, //加工费
|
||||
"managementMemo": "", //管理费备注
|
||||
"checkMemo": "" //检测费备注
|
||||
}
|
||||
},
|
||||
"storeId": 25965086392720693,
|
||||
"tempId": 123
|
||||
}
|
||||
```
|
||||
|
||||
#### 参数说明(完整)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| \------基础信息 | | |
|
||||
| **billNo** | String | _工单号_ |
|
||||
| **maintainType** | String | _工单类型_ |
|
||||
| **balanceStatus** | String | _结算状态_<br/>_"7000" -- 未结算(即存在待付金额)_<br/>_"7100" -- 已结算_<br/>_"7200" -- 部分结算_ |
|
||||
| **creatorName** | String | _创建人名称_ |
|
||||
| **naEmployee** | String | _服务顾问_ |
|
||||
| **spreadRate** | Double | _进销差价率_ |
|
||||
| carCategoryName | String | _客户车辆分类名称_ |
|
||||
| **creationtime** | String | _创建时间_ |
|
||||
| **memo** | String | _工单备注_ |
|
||||
| **printCount** | String | _打印次数_ |
|
||||
| **printTime** | String | _打印时间_ |
|
||||
| **deliveryTime** | String | _交车时间(出厂时间),收款取收款时间,未收款完工的取完工时间,未完工的取预计交车时间_ |
|
||||
| **mergePackageContent** | String | _套餐合并标识_ |
|
||||
| **printContent** | String | _免责条款_ |
|
||||
| **engineNumber** | String | _发动机号_ |
|
||||
| **transmissionNo** | String | 变速箱号 |
|
||||
| **printMaintainGuaZi** | String | _guazi标识_ |
|
||||
| **amountAll** | Double | _应收总计_ |
|
||||
| **disCountAll** | Double | _总优惠合计_ |
|
||||
| **oweAmount** | Double | _未收金额_ |
|
||||
| **vipExpense** | Double | _会员卡消费金额_ |
|
||||
| **vipExpenseFavourable** | Double | _计次卡/套餐卡优惠金额_ |
|
||||
| **czkExpense** | Double | _储值卡消费金额_ |
|
||||
| **czkExpenseFavourable** | Double | _储值卡优惠金额_ |
|
||||
| **czkSettleFavourable** | Double | _储值卡结算优惠金额(仅未收款返回)_ |
|
||||
| **accountAmount** | Double | 记账金额 |
|
||||
| **totalOweAmount** | Double | _未付金额_ |
|
||||
| **serviceFavourable** | Double | _服务项目(非会员项目)客户等级优惠_ |
|
||||
| **partinfoFavourable** | Double | _材料项目(非会员项目)客户等级优惠_ |
|
||||
| **partinfoDiscountFavourable** | Double | _材料折扣优惠_ |
|
||||
| **pointFavourable** | Double | _积分优惠_ |
|
||||
| **packageFavourable** | Double | _套餐优惠_ |
|
||||
| **discountFavourable** | Double | _结算时设置的结清优惠_ |
|
||||
| **gatheringFavourable** | Double | _收银时设置的收银优惠_ |
|
||||
| **couponFavourable** | Double | _优惠券优惠_ |
|
||||
| **customerLevelFavourable** | Double | _客户级别优惠金额_ |
|
||||
| **customerLevelName** | String | _客户级别_ |
|
||||
| **customerDetailAddress** | String | 客户详细地址 |
|
||||
| **channelName** | String | 来店途径名称 |
|
||||
| **receiptMemo** | String | 收银备注 |
|
||||
| **customerSourceName** | String | _客户来源名称_ |
|
||||
| **carSourceName** | String | _车辆来源名称_ |
|
||||
| \-----托修方信息 | | |
|
||||
| **naCustomer** | String | _单位名称/托修方_ |
|
||||
| **repairPerson** | String | _送修人_ |
|
||||
| **carNoWhole** | String | _车牌号整体_ |
|
||||
| **carBrandName** | String | _品牌名称_ |
|
||||
| **carSeriesName** | String | _车系名称_ |
|
||||
| carMemo | String | 车辆备注 |
|
||||
| **businessTypeName** | String | _维修类别_ |
|
||||
| **vin** | String | _车辆VIN码_ |
|
||||
| carFuelTypeNameOriginal | carFuelTypeNameOriginal | 燃料类型 |
|
||||
| **billDate** | String | _进厂日期_ |
|
||||
| **mileage** | java.math.BigDecimal | _出厂里程_ |
|
||||
| **contractNumber** | | _合同编号(空)_ |
|
||||
| **certificateNumber** | | _合格证号(空)_ |
|
||||
| **cellPhone** | String | _联系电话_ |
|
||||
| **email** | String | _组织邮件_ |
|
||||
| \------承修方信息 | | |
|
||||
| **orgName** | String | _单位名称_ |
|
||||
| **abbreviation** | String | 门店简称 |
|
||||
| **orgContactNumber** | String | _联系电话_ |
|
||||
| **orgDetailAddress** | String | _联系地址_ |
|
||||
| **orgContactMobile** | String | _联系电话_ |
|
||||
| **bankAccount** | String | _开户银行_ |
|
||||
| **accountNumber** | String | _账号_ |
|
||||
| **businessLicenseCode** | String | 营业执照编码 |
|
||||
| \------项目信息 | | |
|
||||
| serviceList | array | 项目条目 |
|
||||
| #### orderNumber | String | 序号(验证可用) |
|
||||
| sortNumber | String | _序号_ |
|
||||
| customCode | String | 项目编码 |
|
||||
| serviceName | String | _项目名称_ |
|
||||
| **labelName** | String | _业务分类名称_ |
|
||||
| **nameMember** | String | _会员项目的来源名_ |
|
||||
| **labelName** | String | 业务分类 |
|
||||
| price | Double | _工时单价_ |
|
||||
| workHour | Double | _工时_ |
|
||||
| subtotal | Double | _金额_ |
|
||||
| ```plaintext<br> taxRateOutput <br>``` | BigDecimal | _销项税率_ |
|
||||
| ```plaintext<br> singleFavourable <br>``` | Double | 优惠金额 |
|
||||
| discountedSubtotal | Double | _折后金额_ |
|
||||
| **serviceMemo** | String | _单据服务项目备注_ |
|
||||
| discount | Double | 折扣 |
|
||||
| unusedNumber | Integer | 会员卡项目-未使用次数 |
|
||||
| number | Integer | 会员卡项目-总次数 |
|
||||
| ```plaintext<br>favourableVoList <br>``` | List<FavourableDetailPrintVo> | 优惠明细 |
|
||||
| ```plaintext<br>discountType <br>``` | Integer | 优惠类型(编码) |
|
||||
| ```plaintext<br>discountTypeName <br>``` | String | 优惠类型名称 |
|
||||
| amount | Double | 优惠金额 |
|
||||
| ```plaintext<br>sourceId <br>``` | String | 优惠项目的主键,如:如果优惠项是优惠券,那么该字段为优惠券的id |
|
||||
| **memo** | String | 项目说明 |
|
||||
| **qualityCheckEmployeeName** | String | 质检人姓名 |
|
||||
| **qualityCheckEmployeeCode** | String | 质检人工号 |
|
||||
| **cooperationMemo** | String | 协作备注 |
|
||||
| **totalWorkHour** | Double | _项目工时合计_ |
|
||||
| **serviceSubtotalAll** | Double | _工时费小计_ |
|
||||
| **serviceNum** | Double | _维修项目小计_ |
|
||||
| **serviceDisCountSubTotal** | Double | _项目折后金额合计_ |
|
||||
| \-------材料信息 | | |
|
||||
| partList | array | 材料条目 |
|
||||
| #### orderNumber | String | 序号(验证可用) |
|
||||
| sortNumber | String | _序号_ |
|
||||
| customCode | String | 材料编码 |
|
||||
| partName | String | _材料名称_ |
|
||||
| **partBrand** | String | _配件品牌_ |
|
||||
| spec | String | 规格型号 |
|
||||
| standard | String | 规格型号(旧) |
|
||||
| **partShowName** | String | _配件名称规格型号品牌_ |
|
||||
| **supplierCode** | String | _供应商编码(零件号)_ |
|
||||
| unit | String | _单位_ |
|
||||
| number | Double | _数量_ |
|
||||
| **nameMember** | String | _会员项目的来源名_ |
|
||||
| price | Double | _价格_ |
|
||||
| cost | Double | _材料成本_ |
|
||||
| subtotal | Double | _退货金额_ |
|
||||
| taxRateOutput | BigDecimal | _销项税率_ |
|
||||
| singleFavourable | Double | 优惠金额 |
|
||||
| discountedSubtotal | Double | _折后金额_ |
|
||||
| **partMemo** | String | _单据服务材料备注_ |
|
||||
| discount | Double | 折扣 |
|
||||
| **applyModel** | String | 适用车型 |
|
||||
| ```plaintext<br>cargoSpace <br>``` | String | 材料货位 |
|
||||
| **defSeats** | List<String> | 材料货位列表 |
|
||||
| ```plaintext<br>favourableVoList <br>``` | List<FavourableDetailPrintVo> | 优惠明细 |
|
||||
| ```plaintext<br>discountType <br>``` | Integer | 优惠类型(编码) |
|
||||
| ```plaintext<br>discountTypeName <br>``` | String | 优惠类型名称 |
|
||||
| ```plaintext<br>amount <br>``` | Double | 优惠金额 |
|
||||
| ```plaintext<br>sourceId <br>``` | String | 优惠项目的主键,如:如果优惠项是优惠券,那么该字段为优惠券的id |
|
||||
| \-------自带材料(新版维修/贴膜)信息 | | |
|
||||
| **bringPartList** | array | 自带材料条目 |
|
||||
| **partShowName** | String | 自带材料名称(文本) |
|
||||
| **photoList** | List<String> | 自带图片路径(url) |
|
||||
| empNameStr | String | 技师 |
|
||||
| outStockEmployeeName | String | 领料人 |
|
||||
| **isBring** | String | _是否自带_ |
|
||||
| **selfPartList** | array | _工单对应配件自带材料集合(内容同上面材料)_ |
|
||||
| **totalStuffNum** | String | _材料数量合计_ |
|
||||
| **selfTotalStuffNum** | String | _自带材料数量合计_ |
|
||||
| **stuffSubtotalAll** | Double | _材料费小计_ |
|
||||
| **partFavourableTotal** | Double | _材料优惠金额合计_ |
|
||||
| **partFavourableCommonTotal** | Double | _普通材料优惠金额合计_ |
|
||||
| **stuffDisCountTotal** | Double | _材料折后金额合计_ |
|
||||
| **managementCost** | Double | _进销差价合计_ |
|
||||
| \------附加费用信息 | | |
|
||||
| **extraChargeList** | | |
|
||||
| **sortNumber** | String | _序号_ |
|
||||
| **extraName** | String | _附加费名称_ |
|
||||
| **subtotal** | Double | _金额_ |
|
||||
| **memo** | String | _备注_ |
|
||||
| \-----维修结算费用集合(江苏结算单) | | |
|
||||
| **mainCostList** | array | |
|
||||
| **sortNumber** | String | _序号_ |
|
||||
| **costName** | String | _名称_ |
|
||||
| **memo** | String | _备注_ |
|
||||
| **subtotal** | Double | _金额_ |
|
||||
| \----_其他结算费用集合(江苏结算单)_ | | |
|
||||
| **otherCostList** | array | 内容同上 维修结算费用集合 |
|
||||
| **extraCostTotal** | Double | _附加费小计_ |
|
||||
| **allOtherCost** | Double | _附加费合计应收_ |
|
||||
| **favourableExtraCost** | Double | _附加费优惠金额_ |
|
||||
| **receiptAmount** | Double | _实收金额(已收金额-储值卡金额,如未收款,则还加入了欠款金额+客户等级优惠-积分优惠-结清优惠)_ |
|
||||
| **receiptAmountChinese** | String | _实收金额大写(逻辑同上)_ |
|
||||
| **amountReal** | Double | 工单收款后真正的实收 |
|
||||
| **chineseAmount** | String | _实收金额(大写)(逻辑同上)_ |
|
||||
| **payItemTogetherChinese** | String | _付款方式总额大写_ |
|
||||
| **payItemTogetherExcludeAccountAmountChinese** | String | 付款总额(排除记账金额)大写 |
|
||||
| **settleOweAmout** | Double | 结算单中用的待付金额(未收),使用后台逻辑算好 |
|
||||
| **settleOweAmoutChinese** | String | 待付金额大写 |
|
||||
| \-----结算付款方式及优惠保存信息 | array | |
|
||||
| **settlementPayItemList** | | |
|
||||
| **payWay** | String | _付款方式_ |
|
||||
| **payAmount** | Double | _付款金额_ |
|
||||
| **chinesePayAmount** | String | _大写付款方式_ |
|
||||
| **accountAgreementName** | String | _记账客户名称_ |
|
||||
| \-----付款方式信息 | array | |
|
||||
| **payItemList** | | |
|
||||
| **payWay** | String | _付款方式_ |
|
||||
| **payAmount** | Double | _付款金额_ |
|
||||
| **chinesePayAmount** | String | _大写付款方式_ |
|
||||
| \-----附加项目(江苏结算单) | | |
|
||||
| **extraPrintVo** | obj | |
|
||||
| **commissionCustomName** | String | _代办费自定义名称_ |
|
||||
| **commissionCost** | Double | _代办费成本_ |
|
||||
| **commissionMemo** | String | _代办费备注_ |
|
||||
| **diagnosisCustomName** | String | _诊断费自定义名称_ |
|
||||
| **diagnosisCost** | Double | _诊断费成本_ |
|
||||
| **diagnosisItemName** | String | _诊断详细名称_ |
|
||||
| **diagnosisMemo** | String | _诊断费备注_ |
|
||||
| **checkCustomName** | String | _检查费自定义名称_ |
|
||||
| **checkCost** | Double | _检查费成本_ |
|
||||
| **checkMemo** | String | _检查费备注_ |
|
||||
| **processCustomName** | String | _加工费自定义名称_ |
|
||||
| **processCost** | Double | _加工费成本_ |
|
||||
| **processMemo** | String | _加工费备注_ |
|
||||
| **processItemName** | String | _加工详细名称_ |
|
||||
| **managementCustomName** | String | _管理费自定义名称_ |
|
||||
| **managementCost** | Double | _管理费成本_ |
|
||||
| **managementMemo** | String | _管理费备注_ |
|
||||
| \-----二期新增字段 | | |
|
||||
| **oilCapacity** | String | 油量 |
|
||||
| **nextMileage** | Double | _下次保养里程(工单数据源,目前维保、洗车单读取)_ |
|
||||
| **nextMaintainDate** | String | _下次保养日期(工单数据源,目前维保、洗车单读取)_ |
|
||||
| **nextMileageRemind** | Double | _下次服务里程(服务提醒数据源,目前维修、贴膜单读取)_ |
|
||||
| **nextMaintainDateRemind** | Long | _下次服务时间(服务提醒数据源,目前维修、贴膜单读取)_ |
|
||||
| **repairPersonContact** | String | _送修人联系方式_ |
|
||||
| **memberCardNo** | String | _会员号_ |
|
||||
| **points** | String | _积分_ |
|
||||
| **czkList** | array | 储值卡列表 |
|
||||
| **name** | String | 名称 |
|
||||
| **memberCardNo** | String | 卡号 |
|
||||
| ```plaintext<br> **cardOwner** <br>``` | String | 持卡人 |
|
||||
| **amount** | Double | 金额 |
|
||||
| **cardList** | array | 套餐卡列表 |
|
||||
| **name** | String | 名称 |
|
||||
| **memberCardNo** | String | 卡号 |
|
||||
| ```plaintext<br> **cardOwner** <br>``` | String | 持卡人 |
|
||||
| **amount** | Double | 金额 |
|
||||
| **combineServiceAndPartList** | array | 项目材料组合列表 |
|
||||
| **servicePrintVo** | 参见serviceList | |
|
||||
| **partPrintVo** | 参见partList | |
|
||||
|
||||
# 案例记录:
|
||||
|
||||
#### 1.结算前 待付 结算后实付(跟进结算状态判断,7100 为已结算)
|
||||
|
||||
```plaintext
|
||||
$P{balanceStatus}.equals("7100")?($P{amountAll}.subtract($P{vipExpense}).subtract($P{czkExpense}).subtract($P{serviceFavourable}.add($P{partFavourableCommonTotal}==null?BigDecimal.ZERO:$P{partFavourableCommonTotal}).add($P{serviceFavourableCommonTotal}==null?BigDecimal.ZERO:$P{serviceFavourableCommonTotal}).add($P{partinfoFavourable}).add($P{discountFavourable}).add($P{couponFavourable}).add($P{pointFavourable}).add($P{gatheringFavourable})).setScale( 2, BigDecimal.ROUND_HALF_EVEN ).toString()+($P{payItemTogether}==null?"":"("+$P{payItemTogether}+")")):($P{amountAll}.subtract($P{vipExpense}).subtract($P{czkExpense}).subtract($P{serviceFavourable}.add($P{partFavourableCommonTotal}==null?BigDecimal.ZERO:$P{partFavourableCommonTotal}).add($P{serviceFavourableCommonTotal}==null?BigDecimal.ZERO:$P{serviceFavourableCommonTotal}).add($P{partinfoFavourable}).add($P{discountFavourable}).add($P{couponFavourable}).add($P{pointFavourable}).add($P{gatheringFavourable})).setScale( 2, BigDecimal.ROUND_HALF_EVEN ))
|
||||
```
|
||||
|
||||
* 对应的汉字
|
||||
|
||||
|
||||
```plaintext
|
||||
$P{balanceStatus}.equals("7100")?$P{payItemTogetherChinese}:$P{settleOweAmoutChinese}
|
||||
```
|
||||
|
||||
# 工具类jar包附件下载:
|
||||
|
||||
[请至钉钉文档查看附件《print-core-1.0.7.jar》](https://alidocs.dingtalk.com/i/nodes/vy20BglGWOexYpophlEGoZvGJA7depqY?iframeQuery=anchorId%3DX02mjljl3qzo6fk6o7712b)
|
||||
|
||||
### 数字金额转中文方法调用示例:
|
||||
|
||||
**数字金额**:$P{amount}==null?BigDecimal.ZERO:$P{amount}
|
||||
**转中文**:**com.f6car.printserver.core.CharacterUtil.chinese(**$P{amount}==null?BigDecimal.ZERO:$P{amount})
|
||||
|
||||
### 日期时间戳转日期示例:
|
||||
|
||||
**日期格式选择:**java.lang.Long
|
||||
|
||||
**日期时间戳**:$P{nextMaintainDateRemind} **转为目标格式**:$P{nextMaintainDateRemind} == null ? "" : new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date($P{nextMaintainDateRemind}))
|
||||
|
||||
其中,"yyyy-MM-dd HH:mm:ss" 根据实际需求指定,比如到日则选择 "yyyy-MM-dd"
|
||||
|
||||
### 洗车单
|
||||
|
||||
洗车单小票不支持定制,定制洗车单的模板名称必须包含“洗车单”三个字 ,否则无法显示对应模板
|
||||
|
||||
> 更新: 2025-02-24 17:08:50 原文: <https://xcz.yuque.com/ombipo/rpc7ms/ro5fs1>
|
||||
+1034
File diff suppressed because it is too large
Load Diff
+262
@@ -0,0 +1,262 @@
|
||||
# 打印单定制介绍
|
||||
|
||||
# 打印单定制介绍
|
||||
|
||||
| **最常用的基础操作** |
|
||||
| --- |
|
||||
| [1、新增静态文本](#jwTdk) |
|
||||
| [2、新增动态字段(例如想要展示结算单中的工单号)](#fKwpz) |
|
||||
| [3、列表中增减字段(例如结算单中的项目列表和材料列表)](#IUyOs) |
|
||||
| [4、新增边框和样式设置](#RKqIf) |
|
||||
| [6、保存+输出](#M31IF) |
|
||||
| [7、打印单后台配置](#gr6xz) |
|
||||
|
||||
## 常用链接地址:
|
||||
|
||||
###### 打印单后台地址
|
||||
|
||||
[http://print.f6yc.com/print-server/ui/index.html#/template/classification](http://print.f6yc.com/print-server/ui/index.html#/template/classification)
|
||||
|
||||
###### 打印单模板样式
|
||||
|
||||
[https://xcz.yuque.com/ombipo/rpc7ms/fbd6ay?singleDoc#](https://xcz.yuque.com/ombipo/rpc7ms/fbd6ay?singleDoc#) 《打印单各类模板样式》
|
||||
|
||||
###### 打印单参数表
|
||||
|
||||
[https://xcz.yuque.com/ombipo/rpc7ms/ro5fs1?singleDoc#](https://xcz.yuque.com/ombipo/rpc7ms/ro5fs1?singleDoc#) 《打印单最新接口参数》
|
||||
|
||||
###### 打印单工具简易开发教程(附带案例)
|
||||
|
||||
[《打印单定制简易开发教程》](https://alidocs.dingtalk.com/i/nodes/dQPGYqjpJYgZGbvbCdEKGDGZWakx1Z5N?utm_scene=team_space)
|
||||
|
||||
## 工具下载
|
||||
|
||||
jdk1.8 使用 jaspersoft6.8版本
|
||||
|
||||
[请至钉钉文档查看附件《Jaspersoft Studio-6.8.0.zip》](https://alidocs.dingtalk.com/i/nodes/20eMKjyp81R0ndXdsdYe4BaDWxAZB1Gv?corpId=&iframeQuery=anchorId%3DX02mgkgykvfbfbiqcbc8b4)
|
||||
|
||||
WIN:
|
||||
|
||||
[请至钉钉文档查看附件《Jaspersoft Studio-6.3.1.final.rar》](https://alidocs.dingtalk.com/i/nodes/20eMKjyp81R0ndXdsdYe4BaDWxAZB1Gv?corpId=&iframeQuery=anchorId%3DX02mki20wvdslzwftp0ao)
|
||||
|
||||
MAC:
|
||||
|
||||
[请至钉钉文档查看附件《TIBCOJaspersoftStudio-6.3.1.final-mac-x86\_64.zip》](https://alidocs.dingtalk.com/i/nodes/20eMKjyp81R0ndXdsdYe4BaDWxAZB1Gv?corpId=&iframeQuery=anchorId%3DX02mki26xyvtjfkmi00ki)
|
||||
|
||||
## 打印单模板修改流程
|
||||
|
||||
#### 1、下载需要的模板
|
||||
|
||||
###### 通过模板名称,直接到模板管理中通过模板名称查询并下载
|
||||
|
||||

|
||||
|
||||
#### 2、打开编辑工具 TIBCO Jaspersoft Studio
|
||||
|
||||
###### 打开文件夹,双击Jaspersoft Studio.exe 运行工具
|
||||
|
||||

|
||||
|
||||
###### 点击File-->Open File-->选择下载的模板文件
|
||||
|
||||
###### 进入编辑模板的页面
|
||||
|
||||

|
||||
|
||||
#### 3、常见编辑操作
|
||||
|
||||
##### 1.新增静态文本
|
||||
|
||||
###### 新增组件到模板中
|
||||
|
||||

|
||||
|
||||
###### 双击组件编辑显示文本
|
||||
|
||||

|
||||
|
||||
###### 调整组件大小和位置参数
|
||||
|
||||

|
||||
|
||||
##### 2.新增动态字段(例如想要展示结算单中的工单号)
|
||||
|
||||
###### 在参数表中搜索想要的参数名称和类型:名称是:billNo 类型是文本信息=java.lang.String
|
||||
|
||||

|
||||
|
||||
###### 拖拽一个 Text Field 组件到模板中
|
||||
|
||||

|
||||
|
||||
###### 双击组件写入公式固定写法$P{参数名称}
|
||||
|
||||
###### 
|
||||
|
||||
###### 遇到提示:The current expression is not valid. Please verify it!;表明这个参数在模板中没有预先创建,需要手动创建参数信息
|
||||
|
||||

|
||||
|
||||
###### 模板中预设参数信息:Outline-->Parameters(右键单击)-->Create Parameter
|
||||
|
||||

|
||||
|
||||
###### 编辑参数信息:Name(填写参数名称);Class(数字就选择:java.math.BigDecimal 文本就选择java.lang.String)
|
||||
|
||||

|
||||
|
||||
##### 3.列表中增减字段(例如结算单中的项目列表和材料列表)
|
||||
|
||||
###### 例如查找材料名称,可以发现参数名是partName,是在一个名字叫partList 的列表里面的,在材料信息的列表中能使用到的参数就只有partList下的这个参数,其他参数无法在列表中直接使用(例如工单号在材料列表中展示不了)
|
||||
|
||||

|
||||
|
||||
###### 双击需要编辑的列表,进入列表编辑页面
|
||||
|
||||

|
||||
|
||||
###### 编辑方式与新增动态字段相同,但是固定写法从$P{参数名称} 改为 $F{参数名称}
|
||||
|
||||

|
||||
|
||||
###### 提示The current expression is not valid. Please verify it! 参数没有预设时,在列表编辑页面中新增,逻辑与上面相同
|
||||
|
||||
##### 4.新增边框和样式设置
|
||||
|
||||
###### 选择需要编辑的组件,选择Boeders 进行编辑
|
||||
|
||||

|
||||
|
||||
#### 4、常见语法介绍
|
||||
|
||||
###### 文本拼接参数:$P{参数名称}+"特定文本内容" —— 例如打印单标题:$P{printOrgName}+"结算单"
|
||||
|
||||
###### 小数保留2位小数或多位:$P{参数名称}.setScale( 保留几位小数, BigDecimal.ROUND\_DOWN ) ——例如折后金额小计,保留2位小数:$P{stuffSubtotalAll}.setScale( 2, BigDecimal.ROUND\_DOWN )
|
||||
|
||||
###### 字符串截取:$P{参数名称}.substring(起始位置,截取长度)——例如进厂日期,保留前10位:$P{billDate}.substring(0,10)
|
||||
|
||||
###### 三元运算-IF判断:(关系表达式) ? 表达式1 : 表达式2 ——例如打印单标题:($P{printOrgName}==null?$P{orgName}:($P{printOrgName}.isEmpty()?$P{orgName}:$P{printOrgName}))+"结算单"
|
||||
|
||||
###### 常见运算:
|
||||
|
||||
是否相等:”==“ 或者 $P{参数名称}.equals("文本内容")
|
||||
|
||||
加:$P{参数名称1}.add($P{参数名称2})
|
||||
|
||||
减:$P{参数名称1}.subtract($P{参数名称2})
|
||||
|
||||
乘:$P{参数名称1}.multiply($P{参数名称2}) ;$P{参数名称1}.multiply(new BigDecimal(1.13))
|
||||
|
||||
除:$P{参数名称1}.divide($P{参数名称2}, 2, BigDecimal.ROUND_HALF_UP)
|
||||
|
||||
#### 4.1、高级语法介绍
|
||||
|
||||
###### jar包导入:例如金额转大写,研发通过编写一个jar工具包实现特定功能,下面是导入jar包步骤
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
启用成功后按照研发语法实现具体功能,比如
|
||||
|
||||
###### 从list中取特定的值写入外层表格中:该公式使用jdk1.8语法,jaspersoft6.8可用
|
||||
|
||||
下面表达式的意思是,从支付方式列表(payItemList) 中找到
|
||||
|
||||
支付方式(payWay)
|
||||
|
||||
等于“记账”的
|
||||
|
||||
第一个支付金额(payAmount)
|
||||
|
||||
```java
|
||||
$P{payItemList}.getData().stream()
|
||||
.filter(map -> "记账".equals(map.get("payWay")))
|
||||
.map(map -> {
|
||||
Object amt = map.get("payAmount");
|
||||
return amt == null ? BigDecimal.ZERO : new BigDecimal(amt.toString());
|
||||
})
|
||||
.findFirst()
|
||||
.orElse(BigDecimal.ZERO)
|
||||
```
|
||||
|
||||
#### 5、格式预览
|
||||
|
||||
###### 工具中只能预览模板的样式,涉及到参数判断的需要将模板上传到门店后在F6系统工单中打印预览
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
#### 6、保存+输出
|
||||
|
||||
###### 保存
|
||||
|
||||

|
||||
|
||||
###### 选择.jrxml的文件,右键选择Compile Report 进行编译
|
||||
|
||||

|
||||
|
||||
###### 选择.jasper的文件,右键选择Export Files to...
|
||||
|
||||

|
||||
|
||||
###### 另存到桌面
|
||||
|
||||

|
||||
|
||||
#### 7、打印单后台配置
|
||||
|
||||
###### 新增/编辑模板
|
||||
|
||||
注意:不要随便删除模板,删除一定要再三确认清楚,避免出现误操作的情况(删除不可恢复) 预计5.16号后 对删除的功能二次确认进行优化。
|
||||
|
||||

|
||||
|
||||
###### 模板名称命名规范
|
||||
|
||||
* **简单调整**\*\***\*\*模板名称:基础表+特殊修改需求**
|
||||
|
||||
|
||||
**模板编码:修改人姓名首字母英文大写+模板分类+日期**
|
||||
|
||||
**模板备注:模板各修改点**
|
||||
|
||||

|
||||
|
||||
* **定制调整**\*\***\*\*模板名称:门店名称+定制**
|
||||
|
||||
|
||||
**模板编码:修改人姓名首字母英文大写+模板分类+日期**
|
||||
|
||||
**模板备注:模板各修改点**
|
||||
|
||||

|
||||
|
||||
###### 给指定门店配置打印单
|
||||
|
||||

|
||||
|
||||
#### 8、常见打印分类及对应的通用模板
|
||||
|
||||
| 常见打印单分类 | 对应系统上的打印模块 | 通用模板名称 | 模板编码 |
|
||||
| --- | --- | --- | --- |
|
||||
| 新结算单打印 | 维保单 | F6标准结算单(壹) | newSettleFirst |
|
||||
| 结算单-新 | 除维保单的其他单据(维修单、贴膜单......) | 无 | 无 |
|
||||
| 附表-新 | 新附表 | 无 | 无 |
|
||||
| 销售单 | 销售单 | 销售单(日期版) | xiaoshodanriqiban |
|
||||
| 洗车单 | 洗车单 | 洗车单 | wash01 |
|
||||
| 报价单打印 | 报价单 | 报价单打印 | quotationPrint |
|
||||
| 新库存入库单打印 | 入库单 | 新库存入库单打印 | 9001 |
|
||||
| 新库存出库单打印 | 出库单 | 新库存出库单打印 | 9002 |
|
||||
| | | | |
|
||||
| **注:采购单和采购退货单走打印平台定制,先向赵亚妮提供门店编码、门店名称,开通后再上传配置门店生效** | | | |
|
||||
|
||||
**注意:结算单要在收款后页面打印,请确保模板名称中包含“结算单”三个字**
|
||||
|
||||
> 更新: 2025-05-16 13:54:24 原文: <https://xcz.yuque.com/ombipo/obbigo/kg2qc1sbszwk48bf>
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
# 报价单接口参数
|
||||
|
||||
# 报价单接口参数
|
||||
|
||||
# 参数说明
|
||||
|
||||
## 主单信息
|
||||
|
||||
| 字段 | 含义 | 是否必有 | 类型 |
|
||||
| --- | --- | --- | --- |
|
||||
| partDetailVoList | 材料列表 | | List<QuotationServiceDetailPrintVo> |
|
||||
| serviceDetailVoList | 项目列表 | | List<QuotationPartDetailPrintVo> |
|
||||
| amountChinese | 商品金额中文大写 | | |
|
||||
| realAmountWithoutCardChinese | 待付金额中文大写 | | |
|
||||
|
||||
## QuotationPartDetailPrintVo
|
||||
|
||||
| 字段 | 含义 | 是否必有 | 类型 |
|
||||
| --- | --- | --- | --- |
|
||||
| pkId | 无意义主键 | 是 | BigInteger |
|
||||
| idOwnOrg | 门店id | 是 | BigInteger |
|
||||
| idQuotation | 报价单id | 是 | BigInteger |
|
||||
| idPart | 材料id | 否 | BigInteger |
|
||||
| partName | 材料名称(非组合,对应材料名称字段) | 是 | String |
|
||||
| partShowName | 材料在界面上显示的名称(组合供应商编码等信息) | 是 | String |
|
||||
| idMdmPart | 云材料ID | 否 | String |
|
||||
| labelId | 业务分类id | 否 | BigInteger |
|
||||
| labelName | 荣誉的业务分类名称 | 否 | String |
|
||||
| number | 数量 | 是 | BigDecimal |
|
||||
| price | 单价 | 是 | BigDecimal |
|
||||
| subtotal | 总价 | 是 | BigDecimal |
|
||||
| idEmployee | 服务员工id | 否 | String |
|
||||
| employeeName | 服务员工姓名 | 否 | String |
|
||||
| isMember | 套餐2,套餐卡1,普通0 | 是 | byte |
|
||||
| memo | 备注 | 否 | String |
|
||||
| discount | 折扣 | 是 | BigDecimal |
|
||||
| realSubtotal | 折后总计 | 是 | BigDecimal |
|
||||
| stockNumber | 门店库存数量 | 否 | BigDecimal |
|
||||
| groupId | 公司id | 是 | BigInteger |
|
||||
| unit | 单位 | 否 | String |
|
||||
| spec | 规格型号 | 否 | String |
|
||||
| brand | 品牌名称 | 否 | String |
|
||||
| brandId | 品牌id | 否 | String |
|
||||
| supplierCode | 零件号 | 否 | String |
|
||||
|
||||
## QuotationServiceDetailPrintVo
|
||||
|
||||
| 字段 | 含义 | 是否必有 | 类型 |
|
||||
| --- | --- | --- | --- |
|
||||
| pkId | 无意义主键 | 是 | BigInteger |
|
||||
| customCode | 项目编码 | 否 | String |
|
||||
| serviceName | 项目名称 | 是 | String |
|
||||
| workHour | 工时 | 否 | BigDecimal |
|
||||
| price | 单价 | 是 | BigDecimal |
|
||||
| subtotal | 工时费 | 是 | BigDecimal |
|
||||
| discount | 折扣 | 是 | BigDecimal |
|
||||
| realSubtotal | 折后金额 | 是 | BigDecimal |
|
||||
| memo | 备注 | 否 | String |
|
||||
|
||||
> 更新: 2025-05-26 14:19:50 原文: <https://xcz.yuque.com/ombipo/rpc7ms/gcgxuuzvmyhs4eoe>
|
||||
+675
@@ -0,0 +1,675 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Created with Jaspersoft Studio version 6.3.1.final using JasperReports Library version 6.3.1 -->
|
||||
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="jiesuandan" pageWidth="595" pageHeight="842" columnWidth="575" leftMargin="15" rightMargin="5" topMargin="10" bottomMargin="10" uuid="8fdb09f3-da43-46f9-a6cb-2b26a2247961">
|
||||
<property name="com.jaspersoft.studio.data.defaultdataadapter" value="One Empty Record"/>
|
||||
<property name="com.jaspersoft.studio.unit." value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.pageHeight" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.pageWidth" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.topMargin" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.bottomMargin" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.leftMargin" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.rightMargin" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.columnWidth" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.columnSpacing" value="pixel"/>
|
||||
<style name="Table_TH" mode="Opaque" backcolor="#FFFFFF">
|
||||
<box>
|
||||
<pen lineWidth="0.5" lineColor="#000000"/>
|
||||
<topPen lineWidth="0.5" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.5" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.5" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.5" lineColor="#000000"/>
|
||||
</box>
|
||||
</style>
|
||||
<style name="Table_CH" mode="Opaque" backcolor="#FFFFFF">
|
||||
<box>
|
||||
<pen lineWidth="0.5" lineColor="#000000"/>
|
||||
<topPen lineWidth="0.5" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.5" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.5" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.5" lineColor="#000000"/>
|
||||
</box>
|
||||
</style>
|
||||
<style name="Table_TD" mode="Opaque" backcolor="#FFFFFF">
|
||||
<box>
|
||||
<pen lineWidth="0.5" lineColor="#000000"/>
|
||||
<topPen lineWidth="0.5" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.5" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.5" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.5" lineColor="#000000"/>
|
||||
</box>
|
||||
</style>
|
||||
<subDataset name="Dataset1" uuid="22e86b94-acb8-45ed-960f-04558f91ad82">
|
||||
<queryString>
|
||||
<![CDATA[]]>
|
||||
</queryString>
|
||||
<field name="row1" class="java.lang.String"/>
|
||||
<field name="row2" class="java.lang.String"/>
|
||||
<field name="row3" class="java.lang.String">
|
||||
<fieldDescription><![CDATA[]]></fieldDescription>
|
||||
</field>
|
||||
<field name="row4" class="java.lang.String"/>
|
||||
<field name="row5" class="java.lang.String"/>
|
||||
<field name="row6" class="java.lang.String"/>
|
||||
<field name="row7" class="java.lang.String"/>
|
||||
<field name="row8" class="java.lang.String"/>
|
||||
<field name="row9" class="java.lang.String"/>
|
||||
<field name="row10" class="java.lang.String"/>
|
||||
<field name="row11" class="java.lang.String"/>
|
||||
<field name="row12" class="java.lang.String"/>
|
||||
<field name="row13" class="java.lang.String"/>
|
||||
<field name="row14" class="java.lang.String"/>
|
||||
</subDataset>
|
||||
<parameter name="orgName" class="java.lang.String"/>
|
||||
<parameter name="gatheringTime" class="java.lang.String"/>
|
||||
<parameter name="title" class="java.lang.String"/>
|
||||
<parameter name="printTime" class="java.lang.String"/>
|
||||
<parameter name="rowList" class="net.sf.jasperreports.engine.data.JRMapCollectionDataSource"/>
|
||||
<parameter name="column1" class="java.lang.String"/>
|
||||
<parameter name="column2" class="java.lang.String"/>
|
||||
<parameter name="column3" class="java.lang.String"/>
|
||||
<parameter name="column4" class="java.lang.String"/>
|
||||
<parameter name="column5" class="java.lang.String"/>
|
||||
<parameter name="column6" class="java.lang.String"/>
|
||||
<parameter name="column7" class="java.lang.String"/>
|
||||
<parameter name="column8" class="java.lang.String"/>
|
||||
<parameter name="column9" class="java.lang.String"/>
|
||||
<parameter name="column10" class="java.lang.String"/>
|
||||
<parameter name="column11" class="java.lang.String"/>
|
||||
<parameter name="column12" class="java.lang.String"/>
|
||||
<parameter name="column13" class="java.lang.String"/>
|
||||
<queryString>
|
||||
<![CDATA[]]>
|
||||
</queryString>
|
||||
<detail>
|
||||
<band height="92">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="0" y="-10" width="575" height="84" uuid="7ddf9306-7451-4ea4-bd57-cee86f8e13c9">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="16"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{title}]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement positionType="Float" mode="Opaque" x="1" y="74" width="48" height="18" backcolor="#FFFFFF" uuid="5da51596-6830-44c5-98e4-691007be1a4e">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[所属门店:]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="49" y="74" width="526" height="18" uuid="954bf3e6-7bf3-4deb-becf-217784bdc82a">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{orgName}]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
<band height="25">
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="260" y="0" width="315" height="18" uuid="36caab98-d260-4527-b87e-568ac54f61eb">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Right" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="0" rightIndent="5"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA["收款时间:"+$P{gatheringTime}]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
<band height="36">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement mode="Opaque" x="46" y="0" width="44" height="36" backcolor="#D4D4D4" uuid="b7ced69b-d8a8-45d7-b05b-3a3b83324d93">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$P{column2}!=null]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.4"/>
|
||||
</box>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9" isBold="true"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{column2}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement mode="Opaque" x="90" y="0" width="44" height="36" backcolor="#D4D4D4" uuid="c53a49f2-2d34-455e-b62d-b249f1fced35">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$P{column3}!=null]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.4"/>
|
||||
</box>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9" isBold="true"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{column3}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement mode="Opaque" x="134" y="0" width="44" height="36" backcolor="#D4D4D4" uuid="3385087d-7234-411d-8d79-738cac0295fd">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$P{column4}!=null]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.4"/>
|
||||
</box>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9" isBold="true"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{column4}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement mode="Opaque" x="266" y="0" width="44" height="36" backcolor="#D4D4D4" uuid="ccde0db9-971e-4912-9249-27361902f1b9">
|
||||
<printWhenExpression><![CDATA[$P{column7}!=null]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.4"/>
|
||||
</box>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9" isBold="true"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{column7}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement mode="Opaque" x="310" y="0" width="44" height="36" backcolor="#D4D4D4" uuid="0ae42faa-c6a8-47d6-9620-48ec03fd35d0">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$P{column8}!=null]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.4"/>
|
||||
</box>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9" isBold="true"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{column8}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement mode="Opaque" x="178" y="0" width="44" height="36" backcolor="#D4D4D4" uuid="62d27b1c-bebc-4a97-8fa0-2a6a497ab35e">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$P{column5}!=null]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.4"/>
|
||||
</box>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9" isBold="true"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{column5}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement mode="Opaque" x="222" y="0" width="44" height="36" backcolor="#D4D4D4" uuid="e459b7e6-0136-4c4e-ac76-6a4894311481">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$P{column6}!=null]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.4"/>
|
||||
</box>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9" isBold="true"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{column6}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement mode="Opaque" x="442" y="0" width="44" height="36" backcolor="#D4D4D4" uuid="dbb18e36-2d02-4970-9440-c2d8634e5c39">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$P{column11}!=null]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.4"/>
|
||||
</box>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9" isBold="true"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{column11}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement mode="Opaque" x="398" y="0" width="44" height="36" backcolor="#D4D4D4" uuid="49242b96-56f8-4c62-85f6-87a0342c936d">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$P{column10}!=null]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.4"/>
|
||||
</box>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9" isBold="true"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{column10}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement mode="Opaque" x="486" y="0" width="44" height="36" backcolor="#D4D4D4" uuid="900e6d7d-dc55-4f19-8c11-3ad4429f66ac">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$P{column12}!=null]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.4"/>
|
||||
</box>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9" isBold="true"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{column12}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement mode="Opaque" x="354" y="0" width="44" height="36" backcolor="#D4D4D4" uuid="e0da6daf-273a-4d28-b333-7c91e68a3ee6">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$P{column9}!=null]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.4"/>
|
||||
</box>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9" isBold="true"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{column9}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement mode="Opaque" x="530" y="0" width="45" height="36" backcolor="#D4D4D4" uuid="ad9f6d64-65f9-4dcd-8dbc-37e5899c528a">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$P{column13}!=null]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.4"/>
|
||||
</box>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9" isBold="true"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{column13}]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement mode="Opaque" x="1" y="0" width="45" height="36" backcolor="#D4D4D4" uuid="162abd58-679f-4c66-a256-458805e89193">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.4"/>
|
||||
</box>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
</textElement>
|
||||
<text><![CDATA[]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="16" y="0" width="30" height="18" uuid="652d5210-41df-4c62-a4ba-97f2e42b65ac">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9" isBold="true"/>
|
||||
</textElement>
|
||||
<text><![CDATA[内容]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="1" y="18" width="30" height="18" uuid="6e239a7c-f268-4ba1-b26d-f59cea6bb5ff">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9" isBold="true"/>
|
||||
</textElement>
|
||||
<text><![CDATA[方式]]></text>
|
||||
</staticText>
|
||||
<line>
|
||||
<reportElement mode="Transparent" x="1" y="0" width="45" height="36" backcolor="#D9D9D9" uuid="b02cf093-98f9-4cb6-8bc2-d6611a303b4e"/>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.5"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
</band>
|
||||
<band height="19">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<componentElement>
|
||||
<reportElement isPrintRepeatedValues="false" x="1" y="0" width="574" height="18" uuid="23ae66f5-6e0a-4c24-9fa5-2237d31a1aea">
|
||||
<property name="com.jaspersoft.studio.layout" value="com.jaspersoft.studio.editor.layout.VerticalRowLayout"/>
|
||||
<property name="com.jaspersoft.studio.table.style.table_header" value="Table 1_TH"/>
|
||||
<property name="com.jaspersoft.studio.table.style.column_header" value="Table 1_CH"/>
|
||||
<property name="com.jaspersoft.studio.table.style.detail" value="Table 1_TD"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<jr:table xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd">
|
||||
<datasetRun subDataset="Dataset1" uuid="f221c952-cad7-4dff-9cf7-ca32d2ddef3b">
|
||||
<dataSourceExpression><![CDATA[$P{rowList}]]></dataSourceExpression>
|
||||
</datasetRun>
|
||||
<jr:column width="45" uuid="9627a917-c5b0-4b80-b21f-449e4a1af32a">
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column1"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<jr:detailCell height="18">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="px"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="px"/>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement mode="Opaque" x="0" y="0" width="45" height="18" backcolor="#D4D4D4" uuid="05c9f6b2-819e-415f-8505-e8be2889cab5">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$F{row1}!=null]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.4"/>
|
||||
</box>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9" isBold="true"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$F{row1}]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
<jr:column width="44" uuid="cd30f1df-f54b-42a6-bf80-fcecb57824dc">
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column2"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<jr:detailCell height="18">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="px"/>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="0" y="0" width="44" height="18" uuid="fe6de99c-5be1-4d46-9282-c4d77f126dc9">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$F{row2}!=null]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.4"/>
|
||||
</box>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="8"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$F{row2}]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
<jr:column width="44" uuid="badfb61b-4c3d-443e-9d96-ce2f8871c148">
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column3"/>
|
||||
<jr:detailCell height="18">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="px"/>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="0" y="0" width="44" height="18" uuid="bbc0c8d1-ff73-4d70-bfd9-a3f514bf894b">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$F{row3}!=null]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.4"/>
|
||||
</box>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="8"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$F{row3}]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
<jr:column width="44" uuid="e54a7626-9237-4d3e-bb62-d48c41475cfd">
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column4"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<jr:detailCell height="18">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="px"/>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="0" y="0" width="44" height="18" uuid="8b267259-7609-4612-b6f2-417498e8409f">
|
||||
<printWhenExpression><![CDATA[$F{row4}!=null]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.4"/>
|
||||
</box>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="8"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$F{row4}]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
<jr:column width="44" uuid="1b3cbfb0-6d88-4b14-9215-cedc2a5b9c5e">
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column5"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<jr:detailCell height="18">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="px"/>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="0" y="0" width="44" height="18" uuid="7f6b00bd-a8ce-42ca-94e3-0f9202796b7d">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$F{row5}!=null]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.4"/>
|
||||
</box>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="8"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$F{row5}]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
<jr:column width="44" uuid="867931a4-9fef-46d7-85df-5d77f61bc7a9">
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column6"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<jr:detailCell height="18">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="px"/>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="0" y="0" width="44" height="18" uuid="e38c4d71-5e05-43c6-9d85-cbbdc4b2859b">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$F{row6}!=null]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.4"/>
|
||||
</box>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="8"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$F{row6}]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
<jr:column width="44" uuid="807004cb-f00a-4852-bc11-2a5ad1ae65b5">
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column7"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<jr:detailCell height="18">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="px"/>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="0" y="0" width="44" height="18" uuid="5cb940bc-d863-486d-a8e2-730002019abb">
|
||||
<printWhenExpression><![CDATA[$F{row7}!=null]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.4"/>
|
||||
</box>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="8"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$F{row7}]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
<jr:column width="44" uuid="baa16adc-a1b3-4e93-a6ee-5f5b705fd72d">
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column8"/>
|
||||
<jr:detailCell height="18">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="px"/>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="0" y="0" width="44" height="18" uuid="f66b1d3d-3144-4bea-b57a-571187c122f3">
|
||||
<printWhenExpression><![CDATA[$F{row8}!=null]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.4"/>
|
||||
</box>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="8"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$F{row8}]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
<jr:column width="44" uuid="bee2d403-9d56-4d85-8687-2c4101cc6d06">
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column9"/>
|
||||
<jr:detailCell height="18">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="px"/>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="0" y="0" width="44" height="18" uuid="9e46c6f4-841b-467d-97f1-0542179f7cc6">
|
||||
<printWhenExpression><![CDATA[$F{row9}!=null]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.4"/>
|
||||
</box>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="8"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$F{row9}]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
<jr:column width="44" uuid="fd8e7505-d366-4fde-96ac-1df719f7272e">
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column10"/>
|
||||
<jr:detailCell height="18">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="px"/>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="0" y="0" width="44" height="18" uuid="f0783afb-cce2-47d8-be32-55ab498515a6">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$F{row10}!=null]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.4"/>
|
||||
</box>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="8"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$F{row10}]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
<jr:column width="44" uuid="53cbd27d-048c-4200-8dd5-b21671c68e4b">
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column11"/>
|
||||
<jr:detailCell height="18">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="px"/>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="0" y="0" width="44" height="18" uuid="cce29502-097d-4763-b5c0-330093e14041">
|
||||
<printWhenExpression><![CDATA[$F{row11}!=null]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.4"/>
|
||||
</box>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="8"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$F{row11}]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
<jr:column width="44" uuid="9f2c3f4f-bc90-430d-b865-795def749d2d">
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column12"/>
|
||||
<jr:detailCell height="18">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="px"/>
|
||||
<box>
|
||||
<pen lineWidth="0.4"/>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="0" y="0" width="44" height="18" uuid="29c0a84c-f4d0-4e4b-8d19-3d13a024552b">
|
||||
<printWhenExpression><![CDATA[$F{row12}!=null]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.4"/>
|
||||
</box>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="8"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$F{row12}]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
<jr:column width="45" uuid="3def2e39-4c08-458e-8c36-df8eac735c65">
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column13"/>
|
||||
<jr:detailCell height="18">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="px"/>
|
||||
<box>
|
||||
<pen lineWidth="0.4"/>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement mode="Opaque" x="0" y="0" width="45" height="18" backcolor="#FFFFFF" uuid="573d45d1-bf4e-43e1-8282-49508130a3c0">
|
||||
<printWhenExpression><![CDATA[$F{row13}!=null]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.4"/>
|
||||
</box>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="8"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$F{row13}]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
</jr:table>
|
||||
</componentElement>
|
||||
</band>
|
||||
<band height="75">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<staticText>
|
||||
<reportElement x="454" y="10" width="52" height="18" uuid="c1af5cd0-e851-4fd6-a16b-f461a743d336">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[出纳签字:]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="2" y="50" width="48" height="18" uuid="1cf7fa11-8f01-4764-a9a8-d981c9f32ca6">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[打印时间:]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="50" y="50" width="124" height="18" uuid="b2daacc3-cb7c-443a-946b-be951bf080d5">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{printTime}]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement x="454" y="50" width="52" height="18" uuid="3c4cbf80-712b-4e51-a861-1b1643642612">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[收银签字:]]></text>
|
||||
</staticText>
|
||||
</band>
|
||||
</detail>
|
||||
</jasperReport>
|
||||
+243
@@ -0,0 +1,243 @@
|
||||
# 新版附表打印接口文档
|
||||
|
||||
# 新版附表打印接口文档
|
||||
|
||||
# 接口出参
|
||||
|
||||
| 字段 | 含义 | 类型 |
|
||||
| --- | --- | --- |
|
||||
| billNo | 附表单号 | String |
|
||||
| fromBillNo | 附表源工单号 | String |
|
||||
| fromMaintainType | 来源单据类型 | String |
|
||||
| billDate | 进厂日期 | String |
|
||||
| creatorName | 创建人名称 | String |
|
||||
| creationtime | 创建时间 | String |
|
||||
| naEmployee | 服务顾问 | String |
|
||||
| employeePhone | 服务顾问手机号 | String |
|
||||
| businessTypeName | 业务类型 | String |
|
||||
| nextMaintainDate | 下次保养日期 | String |
|
||||
| oilCapacity | 当前油量 | String |
|
||||
| mileage | 出厂里程(进厂里程) | Double |
|
||||
| nextMileage | 下次保养里程 | Double |
|
||||
| vin | 车辆VIN码 | String |
|
||||
| carNoWhole | 车牌号 | String |
|
||||
| carModel | 品牌车型全称 | String |
|
||||
| carModelShort | 车型简称 | String |
|
||||
| carColor | 车身颜色 | String |
|
||||
| carCategoryName | 车辆分类名称 | String |
|
||||
| carBrandName | 车辆品牌名称 | String |
|
||||
| carSeriesName | 车系名称 | String |
|
||||
| engineNumber | 发动机号 | String |
|
||||
| transmissionNo | 变速箱号 | String |
|
||||
| registerDate | 车辆注册日期 | String |
|
||||
| cardDate | 车辆发证日期 | String |
|
||||
| carNatureOfUseName | 车辆使用性质 | String |
|
||||
| carFuelTypeName | 车辆燃料(能源)类型 | String |
|
||||
| carSourceName | 车辆来源 | String |
|
||||
| carOwnerName | 车辆所有人姓名 | String |
|
||||
| naCustomer | 客户姓名 | String |
|
||||
| customerSourceName | 客户来源名称 | String |
|
||||
| customerDetailAddress | 客户详细地址 | String |
|
||||
| cellPhone | 联系电话(客户) | String |
|
||||
| memberCardNo | 会员卡号 | String |
|
||||
| points | 客户积分 | String |
|
||||
| customerLevelName | 客户等级名称 | String |
|
||||
| repairPerson | 送修人 | String |
|
||||
| repairPersonContact | 送修人联系方式 | String |
|
||||
| memo | 备注 | String |
|
||||
| completeDate | 完工日期 | String |
|
||||
| firstGatheringTime | 初次收款时间 | String |
|
||||
| estimatedDeliveryTime | 预计交车时间 | String |
|
||||
| deliveryTime | 交车时间 | String |
|
||||
| printContent | 免责条款 | String |
|
||||
| printContentJs | 免责条款江苏 | printContentJs |
|
||||
| storeLogo | 门店logo | String |
|
||||
| orgName | 门店名称 | String |
|
||||
| orgMemo | 门店备注 | String |
|
||||
| orgContacts | 联系人(维修厂) | String |
|
||||
| orgContactNumber | 联系电话(维修厂) | String |
|
||||
| orgDetailAddress | 联系地址(维修厂) | String |
|
||||
| orgContactMobile | 联系电话(维修厂) | String |
|
||||
| fax | 传真 | String |
|
||||
| email | 组织邮件 | String |
|
||||
| bankAccount | 开户银行 | String |
|
||||
| accountNumber | 账号 | String |
|
||||
| businessLicenseCode | 企业执照号 | String |
|
||||
| channelName | 来店途径名称 | String |
|
||||
| printOrgName | 打印抬头(需读取配置) | String |
|
||||
| amountAll | 应收总计(合计金额) | Double |
|
||||
| amountAllChinese | 应收总计(合计金额)中文大写 | String |
|
||||
| disCountAll | 总优惠合计(附表:项目优惠+材料优惠+收银优惠) | Double |
|
||||
| disCountAllBak | 项目优惠+材料优惠+收银优惠,等同于disCountAll | Double |
|
||||
| amountReal | 实收金额 | Double |
|
||||
| chineseAmount | 实收金额(中文大写) | Double |
|
||||
| oweAmount | 未收金额 | Double |
|
||||
| vipExpense | 套餐卡消费金额(附表为0) | Double |
|
||||
| vipExpenseFavourable | 套餐卡优惠金额(附表为0) | Double |
|
||||
| czkExpense | 储值卡消费金额(附表为0) | Double |
|
||||
| czkExpenseFavourable | 储值卡优惠金额(附表为0) | Double |
|
||||
| remainAmount | 结算金额tsf<br/>附表:应收-项目优惠-材料优惠 | Double |
|
||||
| receivedAmount | 收款金额tsf<br/>附表:等同于已收金额 | Double |
|
||||
| serviceList | 项目集合 | List |
|
||||
| └─ sortNumber | 序号 | String |
|
||||
| └─ orderNumber | 序号(全部) | String |
|
||||
| └─ name | 名称 | String |
|
||||
| └─ serviceName | 项目名称 | String |
|
||||
| └─ labelName | 业务分类名称 | String |
|
||||
| └─ price | 工时单价 | Double |
|
||||
| └─ workHour | 工时 | Double |
|
||||
| └─ subtotal | 金额 | Double |
|
||||
| └─ singleFavourable | 优惠金额 | Double |
|
||||
| └─ discountedSubtotal | 折后金额 | Double |
|
||||
| └─ serviceMemo | 附加信息备注 | String |
|
||||
| └─ discount | 折扣 | Double |
|
||||
| └─ empNameStr | 服务项目明细对应修理工名称组装字符串 | String |
|
||||
| └─ infiniteFlag | 是否无限,0:否,1:是 | Integer |
|
||||
| └─ customCode | 自定义编码 | String |
|
||||
| totalWorkHour | 项目工时合计 | Double |
|
||||
| totalWorkHourVip | VIP项目工时合计(附表为0) | Double |
|
||||
| serviceSubtotalAll | 工时费小计 | Double |
|
||||
| serviceSubtotalVip | 服务项目明细小计(会员项目,附表为0) | Double |
|
||||
| serviceNum | 维修项目小计 | String |
|
||||
| serviceFavourable | 服务项目(非会员项目)客户等级优惠(附表为0) | Double |
|
||||
| serviceDiscountFavourable | 项目优惠 | Double |
|
||||
| serviceFavourableTotal | 项目优惠金额合计 | Double |
|
||||
| serviceFavourableCommonTotal | 普通项目优惠金额合计 | Double |
|
||||
| serviceDisCountSubTotal | 项目折后金额合计 | Double |
|
||||
| partList | 工单对应配件材料集合 | List |
|
||||
| └─ sortNumber | 序号 | String |
|
||||
| └─ orderNumber | 序号(全部) | String |
|
||||
| └─ name | 名称 | String |
|
||||
| └─ partName | 材料名称 | String |
|
||||
| └─ partShowName | 材料名称(全) | String |
|
||||
| └─ partBrand | 配件品牌 | String |
|
||||
| └─ standard | 配件名称规格型号品牌 | String |
|
||||
| └─ spec | 规格型号 | String |
|
||||
| └─ supplierCode | 供应商编码 | String |
|
||||
| └─ unit | 单位 | String |
|
||||
| └─ number | 数量 | Double |
|
||||
| └─ price | 价格(单价) | Double |
|
||||
| └─ subtotal | 金额(材料金额) | Double |
|
||||
| └─ discount | 折扣 | Double |
|
||||
| └─ singleFavourable | 优惠金额 | Double |
|
||||
| └─ discountedSubtotal | 折后金额 | Double |
|
||||
| └─ partMemo | 备注 | String |
|
||||
| └─ customCode | 自定义编码 | String |
|
||||
| └─ employeeName | 员工名称 | String |
|
||||
| └─ outStockEmployeeName | 领料人 | String |
|
||||
| └─ empNameStr | 明细对应修理工名称组装字符串 | String |
|
||||
| └─ labelName | 业务分类名称 | String |
|
||||
| └─ idPart | 配件材料pk | BigInteger |
|
||||
| └─ idInfo | 本地材料id(长码) | String |
|
||||
| └─ applyModel | 适用车型 | String |
|
||||
| stuffNum | 材料数目合计 | String |
|
||||
| totalStuffNum | 材料数量合计 | String |
|
||||
| totalStuffNumVip | Vip材料数量合计(附表为0) | String |
|
||||
| stuffSubtotalAll | 材料费小计 | Double |
|
||||
| stuffSubtotalVip | 材料收入小计(会员项目,附表为0) | Double |
|
||||
| partinfoFavourable | 材料项目(非会员项目)客户等级优惠(附表为0) | Double |
|
||||
| partinfoDiscountFavourable | 材料折扣优惠 | Double |
|
||||
| partFavourableTotal | 材料优惠金额合计 | Double |
|
||||
| partFavourableCommonTotal | 普通材料优惠金额合计 | Double |
|
||||
| stuffDisCountTotal | 材料折后金额合计 | Double |
|
||||
| pointFavourable | 积分优惠(附表为0) | Double |
|
||||
| packageFavourable | 套餐优惠(附表为0) | Double |
|
||||
| discountFavourable | 结清优惠(附表为0) | Double |
|
||||
| gatheringFavourable | 收银优惠 | Double |
|
||||
| couponFavourable | 优惠券优惠(附表为0) | Double |
|
||||
| czkDiscountFavourable | 储值卡折扣优惠(附表为0) | Double |
|
||||
| customerLevelFavourable | 客户级别优惠金额(附表为0) | Double |
|
||||
| extraChargeList | 附加费用集合 | List |
|
||||
| └─ sortNumber | 序号 | String |
|
||||
| └─ extraName | 附加费名称 | String |
|
||||
| └─ subtotal | 金额 | Double |
|
||||
| └─ memo | 备注 | String |
|
||||
| extraCostTotal | 附加费小计 | Double |
|
||||
| extraNumber | 附加费数量小计 | String |
|
||||
| managementCost | 管理费 | Double |
|
||||
| extraPrintVo | 附加项目 | ExtraPrintAttribute |
|
||||
| └─ commissionCustomName | 代办费自定义名称 | String |
|
||||
| └─ commissionCost | 代办费金额 | Double |
|
||||
| └─ commissionMemo | 代办费备注 | String |
|
||||
| └─ diagnosisCustomName | 诊断费自定义名称 | String |
|
||||
| └─ diagnosisCost | 诊断费金额 | Double |
|
||||
| └─ diagnosisItemName | 诊断详细名称 | String |
|
||||
| └─ diagnosisMemo | 诊断费备注 | String |
|
||||
| └─ checkCustomName | 检查费自定义名称 | String |
|
||||
| └─ checkItemName | 诊断详细名称 | String |
|
||||
| └─ checkCost | 检查费金额 | Double |
|
||||
| └─ checkMemo | 检查费备注 | String |
|
||||
| └─ processCustomName | 加工费自定义名称 | String |
|
||||
| └─ processCost | 加工费金额 | Double |
|
||||
| └─ processMemo | 加工费备注 | String |
|
||||
| └─ processItemName | 加工详细名称 | String |
|
||||
| └─ managementCustomName | 管理费自定义名称 | String |
|
||||
| └─ managementCost | 管理费金额 | Double |
|
||||
| └─ managementMemo | 管理费备注 | String |
|
||||
| └─ fuelName | 加油费 | String |
|
||||
| └─ fuelAmount | 加油费金额 | Double |
|
||||
| └─ trailName | 拖车费 | String |
|
||||
| └─ trailAmount | 拖车费金额 | Double |
|
||||
| allOtherCost | 附加费合计应收 | Double |
|
||||
| receiptAmount | 收据金额(附表:应收-项目优惠-材料优惠-收银优惠) | Double |
|
||||
| receiptAmountChinese | 收据金额中文大写 | String |
|
||||
| payItemList | 付款方式集合 | List |
|
||||
| └─ payWay | 付款方式 | String |
|
||||
| └─ payAmount | 付款金额 | Double |
|
||||
| └─ chinesePayAmount | 付款金额中文大写 | String |
|
||||
| payItemTogether | 付款方式拼接 | String |
|
||||
| payItemTogetherChinese | 付款方式总额中文大写 | String |
|
||||
| paymentTypeDetails | 支付方式汇总 | String |
|
||||
| settleOweAmout | 结算单中用的待付金额(未收) | Double |
|
||||
| settleOweAmoutChinese | 结算单中用的待付金额大写(未收) | String |
|
||||
| settleReceivedAmout | 结算单中用的实付金额(实收) | Double |
|
||||
| settleReceivedAmoutChinese | 结算单中用的实付金额大写(未收) | String |
|
||||
| realPayAmountChinese | 客户实付大写(应收-所有优惠) | String |
|
||||
| naInsurer | 理赔公司名称 | String |
|
||||
| insurancepolicyNo | 理赔单理赔保险单号 | String |
|
||||
| insuranceCompany | 保险公司名称 | String |
|
||||
| contactName | 联系人姓名 | String |
|
||||
| contactCellphone | 联系人电话 | String |
|
||||
| insuranceNo | 商业险单号 | String |
|
||||
| insuranceNoTCI | 交强险单号 | String |
|
||||
| insuranceExpiryDate | 商业险到期日 | String |
|
||||
| insuranceExpiryDateTCI | 交强险到期日 | String |
|
||||
| printEmployeeName | 打印人姓名 | String |
|
||||
| printTime | 打印时间 | String |
|
||||
| printCount | 打印次数 | String |
|
||||
|
||||
# 备注1
|
||||
|
||||
1. ++新版附表没有“状态”字段,所有模板中切勿使用 billStatus【单据状态】、balanceStatus【结算状态】来进行判断输出;采用直接取值方式填值++
|
||||
|
||||
1. ++没有了balanceStatus,采用收款方式列表payItemList判空的方式来验证是否有收款信息++
|
||||
|
||||
1. ++收银金额可写作:++$P{payItemList}.getRecordCount()==0?$P{receivedAmount}:$P{receivedAmount}.setScale( 2, BigDecimal.ROUND\_HALF\_EVEN ).toString()+"("+$P{paymentTypeDetails}+")"
|
||||
|
||||
2. ++待付金额可写作:$P{oweAmount}++
|
||||
|
||||
3. ++实付金额可写作:$P{amountReal}++
|
||||
|
||||
4. ++合计金额可写作:++$P{payItemList}.getRecordCount()==0?($P{settleOweAmout}).setScale( 2, BigDecimal.ROUND_HALF_EVEN ):($P{settleReceivedAmout}).setScale( 2, BigDecimal.ROUND_HALF_EVEN )
|
||||
|
||||
5. ++大写可写作:++$P{payItemList}.getRecordCount()==0?$P{settleOweAmoutChinese}:$P{chineseAmount}
|
||||
|
||||
2. ++新版附表没有“单据类型”字段(原附表的maintainType为"GDFB"、"LPDFB"两种附表类型),所有模板中切勿使用 maintainType【单据类型】字段作为判断条件。根据情况可以取 fromMaintainType【来源单据类型】进行判断。如:++
|
||||
|
||||
1. ++是否展示理赔公司、理赔单等理赔相关信息栏,老附表判断逻辑为 maintainType.equals('LPDFB')。可更换为 fromMaintainType.equals('LPD')++
|
||||
|
||||
|
||||
# 备注2
|
||||
|
||||
1. 出参标注颜色为 **绿 色** 的字段,为 ++**附表本身内容**++(如车牌号、VIN码等) 或 ++**无法变更内容**++(如门店信息等)
|
||||
|
||||
1. 客户在附表页面直接变更信息,会直观反映在打印内容中。
|
||||
|
||||
2. 出参标注颜色为 **橙 色** 的字段,为 ++**通过客户ID、车辆ID、项目ID、材料ID**++ 等,++**反查**++ 基础数据获得内容,
|
||||
|
||||
1. 若客户通过 ++**附表页面选择组件方式**++ 修改附表信息,因ID发生变化,该部分打印内容会随之变化,变更信息将 ++**会体现在打印内容中**++。
|
||||
|
||||
2. 若客户通过 ++**手动填写文本内容方式**++ 修改附表信息,因ID未发生变化,该部分打印内容不会变化,变更信息将 ++**不会体现在打印内容中**++,若客户不满意结果,请客户直接将 ++**基础数据进行变更**++ 后,通过页面组件选择后再进行打印。
|
||||
|
||||
|
||||
> 更新: 2024-01-11 12:11:34 原文: <https://xcz.yuque.com/ombipo/rpc7ms/nmoz9mzqf2q8micw>
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
# 材料标签接口参数
|
||||
|
||||
# 材料标签接口参数
|
||||
|
||||
打印平台模版分类:材料价格通用标签打印
|
||||
|
||||
材料标签支持一次打多张,与labelList集合里的元素个数相匹配:
|
||||
|
||||
| 字段 | 含义 | 是否必有 | 类型 |
|
||||
| --- | --- | --- | --- |
|
||||
| labelList | 材料标签列表 | | List<Label> |
|
||||
| <br/><br/> | | | |
|
||||
|
||||
Label:
|
||||
|
||||
| 字段 | 含义 | 是否必有 | 类型 |
|
||||
| --- | --- | --- | --- |
|
||||
| name | 材料名称 | | String |
|
||||
| supplierCode | 零件号 | | String |
|
||||
| customCode | 材料编码 | | String |
|
||||
| sellPrice | 销售价格 | | BigDecimal |
|
||||
| date | 打印日期 | | String yyyy/MM/dd |
|
||||
| <br/><br/> | | | |
|
||||
|
||||
# 采购库存材料标签打印
|
||||
|
||||
### 打印平台模版分类:
|
||||
|
||||
不带供应商信息:采购库存通用标签打印-新
|
||||
|
||||
带供应商信息:采购库存通用标签打印-包含供应商-新
|
||||
|
||||

|
||||
|
||||
### 打印数据体
|
||||
|
||||
材料标签支持一次打多张,于labelList集合里的元素个数相匹配:
|
||||
|
||||
| 字段 | 含义 | 是否必有 | 类型 |
|
||||
| --- | --- | --- | --- |
|
||||
| labelList | 材料名称 | | List<Object> |
|
||||
|
||||
Object:
|
||||
|
||||
| 字段 | 含义 | 是否必有 | 类型 |
|
||||
| --- | --- | --- | --- |
|
||||
| partName | 材料名称 | | String |
|
||||
| partBrand | 材料品牌 | | String |
|
||||
| customCode | 材料编码 | | String |
|
||||
| partShowName | 组合名称(材料品牌,名称,规格型号组合) | | String |
|
||||
| supplierCode | 材料供应商编码 | | String |
|
||||
| spec | 材料规格型号 | | String |
|
||||
| unit | 材料单位 | | String |
|
||||
| barCode | 材料编码 | | String |
|
||||
| billDate | 单据日期 | | String yyyy-MM-dd |
|
||||
| supplierName | 供应商名称 | | String |
|
||||
| storageName | 材料仓库名称 | | String |
|
||||
| defSeat | 材料货位 | | String |
|
||||
| date | 打印的当前日期 | | String yyyy/MM/dd |
|
||||
|
||||
> 更新: 2023-09-14 14:27:45 原文: <https://xcz.yuque.com/ombipo/rpc7ms/mvq9tlfxeg2k6v9y>
|
||||
+3125
File diff suppressed because it is too large
Load Diff
+100
@@ -0,0 +1,100 @@
|
||||
# 检测单接口参数
|
||||
|
||||
# 检测单接口参数
|
||||
|
||||
# 参数说明
|
||||
|
||||
## 主单信息
|
||||
|
||||
| 字段 | 含义 | 是否必有 | 类型 |
|
||||
| --- | --- | --- | --- |
|
||||
| carCheckPackageName | 模板名称 | | String |
|
||||
| title | 标题 | | String |
|
||||
| billNo | 检测单号 | | String |
|
||||
| printTime | 打印时间 | | String |
|
||||
| naEmployee | 服务顾问 | | String |
|
||||
| billDate | 进厂时间 | | String |
|
||||
| deliveryTime | 预计交车 | | String |
|
||||
| naCustomer | 车主 | | String |
|
||||
| carModel | 车型 | | String |
|
||||
| cellPhone | 车主电话 | | String |
|
||||
| carNoWhole | 车牌号 | | String |
|
||||
| vin | vin码 | | String |
|
||||
| repairPerson | 送修人 | | String |
|
||||
| repairPersonContact | 送修人联系方式 | | String |
|
||||
| mileage | 进厂里程 | | String |
|
||||
| oilCapacity | 进厂油量 | | String |
|
||||
| nextMileage | 下次保养里程 | | String |
|
||||
| nextMaintainDate | 下次保养日期 | | String |
|
||||
| customerMemo | 车主描述 | | String |
|
||||
| merchantAddress | 联系地址 | | String |
|
||||
| merchantPhone | 联系方式(手机 + 固定电话) | | String |
|
||||
| qrCode | 二维码 | | String |
|
||||
| qrCodeToB | 新版检测单B端二维码 | | String |
|
||||
| qrCodeToC | 新版检测单C端二维码 | | String |
|
||||
| icon | 车辆环视图 | | String |
|
||||
| maintainBillNo | 结算单号 | | String |
|
||||
| showComputerCheckInfo | 是否展示电脑检测 | | Boolean |
|
||||
| computerCheckInfoList | 电脑检测 | | List<ComputerPrintItem> |
|
||||
| personalCheckInfoList | 包含正常和异常人工检测项 | | List<PersonalPrintItem> |
|
||||
| sortedPersonalCheckInfoList | 包含正常和异常人工检测项,问题项目排序靠前 | | List<PersonalPrintItem> |
|
||||
| optionPersonalCheckInfoList | 异常人工检测项 | | List<PersonalPrintItem> |
|
||||
| normalPersonalCheckInfoList | 正常人工检测项 | | List<PersonalPrintItem> |
|
||||
| iconMemo | 环视图备注 | | String |
|
||||
| iconResult | 环视图结论 | | String |
|
||||
| warningLightResult | 警示灯结论 | | String |
|
||||
| warningLightMemo | 警示灯备注 | | String |
|
||||
| showWarningLightItem | 是否展示警示灯 | | Boolean |
|
||||
| warningLightItemList | 警示灯 | | List<WarningLightItem> |
|
||||
| warningLightBrightItemUrls | 警示灯列表字符串 | | String |
|
||||
| employeeName | 服务技师 | | String |
|
||||
| | | | |
|
||||
|
||||
## ComputerPrintItem
|
||||
|
||||
| 字段 | 含义 | 类型 |
|
||||
| --- | --- | --- |
|
||||
| index | 序号 | String |
|
||||
| errorCode | 故障码 | String |
|
||||
| itemName | 检测项目 | String |
|
||||
| optionNameS | 建议处理(Y) | String |
|
||||
| optionNameE | 择期处理(Y) | String |
|
||||
| optionNameU | 急需处理(Y) | String |
|
||||
| memo | 备注 | String |
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
|
||||
## PersonalPrintItem(检测小类)
|
||||
|
||||
| 字段 | 含义 | 类型 |
|
||||
| --- | --- | --- |
|
||||
| index | 序号 | BigInteger |
|
||||
| itemComponent | 检测部件(小类名称) | String |
|
||||
| memo | 备注 | String |
|
||||
| childList | 子项目列表 | List<PrintTinyItem> |
|
||||
|
||||
## PrintTinyItem(检测项目)
|
||||
|
||||
| 字段 | 含义 | 类型 |
|
||||
| --- | --- | --- |
|
||||
| itemName | 检测项目 | String |
|
||||
| itemResults | 检测结果 | String |
|
||||
| optionNameS | 建议处理 Y | String |
|
||||
| optionNameE | 择期处理 Y | String |
|
||||
| optionNameU | 急需处理 Y | String |
|
||||
| memo | 备注 | String |
|
||||
|
||||
## ComputerPrintItem
|
||||
|
||||
| 字段 | 含义 | 类型 |
|
||||
| --- | --- | --- |
|
||||
| warningIconCode | 警示灯 | String |
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
|
||||
> 更新: 2025-02-25 13:55:59 原文: <https://xcz.yuque.com/ombipo/rpc7ms/zayna4s335straki>
|
||||
+1135
File diff suppressed because it is too large
Load Diff
+842
@@ -0,0 +1,842 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Created with Jaspersoft Studio version 6.3.1.final using JasperReports Library version 6.3.1 -->
|
||||
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="carWash" pageWidth="136" pageHeight="842" columnWidth="136" leftMargin="0" rightMargin="0" topMargin="0" bottomMargin="10" uuid="8fdb09f3-da43-46f9-a6cb-2b26a2247961">
|
||||
<property name="com.jaspersoft.studio.data.defaultdataadapter" value="One Empty Record"/>
|
||||
<property name="com.jaspersoft.studio.unit." value="mm"/>
|
||||
<property name="com.jaspersoft.studio.unit.pageHeight" value="pixel"/>
|
||||
<style name="Table_TH" mode="Opaque" backcolor="#FFFFFF">
|
||||
<box>
|
||||
<pen lineWidth="0.5" lineColor="#000000"/>
|
||||
<topPen lineWidth="0.5" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.5" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.5" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.5" lineColor="#000000"/>
|
||||
</box>
|
||||
</style>
|
||||
<style name="Table_CH" mode="Opaque" backcolor="#FFFFFF">
|
||||
<box>
|
||||
<pen lineWidth="0.5" lineColor="#000000"/>
|
||||
<topPen lineWidth="0.5" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.5" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.5" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.5" lineColor="#000000"/>
|
||||
</box>
|
||||
</style>
|
||||
<style name="Table_TD" mode="Opaque" backcolor="#FFFFFF">
|
||||
<box>
|
||||
<pen lineWidth="0.5" lineColor="#000000"/>
|
||||
<topPen lineWidth="0.5" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.5" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.5" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.5" lineColor="#000000"/>
|
||||
</box>
|
||||
</style>
|
||||
<subDataset name="Dataset1" uuid="22e86b94-acb8-45ed-960f-04558f91ad82">
|
||||
<queryString>
|
||||
<![CDATA[]]>
|
||||
</queryString>
|
||||
<field name="serviceName" class="java.lang.String"/>
|
||||
<field name="workHour" class="java.math.BigDecimal"/>
|
||||
<field name="leftCount" class="java.math.BigDecimal"/>
|
||||
<field name="unusedNumber" class="java.lang.Integer"/>
|
||||
<field name="number" class="java.lang.Integer"/>
|
||||
<field name="subtotal" class="java.math.BigDecimal"/>
|
||||
<field name="empNameStr" class="java.lang.String"/>
|
||||
</subDataset>
|
||||
<subDataset name="Dataset1sub" uuid="22e86b94-acb8-45ed-960f-04558f91ad82">
|
||||
<queryString>
|
||||
<![CDATA[]]>
|
||||
</queryString>
|
||||
<field name="serviceName" class="java.lang.String"/>
|
||||
<field name="workHour" class="java.math.BigDecimal"/>
|
||||
<field name="leftCount" class="java.math.BigDecimal"/>
|
||||
<field name="unusedNumber" class="java.lang.Integer"/>
|
||||
<field name="number" class="java.lang.Integer"/>
|
||||
<field name="subtotal" class="java.math.BigDecimal"/>
|
||||
</subDataset>
|
||||
<subDataset name="Dataset2" uuid="b9fe50e4-5070-473e-9238-1aa624bd7ae5">
|
||||
<queryString>
|
||||
<![CDATA[]]>
|
||||
</queryString>
|
||||
<field name="customCode" class="java.lang.String"/>
|
||||
<field name="partName" class="java.lang.String"/>
|
||||
<field name="unit" class="java.lang.String"/>
|
||||
<field name="number" class="java.math.BigDecimal"/>
|
||||
<field name="price" class="java.math.BigDecimal"/>
|
||||
<field name="subtotal" class="java.math.BigDecimal"/>
|
||||
<field name="partBrand" class="java.lang.String"/>
|
||||
<field name="standard" class="java.lang.String"/>
|
||||
<field name="supplierCode" class="java.lang.String"/>
|
||||
<field name="discountedSubtotal" class="java.math.BigDecimal"/>
|
||||
<field name="partMemo" class="java.lang.String"/>
|
||||
<field name="isBring" class="java.lang.String"/>
|
||||
<field name="singleFavourable" class="java.math.BigDecimal"/>
|
||||
<field name="isMember" class="java.lang.Integer"/>
|
||||
<field name="discount" class="java.math.BigDecimal"/>
|
||||
<field name="spec" class="java.lang.String"/>
|
||||
<sortField name="isMember" order="Descending"/>
|
||||
</subDataset>
|
||||
<subDataset name="DatasetPay" uuid="6f96d8c9-fa56-4586-9b6d-846e9a678fc3">
|
||||
<queryString>
|
||||
<![CDATA[]]>
|
||||
</queryString>
|
||||
<field name="payWay" class="java.lang.String"/>
|
||||
<field name="payAmount" class="java.math.BigDecimal"/>
|
||||
<field name="chinesePayAmount" class="java.lang.String"/>
|
||||
</subDataset>
|
||||
<subDataset name="DatasetExtra" uuid="6d2afb78-c6ff-45a0-90a2-6e65d25da398">
|
||||
<queryString>
|
||||
<![CDATA[]]>
|
||||
</queryString>
|
||||
<field name="extraName" class="java.lang.String"/>
|
||||
<field name="subtotal" class="java.math.BigDecimal"/>
|
||||
<field name="memo" class="java.lang.String"/>
|
||||
</subDataset>
|
||||
<subDataset name="Dataset_sub" uuid="6a79ccac-0c3d-4ada-a547-6d9f5ef3a7c9">
|
||||
<queryString>
|
||||
<![CDATA[]]>
|
||||
</queryString>
|
||||
<field name="serviceName" class="java.lang.String"/>
|
||||
<field name="workHour" class="java.math.BigDecimal"/>
|
||||
<field name="leftCount" class="java.math.BigDecimal"/>
|
||||
<field name="unusedNumber" class="java.lang.Integer"/>
|
||||
<field name="number" class="java.lang.Integer"/>
|
||||
<field name="subtotal" class="java.math.BigDecimal"/>
|
||||
</subDataset>
|
||||
<subDataset name="CopyOfDataset_1" uuid="fad36331-4b02-4d0a-99c9-d3608c7abffb">
|
||||
<queryString>
|
||||
<![CDATA[]]>
|
||||
</queryString>
|
||||
<field name="serviceName" class="java.lang.String"/>
|
||||
<field name="workHour" class="java.math.BigDecimal"/>
|
||||
<field name="leftCount" class="java.math.BigDecimal"/>
|
||||
<field name="unusedNumber" class="java.lang.Integer"/>
|
||||
<field name="number" class="java.lang.Integer"/>
|
||||
<field name="subtotal" class="java.math.BigDecimal"/>
|
||||
</subDataset>
|
||||
<parameter name="orgName" class="java.lang.String"/>
|
||||
<parameter name="detailAddress" class="java.lang.String"/>
|
||||
<parameter name="contactNumber" class="java.lang.String"/>
|
||||
<parameter name="fax" class="java.lang.String"/>
|
||||
<parameter name="bankAccount" class="java.lang.String"/>
|
||||
<parameter name="email" class="java.lang.String"/>
|
||||
<parameter name="accountNumber" class="java.lang.String"/>
|
||||
<parameter name="naCustomer" class="java.lang.String"/>
|
||||
<parameter name="contactName" class="java.lang.String"/>
|
||||
<parameter name="contactCellphone" class="java.lang.String"/>
|
||||
<parameter name="billNo" class="java.lang.String"/>
|
||||
<parameter name="billDate" class="java.lang.String"/>
|
||||
<parameter name="mileage" class="java.math.BigDecimal"/>
|
||||
<parameter name="carNoWhole" class="java.lang.String"/>
|
||||
<parameter name="carModelShort" class="java.lang.String"/>
|
||||
<parameter name="deliveryTime" class="java.lang.String"/>
|
||||
<parameter name="serviceSubtotalAll" class="java.math.BigDecimal"/>
|
||||
<parameter name="stuffSubtotalAll" class="java.math.BigDecimal"/>
|
||||
<parameter name="extraCostTotal" class="java.math.BigDecimal"/>
|
||||
<parameter name="amountAll" class="java.math.BigDecimal"/>
|
||||
<parameter name="totalWorkHour" class="java.math.BigDecimal"/>
|
||||
<parameter name="numberCount" class="java.lang.String"/>
|
||||
<parameter name="serviceList" class="net.sf.jasperreports.engine.data.JRMapCollectionDataSource"/>
|
||||
<parameter name="partList" class="net.sf.jasperreports.engine.data.JRMapCollectionDataSource"/>
|
||||
<parameter name="businessTypeName" class="java.lang.String"/>
|
||||
<parameter name="creatorName" class="java.lang.String"/>
|
||||
<parameter name="carModel" class="java.lang.String"/>
|
||||
<parameter name="vin" class="java.lang.String"/>
|
||||
<parameter name="printCount" class="java.lang.String"/>
|
||||
<parameter name="serviceNum" class="java.lang.String"/>
|
||||
<parameter name="serviceDisCountSubTotal" class="java.math.BigDecimal"/>
|
||||
<parameter name="totalStuffNum" class="java.lang.String"/>
|
||||
<parameter name="couponFavourable" class="java.math.BigDecimal"/>
|
||||
<parameter name="pointFavourable" class="java.math.BigDecimal"/>
|
||||
<parameter name="partinfoDiscountFavourable" class="java.math.BigDecimal"/>
|
||||
<parameter name="naEmployee" class="java.lang.String"/>
|
||||
<parameter name="memo" class="java.lang.String"/>
|
||||
<parameter name="repairPerson" class="java.lang.String"/>
|
||||
<parameter name="cellPhone" class="java.lang.String"/>
|
||||
<parameter name="carBrandName" class="java.lang.String"/>
|
||||
<parameter name="orgContactMobile" class="java.lang.String"/>
|
||||
<parameter name="orgDetailAddress" class="java.lang.String"/>
|
||||
<parameter name="selfPartList" class="net.sf.jasperreports.engine.data.JRMapCollectionDataSource"/>
|
||||
<parameter name="payItemList" class="net.sf.jasperreports.engine.data.JRMapCollectionDataSource"/>
|
||||
<parameter name="extraChargeList" class="net.sf.jasperreports.engine.data.JRMapCollectionDataSource"/>
|
||||
<parameter name="stuffDisCountTotal" class="java.math.BigDecimal"/>
|
||||
<parameter name="selfTotalStuffNum" class="java.lang.String"/>
|
||||
<parameter name="czkExpense" class="java.math.BigDecimal"/>
|
||||
<parameter name="disCountAll" class="java.math.BigDecimal"/>
|
||||
<parameter name="packageFavourable" class="java.math.BigDecimal"/>
|
||||
<parameter name="serviceFavourable" class="java.math.BigDecimal"/>
|
||||
<parameter name="partinfoFavourable" class="java.math.BigDecimal"/>
|
||||
<parameter name="gatheringFavourable" class="java.math.BigDecimal"/>
|
||||
<parameter name="discountFavourable" class="java.math.BigDecimal"/>
|
||||
<parameter name="oweAmount" class="java.math.BigDecimal"/>
|
||||
<parameter name="amountReal" class="java.math.BigDecimal"/>
|
||||
<parameter name="printTime" class="java.lang.String"/>
|
||||
<parameter name="creationtime" class="java.lang.String"/>
|
||||
<parameter name="extraNumber" class="java.lang.String"/>
|
||||
<parameter name="carSeriesName" class="java.lang.String"/>
|
||||
<parameter name="qRCodeStr" class="java.lang.String"/>
|
||||
<parameter name="vipExpense" class="java.math.BigDecimal"/>
|
||||
<parameter name="storeLogo" class="java.lang.String"/>
|
||||
<parameter name="partFavourableTotal" class="java.math.BigDecimal"/>
|
||||
<parameter name="serviceFavourableTotal" class="java.math.BigDecimal"/>
|
||||
<parameter name="partFavourableCommonTotal" class="java.math.BigDecimal"/>
|
||||
<parameter name="serviceFavourableCommonTotal" class="java.math.BigDecimal"/>
|
||||
<parameter name="serviceSubtotalVip" class="java.math.BigDecimal"/>
|
||||
<parameter name="stuffSubtotalVip" class="java.math.BigDecimal"/>
|
||||
<parameter name="nextMileage" class="java.math.BigDecimal"/>
|
||||
<parameter name="printContent" class="java.lang.String"/>
|
||||
<parameter name="repairPersonContact" class="java.lang.String"/>
|
||||
<parameter name="payItemTogether" class="java.lang.String"/>
|
||||
<parameter name="payItemTogetherChinese" class="java.lang.String"/>
|
||||
<parameter name="printOrgName" class="java.lang.String"/>
|
||||
<parameter name="orgContactNumber" class="java.lang.String"/>
|
||||
<parameter name="balanceStatus" class="java.lang.String"/>
|
||||
<parameter name="receiptAmount" class="java.math.BigDecimal"/>
|
||||
<parameter name="stubPrintFlag" class="java.lang.String"/>
|
||||
<parameter name="stubServiceList" class="net.sf.jasperreports.engine.data.JRMapCollectionDataSource">
|
||||
<parameterDescription><![CDATA[]]></parameterDescription>
|
||||
</parameter>
|
||||
<parameter name="czkDetailInfo" class="java.lang.String"/>
|
||||
<queryString>
|
||||
<![CDATA[]]>
|
||||
</queryString>
|
||||
<variable name="tempServiceList" class="net.sf.jasperreports.engine.data.JRMapCollectionDataSource">
|
||||
<variableExpression><![CDATA[$P{serviceList}]]></variableExpression>
|
||||
</variable>
|
||||
<variable name="tempServiceList2" class="net.sf.jasperreports.engine.data.JRMapCollectionDataSource">
|
||||
<variableExpression><![CDATA[$P{serviceList}]]></variableExpression>
|
||||
</variable>
|
||||
<detail>
|
||||
<band height="43">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="0" y="1" width="136" height="40" uuid="749214fe-d497-4af5-809c-60db5b97deee">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="11"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[($P{printOrgName}==null?$P{orgName}:($P{printOrgName}.isEmpty()?$P{orgName}:$P{printOrgName}))+"洗车单"]]></textFieldExpression>
|
||||
</textField>
|
||||
<line>
|
||||
<reportElement positionType="Float" x="0" y="42" width="136" height="1" uuid="9902b948-f3bc-4318-9162-169d3a18d40e">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.4" lineStyle="Solid"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
</band>
|
||||
<band height="11">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="40" height="11" uuid="a9ea9a61-8b35-4714-abd6-c1b3f01daf4c">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="7"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[打印时间:]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="32" y="0" width="104" height="11" uuid="3e42cdc1-f715-455d-965b-a3862546efe3">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="7"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{printTime}.substring(0,16)]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
<band height="11">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="40" height="11" uuid="d8179c10-e152-47cf-98ed-6d25100423b1">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="7"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[洗车单号:]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="32" y="0" width="104" height="11" uuid="73392fa1-f678-4f97-b702-97d591431a76">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="7"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{billNo}]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
<band height="11">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="32" y="0" width="104" height="11" uuid="4b8e8259-abcb-4b55-8932-645ab3c168db">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="7"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{naEmployee}]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement key="" x="0" y="0" width="40" height="11" uuid="aa005a7f-11f1-4362-94dd-7d4b737f85fb">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="7"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[服务顾问:]]></text>
|
||||
</staticText>
|
||||
</band>
|
||||
<band height="11">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="24" y="0" width="112" height="11" uuid="4c9e2e05-12f0-4c10-a4a7-cfac0dedc4c7">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="7"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{carNoWhole}]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement key="" x="0" y="0" width="40" height="11" uuid="506d2cfc-d948-4a43-971c-e2ae1f4f4a6e">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="7"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[车牌号:]]></text>
|
||||
</staticText>
|
||||
</band>
|
||||
<band height="11">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="18" y="0" width="118" height="11" uuid="7c4f4788-dd00-484c-8762-c907f94aba06">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="7"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{naCustomer}.substring(0, 1) + "(*^_^*)" + $P{naCustomer}.substring($P{naCustomer}.length() > 10 ? 10 : $P{naCustomer}.length(), $P{naCustomer}.length())]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="29" height="11" uuid="1e0990e3-d082-4c2a-b861-ea88ae864819">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="7"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[客户:]]></text>
|
||||
</staticText>
|
||||
</band>
|
||||
<band height="12">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="32" y="0" width="104" height="11" uuid="aa23dce0-7f6f-4324-8368-9040c5460fce">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="7"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{cellPhone}.length() <= 3 ? $P{cellPhone}: $P{cellPhone}.substring(0, 3) + "(*^_^*)" + $P{cellPhone}.substring($P{cellPhone}.length() > 7 ? 7 : $P{cellPhone}.length(), $P{cellPhone}.length())]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="40" height="11" uuid="17c41cd7-40bc-417a-b81f-31cb88c34931">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="7"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[客户电话:]]></text>
|
||||
</staticText>
|
||||
<line>
|
||||
<reportElement positionType="Float" x="0" y="11" width="136" height="1" uuid="83b4e0cf-0321-463b-93ab-cf578aecc422">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.4" lineStyle="Solid"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
</band>
|
||||
<band height="17">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$P{serviceList}!=null]]></printWhenExpression>
|
||||
<staticText>
|
||||
<reportElement positionType="Float" x="0" y="0" width="46" height="16" uuid="3b60f428-f1be-46b4-8844-000b66d37cb3">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="7" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[项目]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement positionType="Float" x="46" y="0" width="38" height="16" uuid="3dce837c-7930-438f-88cf-d0ca69283abf">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="7"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[工时费(元)]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement positionType="Float" x="84" y="0" width="52" height="16" uuid="4f6f1957-c5d3-45d4-9f9e-59f03d002151">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="7"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[卡剩余次数]]></text>
|
||||
</staticText>
|
||||
<line>
|
||||
<reportElement positionType="Float" x="0" y="16" width="136" height="1" uuid="45924492-61d2-4ec2-9dae-9edf6181e7a4">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.4" lineStyle="Dashed"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
</band>
|
||||
<band height="11">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$P{serviceList}!=null]]></printWhenExpression>
|
||||
<componentElement>
|
||||
<reportElement isPrintRepeatedValues="false" x="2" y="0" width="136" height="11" uuid="ecd9cd2e-ad62-4a61-a8a7-6f894e8b881b">
|
||||
<property name="com.jaspersoft.studio.layout" value="com.jaspersoft.studio.editor.layout.VerticalRowLayout"/>
|
||||
<property name="com.jaspersoft.studio.table.style.table_header" value="Table 1_TH"/>
|
||||
<property name="com.jaspersoft.studio.table.style.column_header" value="Table 1_CH"/>
|
||||
<property name="com.jaspersoft.studio.table.style.detail" value="Table 1_TD"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<jr:table xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd">
|
||||
<datasetRun subDataset="Dataset1" uuid="12ce7a05-4dbc-42aa-ab97-ca225ebd48e1">
|
||||
<dataSourceExpression><![CDATA[$P{serviceList}]]></dataSourceExpression>
|
||||
</datasetRun>
|
||||
<jr:column width="46" uuid="4a339d5c-d93e-4d9b-a7f5-478cb3bc4c66">
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column1"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<jr:detailCell height="11">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="px"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="px"/>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement key="" x="0" y="0" width="46" height="11" uuid="d1b9c27f-da5c-43d5-b245-b2ce10285445">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="7"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$F{serviceName}.indexOf("卡消费") > 0 ? $F{serviceName}.replaceAll("卡消费",$F{empNameStr}): $F{serviceName}+"("+$F{empNameStr}+")"]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
<jr:column width="38" uuid="36d33a43-8dc0-421c-89b2-6c17b4c992c2">
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column2"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<jr:detailCell height="11">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="px"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="px"/>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement key="" x="0" y="0" width="38" height="11" uuid="b0a21e7b-9ef2-453a-8b0b-f81e4a8d02ae">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="7"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$F{subtotal}.setScale( 2, BigDecimal.ROUND_HALF_EVEN )]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
<jr:column width="52" uuid="922b68cd-f23e-4d67-9717-74621fa31ed2">
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column3"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<jr:detailCell height="11">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="px"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="px"/>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement key="" x="0" y="0" width="52" height="11" uuid="683ff861-1457-4841-8904-a5b8030d6a63">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="7"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[($F{unusedNumber}==null?"":$F{unusedNumber}+"/")+($F{number}==null?"":$F{number})]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
</jr:table>
|
||||
</componentElement>
|
||||
</band>
|
||||
<band height="20">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<staticText>
|
||||
<reportElement x="0" y="8" width="40" height="11" uuid="26dc81d8-29cc-4024-b7b4-d25a9ed72773">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="7"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[合计金额:]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="37" y="8" width="99" height="11" uuid="2872a1d3-dafc-430d-9cfd-fef01cdcc46a">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="7"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{amountAll}.subtract($P{vipExpense}).setScale( 2, BigDecimal.ROUND_HALF_EVEN )]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement x="33" y="9" width="7" height="11" uuid="f8d751a0-c2f4-45c9-bd4d-168f7250ab40">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="微软雅黑" size="7"/>
|
||||
</textElement>
|
||||
<text><![CDATA[¥]]></text>
|
||||
</staticText>
|
||||
<line>
|
||||
<reportElement positionType="Float" x="0" y="5" width="136" height="1" uuid="aa43bd00-5440-4c07-a3d5-bbbf892646bb">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.4" lineStyle="Solid"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
</band>
|
||||
<band height="11">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$P{serviceFavourable}.add($P{partFavourableCommonTotal}==null?BigDecimal.ZERO:$P{partFavourableCommonTotal}).add($P{serviceFavourableCommonTotal}==null?BigDecimal.ZERO:$P{serviceFavourableCommonTotal}).add($P{partinfoFavourable}).add($P{discountFavourable}).add($P{couponFavourable}).add($P{pointFavourable}).add($P{gatheringFavourable}).setScale( 2, BigDecimal.ROUND_HALF_EVEN ).compareTo(BigDecimal.ZERO) != 0]]></printWhenExpression>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="37" y="-1" width="99" height="11" uuid="d4b00569-8830-4a81-98b9-b02516e9e433">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="7"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{serviceFavourable}.add($P{partFavourableCommonTotal}==null?BigDecimal.ZERO:$P{partFavourableCommonTotal}).add($P{serviceFavourableCommonTotal}==null?BigDecimal.ZERO:$P{serviceFavourableCommonTotal}).add($P{partinfoFavourable}).add($P{discountFavourable}).add($P{couponFavourable}).add($P{pointFavourable}).add($P{gatheringFavourable}).setScale( 2, BigDecimal.ROUND_HALF_EVEN )]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement x="33" y="0" width="7" height="11" uuid="7d3b3e0c-8646-455a-ac17-10c3e46db01f">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="微软雅黑" size="7"/>
|
||||
</textElement>
|
||||
<text><![CDATA[¥]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="0" y="-1" width="40" height="11" uuid="0eb1e983-dbb7-4e21-b8ee-db6f492cdfab">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="7"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[优惠金额:]]></text>
|
||||
</staticText>
|
||||
</band>
|
||||
<band height="22">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="37" y="10" width="99" height="11" uuid="00e5ff0d-525e-4d27-ab0d-5a988300256b">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="7"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{balanceStatus}.equals("7000")?($P{amountAll}.subtract($P{vipExpense}).subtract($P{czkExpense}).subtract($P{serviceFavourable}.add($P{partFavourableCommonTotal}==null?BigDecimal.ZERO:$P{partFavourableCommonTotal}).add($P{serviceFavourableCommonTotal}==null?BigDecimal.ZERO:$P{serviceFavourableCommonTotal}).add($P{partinfoFavourable}).add($P{discountFavourable}).add($P{couponFavourable}).add($P{pointFavourable}).add($P{gatheringFavourable})).setScale( 2, BigDecimal.ROUND_HALF_EVEN )):($P{oweAmount}.setScale( 2, BigDecimal.ROUND_HALF_EVEN ))]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement x="0" y="10" width="40" height="11" uuid="e5619fe5-5014-44c7-be70-428e7fa89a99">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="7"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[待付金额:]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="0" y="-1" width="40" height="11" uuid="b3f329b3-6432-412c-ac54-3c3f1fdbe034">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="7"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[实付金额:]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="37" y="-1" width="99" height="11" uuid="8bbae461-eac5-4e83-9f39-4a27a55bed68">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="7"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{balanceStatus}.equals("7000")?"0.00":($P{amountAll}.subtract($P{vipExpense}).subtract($P{oweAmount}).subtract($P{partFavourableCommonTotal}==null?BigDecimal.ZERO:$P{partFavourableCommonTotal}).subtract($P{serviceFavourableCommonTotal}==null?BigDecimal.ZERO:$P{serviceFavourableCommonTotal}).subtract($P{czkExpense}).
|
||||
subtract($P{serviceFavourable}).subtract($P{partinfoFavourable}).subtract($P{discountFavourable}).subtract($P{couponFavourable}).subtract($P{pointFavourable}).subtract($P{gatheringFavourable}).setScale( 2, BigDecimal.ROUND_HALF_EVEN ))]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement x="33" y="0" width="7" height="11" uuid="d257edd4-940d-4804-a256-5e23b7fc781e">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="微软雅黑" size="7"/>
|
||||
</textElement>
|
||||
<text><![CDATA[¥]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="33" y="11" width="7" height="11" uuid="162688e4-1a42-4f5c-b406-e5c7c780a696">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="微软雅黑" size="7"/>
|
||||
</textElement>
|
||||
<text><![CDATA[¥]]></text>
|
||||
</staticText>
|
||||
</band>
|
||||
<band height="11">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$P{czkExpense}.compareTo(BigDecimal.ZERO) != 0]]></printWhenExpression>
|
||||
<staticText>
|
||||
<reportElement x="40" y="-1" width="7" height="11" uuid="389acfa8-bc97-47ca-b7de-61e45f6392f8">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$P{czkExpense}.compareTo(BigDecimal.ZERO) != 0]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="微软雅黑" size="7"/>
|
||||
</textElement>
|
||||
<text><![CDATA[¥]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="50" height="11" uuid="ef352217-3888-4dee-9291-2e1814474afa">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$P{czkExpense}.compareTo(BigDecimal.ZERO) != 0]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Top">
|
||||
<font fontName="黑体" size="7"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[储值卡消费:]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement positionType="Float" x="43" y="0" width="37" height="11" uuid="9ed79fa8-64a1-401d-b20e-2bd537aa60ce">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$P{czkExpense}.compareTo(BigDecimal.ZERO) != 0]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Top">
|
||||
<font fontName="黑体" size="7"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{czkExpense}.setScale( 2, BigDecimal.ROUND_HALF_EVEN )]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement positionType="Float" x="80" y="0" width="56" height="11" uuid="9ed79fa8-64a1-401d-b20e-2bd537aa60ce">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$P{czkExpense}.compareTo(BigDecimal.ZERO) != 0]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Top">
|
||||
<font fontName="黑体" size="7"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA["("+($P{czkDetailInfo}==null?"":$P{czkDetailInfo}) + ")"]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
<band height="15">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="40" height="11" uuid="107cd24a-9c65-454a-857b-d4343360c17c">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="7"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[收银金额:]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="33" y="1" width="7" height="11" uuid="d3e37020-1703-4943-88cc-f6a27b30051d">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="微软雅黑" size="7"/>
|
||||
</textElement>
|
||||
<text><![CDATA[¥]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement positionType="Float" x="37" y="2" width="99" height="11" uuid="8cac6572-8613-4439-ac11-8a09c05356a6">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="7"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{balanceStatus}.equals("7000")?"0.00":($P{amountAll}.subtract($P{vipExpense}).subtract($P{oweAmount}).subtract($P{partFavourableCommonTotal}==null?BigDecimal.ZERO:$P{partFavourableCommonTotal}).subtract($P{serviceFavourableCommonTotal}==null?BigDecimal.ZERO:$P{serviceFavourableCommonTotal}).subtract($P{czkExpense}).
|
||||
subtract($P{serviceFavourable}).subtract($P{partinfoFavourable}).subtract($P{discountFavourable}).subtract($P{couponFavourable}).subtract($P{pointFavourable}).subtract($P{gatheringFavourable}).setScale( 2, BigDecimal.ROUND_HALF_EVEN ).toString()+"("+$P{payItemTogether}+")")]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
<band height="26">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<staticText>
|
||||
<reportElement x="0" y="2" width="29" height="11" uuid="fc491228-a3a9-47ab-b354-af9f4c4e0f3e">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Left" verticalAlignment="Top">
|
||||
<font fontName="黑体" size="7"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[备注:]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement positionType="Float" x="20" y="2" width="116" height="11" uuid="b7b78327-0448-424d-970e-bada89ec5d60">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Top">
|
||||
<font fontName="黑体" size="7"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{memo}]]></textFieldExpression>
|
||||
</textField>
|
||||
<line>
|
||||
<reportElement x="1" y="0" width="136" height="1" uuid="1d0bcb53-619a-484c-a904-4e88f609d733">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.4" lineStyle="Solid"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
</band>
|
||||
</detail>
|
||||
</jasperReport>
|
||||
+433
@@ -0,0 +1,433 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Created with Jaspersoft Studio version 6.3.1.final using JasperReports Library version 6.3.1 -->
|
||||
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="Blank_A4" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="3fa22123-efc4-4f3f-a186-6a8f692d17e6">
|
||||
<property name="com.jaspersoft.studio.data.defaultdataadapter" value="One Empty Record"/>
|
||||
<subDataset name="List1" uuid="7366c5be-288c-41c7-b295-b8d023ec81ae">
|
||||
<queryString>
|
||||
<![CDATA[]]>
|
||||
</queryString>
|
||||
<field name="index" class="java.lang.String"/>
|
||||
<field name="serviceName" class="java.lang.String"/>
|
||||
<field name="cooperationServiceName" class="java.lang.String"/>
|
||||
<field name="cooperationOrgName" class="java.lang.String"/>
|
||||
<field name="auditStatus" class="java.lang.String"/>
|
||||
<field name="cooperationCost" class="java.math.BigDecimal"/>
|
||||
</subDataset>
|
||||
<parameter name="billNo" class="java.lang.String"/>
|
||||
<parameter name="tradingOrgName" class="java.lang.String"/>
|
||||
<parameter name="tradingDate" class="java.lang.String"/>
|
||||
<parameter name="customerName" class="java.lang.String"/>
|
||||
<parameter name="carNo" class="java.lang.String"/>
|
||||
<parameter name="employeeName" class="java.lang.String"/>
|
||||
<parameter name="cardName" class="java.lang.String"/>
|
||||
<parameter name="memberCardNo" class="java.lang.String"/>
|
||||
<parameter name="cardEndDate" class="java.lang.String"/>
|
||||
<parameter name="tradingAmount" class="java.lang.String"/>
|
||||
<parameter name="amount" class="java.lang.String"/>
|
||||
<parameter name="remark" class="java.lang.String"/>
|
||||
<parameter name="orgOfPrinting" class="java.lang.String"/>
|
||||
<parameter name="dateOfPrinting" class="java.lang.String"/>
|
||||
<queryString>
|
||||
<![CDATA[]]>
|
||||
</queryString>
|
||||
<detail>
|
||||
<band height="103" splitType="Stretch">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="0" y="10" width="555" height="40" uuid="7c3a0deb-dcb0-406e-ba9c-9f279e1518b0">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="16" isBold="true"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA["卡交易单"]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement key="" x="387" y="58" width="50" height="18" isRemoveLineWhenBlank="true" uuid="86735eee-0435-4238-9b93-c08d86ed318f">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Right" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[交易日期:]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="0" y="58" width="50" height="18" uuid="fef0343d-31f4-4b1c-a521-1a1b736aa485">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Right" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[单号:]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="200" y="58" width="50" height="18" uuid="627d90fe-c235-45d8-9f4a-92f8d7ec0de7">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Right" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[交易门店:]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="387" y="80" width="50" height="18" uuid="7af4c3ab-ae72-4f6b-8b40-7b3129bd7eff">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.5" lineStyle="Solid"/>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<textElement textAlignment="Right" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[服务顾问:]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="0" y="80" width="50" height="18" uuid="74602da5-9195-47dd-9416-9cb229aeccad">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.5" lineStyle="Solid"/>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<textElement textAlignment="Right" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[客户姓名:]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="200" y="80" width="50" height="18" uuid="65483940-e0c7-4713-9e9a-6a5a7294d248">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.5" lineStyle="Solid"/>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<textElement textAlignment="Right" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[用卡车辆:]]></text>
|
||||
</staticText>
|
||||
<line>
|
||||
<reportElement x="0" y="78" width="555" height="1" uuid="f6716829-054d-4fed-a12c-2f4d227724c7">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.4" lineStyle="Dotted"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
<line>
|
||||
<reportElement x="0" y="100" width="555" height="1" uuid="9c9a29fc-1a65-4869-8d03-3242ff1fe667">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.4" lineStyle="Solid"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="50" y="80" width="140" height="18" uuid="01160695-dd7d-4038-8476-f20a7f997e62"/>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{customerName}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="50" y="58" width="140" height="18" uuid="d8bc8e14-2a41-4471-8be9-dae7dee48c2b"/>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{billNo}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="250" y="58" width="130" height="18" uuid="f258bb2c-70ce-4b49-a305-a4c0db4671b2"/>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{tradingOrgName}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="250" y="80" width="130" height="18" uuid="8ffee383-6250-4697-8381-b3017b0d67ad"/>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{carNo}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="437" y="58" width="118" height="18" uuid="7daab9f8-bc40-45fc-90b2-510a19fe0578"/>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{tradingDate}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="437" y="80" width="118" height="18" uuid="5cd6ce11-c901-42cb-b84c-fc7b3a0de3b3"/>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{employeeName}]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
<band height="78">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<staticText>
|
||||
<reportElement x="0" y="51" width="50" height="18" uuid="2cf35160-a982-4dcc-881b-c53adcf3761a">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.5" lineStyle="Solid"/>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<textElement textAlignment="Right" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[剩余金额:]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="0" y="2" width="50" height="18" uuid="6b4cf2c5-cb81-43b6-82c9-ee238923a378">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Right" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9" isBold="false"/>
|
||||
<paragraph leftIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[卡名称:]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="0" y="25" width="50" height="18" uuid="782a08a7-c605-4a2f-83b7-4e3ad8ee3c4c">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Right" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[消费金额:]]></text>
|
||||
</staticText>
|
||||
<line>
|
||||
<reportElement x="0" y="47" width="555" height="1" uuid="8699bef5-cebd-4ebc-bb34-3697568375f7">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.4" lineStyle="Dotted"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="50" y="51" width="140" height="18" uuid="4ff3b629-b9e5-49c5-ad89-ce856a556839">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{amount}]]></textFieldExpression>
|
||||
</textField>
|
||||
<line>
|
||||
<reportElement x="0" y="71" width="555" height="1" uuid="98b923f9-1e14-4cc5-b508-12141cefb96e">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.4" lineStyle="Solid"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="50" y="25" width="140" height="18" uuid="7ce3fef6-73c6-49e9-a676-64e402603d93"/>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{tradingAmount}]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement x="200" y="2" width="50" height="18" uuid="04029be9-7783-4583-9f54-0b15047b2e76">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.5" lineStyle="Solid"/>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<textElement textAlignment="Right" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[卡号:]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="388" y="2" width="50" height="18" uuid="471ece50-ac4b-4d63-ba15-e82448944610">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.5" lineStyle="Solid"/>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<textElement textAlignment="Right" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[卡有效期:]]></text>
|
||||
</staticText>
|
||||
<line>
|
||||
<reportElement x="0" y="22" width="555" height="1" uuid="7672b0ab-ea26-468c-a2f5-7188f85f733c">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.4" lineStyle="Solid"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="50" y="2" width="140" height="18" uuid="88cb0ab6-fc29-4d51-b688-0ab2bdb0b2f9"/>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{cardName}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="250" y="2" width="130" height="18" uuid="90dfc3ce-5cf5-42d0-8e6f-670b49922088"/>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{memberCardNo}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="438" y="2" width="117" height="18" uuid="48056694-c19b-4dc3-a0d7-ef3e32ea4cb4"/>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{cardEndDate}]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
<band height="92">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<staticText>
|
||||
<reportElement x="0" y="17" width="50" height="18" uuid="fc27cb3d-0e5d-4143-b83d-daf432fa56c8">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9" isBold="false"/>
|
||||
<paragraph leftIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[打印门店:]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="50" y="17" width="140" height="18" uuid="1a73fa76-4113-4dcd-803c-da26e934f441"/>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{orgOfPrinting}]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement x="200" y="17" width="50" height="18" uuid="786b4cf3-7636-455c-bf05-115ff8ca71b7">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Right" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9" isBold="false"/>
|
||||
<paragraph leftIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[打印日期:]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="250" y="17" width="130" height="18" uuid="61b50ddd-d880-403c-855f-3ae2f0403592"/>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{dateOfPrinting}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="50" y="-4" width="504" height="18" uuid="d9928920-600f-4030-976c-bdf598467704"/>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{remark}]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement x="0" y="-4" width="50" height="18" uuid="03491a27-e480-40c3-aa80-d95b2bed3d95">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9" isBold="false"/>
|
||||
<paragraph leftIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[交易备注:]]></text>
|
||||
</staticText>
|
||||
</band>
|
||||
</detail>
|
||||
</jasperReport>
|
||||
+215
@@ -0,0 +1,215 @@
|
||||
# 结算单(指定内容)接口文档
|
||||
|
||||
# 结算单(指定内容)接口文档
|
||||
|
||||
# 接口
|
||||
|
||||
**接口: /blazer/maintenance/pr****int/file/dispatchCondition**
|
||||
|
||||
**方法: post**
|
||||
|
||||
**支持场景:打印 维保单/洗车单/维修单/贴膜单/理赔单/零售单,支持指定(项目/材料/附加费)打印**
|
||||
|
||||
**支持打印模块(**PrintModuleEnum**):****工时费、材料费、附加费、其他费用、服务费用**
|
||||
|
||||
**入参:**
|
||||
|
||||
```plaintext
|
||||
{
|
||||
"rowId": "10329",
|
||||
"rowCode": "partialSettlementStatement",
|
||||
"pkId": "16126085167868551253",
|
||||
"serviceList": [
|
||||
{
|
||||
"pkId": 16126085168250232896,
|
||||
"module": 1
|
||||
},
|
||||
{
|
||||
"pkId": 16155904656688554043,
|
||||
"module": 4
|
||||
}
|
||||
],
|
||||
"partList": [
|
||||
{
|
||||
"pkId": 11004336,
|
||||
"module": 2
|
||||
},
|
||||
{
|
||||
"pkId": 11004811,
|
||||
"module": 5
|
||||
}
|
||||
],
|
||||
"extraList": [
|
||||
{
|
||||
"type": 4,
|
||||
"module": 3
|
||||
},
|
||||
{
|
||||
"type": 6,
|
||||
"module": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**出参:**
|
||||
|
||||
```plaintext
|
||||
{
|
||||
"preScanUrl": "https://f.f6yc.com/printserver/pdfprint.html?url=https://f.f6yc.com/print-server/test/2024-10/default/49be06dc15444e2793a21fc8c16d3b5c.pdf?Expires=1729152323&OSSAccessKeyId=LTAI4Fcf2C1U99o3e3UQ2bHV&Signature=L86HWRF2ilyXU4BbzKhwXad%2BwXg%3D",
|
||||
"url": "https://f.f6yc.com/print-server/test/2024-10/default/49be06dc15444e2793a21fc8c16d3b5c.pdf?Expires=1729152323&OSSAccessKeyId=LTAI4Fcf2C1U99o3e3UQ2bHV&Signature=L86HWRF2ilyXU4BbzKhwXad%2BwXg%3D"
|
||||
}
|
||||
```
|
||||
|
||||
# jasper取参说明
|
||||
|
||||
| 字段 | 含义 | 是否必有 | 类型 |
|
||||
| --- | --- | --- | --- |
|
||||
| billNo | 工单号 | 是 | String |
|
||||
| maintainType | 工单类型 | 是 | String |
|
||||
| businessTypeName | 业务类别 | 是 | String |
|
||||
| balanceStatus | 结算状态 | 是 | String |
|
||||
| billStatus | 单据状态 | 是 | String |
|
||||
| creatorName | 创建人名称 | 是 | String |
|
||||
| naEmployee | 服务顾问 | 否 | String |
|
||||
| employeePhone | 服务顾问手机号 | 否 | String |
|
||||
| naInsurer | 理赔公司名称 | 否 | String |
|
||||
| insurancepolicyNo | 理赔保险单号 | 否 | Double |
|
||||
| serviceSubtotalVip | 套餐卡项目工时费小计 | 是 | Double |
|
||||
| serviceFavourableCommonTotal | 普通项目优惠金额合计 | 是 | Double |
|
||||
| totalStuffNum | 材料数量合计 | 是 | String |
|
||||
| stuffSubtotalVip | 套餐卡项目材料费小计 | 是 | Double |
|
||||
| stuffSubtotalAll | 材料费小计 | 是 | Double |
|
||||
| partFavourableCommonTotal | 普通材料优惠金额合计 | 是 | Double |
|
||||
| extraNumber | 附加费数量小计 | 是 | String |
|
||||
| extraCostTotal | 附加费小计 | 是 | Double |
|
||||
| favourableTotalList | 优惠明细小计 | 否 | List<FavourableDetailPrintAttribute> |
|
||||
| naCustomer | 客户姓名 | 是 | String |
|
||||
| cellPhone | 客户联系电话 | 是 | String |
|
||||
| repairPerson | 送修人 | 否 | String |
|
||||
| repairPersonContact | 送修人联系方式 | 否 | String |
|
||||
| carNoWhole <br/> | 车牌号 | 是 | String |
|
||||
| vin<br/> | 车辆VIN码 | 否 | String |
|
||||
| carBrandName<br/> | 品牌名称 | 否 | String |
|
||||
| carSeriesName<br/> | 车系名称 | 否 | String |
|
||||
| carModelShort<br/> | 车型简称 | 否 | String |
|
||||
| carModel<br/> | 车型 | 否 | String |
|
||||
| transmissionNo | 变速箱号 | 否 | String |
|
||||
| carFuelTypeName | 燃料类型 | 否 | String |
|
||||
| carColor<br/> | 车身颜色 | 否 | String |
|
||||
| billDate<br/> | 进厂日期 | 是 | String |
|
||||
| estimatedDeliveryTime<br/> | 预计交车时间 | 是 | String |
|
||||
| deliveryTime<br/> | 交车时间(出厂时间) | 是 | String |
|
||||
| mileage<br/> | 进厂里程 | 是 | Double |
|
||||
| nextMaintainDateRemind | 下次服务时间(服务提醒数据源) | 否 | Date |
|
||||
| nextMileageRemind | 下次服务里程(服务提醒数据源) | 否 | Double |
|
||||
| serviceList | 项目列表 | 否 | List<PartialServicePrintAttribute> |
|
||||
| partList | 材料列表 | 否 | List<PartialPartPrintAttribute> |
|
||||
| extraChargeList | 附加费列表 | 否 | List<ExtraChargePrintAttribute> |
|
||||
| extendedModuleList | 扩展模块列表 | 否 | List<ExtendedModulePrintAttribute> |
|
||||
| memo<br/> | 车主备注 | 否 | String |
|
||||
| signaturePhotoUrl<br/> | 签名图片 | 否 | String |
|
||||
| orgName<br/> | 维修厂名称 | 是 | String |
|
||||
| orgContacts<br/> | 维修厂联系人 | 是 | String |
|
||||
| orgDetailAddress<br/> | 维修厂地址 | 是 | String |
|
||||
| orgContactMobile<br/> | 联系电话(维修厂) | 否 | String |
|
||||
| storeLogo<br/> | logo | 否 | String |
|
||||
| printOrgName<br/> | 打印抬头 | 否 | String |
|
||||
| printContent<br/> | 免责条款 | 是 | String |
|
||||
| printCount<br/> | 打印次数 | 是 | String |
|
||||
| printTime<br/> | 打印时间 | 是 | String |
|
||||
|
||||
**PartialServicePrintAttribute**
|
||||
|
||||
| 字段 | 含义 | 是否必有 | 类型 |
|
||||
| --- | --- | --- | --- |
|
||||
| serviceName | 项目名称 | 是 | String |
|
||||
| labelName | 业务分类名称 | 是 | String |
|
||||
| isMember | 当前项目是否使用会员 | 是 | String |
|
||||
| idService | 服务项目id | 是 | BigInteger |
|
||||
| idInfo | 本地项目id | 是 | String |
|
||||
| price | 工时单价 | 是 | Double |
|
||||
| workHour | 工时 | 是 | Double |
|
||||
| subtotal | 金额 | 是 | Double |
|
||||
| singleFavourable | 优惠金额 | 是 | Double |
|
||||
| discountedSubtotal | 折后金额 | 是 | Double |
|
||||
| serviceMemo | 附加信息备注 | 否 | String |
|
||||
| discount | 折扣 | 是 | Double |
|
||||
| empNameStr | 服务项目明细对应修理工名称组装字符串 | 否 | String |
|
||||
| favourableVoList | 优惠明细 | 否 | List<FavourableDetailPrintAttribute> |
|
||||
|
||||
**PartialPartPrintAttribute**
|
||||
|
||||
| 字段 | 含义 | 是否必有 | 类型 |
|
||||
| --- | --- | --- | --- |
|
||||
| partName | 材料名称 | 是 | String |
|
||||
| partShowName | 材料名称(全) | 是 | String |
|
||||
| partBrand | 配件品牌 | 是 | String |
|
||||
| unit | 单位 | 是 | String |
|
||||
| number | 数量 | 是 | Double |
|
||||
| isMember | 当前项目是否使用会员 | 是 | Integer |
|
||||
| price | 价格(单价) | 是 | Double |
|
||||
| subtotal | 金额(材料金额) | 是 | Double |
|
||||
| discount | 折扣 | 是 | Double |
|
||||
| singleFavourable | 优惠金额 | 是 | Double |
|
||||
| discountedSubtotal<br/> | 折后金额 | 是 | Double |
|
||||
| partMemo<br/> | 备注 | 否 | String |
|
||||
| isBring<br/> | 是否自带 | 是 | String |
|
||||
| empNameStr<br/> | 明细对应修理工名称组装字符串 | 否 | String |
|
||||
| outStockEmployeeName<br/> | 领料人 | 否 | String |
|
||||
| labelName<br/> | 业务分类名称 | 是 | String |
|
||||
| idPart<br/> | 配件材料pk | 是 | BigInteger |
|
||||
| idInfo<br/> | 本地材料id | 是 | String |
|
||||
| favourableVoList | 优惠明细 | 否 | List<FavourableDetailPrintAttribute> |
|
||||
|
||||
**ExtraChargePrintAttribute**
|
||||
|
||||
| 字段 | 含义 | 是否必有 | 类型 |
|
||||
| --- | --- | --- | --- |
|
||||
| extraName | 附加费名称 | 是 | String |
|
||||
| subtotal | 金额 | 是 | Double |
|
||||
| memo | 备注 | 否 | String |
|
||||
|
||||
|
||||
**FavourableDetailPrintAttribute**
|
||||
|
||||
| 字段 | 含义 | 是否必有 | 类型 |
|
||||
| --- | --- | --- | --- |
|
||||
| discountType | 优惠类型 | 是 | Integer |
|
||||
| discountTypeName | 优惠类型名称 | 是 | Double |
|
||||
| amount | 优惠金额 | 是 | Double |
|
||||
|
||||
|
||||
|
||||
**ExtendedModulePrintAttribute**
|
||||
|
||||
| 字段 | 含义 | 是否必有 | 类型 |
|
||||
| --- | --- | --- | --- |
|
||||
| module | 打印模块,PrintModuleEnum.code | 是 | Integer |
|
||||
| name | 项目/材料/附加费名称 | 是 | String |
|
||||
| number | 项目对应工时,材料对应数量,附加费为“-” | 是 | Double |
|
||||
| price | 项目对应工时单价,材料对应材料单价,,附加费为“-” | 是 | Double |
|
||||
| subtotal | 项目对应工时费,材料对应材料费,附加费对应为金额 | 是 | Double |
|
||||
| discount | 项目对应折扣,材料对应折扣,附加费为“1.00” | 是 | Double |
|
||||
| discountedSubtotal | 项目对应折后金额,材料对应材料费折后金额,,附加费对应为金额 | 是 | Double |
|
||||
| favourableVoList | 优惠明细 | 否 | List<FavourableDetailPrintAttribute> |
|
||||
|
||||
**PrintModuleEnum 打印模块枚举**
|
||||
|
||||
| **key** | **code** | **name** |
|
||||
| --- | --- | --- |
|
||||
| MAN\_HOUR\_COST | 1 | 工时费模块 |
|
||||
| MATERIAL\_COST | 2 | 材料费模块 |
|
||||
| EXTRA\_COST | 3 | 附加费模块 |
|
||||
| OTHER\_COST | 4 | 其他费用模块 |
|
||||
| SERVICE\_COST | 5 | 服务费用模块 |
|
||||
|
||||
# 工具类jar包附件下载
|
||||
|
||||
[附件: print-core-1.0.7.jar](./attachments/JUhN4OhWjosFCdDg/print-core-1.0.7.jar)
|
||||
|
||||
### 数字金额转中文方法调用示例:
|
||||
|
||||
**数字金额**:$P{amount}==null?BigDecimal.ZERO:$P{amount} **转中文**:com.f6car.printserver.core.CharacterUtil.chinese($P{amount}==null?BigDecimal.ZERO:$P{amount})
|
||||
|
||||
> 更新: 2024-10-17 15:07:46 原文: <https://xcz.yuque.com/ombipo/rpc7ms/qz7dm6e8b06r7t70>
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
# 调拨单打印
|
||||
|
||||
# 采购单模版打印说明
|
||||
|
||||
* 前端调用接口
|
||||
|
||||
|
||||
/stock/allot/print?idAllot=
|
||||
|
||||
* 打印使用模版
|
||||
|
||||
|
||||
模版编码=allotInPrint
|
||||
|
||||

|
||||
|
||||
* 打印模版参数
|
||||
|
||||
|
||||
HashMap<String, Object> resultMap
|
||||
|
||||
| 字段 | 说明 | 备注 |
|
||||
| --- | --- | --- |
|
||||
| printFlag | 均价门店 false<br>批次门店 true | |
|
||||
| showPrice | 参配-打印调拨价格及金额<br>勾选 true<br>未勾选 false | |
|
||||
| orgName | 打印抬头<br>调入门店打印:XXX调入单<br>调出门店打印:XXX调出单 | |
|
||||
| billNo | 调拨单号<br>调入门店打印:DRDXXX<br>调出门店打印:DCDXXX | |
|
||||
| idOwnOrg | 门店ID<br>调入门店打印:调入门店ID<br>调出门店打印:调出门店ID | |
|
||||
| naOrgIn | 调入门店名称 | |
|
||||
| naOrgOut | 调出门店名称 | |
|
||||
| detailAddress | 供应商详细地址 | |
|
||||
| statusName | 调拨单状态(制单/待发货/待收货/已完成) | |
|
||||
| billDate | 单据日期(yyyy-MM-dd) | |
|
||||
| creatorName | 创建单名称 | |
|
||||
| nowDateTime | 打印时间(yyyy-MM-dd HH:mm) | |
|
||||
| remark | 备注信息 | |
|
||||
| showRemark | 是否显示备注<br>备注为空 false<br>备注不为空 true | |
|
||||
| sumNumber | 总数量 | |
|
||||
| sumAmount | 总金额<br>价格脱敏时显示 \*\*\*\* | |
|
||||
| printCount | 打印次数 | |
|
||||
| allotDetailVoList | 调拨单明细行 | |
|
||||
| sortNumber | 序号 | |
|
||||
| partShowName | 材料组合名称 | |
|
||||
| customCode | 材料自定义编码 | |
|
||||
| partName | 材料名称 | 20250731追加 |
|
||||
| partBrand | 材料品牌 | 20250731追加 |
|
||||
| supplierCode | 材料零件号 | 20250731追加 |
|
||||
| standard | 材料规格型号 | 20250731追加 |
|
||||
| carNo | 车牌 | 20250731追加 |
|
||||
| defSeat | 货位<br>调入门店打印:调入门店货位<br>调出门店打印:调出门店货位 | |
|
||||
| unit | 单位 | |
|
||||
| price | 单价<br>价格脱敏时显示 \*\*\*\* | |
|
||||
| numCus | 均价门店<br> 调拨个数<br>批次门店&制单&未选择批次<br> 调拨个数<br>批次门店<br> 选择或使用的批次个数 | |
|
||||
| amount | 均价门店<br> 调拨明细行金额<br>批次门店&制单&未选择批次<br> 调拨明细行金额<br>批次门店<br> 选择或使用的批次个数\*调拨单单价<br>备注:价格脱敏时显示 \*\*\*\* | |
|
||||
| orderNo | 批次号 | |
|
||||
| productDate | 批次生成日期 | |
|
||||
| 明细合计行 | | |
|
||||
| sortNumber | 合计行 | |
|
||||
| partShowName | "" | |
|
||||
| unit | "" | |
|
||||
| numCus | 总数量 | |
|
||||
| amount | 总金额<br>价格脱敏时显示 \*\*\*\* | |
|
||||
| defSeat | "" | |
|
||||
| stockNumber | "" | |
|
||||
+452
@@ -0,0 +1,452 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Created with Jaspersoft Studio version 6.3.1.final using JasperReports Library version 6.3.1 -->
|
||||
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="Blank_A4" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="3fa22123-efc4-4f3f-a186-6a8f692d17e6">
|
||||
<property name="com.jaspersoft.studio.data.defaultdataadapter" value="One Empty Record"/>
|
||||
<subDataset name="List1" uuid="7366c5be-288c-41c7-b295-b8d023ec81ae">
|
||||
<queryString>
|
||||
<![CDATA[]]>
|
||||
</queryString>
|
||||
<field name="index" class="java.lang.String"/>
|
||||
<field name="serviceName" class="java.lang.String"/>
|
||||
<field name="cooperationServiceName" class="java.lang.String"/>
|
||||
<field name="cooperationOrgName" class="java.lang.String"/>
|
||||
<field name="auditStatus" class="java.lang.String"/>
|
||||
<field name="cooperationCost" class="java.math.BigDecimal"/>
|
||||
</subDataset>
|
||||
<parameter name="tradingStoreName" class="java.lang.String"/>
|
||||
<parameter name="tradingTime" class="java.lang.String"/>
|
||||
<parameter name="idSource" class="java.lang.String"/>
|
||||
<parameter name="cardName" class="java.lang.String"/>
|
||||
<parameter name="memberNo" class="java.lang.String"/>
|
||||
<parameter name="noCar" class="java.lang.String"/>
|
||||
<parameter name="customerName" class="java.lang.String"/>
|
||||
<parameter name="paymentTypeAndAmount" class="java.lang.String"/>
|
||||
<parameter name="orgOfPrinting" class="java.lang.String"/>
|
||||
<parameter name="dateOfPrinting" class="java.lang.String"/>
|
||||
<parameter name="amount" class="java.lang.String">
|
||||
<defaultValueExpression><![CDATA[$P{amount}]]></defaultValueExpression>
|
||||
</parameter>
|
||||
<queryString>
|
||||
<![CDATA[]]>
|
||||
</queryString>
|
||||
<detail>
|
||||
<band height="97" splitType="Stretch">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="0" y="10" width="555" height="40" uuid="7c3a0deb-dcb0-406e-ba9c-9f279e1518b0">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="16" isBold="true"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA["会员卡交易单"]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="210" y="60" width="178" height="18" uuid="6849ccdb-a3a0-4d32-a556-7a8fd5a19cca">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{tradingTime}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="437" y="60" width="118" height="18" uuid="b347e5b3-390c-44c3-b746-481aa6dc808e">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{idSource}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="50" y="60" width="90" height="18" uuid="92646184-6d70-4b6e-9f0e-23b4a7b15fb5">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{tradingStoreName}]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement key="" x="389" y="60" width="48" height="18" isRemoveLineWhenBlank="true" uuid="86735eee-0435-4238-9b93-c08d86ed318f">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[交易单号]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="0" y="60" width="50" height="18" uuid="fef0343d-31f4-4b1c-a521-1a1b736aa485">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[交易门店]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="140" y="60" width="70" height="18" uuid="627d90fe-c235-45d8-9f4a-92f8d7ec0de7">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[交易日期]]></text>
|
||||
</staticText>
|
||||
<line>
|
||||
<reportElement x="0" y="60" width="555" height="1" uuid="329fa736-2c18-4d9d-8fab-f54846315633">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.4" lineStyle="Solid"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
<staticText>
|
||||
<reportElement x="389" y="78" width="48" height="18" uuid="7af4c3ab-ae72-4f6b-8b40-7b3129bd7eff">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.5" lineStyle="Solid"/>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[车牌号]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="437" y="78" width="118" height="18" uuid="8971461a-8c2e-4c4e-8c3f-9bd177df4b7e">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.5"/>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{noCar}]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement x="0" y="78" width="50" height="18" uuid="74602da5-9195-47dd-9416-9cb229aeccad">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.5" lineStyle="Solid"/>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[卡名称]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="185" y="78" width="94" height="18" uuid="49312902-8cda-4fe3-a92f-d6ecbf9cb893">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.5"/>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{memberNo}]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement x="140" y="78" width="44" height="18" uuid="65483940-e0c7-4713-9e9a-6a5a7294d248">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.5" lineStyle="Solid"/>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[卡号]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="50" y="78" width="90" height="18" uuid="e9c8328d-22ea-4e66-a23f-5015ffbd8248">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.5"/>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{cardName}]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement x="279" y="78" width="40" height="18" uuid="19b4e87c-4a50-42ef-bfd0-7ca0536d5526">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.5" lineStyle="Solid"/>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[持卡人]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="319" y="78" width="70" height="18" uuid="86c056e0-0ed9-4024-b868-4133a06c5bab">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{customerName}]]></textFieldExpression>
|
||||
</textField>
|
||||
<line>
|
||||
<reportElement x="0" y="78" width="555" height="1" uuid="f6716829-054d-4fed-a12c-2f4d227724c7">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.4" lineStyle="Dotted"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
<line>
|
||||
<reportElement x="0" y="96" width="555" height="1" uuid="9c9a29fc-1a65-4869-8d03-3242ff1fe667">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.4" lineStyle="Solid"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
</band>
|
||||
<band height="78">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<staticText>
|
||||
<reportElement x="0" y="36" width="50" height="18" uuid="2cf35160-a982-4dcc-881b-c53adcf3761a">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.5" lineStyle="Solid"/>
|
||||
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
|
||||
</box>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[退款方式:]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="120" height="18" uuid="6b4cf2c5-cb81-43b6-82c9-ee238923a378">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="10" isBold="true"/>
|
||||
<paragraph leftIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[退卡金额(元)]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="0" y="17" width="50" height="18" uuid="782a08a7-c605-4a2f-83b7-4e3ad8ee3c4c">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
<paragraph leftIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[退款金额]]></text>
|
||||
</staticText>
|
||||
<line>
|
||||
<reportElement x="0" y="35" width="555" height="1" uuid="8699bef5-cebd-4ebc-bb34-3697568375f7">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.4" lineStyle="Dotted"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
<line>
|
||||
<reportElement stretchType="RelativeToTallestObject" x="0" y="18" width="555" height="1" uuid="18287ba4-b04b-4846-9122-3679f693685c">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.4" lineStyle="Dotted"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="50" y="37" width="504" height="16" uuid="4ff3b629-b9e5-49c5-ad89-ce856a556839">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{paymentTypeAndAmount}]]></textFieldExpression>
|
||||
</textField>
|
||||
<line>
|
||||
<reportElement x="0" y="54" width="555" height="1" uuid="98b923f9-1e14-4cc5-b508-12141cefb96e">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.4" lineStyle="Solid"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
<staticText>
|
||||
<reportElement x="0" y="55" width="50" height="18" uuid="fc27cb3d-0e5d-4143-b83d-daf432fa56c8">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9" isBold="false"/>
|
||||
<paragraph leftIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[打印门店]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="50" y="55" width="110" height="18" uuid="1a73fa76-4113-4dcd-803c-da26e934f441"/>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{orgOfPrinting}]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement x="160" y="55" width="80" height="18" uuid="786b4cf3-7636-455c-bf05-115ff8ca71b7">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9" isBold="false"/>
|
||||
<paragraph leftIndent="5"/>
|
||||
</textElement>
|
||||
<text><![CDATA[打印日期]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="240" y="55" width="314" height="18" uuid="61b50ddd-d880-403c-855f-3ae2f0403592"/>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{dateOfPrinting}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="50" y="18" width="504" height="16" uuid="7ce3fef6-73c6-49e9-a676-64e402603d93"/>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="9"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{amount}]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
<band height="39">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</band>
|
||||
</detail>
|
||||
</jasperReport>
|
||||
+1586
File diff suppressed because it is too large
Load Diff
+3
@@ -0,0 +1,3 @@
|
||||
# 采购单/采购退模版打印
|
||||
|
||||
[《采购单/采购退打印》](https://alidocs.dingtalk.com/i/nodes/7NkDwLng8ZMajY9YijOwlz4bJKMEvZBY)
|
||||
+1428
File diff suppressed because it is too large
Load Diff
+922
@@ -0,0 +1,922 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Created with Jaspersoft Studio version 6.3.1.final using JasperReports Library version 6.3.1 -->
|
||||
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="Blank_A4" pageWidth="222" pageHeight="352" whenNoDataType="NoPages" columnWidth="202" leftMargin="10" rightMargin="10" topMargin="0" bottomMargin="10" isIgnorePagination="true" uuid="5195ed21-e8c1-4daf-ab55-5f5dc9c07b0a">
|
||||
<property name="com.jaspersoft.studio.unit." value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.topMargin" value="mm"/>
|
||||
<property name="com.jaspersoft.studio.unit.bottomMargin" value="mm"/>
|
||||
<property name="com.jaspersoft.studio.unit.leftMargin" value="mm"/>
|
||||
<property name="com.jaspersoft.studio.unit.rightMargin" value="mm"/>
|
||||
<property name="com.jaspersoft.studio.data.defaultdataadapter" value="One Empty Record"/>
|
||||
<property name="ireport.zoom" value="1.0"/>
|
||||
<property name="ireport.x" value="0"/>
|
||||
<property name="ireport.y" value="0"/>
|
||||
<property name="com.jaspersoft.studio.unit.pageWidth" value="mm"/>
|
||||
<property name="com.jaspersoft.studio.unit.pageHeight" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.columnWidth" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.columnSpacing" value="pixel"/>
|
||||
<subDataset name="Dataset1" uuid="7e6cf9c7-d927-4f84-a0f6-e84863998e11">
|
||||
<property name="com.jaspersoft.studio.data.defaultdataadapter" value="One Empty Record"/>
|
||||
<queryString>
|
||||
<![CDATA[]]>
|
||||
</queryString>
|
||||
<field name="subtotal" class="java.math.BigDecimal"/>
|
||||
<field name="serviceName" class="java.lang.String"/>
|
||||
<field name="unusedNumber" class="java.lang.Integer"/>
|
||||
<field name="number" class="java.lang.Integer"/>
|
||||
<field name="isMember" class="java.lang.Integer"/>
|
||||
</subDataset>
|
||||
<subDataset name=" Dataset2" uuid="7dae8b10-73a8-43eb-a81d-296b60197ab3">
|
||||
<field name="partName" class="java.lang.String"/>
|
||||
<field name="number" class="java.math.BigDecimal"/>
|
||||
<field name="subtotal" class="java.math.BigDecimal"/>
|
||||
<field name="isMember" class="java.lang.Integer"/>
|
||||
</subDataset>
|
||||
<parameter name="title" class="java.lang.String"/>
|
||||
<parameter name="abbreviation" class="java.lang.String"/>
|
||||
<parameter name="billNo" class="java.lang.String">
|
||||
<parameterDescription><![CDATA[]]></parameterDescription>
|
||||
</parameter>
|
||||
<parameter name="printTime" class="java.lang.String"/>
|
||||
<parameter name="customerName" class="java.lang.String"/>
|
||||
<parameter name="cellPhone" class="java.lang.String"/>
|
||||
<parameter name="carNo" class="java.lang.String"/>
|
||||
<parameter name="orgName" class="java.lang.String"/>
|
||||
<parameter name="amountAll" class="java.math.BigDecimal"/>
|
||||
<parameter name="memo" class="java.lang.String"/>
|
||||
<parameter name="settlePerson" class="java.lang.String"/>
|
||||
<parameter name="employeeName" class="java.lang.String"/>
|
||||
<parameter name="billDate" class="java.lang.String"/>
|
||||
<parameter name="detailAddress" class="java.lang.String"/>
|
||||
<parameter name="contactMobile" class="java.lang.String"/>
|
||||
<parameter name="partList" class="net.sf.jasperreports.engine.data.JRMapCollectionDataSource"/>
|
||||
<parameter name="transactionDate" class="java.lang.String"/>
|
||||
<parameter name="naEmployee" class="java.lang.String"/>
|
||||
<parameter name="mileage" class="java.math.BigDecimal"/>
|
||||
<parameter name="deliveryTime" class="java.lang.String"/>
|
||||
<parameter name="vin" class="java.lang.String"/>
|
||||
<parameter name="carNoWhole" class="java.lang.String"/>
|
||||
<parameter name="naCustomer" class="java.lang.String"/>
|
||||
<parameter name="carModelShort" class="java.lang.String"/>
|
||||
<parameter name="vipExpense" class="java.math.BigDecimal"/>
|
||||
<parameter name="serviceFavourable" class="java.math.BigDecimal"/>
|
||||
<parameter name="partFavourableCommonTotal" class="java.math.BigDecimal"/>
|
||||
<parameter name="oweAmount" class="java.math.BigDecimal"/>
|
||||
<parameter name="serviceFavourableCommonTotal" class="java.math.BigDecimal"/>
|
||||
<parameter name="czkExpense" class="java.math.BigDecimal"/>
|
||||
<parameter name="partinfoFavourable" class="java.math.BigDecimal"/>
|
||||
<parameter name="discountFavourable" class="java.math.BigDecimal"/>
|
||||
<parameter name="pointFavourable" class="java.math.BigDecimal"/>
|
||||
<parameter name="couponFavourable" class="java.math.BigDecimal"/>
|
||||
<parameter name="balanceStatus" class="java.lang.String"/>
|
||||
<parameter name="gatheringFavourable" class="java.math.BigDecimal"/>
|
||||
<parameter name="payItemTogether" class="java.lang.String"/>
|
||||
<parameter name="orgContactMobile" class="java.lang.String"/>
|
||||
<parameter name="orgDetailAddress" class="java.lang.String"/>
|
||||
<parameter name="printOrgName" class="java.lang.String"/>
|
||||
<parameter name="serviceList" class="net.sf.jasperreports.engine.data.JRMapCollectionDataSource"/>
|
||||
<parameter name="firstSettlementTime" class="java.lang.String"/>
|
||||
<parameter name="extraCostTotal" class="java.math.BigDecimal">
|
||||
<parameterDescription><![CDATA[]]></parameterDescription>
|
||||
</parameter>
|
||||
<parameter name="extraChargeList" class="net.sf.jasperreports.engine.data.JRMapCollectionDataSource"/>
|
||||
<parameter name="orgContactNumber" class="java.lang.String"/>
|
||||
<parameter name="czkDetailInfo" class="java.lang.String"/>
|
||||
<parameter name="creatorName" class="java.lang.String"/>
|
||||
<parameter name="totalStuffNum" class="java.lang.String"/>
|
||||
<parameter name="stuffSubtotalAll" class="java.math.BigDecimal"/>
|
||||
<parameter name="stuffSubtotalVip" class="java.math.BigDecimal"/>
|
||||
<queryString>
|
||||
<![CDATA[]]>
|
||||
</queryString>
|
||||
<detail>
|
||||
<band height="20" splitType="Stretch">
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="0" y="0" width="202" height="20" isPrintWhenDetailOverflows="true" uuid="fdd7c75d-7f0c-42a3-afa1-9927522a4dd1"/>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="16" isBold="false"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[($P{printOrgName}==null?$P{orgName}:($P{printOrgName}.isEmpty()?$P{orgName}:$P{printOrgName}))+"销售单"]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
<band height="20">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<staticText>
|
||||
<reportElement x="0" y="4" width="51" height="16" uuid="8210a1bf-fb5f-465d-8e13-15ee265db665">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[工单号:]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="51" y="4" width="151" height="16" uuid="e79b3ef6-3727-46d0-8de1-035b71f358f4">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="0"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{billNo}]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
<band height="16">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<staticText>
|
||||
<reportElement x="0" y="2" width="51" height="12" uuid="c34510ca-1706-47a6-bd9f-f78a472136a9">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Top">
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[销售人员:]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="51" y="2" width="150" height="12" uuid="13df7d48-2be4-4a9f-848b-6a1fa1573a2e">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="0"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{naEmployee}]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
<band height="16">
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="31" y="2" width="60" height="12" uuid="62146321-e5d6-4c36-b91c-db8c0a5653de">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体"/>
|
||||
<paragraph leftIndent="0"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{naCustomer}.substring(0, 1) + "(*^_^*)" + $P{naCustomer}.substring($P{naCustomer}.length() > 10 ? 10 : $P{naCustomer}.length(), $P{naCustomer}.length())]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="91" y="2" width="110" height="12" uuid="8c918e6d-69a1-4dc3-9336-f54cc900e659">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{cellPhone}.length() <= 3 ? $P{cellPhone}: $P{cellPhone}.substring(0, 3) + "(*^_^*)" + $P{cellPhone}.substring($P{cellPhone}.length() > 7 ? 7 : $P{cellPhone}.length(), $P{cellPhone}.length())]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement x="0" y="2" width="31" height="12" uuid="16d36e31-361b-4fee-a18e-a4ad7991e6c6">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[客户:]]></text>
|
||||
</staticText>
|
||||
</band>
|
||||
<band height="14">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<staticText>
|
||||
<reportElement x="0" y="2" width="31" height="12" uuid="53391abc-4be2-40a8-8c2d-a770e6c13f18">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[车牌:]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="31" y="2" width="171" height="12" uuid="de1db383-eb89-4a11-acd1-ec590d10da96">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{carNoWhole}]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
<band height="4">
|
||||
<line>
|
||||
<reportElement x="3" y="3" width="196" height="1" uuid="fcbb9490-ed14-4cb0-8117-6d17915d2403">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.3" lineStyle="Solid"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
</band>
|
||||
<band height="12">
|
||||
<printWhenExpression><![CDATA[$P{partList}!=null]]></printWhenExpression>
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="95" height="12" uuid="c3e05a21-6ba4-4708-991a-825a994a1b2f">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[材料]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="95" y="0" width="53" height="12" uuid="07662de2-32dd-4e19-9f70-9b1f2927b7ab">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[数量]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="148" y="0" width="54" height="12" uuid="9c43fe3b-01e3-4683-935a-993973d42461">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[材料费(元)]]></text>
|
||||
</staticText>
|
||||
</band>
|
||||
<band height="12">
|
||||
<printWhenExpression><![CDATA[$P{partList}!=null]]></printWhenExpression>
|
||||
<componentElement>
|
||||
<reportElement x="0" y="0" width="202" height="12" uuid="d0a60b3d-9ead-4191-b6c1-b76521bf47f6">
|
||||
<property name="com.jaspersoft.studio.layout" value="com.jaspersoft.studio.editor.layout.VerticalRowLayout"/>
|
||||
<property name="com.jaspersoft.studio.table.style.table_header" value="Table_TH"/>
|
||||
<property name="com.jaspersoft.studio.table.style.column_header" value="Table_CH"/>
|
||||
<property name="com.jaspersoft.studio.table.style.detail" value="Table_TD"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<jr:table xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd" whenNoDataType="Blank">
|
||||
<datasetRun subDataset=" Dataset2" uuid="2d38cb48-be8c-41f9-a529-866d4b65253f">
|
||||
<dataSourceExpression><![CDATA[$P{partList}]]></dataSourceExpression>
|
||||
</datasetRun>
|
||||
<jr:column width="95" uuid="13512459-4d71-4edc-b745-751e555e284e">
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column1"/>
|
||||
<jr:detailCell height="12">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="px"/>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="0" y="0" width="95" height="12" uuid="8d7ef19e-5295-4cfa-ba8e-dfac9dc5029c"/>
|
||||
<box topPadding="2" bottomPadding="2"/>
|
||||
<textElement>
|
||||
<font fontName="黑体"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$F{partName}]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
<jr:column width="53" uuid="eb394fd2-532e-4da9-8058-785d644277ac">
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column2"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<jr:detailCell height="12">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="px"/>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="0" y="0" width="53" height="12" uuid="31f7ac04-d923-44d2-85ed-9c2d5f22d3b3"/>
|
||||
<box topPadding="2" bottomPadding="2"/>
|
||||
<textElement textAlignment="Left">
|
||||
<font fontName="黑体"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$F{number}]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
<jr:column width="54" uuid="02e06895-4360-460c-ad3a-d4036bde9323">
|
||||
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column3"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<jr:detailCell height="12">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="px"/>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="0" y="0" width="54" height="12" uuid="544a881f-1055-4089-a49d-e1c979d0b452"/>
|
||||
<box topPadding="2" bottomPadding="2"/>
|
||||
<textElement textAlignment="Left">
|
||||
<font fontName="黑体"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$F{isMember} == 1 ? "0.00" :$F{subtotal}.setScale( 2, BigDecimal.ROUND_HALF_EVEN )]]></textFieldExpression>
|
||||
</textField>
|
||||
</jr:detailCell>
|
||||
</jr:column>
|
||||
</jr:table>
|
||||
</componentElement>
|
||||
</band>
|
||||
<band height="4">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$P{extraChargeList}!=null && $P{partList}!=null]]></printWhenExpression>
|
||||
<line>
|
||||
<reportElement x="0" y="3" width="196" height="1" uuid="e343ed32-d402-484e-9550-a3f92a5f1d95">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.5" lineStyle="Dashed"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
</band>
|
||||
<band height="12">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$P{extraChargeList}!=null]]></printWhenExpression>
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="51" height="12" uuid="ab72a883-2de5-4b77-974f-86ce04a85321">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.0"/>
|
||||
</box>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="10"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[数量小计:]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="51" y="0" width="98" height="12" uuid="fd7e12a8-bb87-4181-b961-362f5011d2c7">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.0"/>
|
||||
</box>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="10"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{totalStuffNum}]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
<band height="36">
|
||||
<staticText>
|
||||
<reportElement x="62" y="0" width="5" height="12" isRemoveLineWhenBlank="true" uuid="4b3ef70a-6f98-4270-996d-71c65a31b4b7">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.0"/>
|
||||
</box>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="微软雅黑" size="10"/>
|
||||
<paragraph spacingBefore="2"/>
|
||||
</textElement>
|
||||
<text><![CDATA[¥]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="67" y="0" width="82" height="12" uuid="c234c01c-7802-4177-9cf1-ddb4b3a64380">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.0"/>
|
||||
</box>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="10"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{stuffSubtotalAll}.subtract($P{stuffSubtotalVip}).setScale( 2, BigDecimal.ROUND_HALF_EVEN )]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="62" height="12" uuid="0ee54c87-b5c2-43bf-a362-9c79fbd020b2">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.0"/>
|
||||
</box>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="10"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[材料费小计:]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="56" y="12" width="93" height="12" uuid="651ea460-07ba-4514-b29e-2f07cea1c7b5">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.0"/>
|
||||
</box>
|
||||
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="10"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{partFavourableCommonTotal}.setScale( 2, BigDecimal.ROUND_HALF_EVEN )]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement x="51" y="12" width="5" height="12" uuid="ec51a4b4-84d6-4896-9b51-1bcb63db905f">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.0"/>
|
||||
</box>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="微软雅黑" size="10"/>
|
||||
<paragraph spacingBefore="2"/>
|
||||
</textElement>
|
||||
<text><![CDATA[¥]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="0" y="12" width="51" height="12" uuid="3b7564d7-fd10-45ae-b35d-8b9e7996b37b">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.0"/>
|
||||
</box>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="10"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[优惠小计:]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="70" y="24" width="5" height="12" uuid="df93cf01-d9b9-4e5a-9b54-ecb6d1500ffc">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.0"/>
|
||||
</box>
|
||||
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||
<font fontName="微软雅黑" size="10"/>
|
||||
<paragraph spacingBefore="2"/>
|
||||
</textElement>
|
||||
<text><![CDATA[¥]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="75" y="24" width="74" height="12" uuid="695cf981-09b0-4b5b-8634-6a6e80812934">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.0"/>
|
||||
</box>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="10"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{stuffSubtotalAll}.subtract($P{stuffSubtotalVip}).subtract($P{partFavourableCommonTotal}).setScale( 2, BigDecimal.ROUND_HALF_EVEN )]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement x="0" y="24" width="70" height="12" uuid="8745ff2b-c3e7-4dfe-8c42-3b62f1d198ca">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<box>
|
||||
<pen lineWidth="0.0"/>
|
||||
</box>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" size="10"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[折后金额小计:]]></text>
|
||||
</staticText>
|
||||
</band>
|
||||
<band height="6">
|
||||
<printWhenExpression><![CDATA[$P{partList}!=null || $P{serviceList}!=null || $P{extraChargeList}!=null]]></printWhenExpression>
|
||||
<line>
|
||||
<reportElement x="0" y="5" width="196" height="1" uuid="92031c32-47e1-4778-9696-acfd36cea5c1">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.5" lineStyle="Solid"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
</band>
|
||||
<band height="17">
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="56" y="4" width="45" height="12" isPrintWhenDetailOverflows="true" uuid="429e5e34-e7cc-4b2e-a7ec-f9bdc72268ce">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{amountAll}.subtract($P{vipExpense}).setScale( 2, BigDecimal.ROUND_HALF_EVEN )]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement x="0" y="4" width="51" height="12" uuid="91cf76df-ccf1-417b-8ad1-73b7e1be2306">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[合计金额:]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement key="" x="101" y="4" width="51" height="12" uuid="0dc06605-4e07-4c3c-855e-22f496455a6a">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$P{serviceFavourable}.add($P{partFavourableCommonTotal}==null?BigDecimal.ZERO:$P{partFavourableCommonTotal}).add($P{serviceFavourableCommonTotal}==null?BigDecimal.ZERO:$P{serviceFavourableCommonTotal}).add($P{partinfoFavourable}).add($P{discountFavourable}).add($P{couponFavourable}).add($P{pointFavourable}).add($P{gatheringFavourable}).setScale( 2, BigDecimal.ROUND_HALF_EVEN ).compareTo(BigDecimal.ZERO) != 0]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[优惠金额:]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="157" y="4" width="45" height="12" isPrintWhenDetailOverflows="true" uuid="a7ee1bfa-c68a-441d-8cde-368dd1642208">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$P{serviceFavourable}.add($P{partFavourableCommonTotal}==null?BigDecimal.ZERO:$P{partFavourableCommonTotal}).add($P{serviceFavourableCommonTotal}==null?BigDecimal.ZERO:$P{serviceFavourableCommonTotal}).add($P{partinfoFavourable}).add($P{discountFavourable}).add($P{couponFavourable}).add($P{pointFavourable}).add($P{gatheringFavourable}).setScale( 2, BigDecimal.ROUND_HALF_EVEN ).compareTo(BigDecimal.ZERO) != 0]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{serviceFavourable}.add($P{partFavourableCommonTotal}==null?BigDecimal.ZERO:$P{partFavourableCommonTotal}).add($P{serviceFavourableCommonTotal}==null?BigDecimal.ZERO:$P{serviceFavourableCommonTotal}).add($P{partinfoFavourable}).add($P{discountFavourable}).add($P{couponFavourable}).add($P{pointFavourable}).add($P{gatheringFavourable}).setScale( 2, BigDecimal.ROUND_HALF_EVEN )]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement x="152" y="5" width="5" height="12" uuid="5334ca45-b9a7-4bda-949c-8532255cbf73">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<printWhenExpression><![CDATA[$P{serviceFavourable}.add($P{partFavourableCommonTotal}==null?BigDecimal.ZERO:$P{partFavourableCommonTotal}).add($P{serviceFavourableCommonTotal}==null?BigDecimal.ZERO:$P{serviceFavourableCommonTotal}).add($P{partinfoFavourable}).add($P{discountFavourable}).add($P{couponFavourable}).add($P{pointFavourable}).add($P{gatheringFavourable}).setScale( 2, BigDecimal.ROUND_HALF_EVEN ).compareTo(BigDecimal.ZERO) != 0]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font isBold="false"/>
|
||||
<paragraph leftIndent="0"/>
|
||||
</textElement>
|
||||
<text><![CDATA[¥]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="51" y="5" width="5" height="12" uuid="93dba0ec-ff63-4524-ad00-7677de202fb0">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font isBold="false" isUnderline="false"/>
|
||||
<paragraph leftIndent="0"/>
|
||||
</textElement>
|
||||
<text><![CDATA[¥]]></text>
|
||||
</staticText>
|
||||
</band>
|
||||
<band height="13">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="51" height="12" uuid="ad0a3fc9-c823-44f3-90bb-ec4358472ece">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[实付金额:]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement key="" x="51" y="1" width="5" height="12" uuid="48a4a2fc-5e83-43b5-9faf-593ced47fba0">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font isBold="false"/>
|
||||
<paragraph leftIndent="0"/>
|
||||
</textElement>
|
||||
<text><![CDATA[¥]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="56" y="0" width="45" height="12" isPrintWhenDetailOverflows="true" uuid="d71691b9-8665-4b03-ba8b-e3dc6081afd2">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{balanceStatus}.equals("7000")?"0.00":($P{amountAll}.subtract($P{vipExpense}).subtract($P{oweAmount}).subtract($P{partFavourableCommonTotal}==null?BigDecimal.ZERO:$P{partFavourableCommonTotal}).subtract($P{serviceFavourableCommonTotal}==null?BigDecimal.ZERO:$P{serviceFavourableCommonTotal}).
|
||||
subtract($P{serviceFavourable}).subtract($P{partinfoFavourable}).subtract($P{discountFavourable}).subtract($P{couponFavourable}).subtract($P{pointFavourable}).subtract($P{gatheringFavourable}).setScale( 2, BigDecimal.ROUND_HALF_EVEN ))]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement x="101" y="0" width="51" height="12" uuid="60a16c6f-0ae8-412f-94ea-bcf27f9ae0a3">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[待付金额:]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="152" y="1" width="5" height="12" uuid="18cf2b7d-cf81-477b-8ef7-1ec2b9a3cb2b">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font isBold="false"/>
|
||||
<paragraph leftIndent="0"/>
|
||||
</textElement>
|
||||
<text><![CDATA[¥]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="157" y="0" width="45" height="12" isPrintWhenDetailOverflows="true" uuid="ce222378-cff4-47d0-9658-edb83a64f33e">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{balanceStatus}.equals("7000")?($P{amountAll}.subtract($P{vipExpense}).subtract($P{czkExpense}).subtract($P{serviceFavourable}.add($P{partFavourableCommonTotal}==null?BigDecimal.ZERO:$P{partFavourableCommonTotal}).add($P{serviceFavourableCommonTotal}==null?BigDecimal.ZERO:$P{serviceFavourableCommonTotal}).add($P{partinfoFavourable}).add($P{discountFavourable}).add($P{couponFavourable}).add($P{pointFavourable}).add($P{gatheringFavourable})).setScale( 2, BigDecimal.ROUND_HALF_EVEN )):($P{oweAmount}.setScale( 2, BigDecimal.ROUND_HALF_EVEN ))]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
<band height="13">
|
||||
<printWhenExpression><![CDATA[$P{czkExpense}.compareTo(BigDecimal.ZERO) != 0]]></printWhenExpression>
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="61" height="12" uuid="e3d118e6-8e4c-4562-a92f-b02171737fa4">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[储值卡消费:]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="61" y="1" width="5" height="12" uuid="dc416d41-3d4e-4ec2-8df2-8fd963d34b2f">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="SansSerif" isBold="false"/>
|
||||
<paragraph leftIndent="0"/>
|
||||
</textElement>
|
||||
<text><![CDATA[¥]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="67" y="0" width="45" height="12" isPrintWhenDetailOverflows="true" uuid="93fc5f6c-5c7c-4e75-9054-783e6dbbfb0d">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{czkExpense}.setScale( 2, BigDecimal.ROUND_HALF_EVEN )]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="112" y="0" width="90" height="12" isPrintWhenDetailOverflows="true" uuid="7b247b30-a5cc-4d9a-84e2-24128a6b4775">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" size="9" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{czkDetailInfo}==null?"":"(" + $P{czkDetailInfo} + ")"]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
<band height="17">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="51" height="12" uuid="2f9041fb-4bfa-43a0-9642-e429c87c8326">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[收银金额:]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="51" y="1" width="5" height="12" uuid="9f6a7ec2-4243-454c-a1b6-2adc655dd86a">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="SansSerif" isBold="false"/>
|
||||
<paragraph leftIndent="0"/>
|
||||
</textElement>
|
||||
<text><![CDATA[¥]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="57" y="0" width="55" height="12" isPrintWhenDetailOverflows="true" uuid="507cb11e-dfc7-477d-ae35-49de03f644f1">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{balanceStatus}.equals("7000")?"0.00":($P{amountAll}.subtract($P{vipExpense}).subtract($P{oweAmount}).subtract($P{partFavourableCommonTotal}==null?BigDecimal.ZERO:$P{partFavourableCommonTotal}).subtract($P{serviceFavourableCommonTotal}==null?BigDecimal.ZERO:$P{serviceFavourableCommonTotal}).subtract($P{czkExpense}).
|
||||
subtract($P{serviceFavourable}).subtract($P{partinfoFavourable}).subtract($P{discountFavourable}).subtract($P{couponFavourable}).subtract($P{pointFavourable}).subtract($P{gatheringFavourable}).setScale( 2, BigDecimal.ROUND_HALF_EVEN ).toString())]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="112" y="0" width="90" height="12" isPrintWhenDetailOverflows="true" uuid="1d396dda-a308-4062-addd-bf1e6d367ef0">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" size="9" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{balanceStatus}.equals("7000")? "" : $P{payItemTogether} == null ? "" : "("+$P{payItemTogether}+")"]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
<band height="1">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<line>
|
||||
<reportElement x="0" y="0" width="196" height="1" uuid="232d5e4a-f361-483f-a3d5-b5ebe29dc22e">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.5" lineStyle="Solid"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
</band>
|
||||
<band height="47">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<staticText>
|
||||
<reportElement x="0" y="4" width="53" height="12" uuid="1d22bc87-0fc0-4f8f-8c98-62adcc943822">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[客户签名:]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement x="0" y="30" width="31" height="12" uuid="caf074dd-5c62-4224-a0d8-ef4380188ecd">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[备注:]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="31" y="30" width="81" height="12" uuid="049afdd2-76f6-4be7-86e9-b213c9fbf31a">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="0"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{memo}]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement x="112" y="30" width="31" height="12" uuid="bac0ce57-79c7-4cc7-842e-5f15284486a1">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[日期:]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="143" y="30" width="59" height="12" isPrintWhenDetailOverflows="true" uuid="a8131af0-d94a-4b50-93f8-c187293efb33">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Top">
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="0"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{deliveryTime}.isEmpty()?"":($P{deliveryTime}.substring( 0, 10))]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
<band height="1">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<line>
|
||||
<reportElement x="0" y="0" width="202" height="1" uuid="c936fb70-4d8c-405d-ab85-2e8916a715c1">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
</reportElement>
|
||||
<graphicElement>
|
||||
<pen lineWidth="0.3"/>
|
||||
</graphicElement>
|
||||
</line>
|
||||
</band>
|
||||
<band height="20">
|
||||
<staticText>
|
||||
<reportElement x="0" y="4" width="51" height="16" uuid="d47fdd5c-eb46-4023-8e59-19de6fe9f43a">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[门店名称:]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="51" y="6" width="151" height="12" uuid="519ca386-a8c3-47ee-bbe8-6046d7a8512b">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="0"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{orgName}]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
<band height="16">
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="51" height="16" uuid="477d09a8-4cd9-4a13-88eb-65a6f70e13a6">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[联系电话:]]></text>
|
||||
</staticText>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="51" y="0" width="151" height="16" uuid="5fe5a641-383e-488e-b59b-604282cdb856">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="0"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{orgContactMobile}==null?"":$P{orgContactMobile}]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
<band height="16">
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
<textField isStretchWithOverflow="true" isBlankWhenNull="true">
|
||||
<reportElement x="0" y="0" width="202" height="16" uuid="8d8ad542-4e85-4c3c-93b1-dcf7fcb38720">
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.height" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement verticalAlignment="Middle">
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{orgDetailAddress}]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
<band height="12">
|
||||
<staticText>
|
||||
<reportElement x="62" y="0" width="51" height="12" uuid="fca6fa0d-2eaf-42f4-986c-62724d5e6e17">
|
||||
<property name="com.jaspersoft.studio.unit.width" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="3"/>
|
||||
</textElement>
|
||||
<text><![CDATA[打印时间:]]></text>
|
||||
</staticText>
|
||||
<textField isBlankWhenNull="true">
|
||||
<reportElement x="113" y="0" width="89" height="12" uuid="a987d0cf-8310-4b16-b278-5eeadb07c893">
|
||||
<property name="com.jaspersoft.studio.unit.y" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.x" value="pixel"/>
|
||||
</reportElement>
|
||||
<textElement>
|
||||
<font fontName="黑体" isBold="false"/>
|
||||
<paragraph leftIndent="0"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{printTime}.substring( 0, 16)]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
</detail>
|
||||
</jasperReport>
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"kb_id": "db5e3844c382439dba91c29f4f29eeca",
|
||||
"user_id": "d198ae3b32cd49f09736c4290dd1223a",
|
||||
"name": "测试csv",
|
||||
"description": "csv",
|
||||
"created_at": "2026-05-23T15:31:44.119922+00:00",
|
||||
"updated_at": "2026-05-23T15:31:44.119922+00:00",
|
||||
"fields": [],
|
||||
"templates": [],
|
||||
"file_count": 0,
|
||||
"chunk_count": 0,
|
||||
"parse_status": "empty"
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"user_id": "d198ae3b32cd49f09736c4290dd1223a",
|
||||
"name": "默认用户",
|
||||
"created_at": "2026-05-23T12:19:43.785929+00:00"
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
[
|
||||
{
|
||||
"user_id": "d198ae3b32cd49f09736c4290dd1223a",
|
||||
"name": "默认用户",
|
||||
"created_at": "2026-05-23T12:19:43.785929+00:00"
|
||||
},
|
||||
{
|
||||
"user_id": "2db10c2ebbf6434aab28035026e196c3",
|
||||
"name": "SmokeTest",
|
||||
"created_at": "2026-05-23T12:21:32.399217+00:00"
|
||||
}
|
||||
]
|
||||
@@ -25,4 +25,6 @@
|
||||
|
||||
{fidelity_context}
|
||||
|
||||
{template_context}
|
||||
|
||||
立即生成修正后的 JRXML:
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
你是一位资深 JasperReports 工程师。当前有一个 JRXML 使用占位字段名($F{{field_1}}, $F{{field_2}}, ...),需要替换为从 OCR 提取的真实字段名。
|
||||
|
||||
**你必须基于已有的 JRXML 进行修改,而不是重新生成。保留所有现有的元素,只替换字段名。**
|
||||
|
||||
关键规则:
|
||||
- 只输出完整修改后的 JRXML 代码,不要解释,不要 markdown 标记。
|
||||
- **保留所有现有的 field、staticText、textField、band、reportElement 元素,一个都不能少。**
|
||||
- **不要删除、简化、合并或重写任何元素。不要改动任何坐标值(x, y, width, height)。**
|
||||
- 将每个 $F{{field_N}} 占位符替换为 OCR 提取结果中对应的真实字段名。
|
||||
- 替换规则:根据列的顺序映射——$F{{field_1}} 对应第 1 列的 OCR 字段名,$F{{field_2}} 对应第 2 列,以此类推。
|
||||
- 同时更新 <field name="..."> 声明和所有 $F{{...}} 表达式中的引用。
|
||||
- 同时更新 field name="..." 声明和所有 $F{{...}} 表达式中的引用。
|
||||
- 如果 OCR 提取的字段数少于占位字段数,保留多余的占位字段。
|
||||
- 不要修改 band 结构、元素位置或大小。
|
||||
- 确保 JRXML 兼容 JasperReports 7.0.6。
|
||||
- **输出的 JRXML 字符数应与输入的 JRXML 大致相同(允许 ±15% 偏差),因为只替换字段名,不增删修改任何元素。**
|
||||
|
||||
当前 JRXML(含占位字段):
|
||||
{current_jrxml}
|
||||
|
||||
{template_context}
|
||||
|
||||
OCR 提取的结构化字段:
|
||||
{ocr_fields}
|
||||
|
||||
@@ -11,5 +11,7 @@ JRXML 必须兼容 JasperReports 7.0.6 schema。
|
||||
参考模板和组件:
|
||||
{context}
|
||||
|
||||
{template_context}
|
||||
|
||||
用户需求:
|
||||
{user_request}
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
|
||||
{ocr_context}
|
||||
|
||||
{template_context}
|
||||
|
||||
当前 JRXML:
|
||||
{current_jrxml}
|
||||
|
||||
|
||||
+19
-13
@@ -1,17 +1,23 @@
|
||||
你是一位资深 JasperReports 工程师。当前有一个骨架 JRXML,需要根据精确的像素坐标调整每个元素的位置。
|
||||
你是一位 JRXML 坐标调整器。你的唯一任务是修改 <reportElement> 标签内的 x, y, width, height 属性值。
|
||||
|
||||
关键规则:
|
||||
- 只输出完整修改后的 JRXML 代码,不要解释,不要 markdown 标记。
|
||||
- 根据提供的采样坐标,精确调整每个 textField/staticText 的 x, y, width, height。
|
||||
- 表头行的坐标直接使用采样坐标中 header_row 对应列的 x, y, width, height。
|
||||
- 数据行:根据 first_data_row 的坐标模式,向下插值生成剩余数据行(每行 y 递增行高)。
|
||||
- 标题行(如有)和表尾行:保持其在骨架中的 y 位置大致不变,但调整 x 和 width 与列的采样坐标对齐。
|
||||
- 不要修改字段名(保持 $F{{field_N}} 占位名不变)。
|
||||
- 不要修改 band 结构。
|
||||
- 确保 JRXML 兼容 JasperReports 7.0.6。
|
||||
**这是 Band "{band_name}"(高度 {band_height}px)的第 {window_index}/{total_windows} 个窗口。你只看到该 band 的一个片段,不要尝试生成完整报表。**
|
||||
|
||||
当前骨架 JRXML:
|
||||
{current_jrxml}
|
||||
严格规则:
|
||||
- 只修改 x, y, width, height。不改任何其他内容。
|
||||
- 不添加、删除、重命名任何元素。
|
||||
- 不修改文本内容(CDATA)、表达式(textFieldExpression)、样式属性。
|
||||
- 只输出修改后的 XML 片段,不要解释,不要 markdown,不要代码块标记。
|
||||
- 输出的字符数应与输入片段大致相同。
|
||||
|
||||
采样坐标(表头行 + 第一行数据行,像素位置):
|
||||
坐标调整规则:
|
||||
- 表头行:直接使用 header_row 对应列的 x, y, width, height
|
||||
- 数据行:根据 first_data_row 的坐标模式,向下插值(每行 y 递增行高)
|
||||
- 标题行和表尾行:保持 y 位置大致不变,但调整 x 和 width 与列的采样坐标对齐
|
||||
|
||||
{template_context}
|
||||
|
||||
采样坐标参考:
|
||||
{sampled_coordinates}
|
||||
|
||||
请调整以下片段的坐标:
|
||||
{xml_fragment}
|
||||
|
||||
@@ -15,5 +15,7 @@
|
||||
参考模板和组件:
|
||||
{context}
|
||||
|
||||
{template_context}
|
||||
|
||||
用户需求:
|
||||
{user_request}
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
"""初始化默认用户和预置知识库。
|
||||
|
||||
解析 rag/jrxml_source/ 下的全部 JRXML 模板 + 接口文档,
|
||||
创建默认用户 "默认用户" 和知识库 "F6-汽车维修打印默认知识库",
|
||||
执行完整的 parse -> chunk -> embed 管线。
|
||||
|
||||
用法:
|
||||
python scripts/init_default_kb.py
|
||||
python scripts/init_default_kb.py --force # 强制重建
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
PROJECT_ROOT = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(PROJECT_ROOT))
|
||||
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv()
|
||||
|
||||
from backend.logger import get_logger
|
||||
|
||||
_log = get_logger("init_kb")
|
||||
|
||||
DEFAULT_USER_NAME = "默认用户"
|
||||
DEFAULT_KB_NAME = "F6-汽车维修打印默认知识库"
|
||||
DEFAULT_KB_DESC = "预置的汽车维修打印单模板与接口文档知识库"
|
||||
|
||||
|
||||
def find_source_files(source_dir: Path) -> list[str]:
|
||||
"""收集源目录下的所有 .jrxml 和 .md 文件。"""
|
||||
files = []
|
||||
if not source_dir.exists():
|
||||
_log.warning("源目录不存在: %s", source_dir)
|
||||
return files
|
||||
|
||||
for pattern in ("*.jrxml", "*.md", "**/*.jrxml", "**/*.md"):
|
||||
for fp in source_dir.glob(pattern):
|
||||
if fp.is_file():
|
||||
files.append(str(fp))
|
||||
|
||||
return list(dict.fromkeys(files))
|
||||
|
||||
|
||||
def init_default_kb(force: bool = False) -> dict:
|
||||
"""初始化默认 KB,返回结果摘要。"""
|
||||
from backend.kb_manager import create_user, list_users, create_kb, list_kbs
|
||||
from backend.kb_parser import build_kb_from_files
|
||||
|
||||
# 1. 查找或创建默认用户
|
||||
users = list_users()
|
||||
default_user = None
|
||||
for u in users:
|
||||
if u.get("name") == DEFAULT_USER_NAME:
|
||||
default_user = u
|
||||
break
|
||||
|
||||
if default_user is None:
|
||||
default_user = create_user(DEFAULT_USER_NAME)
|
||||
_log.info("创建默认用户: %s", default_user["user_id"])
|
||||
else:
|
||||
_log.info("默认用户已存在: %s", default_user["user_id"])
|
||||
|
||||
user_id = default_user["user_id"]
|
||||
|
||||
# 2. 查找或创建默认 KB
|
||||
user_kbs = list_kbs(user_id)
|
||||
default_kb = None
|
||||
for kb in user_kbs:
|
||||
if kb.get("name") == DEFAULT_KB_NAME:
|
||||
default_kb = kb
|
||||
break
|
||||
|
||||
if default_kb is not None and force:
|
||||
from backend.kb_manager import delete_kb
|
||||
delete_kb(default_kb["kb_id"])
|
||||
default_kb = None
|
||||
_log.info("强制重建: 已删除旧 KB")
|
||||
|
||||
if default_kb is None:
|
||||
default_kb = create_kb(user_id, DEFAULT_KB_NAME, DEFAULT_KB_DESC)
|
||||
_log.info("创建默认知识库: %s", default_kb["kb_id"])
|
||||
elif default_kb.get("parse_status") == "ready":
|
||||
_log.info("默认知识库已就绪: chunks=%s", default_kb.get("chunk_count", 0))
|
||||
return {"status": "already_ready", "kb_id": default_kb["kb_id"],
|
||||
"user_id": user_id, "chunk_count": default_kb.get("chunk_count", 0)}
|
||||
|
||||
kb_id = default_kb["kb_id"]
|
||||
|
||||
# 3. 收集源文件
|
||||
source_dir = PROJECT_ROOT / "rag" / "jrxml_source"
|
||||
files = find_source_files(source_dir)
|
||||
if not files:
|
||||
_log.warning("未找到源文件,跳过构建")
|
||||
return {"status": "no_files", "kb_id": kb_id, "user_id": user_id}
|
||||
|
||||
_log.info("找到 %d 个源文件", len(files))
|
||||
|
||||
# 4. 构建 KB
|
||||
result = build_kb_from_files(kb_id, files)
|
||||
_log.info("KB 构建完成: %s", result)
|
||||
|
||||
return {**result, "kb_id": kb_id, "user_id": user_id, "file_count": len(files)}
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="初始化默认知识库")
|
||||
parser.add_argument("--force", action="store_true", help="强制重建(删除已有 KB)")
|
||||
args = parser.parse_args()
|
||||
|
||||
print("=" * 60)
|
||||
print("JRXML Agent - 默认知识库初始化")
|
||||
print("=" * 60)
|
||||
|
||||
result = init_default_kb(force=args.force)
|
||||
|
||||
print(f"\n用户: {DEFAULT_USER_NAME}")
|
||||
print(f"知识库: {DEFAULT_KB_NAME}")
|
||||
print(f"状态: {result.get('status', 'unknown')}")
|
||||
print(f"字段数: {result.get('field_count', 0)}")
|
||||
print(f"模板数: {result.get('template_count', 0)}")
|
||||
print(f"Chunk数: {result.get('chunk_count', 0)}")
|
||||
if result.get("errors"):
|
||||
print(f"错误: {len(result['errors'])} 条")
|
||||
for e in result["errors"]:
|
||||
print(f" - {e.get('file', '')}: {e.get('error', '')}")
|
||||
|
||||
print("\n初始化完成!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -104,9 +104,10 @@ def main():
|
||||
subprocess.run(["npm", "install"], cwd=str(FRONTEND_DIR), check=True)
|
||||
|
||||
subprocess.Popen(
|
||||
["npm", "run", "dev"],
|
||||
"npm run dev",
|
||||
cwd=str(FRONTEND_DIR),
|
||||
creationflags=subprocess.CREATE_NO_WINDOW,
|
||||
shell=True,
|
||||
)
|
||||
if not wait_port(5173):
|
||||
print("[FAIL] Frontend did not start in time.")
|
||||
|
||||
@@ -265,3 +265,249 @@ class TestBoundaries:
|
||||
json={"text": large_text, "file_ids": []},
|
||||
) as resp:
|
||||
assert resp.status_code == 200
|
||||
|
||||
|
||||
# ── 用户 CRUD API ───────────────────────────────────────────────
|
||||
|
||||
class TestUserAPI:
|
||||
@pytest.fixture(autouse=True)
|
||||
def temp_kb_data(self, monkeypatch, tmp_path):
|
||||
kb_data = tmp_path / "kb_data"
|
||||
monkeypatch.setattr("backend.kb_manager.KB_DATA_DIR", kb_data)
|
||||
monkeypatch.setattr("backend.kb_manager._USERS_FILE", kb_data / "users.json")
|
||||
yield kb_data
|
||||
|
||||
def test_create_user(self, client):
|
||||
resp = client.post("/api/users", json={"name": "测试用户"})
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert data["name"] == "测试用户"
|
||||
assert len(data["user_id"]) >= 12
|
||||
|
||||
def test_create_user_empty_name_rejected(self, client):
|
||||
resp = client.post("/api/users", json={"name": ""})
|
||||
assert resp.status_code == 400
|
||||
|
||||
def test_list_users(self, client):
|
||||
client.post("/api/users", json={"name": "A"})
|
||||
client.post("/api/users", json={"name": "B"})
|
||||
resp = client.get("/api/users")
|
||||
assert resp.status_code == 200
|
||||
assert len(resp.json()["users"]) == 2
|
||||
|
||||
def test_get_user(self, client):
|
||||
uid = client.post("/api/users", json={"name": "张三"}).json()["user_id"]
|
||||
resp = client.get(f"/api/users/{uid}")
|
||||
assert resp.status_code == 200
|
||||
assert resp.json()["name"] == "张三"
|
||||
|
||||
def test_get_user_not_found(self, client):
|
||||
resp = client.get("/api/users/deadbeef1234567890abcd")
|
||||
assert resp.status_code == 404
|
||||
|
||||
def test_delete_user(self, client):
|
||||
uid = client.post("/api/users", json={"name": "待删除"}).json()["user_id"]
|
||||
resp = client.delete(f"/api/users/{uid}")
|
||||
assert resp.status_code == 200
|
||||
assert resp.json()["status"] == "deleted"
|
||||
assert client.get(f"/api/users/{uid}").status_code == 404
|
||||
|
||||
def test_delete_nonexistent_user(self, client):
|
||||
resp = client.delete("/api/users/deadbeef1234567890abcd")
|
||||
assert resp.status_code == 404
|
||||
|
||||
|
||||
# ── 知识库 CRUD API ─────────────────────────────────────────────
|
||||
|
||||
class TestKbAPI:
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_kb(self, monkeypatch, tmp_path):
|
||||
kb_data = tmp_path / "kb_data"
|
||||
monkeypatch.setattr("backend.kb_manager.KB_DATA_DIR", kb_data)
|
||||
monkeypatch.setattr("backend.kb_manager._USERS_FILE", kb_data / "users.json")
|
||||
# 使用 raw TestClient 来创建前置用户
|
||||
from fastapi.testclient import TestClient as TC
|
||||
tc = TC(app)
|
||||
resp = tc.post("/api/users", json={"name": "KB测试用户"})
|
||||
self.uid = resp.json()["user_id"]
|
||||
|
||||
def test_create_kb(self, client):
|
||||
resp = client.post(f"/api/users/{self.uid}/kbs", json={"name": "测试库", "description": "描述"})
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert data["name"] == "测试库"
|
||||
assert data["parse_status"] == "empty"
|
||||
|
||||
def test_create_kb_empty_name_rejected(self, client):
|
||||
resp = client.post(f"/api/users/{self.uid}/kbs", json={"name": ""})
|
||||
assert resp.status_code == 400
|
||||
|
||||
def test_list_kbs(self, client):
|
||||
client.post(f"/api/users/{self.uid}/kbs", json={"name": "KB1"})
|
||||
client.post(f"/api/users/{self.uid}/kbs", json={"name": "KB2"})
|
||||
resp = client.get(f"/api/users/{self.uid}/kbs")
|
||||
assert resp.status_code == 200
|
||||
assert len(resp.json()["kbs"]) == 2
|
||||
|
||||
def test_get_kb(self, client):
|
||||
kid = client.post(f"/api/users/{self.uid}/kbs", json={"name": "查询库"}).json()["kb_id"]
|
||||
resp = client.get(f"/api/kbs/{kid}")
|
||||
assert resp.status_code == 200
|
||||
assert resp.json()["name"] == "查询库"
|
||||
|
||||
def test_get_kb_not_found(self, client):
|
||||
resp = client.get("/api/kbs/deadbeef1234567890abcd")
|
||||
assert resp.status_code == 404
|
||||
|
||||
def test_delete_kb(self, client):
|
||||
kid = client.post(f"/api/users/{self.uid}/kbs", json={"name": "待删库"}).json()["kb_id"]
|
||||
resp = client.delete(f"/api/kbs/{kid}")
|
||||
assert resp.status_code == 200
|
||||
assert resp.json()["status"] == "deleted"
|
||||
|
||||
def test_kb_status(self, client):
|
||||
kid = client.post(f"/api/users/{self.uid}/kbs", json={"name": "状态库"}).json()["kb_id"]
|
||||
resp = client.get(f"/api/kbs/{kid}/status")
|
||||
assert resp.status_code == 200
|
||||
assert resp.json()["parse_status"] == "empty"
|
||||
assert resp.json()["file_count"] == 0
|
||||
|
||||
def test_kb_fields(self, client):
|
||||
kid = client.post(f"/api/users/{self.uid}/kbs", json={"name": "字段库"}).json()["kb_id"]
|
||||
resp = client.get(f"/api/kbs/{kid}/fields")
|
||||
assert resp.status_code == 200
|
||||
assert resp.json()["fields"] == []
|
||||
assert resp.json()["templates"] == []
|
||||
|
||||
|
||||
# ── KB 文件上传 & 构建 API ──────────────────────────────────────
|
||||
|
||||
class TestKbUploadBuild:
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_up(self, monkeypatch, tmp_path):
|
||||
kb_data = tmp_path / "kb_data"
|
||||
kb_data.mkdir(parents=True, exist_ok=True)
|
||||
monkeypatch.setattr("backend.kb_manager.KB_DATA_DIR", kb_data)
|
||||
monkeypatch.setattr("backend.kb_manager._USERS_FILE", kb_data / "users.json")
|
||||
# Mock process_file_for_kb to avoid SameFileError (API already writes to raw_dir)
|
||||
monkeypatch.setattr(
|
||||
"backend.kb_parser.process_file_for_kb",
|
||||
lambda kb_id, file_path, source_name="": {
|
||||
"filename": source_name, "type": "txt", "error": None})
|
||||
from fastapi.testclient import TestClient as TC
|
||||
tc = TC(app)
|
||||
resp = tc.post("/api/users", json={"name": "上传测试用户"})
|
||||
self.uid = resp.json()["user_id"]
|
||||
|
||||
def test_upload_to_kb(self, client):
|
||||
kid = client.post(f"/api/users/{self.uid}/kbs", json={"name": "上传库"}).json()["kb_id"]
|
||||
resp = client.post(
|
||||
f"/api/kbs/{kid}/upload",
|
||||
files={"file": ("readme.md", io.BytesIO(b"# test"), "text/markdown")},
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
assert resp.json()["filename"] == "readme.md"
|
||||
|
||||
def test_upload_to_nonexistent_kb(self, client):
|
||||
resp = client.post(
|
||||
"/api/kbs/deadbeef1234567890abcd/upload",
|
||||
files={"file": ("x.txt", io.BytesIO(b"x"), "text/plain")},
|
||||
)
|
||||
assert resp.status_code == 404
|
||||
|
||||
def test_build_empty_kb_fails(self, client):
|
||||
kid = client.post(f"/api/users/{self.uid}/kbs", json={"name": "空库"}).json()["kb_id"]
|
||||
resp = client.post(f"/api/kbs/{kid}/build")
|
||||
assert resp.status_code == 400
|
||||
|
||||
def test_search_kb_empty_query_rejected(self, client):
|
||||
kid = client.post(f"/api/users/{self.uid}/kbs", json={"name": "搜索库"}).json()["kb_id"]
|
||||
resp = client.get(f"/api/kbs/{kid}/search")
|
||||
assert resp.status_code == 400
|
||||
|
||||
|
||||
# ── 会话-KB 绑定 API ────────────────────────────────────────────
|
||||
|
||||
class TestSessionKbBinding:
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_bind(self, monkeypatch, tmp_path):
|
||||
kb_data = tmp_path / "kb_data"
|
||||
kb_data.mkdir(parents=True, exist_ok=True)
|
||||
sessions_dir = tmp_path / "sessions"
|
||||
monkeypatch.setattr("backend.kb_manager.KB_DATA_DIR", kb_data)
|
||||
monkeypatch.setattr("backend.kb_manager._USERS_FILE", kb_data / "users.json")
|
||||
monkeypatch.setattr("backend.session.SESSIONS_DIR", sessions_dir)
|
||||
monkeypatch.setattr("api_server.UPLOADS_DIR", tmp_path / "uploads")
|
||||
|
||||
def test_bind_kb_to_session(self, client):
|
||||
uid = client.post("/api/users", json={"name": "绑定用户"}).json()["user_id"]
|
||||
kid = client.post(f"/api/users/{uid}/kbs", json={"name": "绑定库"}).json()["kb_id"]
|
||||
sid = client.post("/api/sessions").json()["session_id"]
|
||||
resp = client.put(f"/api/sessions/{sid}/kb", json={"kb_id": kid})
|
||||
assert resp.status_code == 200
|
||||
assert resp.json()["kb_id"] == kid
|
||||
|
||||
def test_get_session_kb(self, client):
|
||||
uid = client.post("/api/users", json={"name": "查询用户"}).json()["user_id"]
|
||||
kid = client.post(f"/api/users/{uid}/kbs", json={"name": "查询KB"}).json()["kb_id"]
|
||||
sid = client.post("/api/sessions").json()["session_id"]
|
||||
client.put(f"/api/sessions/{sid}/kb", json={"kb_id": kid})
|
||||
resp = client.get(f"/api/sessions/{sid}/kb")
|
||||
assert resp.status_code == 200
|
||||
assert resp.json()["kb_id"] == kid
|
||||
assert resp.json()["kb_name"] == "查询KB"
|
||||
|
||||
def test_unbind_kb(self, client):
|
||||
sid = client.post("/api/sessions").json()["session_id"]
|
||||
resp = client.put(f"/api/sessions/{sid}/kb", json={"kb_id": ""})
|
||||
assert resp.status_code == 200
|
||||
assert resp.json()["kb_id"] is None
|
||||
|
||||
def test_bind_nonexistent_kb(self, client):
|
||||
sid = client.post("/api/sessions").json()["session_id"]
|
||||
resp = client.put(f"/api/sessions/{sid}/kb", json={"kb_id": "deadbeef1234567890abcd"})
|
||||
assert resp.status_code == 404
|
||||
|
||||
def test_bind_to_nonexistent_session(self, client):
|
||||
resp = client.put("/api/sessions/deadbeef1234567890abcd/kb", json={"kb_id": ""})
|
||||
assert resp.status_code == 404
|
||||
|
||||
|
||||
# ── 用户-KB 端到端流程 ──────────────────────────────────────────
|
||||
|
||||
class TestUserKbE2E:
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_e2e(self, monkeypatch, tmp_path):
|
||||
kb_data = tmp_path / "kb_data"
|
||||
kb_data.mkdir(parents=True, exist_ok=True)
|
||||
sessions_dir = tmp_path / "sessions"
|
||||
monkeypatch.setattr("backend.kb_manager.KB_DATA_DIR", kb_data)
|
||||
monkeypatch.setattr("backend.kb_manager._USERS_FILE", kb_data / "users.json")
|
||||
monkeypatch.setattr("backend.session.SESSIONS_DIR", sessions_dir)
|
||||
monkeypatch.setattr("api_server.UPLOADS_DIR", tmp_path / "uploads")
|
||||
# Mock process_file_for_kb to avoid SameFileError
|
||||
monkeypatch.setattr(
|
||||
"backend.kb_parser.process_file_for_kb",
|
||||
lambda kb_id, file_path, source_name="": {
|
||||
"filename": source_name, "type": "txt", "error": None})
|
||||
|
||||
def test_full_flow(self, client):
|
||||
# 1. 创建用户
|
||||
uid = client.post("/api/users", json={"name": "E2E用户"}).json()["user_id"]
|
||||
# 2. 创建 KB
|
||||
kid = client.post(f"/api/users/{uid}/kbs", json={"name": "E2E库"}).json()["kb_id"]
|
||||
# 3. 上传文件
|
||||
resp = client.post(
|
||||
f"/api/kbs/{kid}/upload",
|
||||
files={"file": ("readme.md", io.BytesIO(b"# E2E test"), "text/markdown")},
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
# 4. 创建会话
|
||||
sid = client.post("/api/sessions").json()["session_id"]
|
||||
# 5. 绑定 KB 到会话
|
||||
bind = client.put(f"/api/sessions/{sid}/kb", json={"kb_id": kid})
|
||||
assert bind.status_code == 200
|
||||
assert bind.json()["kb_id"] == kid
|
||||
# 6. 查询会话 KB
|
||||
info = client.get(f"/api/sessions/{sid}/kb")
|
||||
assert info.json()["kb_name"] == "E2E库"
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
"""datasource.py 测试 — 数据源模式解析, JDBC 检测, 上下文构建。"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
|
||||
from agent.datasource import (
|
||||
resolve_datasource_mode, _detect_jdbc_intent,
|
||||
build_datasource_context, configure_jdbc, ask_db_config,
|
||||
)
|
||||
|
||||
|
||||
def _make_state(**overrides):
|
||||
s = {
|
||||
"user_input": "",
|
||||
"conversation_history": [],
|
||||
"current_jrxml": "",
|
||||
"status": "",
|
||||
"error_msg": "",
|
||||
"natural_explanation": "",
|
||||
"retry_count": 0,
|
||||
"user_modification_request": "",
|
||||
"final_jrxml": "",
|
||||
"stage": "",
|
||||
"retrieved_context": "",
|
||||
**overrides,
|
||||
}
|
||||
return s
|
||||
|
||||
|
||||
# ── JDBC 意图检测 ───────────────────────────────────────────────
|
||||
|
||||
class TestDetectJdbcIntent:
|
||||
def test_direct_connect_keywords(self):
|
||||
assert _detect_jdbc_intent("我想从数据库直连查询") is True
|
||||
assert _detect_jdbc_intent("直连数据库获取数据") is True
|
||||
|
||||
def test_db_name_mentions(self):
|
||||
assert _detect_jdbc_intent("从MySQL数据库查询用户表") is True
|
||||
assert _detect_jdbc_intent("在PostgreSQL中执行查询") is True
|
||||
assert _detect_jdbc_intent("从Oracle读取数据") is True
|
||||
|
||||
def test_jdbc_explicit_mention(self):
|
||||
assert _detect_jdbc_intent("使用JDBC连接") is True
|
||||
|
||||
def test_sql_keywords(self):
|
||||
assert _detect_jdbc_intent("SELECT * FROM users") is True
|
||||
assert _detect_jdbc_intent("从数据库查询用户表") is True
|
||||
assert _detect_jdbc_intent("先查询 数据库") is True
|
||||
|
||||
def test_normal_request_is_not_jdbc(self):
|
||||
assert _detect_jdbc_intent("生成一个员工报表") is False
|
||||
assert _detect_jdbc_intent("修改标题为XX公司") is False
|
||||
|
||||
def test_empty_input(self):
|
||||
assert _detect_jdbc_intent("") is False
|
||||
|
||||
|
||||
# ── 模式解析 ────────────────────────────────────────────────────
|
||||
|
||||
class TestResolveDatasourceMode:
|
||||
def test_defaults_to_parameter_mode(self):
|
||||
state = _make_state(user_input="生成报表")
|
||||
assert resolve_datasource_mode(state) == "parameter"
|
||||
|
||||
def test_detects_jdbc_from_input(self):
|
||||
state = _make_state(user_input="从数据库直连查询")
|
||||
assert resolve_datasource_mode(state) == "jdbc"
|
||||
|
||||
def test_respects_existing_mode_in_state(self):
|
||||
state = _make_state(datasource_mode="jdbc", user_input="生成报表")
|
||||
assert resolve_datasource_mode(state) == "jdbc"
|
||||
|
||||
def test_existing_parameter_overrides_jdbc_input(self):
|
||||
state = _make_state(datasource_mode="parameter", user_input="从数据库直连")
|
||||
assert resolve_datasource_mode(state) == "parameter"
|
||||
|
||||
def test_ignores_invalid_mode_in_state(self):
|
||||
state = _make_state(datasource_mode="unknown", user_input="从数据库直连")
|
||||
assert resolve_datasource_mode(state) == "jdbc"
|
||||
|
||||
|
||||
# ── 上下文构建 ──────────────────────────────────────────────────
|
||||
|
||||
class TestBuildDatasourceContext:
|
||||
def test_parameter_mode_with_fields(self):
|
||||
fields = [
|
||||
{"name": "billNo", "description": "工单号", "type": "java.lang.String"},
|
||||
{"name": "amount", "description": "金额", "type": "java.math.BigDecimal"},
|
||||
]
|
||||
ctx = build_datasource_context("parameter", fields)
|
||||
assert "[数据源模式: 参数]" in ctx
|
||||
assert "$P{xxx}" in ctx
|
||||
assert "billNo" in ctx
|
||||
assert "amount" in ctx
|
||||
|
||||
def test_parameter_mode_without_fields(self):
|
||||
ctx = build_datasource_context("parameter", [])
|
||||
assert "[数据源模式: 参数]" in ctx
|
||||
assert "$P{xxx}" in ctx
|
||||
|
||||
def test_jdbc_mode_with_config(self):
|
||||
db_config = {"url": "jdbc:mysql://localhost:3306/mydb",
|
||||
"driver": "com.mysql.cj.jdbc.Driver"}
|
||||
ctx = build_datasource_context("jdbc", [], db_config)
|
||||
assert "[数据源模式: JDBC]" in ctx
|
||||
assert "jdbc:mysql://" in ctx
|
||||
assert "CDATA" in ctx
|
||||
|
||||
def test_jdbc_mode_without_config_shows_warning(self):
|
||||
ctx = build_datasource_context("jdbc", [])
|
||||
assert "尚未配置数据库连接" in ctx
|
||||
assert "P{xxx}" in ctx
|
||||
|
||||
|
||||
# ── JDBC 配置 ───────────────────────────────────────────────────
|
||||
|
||||
class TestConfigureJdbc:
|
||||
def test_configure_returns_update_dict(self):
|
||||
state = _make_state()
|
||||
update = configure_jdbc(
|
||||
state, url="jdbc:mysql://localhost/db",
|
||||
driver="com.mysql.cj.jdbc.Driver",
|
||||
username="root", password="pass")
|
||||
assert update["datasource_mode"] == "jdbc"
|
||||
assert update["db_config"]["url"] == "jdbc:mysql://localhost/db"
|
||||
assert update["db_config"]["username"] == "root"
|
||||
|
||||
def test_default_driver_is_mysql(self):
|
||||
update = configure_jdbc(_make_state(), url="jdbc:postgresql://localhost/db")
|
||||
assert "mysql" in update["db_config"]["driver"]
|
||||
|
||||
|
||||
# ── ask_db_config ───────────────────────────────────────────────
|
||||
|
||||
class TestAskDbConfig:
|
||||
def test_returns_none_for_parameter_mode(self):
|
||||
state = _make_state(datasource_mode="parameter")
|
||||
assert ask_db_config(state) is None
|
||||
|
||||
def test_returns_none_when_jdbc_configured(self):
|
||||
state = _make_state(datasource_mode="jdbc",
|
||||
db_config={"url": "jdbc:mysql://localhost/db"})
|
||||
assert ask_db_config(state) is None
|
||||
|
||||
def test_returns_prompt_when_jdbc_missing_config(self):
|
||||
state = _make_state(datasource_mode="jdbc")
|
||||
msg = ask_db_config(state)
|
||||
assert msg is not None
|
||||
assert "JDBC URL" in msg
|
||||
assert "用户名" in msg
|
||||
assert "密码" in msg
|
||||
|
||||
def test_returns_none_when_db_config_empty(self):
|
||||
state = _make_state(datasource_mode="jdbc", db_config={})
|
||||
msg = ask_db_config(state)
|
||||
assert msg is not None
|
||||
@@ -0,0 +1,157 @@
|
||||
"""field_matcher.py 测试 — OCR 字段 → KB 字段匹配, embedding + LLM。"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch, MagicMock
|
||||
|
||||
import pytest
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
|
||||
from backend.field_matcher import (
|
||||
_cosine_similarity, match_ocr_to_kb, _match_via_llm,
|
||||
format_field_mapping_context,
|
||||
)
|
||||
|
||||
|
||||
# ── 余弦相似度 ──────────────────────────────────────────────────
|
||||
|
||||
class TestCosineSimilarity:
|
||||
def test_identical_vectors(self):
|
||||
assert _cosine_similarity([1, 0, 0], [1, 0, 0]) == 1.0
|
||||
|
||||
def test_orthogonal_vectors(self):
|
||||
assert _cosine_similarity([1, 0, 0], [0, 1, 0]) == 0.0
|
||||
|
||||
def test_opposite_vectors(self):
|
||||
assert _cosine_similarity([1, 0], [-1, 0]) == -1.0
|
||||
|
||||
def test_normalized_vectors_range(self):
|
||||
sim = _cosine_similarity([0.6, 0.8], [0.8, 0.6])
|
||||
assert -1.0 <= sim <= 1.0
|
||||
|
||||
|
||||
# ── LLM 匹配 ────────────────────────────────────────────────────
|
||||
|
||||
class TestMatchViaLlm:
|
||||
def test_returns_json_mapping(self):
|
||||
mock_llm = MagicMock()
|
||||
mock_response = MagicMock()
|
||||
mock_response.content = '{"工单号": "billNo", "客户": "customerName"}'
|
||||
mock_llm.invoke.return_value = mock_response
|
||||
|
||||
kb_fields = [
|
||||
{"name": "billNo", "description": "工单号", "type": "String"},
|
||||
{"name": "customerName", "description": "客户名称", "type": "String"},
|
||||
]
|
||||
result = _match_via_llm(["工单号", "客户"], kb_fields, mock_llm)
|
||||
assert result == {"工单号": "billNo", "客户": "customerName"}
|
||||
|
||||
def test_includes_candidates_hint_when_provided(self):
|
||||
mock_llm = MagicMock()
|
||||
mock_response = MagicMock()
|
||||
mock_response.content = '{"工单号": "billNo"}'
|
||||
mock_llm.invoke.return_value = mock_response
|
||||
candidates = {"工单号": [("billNo", 0.85), ("orderId", 0.62)]}
|
||||
result = _match_via_llm(
|
||||
["工单号"],
|
||||
[{"name": "billNo", "description": "工单号", "type": "String"}],
|
||||
mock_llm, candidates=candidates)
|
||||
call_args = mock_llm.invoke.call_args[0][0]
|
||||
assert "候选" in call_args
|
||||
assert "billNo" in call_args
|
||||
|
||||
def test_llm_error_returns_empty_dict(self):
|
||||
mock_llm = MagicMock()
|
||||
mock_llm.invoke.side_effect = RuntimeError("LLM crash")
|
||||
result = _match_via_llm(["x"], [{"name": "y", "description": "", "type": "String"}], mock_llm)
|
||||
assert result == {}
|
||||
|
||||
def test_llm_returns_invalid_json_returns_empty(self):
|
||||
mock_llm = MagicMock()
|
||||
mock_response = MagicMock()
|
||||
mock_response.content = "not json at all"
|
||||
mock_llm.invoke.return_value = mock_response
|
||||
result = _match_via_llm(["x"], [{"name": "y", "description": "", "type": "String"}], mock_llm)
|
||||
assert result == {}
|
||||
|
||||
|
||||
# ── 完整匹配流程 ────────────────────────────────────────────────
|
||||
|
||||
class TestMatchOcrToKb:
|
||||
@pytest.fixture(autouse=True)
|
||||
def mock_embed(self):
|
||||
with patch("backend.field_matcher._embed") as mock_embed:
|
||||
def _fake_embed(text):
|
||||
if "billNo" in text or "工单" in text:
|
||||
return [1.0, 0.0, 0.0]
|
||||
if "customerName" in text or "客户" in text:
|
||||
return [0.0, 1.0, 0.0]
|
||||
if "amount" in text or "金额" in text:
|
||||
return [0.0, 0.0, 1.0]
|
||||
return [0.0, 0.0, 0.0]
|
||||
mock_embed.side_effect = _fake_embed
|
||||
yield mock_embed
|
||||
|
||||
def test_matches_without_llm(self):
|
||||
kb_fields = [
|
||||
{"name": "billNo", "description": "工单号", "type": "String"},
|
||||
{"name": "customerName", "description": "客户名称", "type": "String"},
|
||||
{"name": "amount", "description": "金额", "type": "BigDecimal"},
|
||||
]
|
||||
mapping = match_ocr_to_kb(
|
||||
["工单号", "客户名称", "金额"], kb_fields, llm=None)
|
||||
assert mapping["工单号"] == "billNo"
|
||||
assert mapping["客户名称"] == "customerName"
|
||||
assert mapping["金额"] == "amount"
|
||||
|
||||
def test_empty_inputs_return_empty(self):
|
||||
assert match_ocr_to_kb([], [], llm=None) == {}
|
||||
assert match_ocr_to_kb(["x"], [], llm=None) == {}
|
||||
assert match_ocr_to_kb([], [{"name": "y", "description": "", "type": "String"}], llm=None) == {}
|
||||
|
||||
def test_low_similarity_not_matched(self):
|
||||
kb_fields = [{"name": "far", "description": "不相关字段", "type": "String"}]
|
||||
mapping = match_ocr_to_kb(["无关"], kb_fields, llm=None)
|
||||
assert "无关" not in mapping or mapping == {}
|
||||
|
||||
def test_uses_llm_when_provided(self):
|
||||
mock_llm = MagicMock()
|
||||
mock_response = MagicMock()
|
||||
mock_response.content = '{"工单号": "billNo", "客户名称": "customerName"}'
|
||||
mock_llm.invoke.return_value = mock_response
|
||||
kb_fields = [
|
||||
{"name": "billNo", "description": "工单号", "type": "String"},
|
||||
{"name": "customerName", "description": "客户", "type": "String"},
|
||||
]
|
||||
mapping = match_ocr_to_kb(["工单号", "客户名称"], kb_fields, llm=mock_llm)
|
||||
assert mapping["工单号"] == "billNo"
|
||||
|
||||
def test_embedding_failure_falls_back_to_llm(self):
|
||||
mock_llm = MagicMock()
|
||||
mock_response = MagicMock()
|
||||
mock_response.content = '{"工单号": "billNo"}'
|
||||
mock_llm.invoke.return_value = mock_response
|
||||
with patch("backend.field_matcher._embed", side_effect=RuntimeError("model error")):
|
||||
kb_fields = [{"name": "billNo", "description": "工单号", "type": "String"}]
|
||||
mapping = match_ocr_to_kb(["工单号"], kb_fields, llm=mock_llm)
|
||||
assert mapping["工单号"] == "billNo"
|
||||
|
||||
|
||||
# ── 格式化上下文 ────────────────────────────────────────────────
|
||||
|
||||
class TestFormatFieldMappingContext:
|
||||
def test_formats_mapping_as_table(self):
|
||||
ctx = format_field_mapping_context({"工单号": "billNo", "客户": "customerName"})
|
||||
assert "[字段映射" in ctx
|
||||
assert "$P{billNo}" in ctx
|
||||
assert "$P{customerName}" in ctx
|
||||
assert "工单号" in ctx
|
||||
assert "客户" in ctx
|
||||
|
||||
def test_empty_mapping_returns_empty_string(self):
|
||||
assert format_field_mapping_context({}) == ""
|
||||
|
||||
def test_single_entry(self):
|
||||
ctx = format_field_mapping_context({"发票号码": "invoiceNo"})
|
||||
assert "$P{invoiceNo}" in ctx
|
||||
@@ -0,0 +1,325 @@
|
||||
"""JRXML 窗口化模块单元测试。
|
||||
|
||||
测试 decompose → split → reassemble 往返链路,
|
||||
以及元素计数和校验逻辑。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
from agent.jrxml_windower import (
|
||||
decompose_jrxml, reassemble_jrxml,
|
||||
split_band_into_windows, reassemble_band_windows,
|
||||
count_elements, validate_element_count,
|
||||
BandInfo,
|
||||
)
|
||||
|
||||
# ── 最小 JRXML 测试夹具 ──────────────────────────────────────────────
|
||||
|
||||
MINIMAL_JRXML = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<jasperReport name="test" pageWidth="595" pageHeight="842" columnCount="3">
|
||||
<property name="test.prop" value="1"/>
|
||||
<field name="name" class="java.lang.String"/>
|
||||
<field name="amount" class="java.math.BigDecimal"/>
|
||||
<queryString><![CDATA[SELECT * FROM t]]></queryString>
|
||||
<title>
|
||||
<band height="50">
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="100" height="20"/>
|
||||
<text><![CDATA[Title]]></text>
|
||||
</staticText>
|
||||
<textField>
|
||||
<reportElement x="200" y="0" width="80" height="20"/>
|
||||
<textFieldExpression><![CDATA[$F{name}]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
</title>
|
||||
<columnHeader>
|
||||
<band height="30">
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="100" height="30"/>
|
||||
<text><![CDATA[Header]]></text>
|
||||
</staticText>
|
||||
</band>
|
||||
</columnHeader>
|
||||
<detail>
|
||||
<band height="40">
|
||||
<textField>
|
||||
<reportElement x="0" y="0" width="100" height="20"/>
|
||||
<textFieldExpression><![CDATA[$F{name}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField>
|
||||
<reportElement x="200" y="0" width="80" height="20"/>
|
||||
<textFieldExpression><![CDATA[$F{amount}]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
</detail>
|
||||
<pageFooter>
|
||||
<band height="30">
|
||||
<textField>
|
||||
<reportElement x="0" y="0" width="100" height="20"/>
|
||||
<textFieldExpression><![CDATA["Page " + $V{PAGE_NUMBER}]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
</pageFooter>
|
||||
</jasperReport>"""
|
||||
|
||||
|
||||
# ── Decompose 测试 ────────────────────────────────────────────────────
|
||||
|
||||
class TestDecompose:
|
||||
def test_parses_minimal_jrxml(self):
|
||||
parts = decompose_jrxml(MINIMAL_JRXML)
|
||||
assert parts is not None
|
||||
assert parts.band_count == 4 # title, columnHeader, detail, pageFooter
|
||||
assert parts.total_elements == 6 # 2 + 1 + 2 + 1
|
||||
|
||||
def test_declaration_preserved(self):
|
||||
parts = decompose_jrxml(MINIMAL_JRXML)
|
||||
assert '<?xml' in parts.declaration
|
||||
|
||||
def test_root_open_has_jasperreport(self):
|
||||
parts = decompose_jrxml(MINIMAL_JRXML)
|
||||
assert 'jasperReport' in parts.root_open
|
||||
|
||||
def test_header_children_separated(self):
|
||||
parts = decompose_jrxml(MINIMAL_JRXML)
|
||||
assert 'field name="name"' in parts.header_xml
|
||||
assert 'field name="amount"' in parts.header_xml
|
||||
assert 'queryString' in parts.header_xml
|
||||
assert 'property name' in parts.header_xml
|
||||
|
||||
def test_band_labels(self):
|
||||
parts = decompose_jrxml(MINIMAL_JRXML)
|
||||
labels = [b.label for b in parts.bands]
|
||||
assert labels == ["title", "columnHeader", "detail", "pageFooter"]
|
||||
|
||||
def test_footer_closes_jasperreport(self):
|
||||
parts = decompose_jrxml(MINIMAL_JRXML)
|
||||
assert 'jasperReport' in parts.footer
|
||||
assert parts.footer.strip().endswith('>')
|
||||
|
||||
def test_returns_none_for_non_jrxml(self):
|
||||
parts = decompose_jrxml("<html><body></body></html>")
|
||||
assert parts is None
|
||||
|
||||
def test_returns_none_for_malformed_xml(self):
|
||||
parts = decompose_jrxml("not xml at all <<<")
|
||||
assert parts is None
|
||||
|
||||
|
||||
# ── Roundtrip 测试 ────────────────────────────────────────────────────
|
||||
|
||||
class TestRoundtrip:
|
||||
def test_decompose_reassemble_element_count_unchanged(self):
|
||||
parts = decompose_jrxml(MINIMAL_JRXML)
|
||||
band_map = {b.label: b.band_xml for b in parts.bands}
|
||||
result = reassemble_jrxml(parts, band_map)
|
||||
|
||||
orig = count_elements(MINIMAL_JRXML)
|
||||
reassembled = count_elements(result)
|
||||
assert orig == reassembled, f"Elements: {orig} -> {reassembled}"
|
||||
|
||||
def test_roundtrip_preserves_text_content(self):
|
||||
parts = decompose_jrxml(MINIMAL_JRXML)
|
||||
band_map = {b.label: b.band_xml for b in parts.bands}
|
||||
result = reassemble_jrxml(parts, band_map)
|
||||
|
||||
assert 'Title' in result
|
||||
assert 'Header' in result
|
||||
assert '$F{name}' in result
|
||||
assert '$F{amount}' in result
|
||||
|
||||
def test_empty_bands_preserved(self):
|
||||
"""空 band(无元素)在 roundtrip 中不丢失。"""
|
||||
jrxml = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<jasperReport name="t" pageWidth="595" pageHeight="842">
|
||||
<queryString><![CDATA[]]></queryString>
|
||||
<background>
|
||||
<band height="10"/>
|
||||
</background>
|
||||
<title>
|
||||
<band height="50">
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="100" height="20"/>
|
||||
<text><![CDATA[T]]></text>
|
||||
</staticText>
|
||||
</band>
|
||||
</title>
|
||||
</jasperReport>"""
|
||||
parts = decompose_jrxml(jrxml)
|
||||
assert parts.band_count == 2
|
||||
band_map = {b.label: b.band_xml for b in parts.bands}
|
||||
result = reassemble_jrxml(parts, band_map)
|
||||
assert count_elements(jrxml) == count_elements(result)
|
||||
|
||||
|
||||
# ── Window Split 测试 ─────────────────────────────────────────────────
|
||||
|
||||
class TestWindowSplit:
|
||||
def test_small_band_not_split(self):
|
||||
"""小 band 不会被切分。"""
|
||||
band = BandInfo(
|
||||
section_name="title", band_index=0,
|
||||
band_xml='<band height="50"><staticText><reportElement x="0" y="0" width="1" height="1"/><text><![CDATA[X]]></text></staticText></band>',
|
||||
element_count=1, char_length=150,
|
||||
)
|
||||
windows = split_band_into_windows(band, max_chars=4000)
|
||||
assert len(windows) == 1
|
||||
|
||||
def test_large_band_split_at_element_boundaries(self):
|
||||
"""超过字符阈值的 band 在元素边界切分。"""
|
||||
inner = "<staticText><reportElement x=\"0\" y=\"0\" width=\"100\" height=\"20\"/><text><![CDATA[A]]></text></staticText>\n" * 80
|
||||
band_xml = f'<band height="50">{inner}</band>'
|
||||
band = BandInfo(
|
||||
section_name="detail", band_index=0,
|
||||
band_xml=band_xml,
|
||||
element_count=80, char_length=len(band_xml),
|
||||
)
|
||||
windows = split_band_into_windows(band, max_chars=4000)
|
||||
assert len(windows) > 1, f"Expected multiple windows, got {len(windows)}"
|
||||
|
||||
def test_split_preserves_element_count(self):
|
||||
"""切分后重组元素数不变。"""
|
||||
inner = "<staticText><reportElement x=\"0\" y=\"0\" width=\"100\" height=\"20\"/><text><![CDATA[A]]></text></staticText>\n" * 80
|
||||
band_xml = f'<band height="50">{inner}</band>'
|
||||
band = BandInfo(
|
||||
section_name="detail", band_index=0,
|
||||
band_xml=band_xml,
|
||||
element_count=80, char_length=len(band_xml),
|
||||
)
|
||||
windows = split_band_into_windows(band, max_chars=4000)
|
||||
reassembled = reassemble_band_windows(windows)
|
||||
assert count_elements(band_xml) == count_elements(reassembled)
|
||||
|
||||
def test_no_empty_windows(self):
|
||||
"""所有窗口非空。"""
|
||||
inner = "<staticText><reportElement x=\"0\" y=\"0\" width=\"100\" height=\"20\"/><text><![CDATA[A]]></text></staticText>\n" * 80
|
||||
band_xml = f'<band height="50">{inner}</band>'
|
||||
band = BandInfo(
|
||||
section_name="detail", band_index=0,
|
||||
band_xml=band_xml,
|
||||
element_count=80, char_length=len(band_xml),
|
||||
)
|
||||
windows = split_band_into_windows(band, max_chars=4000)
|
||||
for i, w in enumerate(windows):
|
||||
assert len(w.strip()) > 0, f"Window {i} is empty"
|
||||
assert '<band' in w, f"Window {i} missing <band>"
|
||||
|
||||
def test_namespaced_band_split(self):
|
||||
"""命名空间前缀的 band 也能正确切分。"""
|
||||
inner = "<ns0:staticText><ns0:reportElement x=\"0\" y=\"0\" width=\"100\" height=\"20\"/><ns0:text><![CDATA[A]]></ns0:text></ns0:staticText>\n" * 80
|
||||
band_xml = f'<ns0:band xmlns:ns0="http://jasperreports.sourceforge.net/jasperreports" height="50">{inner}</ns0:band>'
|
||||
band = BandInfo(
|
||||
section_name="detail", band_index=0,
|
||||
band_xml=band_xml,
|
||||
element_count=80, char_length=len(band_xml),
|
||||
)
|
||||
windows = split_band_into_windows(band, max_chars=4000)
|
||||
assert len(windows) > 1, f"Expected multiple, got {len(windows)}"
|
||||
for w in windows:
|
||||
assert '</ns0:band>' in w or w.startswith('<ns0:band')
|
||||
|
||||
|
||||
# ── Element Count 测试 ────────────────────────────────────────────────
|
||||
|
||||
class TestElementCount:
|
||||
def test_counts_textfield_statictext(self):
|
||||
xml = '<textField/><staticText/>'
|
||||
assert count_elements(xml) == 2
|
||||
|
||||
def test_counts_field_declarations(self):
|
||||
xml = '<field name="a" class="java.lang.String"/>'
|
||||
assert count_elements(xml) == 1
|
||||
|
||||
def test_counts_namespaced_elements(self):
|
||||
xml = '<ns0:textField/><ns0:staticText/><ns0:field name="x"/>'
|
||||
assert count_elements(xml) == 3
|
||||
|
||||
def test_minimal_jrxml_count(self):
|
||||
assert count_elements(MINIMAL_JRXML) == 8
|
||||
|
||||
def test_empty_string_zero(self):
|
||||
assert count_elements("") == 0
|
||||
|
||||
|
||||
# ── Validate 测试 ─────────────────────────────────────────────────────
|
||||
|
||||
class TestValidateElementCount:
|
||||
def test_no_change_ok(self):
|
||||
r = validate_element_count(MINIMAL_JRXML, MINIMAL_JRXML, "test")
|
||||
assert r["ok"] is True
|
||||
assert r["change_pct"] == 0
|
||||
|
||||
def test_small_change_ok(self):
|
||||
"""< 5% 变化静默通过。"""
|
||||
xml2 = MINIMAL_JRXML.replace('<staticText>', '<staticText><!-- comment -->')
|
||||
r = validate_element_count(MINIMAL_JRXML, xml2, "test")
|
||||
# 0% change since comments don't count as elements
|
||||
assert r["ok"] is True
|
||||
|
||||
def test_large_change_not_ok(self):
|
||||
"""> 10% 变化返回 ok=False。"""
|
||||
short = MINIMAL_JRXML[:500] # 大幅截断
|
||||
r = validate_element_count(MINIMAL_JRXML, short, "test")
|
||||
if r["original"] > 0 and r["change_pct"] > 0.10:
|
||||
assert r["ok"] is False
|
||||
|
||||
def test_zero_original_always_ok(self):
|
||||
r = validate_element_count("", MINIMAL_JRXML, "test")
|
||||
assert r["ok"] is True
|
||||
|
||||
|
||||
# ── 多 section 多 band 测试 ──────────────────────────────────────────
|
||||
|
||||
MULTI_BAND_JRXML = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<jasperReport name="multi" pageWidth="595" pageHeight="842">
|
||||
<field name="f1" class="java.lang.String"/>
|
||||
<queryString><![CDATA[SELECT 1]]></queryString>
|
||||
<detail>
|
||||
<band height="30">
|
||||
<textField>
|
||||
<reportElement x="0" y="0" width="100" height="20"/>
|
||||
<textFieldExpression><![CDATA[$F{f1}]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
<band height="20">
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="100" height="15"/>
|
||||
<text><![CDATA[Sub]]></text>
|
||||
</staticText>
|
||||
</band>
|
||||
</detail>
|
||||
<summary>
|
||||
<band height="40">
|
||||
<textField>
|
||||
<reportElement x="0" y="0" width="200" height="30"/>
|
||||
<textFieldExpression><![CDATA["Total"]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
</summary>
|
||||
</jasperReport>"""
|
||||
|
||||
|
||||
class TestMultiBand:
|
||||
def test_multiple_bands_same_section(self):
|
||||
"""同一 section 内的多个 band 分别处理。"""
|
||||
parts = decompose_jrxml(MULTI_BAND_JRXML)
|
||||
assert parts.band_count == 3 # detail_band0, detail_band1, summary
|
||||
labels = [b.label for b in parts.bands]
|
||||
assert labels == ["detail", "detail_band1", "summary"]
|
||||
|
||||
def test_multi_band_roundtrip(self):
|
||||
parts = decompose_jrxml(MULTI_BAND_JRXML)
|
||||
band_map = {b.label: b.band_xml for b in parts.bands}
|
||||
result = reassemble_jrxml(parts, band_map)
|
||||
assert count_elements(MULTI_BAND_JRXML) == count_elements(result)
|
||||
|
||||
def test_reassemble_opens_closes_sections(self):
|
||||
parts = decompose_jrxml(MULTI_BAND_JRXML)
|
||||
band_map = {b.label: b.band_xml for b in parts.bands}
|
||||
result = reassemble_jrxml(parts, band_map)
|
||||
assert result.count('<detail>') == 1
|
||||
assert result.count('</detail>') == 1
|
||||
assert result.count('<summary>') == 1
|
||||
assert result.count('</summary>') == 1
|
||||
@@ -0,0 +1,265 @@
|
||||
"""kb_manager.py 测试 — 用户 + KB CRUD, 原子写入, ID 验证。"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
|
||||
from backend.kb_manager import (
|
||||
_validate_id, _now_iso, _ensure_dir, _read_json, _write_json_atomic,
|
||||
_load_users, _save_users,
|
||||
create_user, list_users, get_user, delete_user,
|
||||
create_kb, list_kbs, get_kb, update_kb_meta, delete_kb,
|
||||
get_kb_raw_dir, get_kb_chunks_path, get_kb_chroma_path,
|
||||
KB_DATA_DIR, _USERS_FILE,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def temp_kb_data(monkeypatch):
|
||||
with tempfile.TemporaryDirectory(prefix="test_kb_") as tmpdir:
|
||||
monkeypatch.setattr("backend.kb_manager.KB_DATA_DIR", Path(tmpdir))
|
||||
monkeypatch.setattr("backend.kb_manager._USERS_FILE", Path(tmpdir) / "users.json")
|
||||
yield Path(tmpdir)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def user(temp_kb_data):
|
||||
return create_user("测试用户")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def kb(temp_kb_data, user):
|
||||
return create_kb(user["user_id"], "测试知识库", "测试描述")
|
||||
|
||||
|
||||
# ── ID 验证 ─────────────────────────────────────────────────────
|
||||
|
||||
class TestIDValidation:
|
||||
def test_valid_hex_id_passes(self):
|
||||
_validate_id("aabbccddeeff0011223344", "test_id")
|
||||
|
||||
def test_short_id_raises(self):
|
||||
with pytest.raises(ValueError, match="Invalid"):
|
||||
_validate_id("abc", "test_id")
|
||||
|
||||
def test_non_hex_id_raises(self):
|
||||
with pytest.raises(ValueError, match="Invalid"):
|
||||
_validate_id("not_valid!!!", "test_id")
|
||||
|
||||
def test_empty_id_raises(self):
|
||||
with pytest.raises(ValueError, match="Invalid"):
|
||||
_validate_id("", "test_id")
|
||||
|
||||
|
||||
# ── 原子写入 ────────────────────────────────────────────────────
|
||||
|
||||
class TestAtomicWrite:
|
||||
def test_write_json_atomic_creates_file(self, temp_kb_data):
|
||||
fp = temp_kb_data / "test.json"
|
||||
_write_json_atomic(fp, {"key": "value"})
|
||||
assert fp.exists()
|
||||
assert json.loads(fp.read_text(encoding="utf-8")) == {"key": "value"}
|
||||
|
||||
def test_write_json_atomic_overwrites(self, temp_kb_data):
|
||||
fp = temp_kb_data / "test.json"
|
||||
_write_json_atomic(fp, {"a": 1})
|
||||
_write_json_atomic(fp, {"b": 2})
|
||||
assert json.loads(fp.read_text(encoding="utf-8")) == {"b": 2}
|
||||
|
||||
def test_write_json_atomic_creates_parent_dir(self, temp_kb_data):
|
||||
fp = temp_kb_data / "deep" / "nested" / "test.json"
|
||||
_write_json_atomic(fp, {"ok": True})
|
||||
assert fp.exists()
|
||||
|
||||
def test_write_json_atomic_no_partial_file_on_error(self, temp_kb_data):
|
||||
fp = temp_kb_data / "fail.json"
|
||||
with patch("json.dump", side_effect=RuntimeError("boom")):
|
||||
with pytest.raises(RuntimeError):
|
||||
_write_json_atomic(fp, {"x": 1})
|
||||
assert not fp.exists()
|
||||
tmps = list(temp_kb_data.glob("*.json*"))
|
||||
assert len(tmps) == 0 or all(not f.name.endswith(".tmp") for f in tmps)
|
||||
|
||||
|
||||
# ── 用户 CRUD ───────────────────────────────────────────────────
|
||||
|
||||
class TestUserCRUD:
|
||||
def test_create_user_returns_dict(self, temp_kb_data):
|
||||
u = create_user("张三")
|
||||
assert u["name"] == "张三"
|
||||
assert len(u["user_id"]) >= 12
|
||||
assert "created_at" in u
|
||||
|
||||
def test_create_user_persists_to_disk(self, temp_kb_data):
|
||||
u = create_user("李四")
|
||||
loaded = list_users()
|
||||
assert any(x["user_id"] == u["user_id"] for x in loaded)
|
||||
|
||||
def test_create_user_with_custom_id(self, temp_kb_data):
|
||||
uid = "abcdef1234567890abcdef"
|
||||
u = create_user("王五", user_id=uid)
|
||||
assert u["user_id"] == uid
|
||||
|
||||
def test_create_duplicate_user_id_raises(self, temp_kb_data):
|
||||
uid = "deadbeef1234567890abcd"
|
||||
create_user("用户1", user_id=uid)
|
||||
with pytest.raises(ValueError, match="already exists"):
|
||||
create_user("用户2", user_id=uid)
|
||||
|
||||
def test_list_users_empty(self, temp_kb_data):
|
||||
assert list_users() == []
|
||||
|
||||
def test_list_users_returns_all(self, temp_kb_data):
|
||||
create_user("A")
|
||||
create_user("B")
|
||||
assert len(list_users()) == 2
|
||||
|
||||
def test_get_user_found(self, user):
|
||||
u = get_user(user["user_id"])
|
||||
assert u is not None
|
||||
assert u["name"] == user["name"]
|
||||
|
||||
def test_get_user_not_found(self, temp_kb_data):
|
||||
assert get_user("deadbeef1234567890abcd") is None
|
||||
|
||||
def test_get_user_invalid_id_raises(self, temp_kb_data):
|
||||
with pytest.raises(ValueError):
|
||||
get_user("invalid")
|
||||
|
||||
def test_delete_user_returns_true(self, user):
|
||||
assert delete_user(user["user_id"]) is True
|
||||
|
||||
def test_delete_user_removes_from_list(self, user):
|
||||
delete_user(user["user_id"])
|
||||
assert get_user(user["user_id"]) is None
|
||||
|
||||
def test_delete_user_removes_dir(self, temp_kb_data, user):
|
||||
user_dir = temp_kb_data / user["user_id"]
|
||||
assert user_dir.exists()
|
||||
delete_user(user["user_id"])
|
||||
assert not user_dir.exists()
|
||||
|
||||
def test_delete_user_not_found_returns_false(self, temp_kb_data):
|
||||
assert delete_user("deadbeef1234567890abcd") is False
|
||||
|
||||
def test_delete_user_invalid_id_raises(self, temp_kb_data):
|
||||
with pytest.raises(ValueError):
|
||||
delete_user("bad_id")
|
||||
|
||||
|
||||
# ── KB CRUD ─────────────────────────────────────────────────────
|
||||
|
||||
class TestKbCRUD:
|
||||
def test_create_kb_returns_meta(self, kb):
|
||||
assert kb["name"] == "测试知识库"
|
||||
assert len(kb["kb_id"]) >= 12
|
||||
assert kb["parse_status"] == "empty"
|
||||
assert kb["file_count"] == 0
|
||||
|
||||
def test_create_kb_creates_dir_structure(self, temp_kb_data, user, kb):
|
||||
kb_dir = temp_kb_data / user["user_id"] / kb["kb_id"]
|
||||
assert kb_dir.is_dir()
|
||||
assert (kb_dir / "raw").is_dir()
|
||||
assert (kb_dir / "meta.json").exists()
|
||||
|
||||
def test_create_kb_with_custom_id(self, user):
|
||||
kid = "cafebabe1234567890feed"
|
||||
kb = create_kb(user["user_id"], "自定义ID库", kb_id=kid)
|
||||
assert kb["kb_id"] == kid
|
||||
|
||||
def test_list_kbs_empty(self, user):
|
||||
assert list_kbs(user["user_id"]) == []
|
||||
|
||||
def test_list_kbs_returns_all(self, user):
|
||||
create_kb(user["user_id"], "B库")
|
||||
create_kb(user["user_id"], "A库")
|
||||
assert len(list_kbs(user["user_id"])) == 2
|
||||
|
||||
def test_list_kbs_summary_format(self, user, kb):
|
||||
kbs = list_kbs(user["user_id"])
|
||||
s = kbs[0]
|
||||
for key in ("kb_id", "name", "field_count", "template_count", "parse_status"):
|
||||
assert key in s
|
||||
|
||||
def test_get_kb_found(self, kb):
|
||||
k = get_kb(kb["kb_id"])
|
||||
assert k is not None
|
||||
assert k["name"] == kb["name"]
|
||||
|
||||
def test_get_kb_not_found(self, temp_kb_data):
|
||||
assert get_kb("deadbeef1234567890abcd") is None
|
||||
|
||||
def test_get_kb_invalid_id_raises(self, temp_kb_data):
|
||||
with pytest.raises(ValueError):
|
||||
get_kb("bad")
|
||||
|
||||
def test_update_kb_meta_changes_fields(self, kb):
|
||||
updated = update_kb_meta(kb["kb_id"], {"parse_status": "ready", "file_count": 5})
|
||||
assert updated is not None
|
||||
assert updated["parse_status"] == "ready"
|
||||
assert updated["file_count"] == 5
|
||||
assert "updated_at" in updated
|
||||
|
||||
def test_update_kb_meta_not_found(self, temp_kb_data):
|
||||
assert update_kb_meta("deadbeef1234567890abcd", {"x": 1}) is None
|
||||
|
||||
def test_delete_kb_returns_true(self, kb):
|
||||
assert delete_kb(kb["kb_id"]) is True
|
||||
|
||||
def test_delete_kb_removes_dir(self, temp_kb_data, user, kb):
|
||||
kb_dir = temp_kb_data / user["user_id"] / kb["kb_id"]
|
||||
assert kb_dir.exists()
|
||||
delete_kb(kb["kb_id"])
|
||||
assert not kb_dir.exists()
|
||||
|
||||
def test_delete_kb_not_found_returns_false(self, temp_kb_data):
|
||||
assert delete_kb("deadbeef1234567890abcd") is False
|
||||
|
||||
|
||||
# ── 工具函数 ────────────────────────────────────────────────────
|
||||
|
||||
class TestHelpers:
|
||||
def test_get_kb_raw_dir(self, kb):
|
||||
d = get_kb_raw_dir(kb["kb_id"])
|
||||
assert d is not None
|
||||
assert d.name == "raw"
|
||||
|
||||
def test_get_kb_raw_dir_not_found(self, temp_kb_data):
|
||||
assert get_kb_raw_dir("deadbeef1234567890abcd") is None
|
||||
|
||||
def test_get_kb_chunks_path(self, kb):
|
||||
p = get_kb_chunks_path(kb["kb_id"])
|
||||
assert p is not None
|
||||
assert p.name == "chunks.json"
|
||||
|
||||
def test_get_kb_chroma_path_creates_dir(self, kb):
|
||||
p = get_kb_chroma_path(kb["kb_id"])
|
||||
assert p is not None
|
||||
assert p.name == "chroma"
|
||||
assert p.exists()
|
||||
|
||||
def test_user_can_own_multiple_kbs(self, user):
|
||||
create_kb(user["user_id"], "KB1")
|
||||
create_kb(user["user_id"], "KB2")
|
||||
create_kb(user["user_id"], "KB3")
|
||||
assert len(list_kbs(user["user_id"])) == 3
|
||||
|
||||
def test_different_users_have_isolated_kbs(self, temp_kb_data):
|
||||
u1 = create_user("用户A")
|
||||
u2 = create_user("用户B")
|
||||
create_kb(u1["user_id"], "A的库")
|
||||
create_kb(u2["user_id"], "B的库")
|
||||
assert len(list_kbs(u1["user_id"])) == 1
|
||||
assert len(list_kbs(u2["user_id"])) == 1
|
||||
|
||||
def test_delete_user_cascades_to_kbs(self, temp_kb_data, user):
|
||||
create_kb(user["user_id"], "要被删除的库")
|
||||
delete_user(user["user_id"])
|
||||
assert not (temp_kb_data / user["user_id"]).exists()
|
||||
@@ -0,0 +1,311 @@
|
||||
"""kb_parser.py 测试 — JRXML 解析, 文件处理, 分块, 字段提取。"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch, MagicMock
|
||||
|
||||
import pytest
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
|
||||
from backend.kb_parser import (
|
||||
parse_jrxml_fields, _extract_archive, process_file_for_kb,
|
||||
chunk_file_results, extract_fields_with_llm, _extract_fields_from_table,
|
||||
_find_tag, _find_all_tags, _collect_from_result, build_kb_from_files,
|
||||
)
|
||||
|
||||
SAMPLE_JRXML = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<jasperReport name="TestReport" pageWidth="595" pageHeight="842"
|
||||
xmlns="http://jasperreports.sourceforge.net/jasperreports">
|
||||
<parameter name="billNo" class="java.lang.String">
|
||||
<parameterDescription>工单号</parameterDescription>
|
||||
</parameter>
|
||||
<parameter name="customerName" class="java.lang.String"/>
|
||||
<field name="amount" class="java.math.BigDecimal"/>
|
||||
<field name="createDate" class="java.sql.Date"/>
|
||||
<queryString><![CDATA[SELECT * FROM orders WHERE bill_no = $P{billNo}]]></queryString>
|
||||
</jasperReport>"""
|
||||
|
||||
SAMPLE_JRXML_NO_NS = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<jasperReport name="SimpleReport" pageWidth="800" pageHeight="600">
|
||||
<parameter name="title" class="java.lang.String"/>
|
||||
<field name="name" class="java.lang.String"/>
|
||||
</jasperReport>"""
|
||||
|
||||
INVALID_XML = """<?xml version="1.0"?>
|
||||
<jasperReport>
|
||||
<parameter name="broken"
|
||||
</jasperReport>"""
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def jrxml_file():
|
||||
with tempfile.NamedTemporaryFile(mode="w", suffix=".jrxml",
|
||||
delete=False, encoding="utf-8") as f:
|
||||
f.write(SAMPLE_JRXML)
|
||||
path = f.name
|
||||
yield path
|
||||
os.unlink(path)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def temp_kb(monkeypatch):
|
||||
with tempfile.TemporaryDirectory(prefix="test_kb_parser_") as tmpdir:
|
||||
kb_data = Path(tmpdir)
|
||||
user_dir = kb_data / "default"
|
||||
kb_dir = user_dir / "abcdef1234567890abcd"
|
||||
raw_dir = kb_dir / "raw"
|
||||
raw_dir.mkdir(parents=True)
|
||||
monkeypatch.setattr(
|
||||
"backend.kb_manager.get_kb_raw_dir",
|
||||
lambda kb_id: raw_dir if kb_id == "abcdef1234567890abcd" else None)
|
||||
monkeypatch.setattr(
|
||||
"backend.kb_manager.get_kb_chunks_path",
|
||||
lambda kb_id: kb_dir / "chunks.json" if kb_id == "abcdef1234567890abcd" else None)
|
||||
monkeypatch.setattr(
|
||||
"backend.kb_manager.update_kb_meta",
|
||||
lambda kb_id, updates: None)
|
||||
yield {"kb_id": "abcdef1234567890abcd", "kb_dir": kb_dir, "raw_dir": raw_dir,
|
||||
"data_dir": kb_data}
|
||||
|
||||
|
||||
# ── JRXML 解析 ──────────────────────────────────────────────────
|
||||
|
||||
class TestParseJrxmlFields:
|
||||
def test_parses_parameters(self, jrxml_file):
|
||||
result = parse_jrxml_fields(jrxml_file)
|
||||
assert result["error"] is None
|
||||
assert len(result["parameters"]) == 2
|
||||
assert result["parameters"][0]["name"] == "billNo"
|
||||
assert result["parameters"][0]["type"] == "java.lang.String"
|
||||
assert result["parameters"][0]["description"] == "工单号"
|
||||
|
||||
def test_parses_fields(self, jrxml_file):
|
||||
result = parse_jrxml_fields(jrxml_file)
|
||||
assert len(result["fields"]) == 2
|
||||
field_names = [f["name"] for f in result["fields"]]
|
||||
assert "amount" in field_names
|
||||
assert "createDate" in field_names
|
||||
|
||||
def test_parses_query(self, jrxml_file):
|
||||
result = parse_jrxml_fields(jrxml_file)
|
||||
assert "SELECT * FROM orders" in result["query"]
|
||||
|
||||
def test_parses_report_metadata(self, jrxml_file):
|
||||
result = parse_jrxml_fields(jrxml_file)
|
||||
assert result["report_name"] == "TestReport"
|
||||
assert result["page_width"] == "595"
|
||||
assert result["page_height"] == "842"
|
||||
|
||||
def test_parses_jrxml_without_namespace(self, tmp_path):
|
||||
fp = tmp_path / "simple.jrxml"
|
||||
fp.write_text(SAMPLE_JRXML_NO_NS, encoding="utf-8")
|
||||
result = parse_jrxml_fields(str(fp))
|
||||
assert result["report_name"] == "SimpleReport"
|
||||
assert len(result["parameters"]) == 1
|
||||
|
||||
def test_invalid_xml_returns_error(self, tmp_path):
|
||||
fp = tmp_path / "bad.jrxml"
|
||||
fp.write_text(INVALID_XML, encoding="utf-8")
|
||||
result = parse_jrxml_fields(str(fp))
|
||||
assert result["error"] is not None
|
||||
assert "解析失败" in result["error"]
|
||||
|
||||
def test_empty_jrxml_has_no_fields(self, tmp_path):
|
||||
fp = tmp_path / "empty.jrxml"
|
||||
fp.write_text(
|
||||
'<?xml version="1.0"?>'
|
||||
'<jasperReport name="Empty"/>',
|
||||
encoding="utf-8")
|
||||
result = parse_jrxml_fields(str(fp))
|
||||
assert result["parameters"] == []
|
||||
assert result["fields"] == []
|
||||
|
||||
def test_nonexistent_file_raises(self):
|
||||
with pytest.raises(FileNotFoundError):
|
||||
parse_jrxml_fields("/nonexistent/path.jrxml")
|
||||
|
||||
|
||||
# ── 表格字段提取 ────────────────────────────────────────────────
|
||||
|
||||
class TestExtractFieldsFromTable:
|
||||
def test_extracts_from_markdown_table(self):
|
||||
text = """| 字段名 | 含义 | 必填 | 类型 |
|
||||
|--------|------|------|------|
|
||||
| billNo | 工单号 | 是 | String |
|
||||
| amount | 金额 | 否 | BigDecimal |"""
|
||||
fields = _extract_fields_from_table(text)
|
||||
assert len(fields) == 2
|
||||
assert fields[0]["name"] == "billNo"
|
||||
assert fields[0]["description"] == "工单号"
|
||||
assert fields[0]["required"] is True
|
||||
assert fields[1]["name"] == "amount"
|
||||
|
||||
def test_skips_separator_rows(self):
|
||||
text = """| 字段 | 说明 |
|
||||
|------|------|
|
||||
|------|------|
|
||||
| name | 名称 |"""
|
||||
fields = _extract_fields_from_table(text)
|
||||
assert len(fields) == 1
|
||||
assert fields[0]["name"] == "name"
|
||||
|
||||
def test_returns_empty_for_plain_text(self):
|
||||
fields = _extract_fields_from_table("这是一段普通文本,没有表格。")
|
||||
assert fields == []
|
||||
|
||||
def test_cells_with_bold_markers_stripped(self):
|
||||
text = """| 名称 | 含义 |
|
||||
|------|------|
|
||||
| **billNo** | 单号 |"""
|
||||
fields = _extract_fields_from_table(text)
|
||||
assert fields[0]["name"] == "billNo"
|
||||
|
||||
|
||||
# ── LLM 字段提取 ────────────────────────────────────────────────
|
||||
|
||||
class TestExtractFieldsWithLlm:
|
||||
def test_falls_back_to_table_when_no_llm(self):
|
||||
text = "| 字段 | 说明 |\n|------|------|\n| code | 编码 |"
|
||||
fields = extract_fields_with_llm(text, llm=None)
|
||||
assert len(fields) >= 1
|
||||
assert any(f["name"] == "code" for f in fields)
|
||||
|
||||
def test_uses_llm_when_provided(self):
|
||||
mock_llm = MagicMock()
|
||||
mock_response = MagicMock()
|
||||
mock_response.content = '[{"name": "id", "description": "ID", "type": "Long", "required": true}]'
|
||||
mock_llm.invoke.return_value = mock_response
|
||||
fields = extract_fields_with_llm("some text", llm=mock_llm)
|
||||
assert len(fields) == 1
|
||||
assert fields[0]["name"] == "id"
|
||||
|
||||
def test_llm_failure_falls_back_to_table(self):
|
||||
mock_llm = MagicMock()
|
||||
mock_llm.invoke.side_effect = RuntimeError("LLM down")
|
||||
text = "| 字段 | 说明 |\n|------|------|\n| code | 编码 |"
|
||||
fields = extract_fields_with_llm(text, llm=mock_llm)
|
||||
assert any(f["name"] == "code" for f in fields)
|
||||
|
||||
|
||||
# ── 文件处理 ────────────────────────────────────────────────────
|
||||
|
||||
class TestProcessFileForKb:
|
||||
def test_process_jrxml_copies_and_parses(self, jrxml_file, temp_kb):
|
||||
result = process_file_for_kb(temp_kb["kb_id"], jrxml_file)
|
||||
assert result["type"] == "jrxml"
|
||||
assert result["jrxml_info"]["report_name"] == "TestReport"
|
||||
assert result["error"] is None
|
||||
copied = list(temp_kb["raw_dir"].glob("*.jrxml"))
|
||||
assert len(copied) == 1
|
||||
|
||||
def test_process_nonexistent_kb_returns_error(self, jrxml_file):
|
||||
result = process_file_for_kb("deadbeef1234567890abcd", jrxml_file)
|
||||
assert result["error"] is not None
|
||||
|
||||
def test_process_text_file(self, tmp_path, temp_kb):
|
||||
fp = tmp_path / "readme.md"
|
||||
fp.write_text("# 标题\n\n这是一段内容。\n\n另一段内容。", encoding="utf-8")
|
||||
with patch("backend.kb_parser.parse_file") as mock_parse:
|
||||
mock_parse.return_value = {"text": "parsed content", "error": None}
|
||||
result = process_file_for_kb(temp_kb["kb_id"], str(fp))
|
||||
assert result["filename"] is not None
|
||||
assert result["error"] is None
|
||||
|
||||
|
||||
# ── 分块 ────────────────────────────────────────────────────────
|
||||
|
||||
class TestChunkFileResults:
|
||||
def test_jrxml_result_produces_template_chunk(self, jrxml_file):
|
||||
info = parse_jrxml_fields(jrxml_file)
|
||||
raw = Path(jrxml_file).read_text(encoding="utf-8")
|
||||
results = [{
|
||||
"filename": "test.jrxml", "type": "jrxml",
|
||||
"text": "text content", "raw_xml": raw,
|
||||
"jrxml_info": info, "error": None,
|
||||
}]
|
||||
chunks = chunk_file_results(results, kb_name="测试库")
|
||||
assert len(chunks) >= 1
|
||||
tmpl = [c for c in chunks if c["metadata"]["chunk_type"] == "jrxml_template"]
|
||||
assert len(tmpl) == 1
|
||||
assert tmpl[0]["metadata"]["report_name"] == "TestReport"
|
||||
assert "TestReport" in tmpl[0]["content"]
|
||||
|
||||
def test_archive_result_recurses(self):
|
||||
results = [{
|
||||
"filename": "bundle.zip", "type": "archive", "text": "",
|
||||
"archive_contents": [
|
||||
{"filename": "inner.jrxml", "type": "jrxml",
|
||||
"text": "inner text", "raw_xml": "<xml/>",
|
||||
"jrxml_info": {"report_name": "Inner", "parameters": [], "fields": []},
|
||||
"error": None},
|
||||
], "error": None,
|
||||
}]
|
||||
chunks = chunk_file_results(results)
|
||||
assert any(c["metadata"]["report_name"] == "Inner" for c in chunks)
|
||||
|
||||
def test_empty_text_skipped(self):
|
||||
results = [{"filename": "empty.md", "type": "md", "text": "", "error": None}]
|
||||
assert chunk_file_results(results) == []
|
||||
|
||||
def test_short_paragraphs_skipped(self):
|
||||
results = [{"filename": "short.txt", "type": "txt", "text": "hi", "error": None}]
|
||||
assert chunk_file_results(results) == []
|
||||
|
||||
def test_text_split_into_paragraphs(self):
|
||||
long_para = "A" * 50
|
||||
results = [
|
||||
{"filename": "doc.txt", "type": "txt",
|
||||
"text": f"{long_para}\n\n{long_para}\n\n{long_para}", "error": None},
|
||||
]
|
||||
chunks = chunk_file_results(results)
|
||||
assert len(chunks) == 3
|
||||
|
||||
|
||||
# ── _collect_from_result ────────────────────────────────────────
|
||||
|
||||
class TestCollectFromResult:
|
||||
def test_collects_jrxml_parameters_as_fields(self):
|
||||
fields = []
|
||||
templates = []
|
||||
_collect_from_result({
|
||||
"jrxml_info": {
|
||||
"report_name": "R1",
|
||||
"parameters": [{"name": "p1", "type": "String", "description": "参数1"}],
|
||||
"fields": [],
|
||||
},
|
||||
"filename": "r1.jrxml",
|
||||
}, fields, templates)
|
||||
assert len(templates) == 1
|
||||
assert any(f["name"] == "p1" for f in fields)
|
||||
|
||||
def test_collects_jrxml_fields(self):
|
||||
fields = []
|
||||
templates = []
|
||||
_collect_from_result({
|
||||
"jrxml_info": {
|
||||
"report_name": "R2",
|
||||
"parameters": [],
|
||||
"fields": [{"name": "f1", "type": "Double", "description": ""}],
|
||||
},
|
||||
"filename": "r2.jrxml",
|
||||
}, fields, templates)
|
||||
assert any(f["name"] == "f1" for f in fields)
|
||||
|
||||
def test_skips_non_jrxml(self):
|
||||
fields = []
|
||||
templates = []
|
||||
_collect_from_result({"type": "csv", "filename": "data.csv"}, fields, templates)
|
||||
assert templates == []
|
||||
assert fields == []
|
||||
|
||||
def test_deduplicates_fields(self):
|
||||
fields = []
|
||||
templates = []
|
||||
info = {"report_name": "R", "parameters": [{"name": "dup", "type": "String", "description": ""}], "fields": []}
|
||||
_collect_from_result({"jrxml_info": info, "filename": "a.jrxml"}, fields, templates)
|
||||
_collect_from_result({"jrxml_info": info, "filename": "b.jrxml"}, fields, templates)
|
||||
assert sum(1 for f in fields if f["name"] == "dup") == 1
|
||||
@@ -0,0 +1,214 @@
|
||||
"""kb_searcher.py 测试 — KBChromaSearcher 创建, 搜索, 模板检索。"""
|
||||
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch, MagicMock
|
||||
|
||||
import pytest
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
|
||||
from backend.kb_searcher import (
|
||||
KBChromaSearcher, get_kb_searcher, search_kb, search_templates_in_kb,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_chromadb(monkeypatch):
|
||||
mock_client = MagicMock()
|
||||
mock_collection = MagicMock()
|
||||
mock_client.get_collection.return_value = mock_collection
|
||||
mock_client.create_collection.return_value = mock_collection
|
||||
monkeypatch.setattr(
|
||||
"chromadb.PersistentClient",
|
||||
lambda path: mock_client)
|
||||
mock_st = MagicMock()
|
||||
mock_st_model = MagicMock()
|
||||
mock_st_model.encode.return_value = MagicMock()
|
||||
mock_st_model.encode.return_value.tolist.return_value = [0.1, 0.2, 0.3]
|
||||
mock_st.return_value = mock_st_model
|
||||
monkeypatch.setattr("sentence_transformers.SentenceTransformer", mock_st)
|
||||
yield {"client": mock_client, "collection": mock_collection,
|
||||
"st_model": mock_st_model, "st": mock_st}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def searcher(mock_chromadb):
|
||||
with tempfile.TemporaryDirectory(prefix="test_chroma_") as tmpdir:
|
||||
s = KBChromaSearcher(chroma_path=tmpdir, collection_name="test_kb")
|
||||
s._model = mock_chromadb["st_model"]
|
||||
s._client = mock_chromadb["client"]
|
||||
s._collection = mock_chromadb["collection"]
|
||||
yield s
|
||||
|
||||
|
||||
# ── 创建 & 就绪检查 ─────────────────────────────────────────────
|
||||
|
||||
class TestKBChromaSearcherInit:
|
||||
def test_creates_with_defaults(self, mock_chromadb):
|
||||
with tempfile.TemporaryDirectory(prefix="test_chroma_") as tmpdir:
|
||||
s = KBChromaSearcher(chroma_path=tmpdir)
|
||||
assert s.collection_name == "kb_chunks"
|
||||
assert s.chroma_path == str(tmpdir)
|
||||
|
||||
def test_custom_collection_name(self, mock_chromadb):
|
||||
with tempfile.TemporaryDirectory(prefix="test_chroma_") as tmpdir:
|
||||
s = KBChromaSearcher(chroma_path=tmpdir, collection_name="custom")
|
||||
assert s.collection_name == "custom"
|
||||
|
||||
def test_model_lazy_loaded(self, mock_chromadb):
|
||||
with tempfile.TemporaryDirectory(prefix="test_chroma_") as tmpdir:
|
||||
s = KBChromaSearcher(chroma_path=tmpdir)
|
||||
assert s._model is None
|
||||
|
||||
def test_is_ready_true(self, searcher):
|
||||
assert searcher.is_ready() is True
|
||||
|
||||
def test_is_ready_false(self, searcher, mock_chromadb):
|
||||
mock_chromadb["client"].get_collection.side_effect = Exception("no collection")
|
||||
assert searcher.is_ready() is False
|
||||
|
||||
|
||||
# ── 搜索 ────────────────────────────────────────────────────────
|
||||
|
||||
class TestSearch:
|
||||
def test_search_returns_empty_when_not_ready(self, searcher, mock_chromadb):
|
||||
mock_chromadb["client"].get_collection.side_effect = Exception("no collection")
|
||||
results = searcher.search("test query")
|
||||
assert results == []
|
||||
|
||||
def test_search_calls_collection_query(self, searcher, mock_chromadb):
|
||||
mock_chromadb["collection"].query.return_value = {
|
||||
"ids": [["chunk_0", "chunk_1"]],
|
||||
"documents": [["doc1", "doc2"]],
|
||||
"metadatas": [[{"chunk_type": "md"}, {"chunk_type": "txt"}]],
|
||||
"distances": [[0.1, 0.3]],
|
||||
}
|
||||
results = searcher.search("query", k=5)
|
||||
assert len(results) == 2
|
||||
assert results[0]["id"] == "chunk_0"
|
||||
assert results[0]["content"] == "doc1"
|
||||
assert results[0]["metadata"]["chunk_type"] == "md"
|
||||
assert results[0]["distance"] == 0.1
|
||||
|
||||
def test_search_respects_threshold(self, searcher, mock_chromadb):
|
||||
mock_chromadb["collection"].query.return_value = {
|
||||
"ids": [["chunk_0", "chunk_1"]],
|
||||
"documents": [["doc1", "doc2"]],
|
||||
"metadatas": [[{}, {}]],
|
||||
"distances": [[0.2, 0.8]],
|
||||
}
|
||||
results = searcher.search("query", threshold=0.5)
|
||||
assert len(results) == 1
|
||||
assert results[0]["id"] == "chunk_0"
|
||||
|
||||
def test_search_empty_results(self, searcher, mock_chromadb):
|
||||
mock_chromadb["collection"].query.return_value = {
|
||||
"ids": [[]], "documents": [[]], "metadatas": [[]], "distances": [[]],
|
||||
}
|
||||
assert searcher.search("query") == []
|
||||
|
||||
|
||||
# ── 模板搜索 ────────────────────────────────────────────────────
|
||||
|
||||
class TestSearchTemplates:
|
||||
def test_filters_jrxml_chunks(self, searcher, mock_chromadb):
|
||||
mock_chromadb["collection"].query.return_value = {
|
||||
"ids": [["c0", "c1", "c2"]],
|
||||
"documents": [["t1", "t2", "t3"]],
|
||||
"metadatas": [[
|
||||
{"chunk_type": "jrxml_template", "report_name": "R1"},
|
||||
{"chunk_type": "md_section"},
|
||||
{"chunk_type": "jrxml_template", "report_name": "R2"},
|
||||
]],
|
||||
"distances": [[0.1, 0.2, 0.3]],
|
||||
}
|
||||
templates = searcher.search_templates("query", k=3)
|
||||
assert len(templates) >= 1
|
||||
for t in templates:
|
||||
meta = t["metadata"]
|
||||
assert "jrxml" in meta.get("chunk_type", "").lower() or meta.get("report_name")
|
||||
|
||||
def test_no_jrxml_chunks_returns_empty(self, searcher, mock_chromadb):
|
||||
mock_chromadb["collection"].query.return_value = {
|
||||
"ids": [["c0"]],
|
||||
"documents": [["text"]],
|
||||
"metadatas": [[{"chunk_type": "md_section"}]],
|
||||
"distances": [[0.1]],
|
||||
}
|
||||
templates = searcher.search_templates("query")
|
||||
assert templates == []
|
||||
|
||||
|
||||
# ── search_as_context ───────────────────────────────────────────
|
||||
|
||||
class TestSearchAsContext:
|
||||
def test_returns_formatted_context(self, searcher, mock_chromadb):
|
||||
mock_chromadb["collection"].query.return_value = {
|
||||
"ids": [["c0", "c1"]],
|
||||
"documents": [["内容1", "内容2"]],
|
||||
"metadatas": [[
|
||||
{"chunk_type": "md", "report_name": "R1"},
|
||||
{"chunk_type": "txt"},
|
||||
]],
|
||||
"distances": [[0.1, 0.2]],
|
||||
}
|
||||
ctx = searcher.search_as_context("q", k=2)
|
||||
assert "内容1" in ctx
|
||||
assert "内容2" in ctx
|
||||
assert "类型" in ctx
|
||||
assert "报表" in ctx
|
||||
assert "---" in ctx
|
||||
|
||||
def test_empty_returns_empty_string(self, searcher, mock_chromadb):
|
||||
mock_chromadb["collection"].query.return_value = {
|
||||
"ids": [[]], "documents": [[]], "metadatas": [[]], "distances": [[]],
|
||||
}
|
||||
assert searcher.search_as_context("q") == ""
|
||||
|
||||
|
||||
# ── add_chunks ──────────────────────────────────────────────────
|
||||
|
||||
class TestAddChunks:
|
||||
def test_add_chunks_calls_upsert(self, searcher, mock_chromadb):
|
||||
chunks = [{"id": "c0", "content": "test content", "metadata": {"chunk_type": "md"}}]
|
||||
searcher.add_chunks(chunks)
|
||||
mock_chromadb["collection"].upsert.assert_called_once()
|
||||
kwargs = mock_chromadb["collection"].upsert.call_args[1]
|
||||
assert kwargs["ids"] == ["c0"]
|
||||
assert kwargs["documents"] == ["test content"]
|
||||
|
||||
def test_empty_chunks_noop(self, searcher, mock_chromadb):
|
||||
searcher.add_chunks([])
|
||||
mock_chromadb["collection"].upsert.assert_not_called()
|
||||
|
||||
|
||||
# ── 工厂函数 ────────────────────────────────────────────────────
|
||||
|
||||
class TestGetKbSearcher:
|
||||
def test_returns_cached_instance(self, monkeypatch, mock_chromadb):
|
||||
with tempfile.TemporaryDirectory(prefix="test_chroma_") as tmpdir:
|
||||
monkeypatch.setattr(
|
||||
"backend.kb_manager.get_kb_chroma_path",
|
||||
lambda kb_id: Path(tmpdir) if kb_id == "abcdef1234567890abcd" else None)
|
||||
s1 = get_kb_searcher("abcdef1234567890abcd")
|
||||
s2 = get_kb_searcher("abcdef1234567890abcd")
|
||||
assert s1 is s2
|
||||
|
||||
def test_returns_none_for_invalid_kb(self, monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
"backend.kb_manager.get_kb_chroma_path", lambda kb_id: None)
|
||||
assert get_kb_searcher("deadbeef1234567890abcd") is None
|
||||
|
||||
|
||||
class TestSearchKbFunction:
|
||||
def test_returns_empty_for_invalid_kb(self, monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
"backend.kb_manager.get_kb_chroma_path", lambda kb_id: None)
|
||||
assert search_kb("deadbeef1234567890abcd", "query") == ""
|
||||
|
||||
def test_returns_empty_for_invalid_template_search(self, monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
"backend.kb_manager.get_kb_chroma_path", lambda kb_id: None)
|
||||
assert search_templates_in_kb("deadbeef1234567890abcd", "query") == []
|
||||
@@ -0,0 +1,200 @@
|
||||
"""程序化字段映射单元测试。
|
||||
|
||||
测试 _programmatic_map_fields 和 _sanitize_field_name
|
||||
的确定性替换行为,以及 validate_element_count 校验。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
from agent.nodes import _programmatic_map_fields, _sanitize_field_name
|
||||
from agent.jrxml_windower import count_elements, validate_element_count
|
||||
|
||||
# ── 最小 JRXML 模板(含占位字段)────────────────────────────────────
|
||||
|
||||
JRXML_WITH_PLACEHOLDERS = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<jasperReport name="test" pageWidth="595" pageHeight="842">
|
||||
<field name="field_1" class="java.lang.String"/>
|
||||
<field name="field_2" class="java.math.BigDecimal"/>
|
||||
<field name="field_3" class="java.lang.String"/>
|
||||
<queryString><![CDATA[SELECT * FROM t]]></queryString>
|
||||
<title>
|
||||
<band height="50">
|
||||
<staticText>
|
||||
<reportElement x="0" y="0" width="100" height="20"/>
|
||||
<text><![CDATA[$F{field_1}]]></text>
|
||||
</staticText>
|
||||
<textField>
|
||||
<reportElement x="100" y="0" width="80" height="20"/>
|
||||
<textFieldExpression><![CDATA[$F{field_2}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField>
|
||||
<reportElement x="200" y="0" width="80" height="20"/>
|
||||
<textFieldExpression><![CDATA[$F{field_3}]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
</title>
|
||||
<detail>
|
||||
<band height="30">
|
||||
<textField>
|
||||
<reportElement x="0" y="0" width="100" height="20"/>
|
||||
<textFieldExpression><![CDATA[$F{field_1} + " " + $F{field_2}]]></textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
</detail>
|
||||
</jasperReport>"""
|
||||
|
||||
|
||||
# ── _sanitize_field_name 测试 ────────────────────────────────────────
|
||||
|
||||
class TestSanitizeFieldName:
|
||||
def test_ascii_name_passes_through(self):
|
||||
assert _sanitize_field_name("customer_name") == "customer_name"
|
||||
|
||||
def test_uppercase_lowered(self):
|
||||
assert _sanitize_field_name("CustomerName") == "customername"
|
||||
|
||||
def test_spaces_replaced(self):
|
||||
assert _sanitize_field_name("customer name") == "customer_name"
|
||||
|
||||
def test_chinese_characters_escaped(self):
|
||||
result = _sanitize_field_name("发票代码")
|
||||
assert "发票" not in result
|
||||
assert "u53d1_" in result
|
||||
assert "u7968_" in result
|
||||
|
||||
def test_mixed_ascii_chinese(self):
|
||||
result = _sanitize_field_name("发票_code")
|
||||
assert "_code" in result
|
||||
assert "u53d1_" in result
|
||||
|
||||
def test_empty_returns_unnamed(self):
|
||||
assert _sanitize_field_name("") == "unnamed_field"
|
||||
|
||||
def test_all_special_chars_returns_unnamed(self):
|
||||
assert _sanitize_field_name("!!!") == "unnamed_field"
|
||||
|
||||
def test_leading_digit_prefixed(self):
|
||||
result = _sanitize_field_name("123abc")
|
||||
assert result == "f_123abc"
|
||||
|
||||
def test_consecutive_underscores_collapsed(self):
|
||||
result = _sanitize_field_name("a__b___c")
|
||||
assert result == "a_b_c"
|
||||
|
||||
def test_japanese_characters_escaped(self):
|
||||
result = _sanitize_field_name("請求書")
|
||||
assert "請求" not in result
|
||||
|
||||
|
||||
# ── _programmatic_map_fields 测试 ────────────────────────────────────
|
||||
|
||||
class TestProgrammaticMapFields:
|
||||
def test_replaces_field_declarations(self):
|
||||
ocr = [
|
||||
{"field_name": "customer_name"},
|
||||
{"field_name": "total_amount"},
|
||||
{"field_name": "invoice_date"},
|
||||
]
|
||||
result = _programmatic_map_fields(JRXML_WITH_PLACEHOLDERS, ocr)
|
||||
assert 'field name="customer_name"' in result
|
||||
assert 'field name="total_amount"' in result
|
||||
assert 'field name="invoice_date"' in result
|
||||
assert 'field name="field_1"' not in result
|
||||
|
||||
def test_replaces_field_references(self):
|
||||
ocr = [
|
||||
{"field_name": "customer_name"},
|
||||
{"field_name": "total_amount"},
|
||||
{"field_name": "invoice_date"},
|
||||
]
|
||||
result = _programmatic_map_fields(JRXML_WITH_PLACEHOLDERS, ocr)
|
||||
assert "$F{field_1}" not in result
|
||||
assert "$F{customer_name}" in result
|
||||
assert "$F{total_amount}" in result
|
||||
assert "$F{invoice_date}" in result
|
||||
|
||||
def test_preserves_element_count(self):
|
||||
ocr = [
|
||||
{"field_name": "customer_name"},
|
||||
{"field_name": "total_amount"},
|
||||
{"field_name": "invoice_date"},
|
||||
]
|
||||
result = _programmatic_map_fields(JRXML_WITH_PLACEHOLDERS, ocr)
|
||||
orig = count_elements(JRXML_WITH_PLACEHOLDERS)
|
||||
mod = count_elements(result)
|
||||
assert orig == mod, f"Elements: {orig} -> {mod}"
|
||||
|
||||
def test_preserves_coordinates(self):
|
||||
ocr = [
|
||||
{"field_name": "customer_name"},
|
||||
{"field_name": "total_amount"},
|
||||
{"field_name": "invoice_date"},
|
||||
]
|
||||
result = _programmatic_map_fields(JRXML_WITH_PLACEHOLDERS, ocr)
|
||||
assert 'x="0"' in result
|
||||
assert 'x="100"' in result
|
||||
assert 'x="200"' in result
|
||||
assert 'y="0"' in result
|
||||
assert 'width="100"' in result
|
||||
assert 'height="20"' in result
|
||||
|
||||
def test_partial_fields_preserved(self):
|
||||
"""当 OCR 字段少于占位字段时,多余占位字段保留。"""
|
||||
ocr = [
|
||||
{"field_name": "customer_name"},
|
||||
{"field_name": "total_amount"},
|
||||
]
|
||||
result = _programmatic_map_fields(JRXML_WITH_PLACEHOLDERS, ocr)
|
||||
assert 'field name="field_3"' in result
|
||||
assert "$F{field_3}" in result
|
||||
|
||||
def test_empty_field_name_skipped(self):
|
||||
"""空 field_name 的 OCR 字段不触发替换。"""
|
||||
ocr = [
|
||||
{"field_name": ""},
|
||||
{"field_name": "total_amount"},
|
||||
{"field_name": ""},
|
||||
]
|
||||
result = _programmatic_map_fields(JRXML_WITH_PLACEHOLDERS, ocr)
|
||||
assert '$F{field_1}' in result
|
||||
assert '$F{total_amount}' in result
|
||||
assert '$F{field_3}' in result
|
||||
|
||||
def test_no_ocr_fields_no_change(self):
|
||||
result = _programmatic_map_fields(JRXML_WITH_PLACEHOLDERS, [])
|
||||
assert result == JRXML_WITH_PLACEHOLDERS
|
||||
|
||||
def test_chinese_field_names_sanitized(self):
|
||||
ocr = [
|
||||
{"field_name": "发票代码"},
|
||||
{"field_name": "发票号码"},
|
||||
{"field_name": "金额"},
|
||||
]
|
||||
result = _programmatic_map_fields(JRXML_WITH_PLACEHOLDERS, ocr)
|
||||
assert "发票代码" not in result
|
||||
|
||||
def test_validate_element_count_passes(self):
|
||||
ocr = [
|
||||
{"field_name": "customer_name"},
|
||||
{"field_name": "total_amount"},
|
||||
{"field_name": "invoice_date"},
|
||||
]
|
||||
result = _programmatic_map_fields(JRXML_WITH_PLACEHOLDERS, ocr)
|
||||
validation = validate_element_count(
|
||||
JRXML_WITH_PLACEHOLDERS, result, "map_fields"
|
||||
)
|
||||
assert validation["ok"] is True
|
||||
assert validation["modified"] == validation["original"]
|
||||
|
||||
def test_expression_with_multiple_fields(self):
|
||||
"""包含多个 $F{} 的表达式正确替换。"""
|
||||
ocr = [
|
||||
{"field_name": "unit_price"},
|
||||
{"field_name": "quantity"},
|
||||
]
|
||||
result = _programmatic_map_fields(JRXML_WITH_PLACEHOLDERS, ocr)
|
||||
assert '$F{unit_price}' in result
|
||||
assert '$F{quantity}' in result
|
||||
assert '$F{field_1}' not in result
|
||||
assert '$F{field_2}' not in result
|
||||
Reference in New Issue
Block a user