This commit is contained in:
liubiren 2026-01-11 22:04:57 +08:00
parent 0110be4b16
commit f30b837212
11 changed files with 922 additions and 2158 deletions

View File

@ -1,4 +0,0 @@
[settings]
order_by_type = true
multi_line_output = 3
indent = " "

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"python.languageServer": "None"
}

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
认证器 认证器模块
""" """
import hashlib import hashlib

View File

@ -1,10 +1,13 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""通用模块""" """通用模块"""
from typing import Any, Dict, List
from decimal import Decimal, ROUND_HALF_UP from decimal import Decimal, ROUND_HALF_UP
from pathlib import Path
from typing import Any, Dict, List
from datetime import datetime
from jinja2 import Environment, FileSystemLoader
import pandas import pandas
from common import masterdata, rules_engine from common import masterdata, rules_engine
@ -28,17 +31,75 @@ def case_adjust(dossier: Dict[str, Any]) -> None:
return return
# 赔案理算记录 # 赔案理算记录
adjustments = ( receipts_adjustments = (
pandas.DataFrame(data=dossier["receipts_layer"]).assing( (
adjustments=lambda dataframe: dataframe.apply( pandas.DataFrame(data=dossier["receipts_layer"]).assign(
receipt_adjustments=lambda dataframe: dataframe.apply(
lambda row: receipt_adjust( lambda row: receipt_adjust(
row=row, liabilities=dossier["liabilities_layer"] row=row, liabilities=dossier["liabilities_layer"]
), ),
axis="columns", axis="columns",
) # 票据理算 ) # 票据理算
) )
).explode("adjustments", ignore_index=True) )
print(adjustments) .explode(column="receipt_adjustments", ignore_index=True)
.pipe(
lambda dataframe: pandas.concat(
[
dataframe.drop(
[
"receipt_adjustments",
],
axis="columns",
),
pandas.json_normalize(dataframe["receipt_adjustments"]),
],
axis="columns",
)
)
)
dossier["receipts_layer"] = receipts_adjustments.to_dict(orient="records")
print(dossier["receipts_layer"])
# 赔案理算金额
dossier["adjustment_layer"].update(
{
"adjustment_amount": (
receipts_adjustments["adjustment_amount"]
.sum()
.quantize(
Decimal("0.00"),
rounding=ROUND_HALF_UP,
)
), # 理算金额
}
)
# 实例化JINJA2
environment = Environment(
loader=FileSystemLoader(file_path := Path(__file__).parent)
)
# 添加过滤器
environment.filters["DateTime"] = lambda i: (
i.strftime("%Y-%m-%d") if i != datetime(9999, 12, 31) else "长期"
)
# 加载赔案档案模版
template = environment.get_template("template.html")
with open(
file_path / f"dossiers/{dossier["report_layer"]["case_number"]}.html",
"w",
encoding="utf-8",
) as file:
file.write(
template.render(
{
"dossier": dossier,
}
)
)
def receipt_adjust( def receipt_adjust(
@ -46,72 +107,140 @@ def receipt_adjust(
) -> List[Dict[str, Any]]: ) -> List[Dict[str, Any]]:
""" """
理算票据 理算票据
:param row: 一张票据数据 :param row: 票据数据
:param liabilities: 理算责任 :param liabilities: 理算责任
:return: 理算记录 :return: 理算记录
""" """
# 初始化票据理算记录 # 初始化票据理算记录
adjustments = [] receipt_adjustments = []
# 初始化剩余个人自费金额
remaining_personal_self_payment = row["personal_self_payment"]
# 初始化剩余个人自付金额
remaining_non_medical_payment = row["non_medical_payment"]
# 初始化剩余合理金额
remaining_reasonable_amount = row["reasonable_amount"]
# 出险事故 # 初始化票据剩余可理算金额
accident = row["accident"] remaining_adjustable_amount = (
# 出险人
accident_person = row["payer"]
# 出险日期
accident_date = row["date"]
# 查验状态
verification = row["verification"]
# 初始化理赔责任理算金额
adjustment_amount = Decimal("0.00")
# 初始化理赔责任理赔金额
claim_amount = Decimal("0.00")
# 遍历所有理赔责任,根据出险事故、出险人、出险日期和查验状态匹配责任
for liability in liabilities:
if (
accident == liability["accident"]
and accident_person == liability["insured_person"]
and liability["commencement_date"]
<= accident_date
<= liability["termination_date"]
and verification == "真票"
):
# 理赔责任理算金额
adjustment_amount = (
row["personal_self_payment"] row["personal_self_payment"]
* liability["personal_self_ratio"] # 个人自费金额
+ row["non_medical_payment"] + row["non_medical_payment"]
* liability["non_medical_ratio"] # 个人自付金额 + row["reasonable_amount"]
+ row["reasonable_amount"] * liability["reasonable_ratio"] # 合理金额 ).quantize( # type: ignore[reportAttributeAccessIssue]
).quantize(
Decimal("0.00"), Decimal("0.00"),
rounding=ROUND_HALF_UP, rounding=ROUND_HALF_UP,
) )
# 据变动保单唯一标识查询最新一条保额变动记录的变动后金额(理赔责任的理赔保单余额) # 遍历所有理赔责任,根据出险人、出险事故、查验状态和出险日期匹配理赔责任
for liability in liabilities:
if (
row["payer"] in [liability["insured_person"] for liability in liabilities]
and row["accident"] == liability["accident"]
and row["verification"] in ["真票", "无法查验"]
and liability["commencement_date"]
<= row["date"]
<= liability["termination_date"]
):
# 个单余额
remaining_amount = masterdata.query_remaining_amount( remaining_amount = masterdata.query_remaining_amount(
policy_guid=liability["policy_guid"], person_policy_guid=liability["person_policy_guid"],
) )
# 理赔责任理赔金额
claim_amount = min( # 个人自费可理算金额
personal_self_adjustable_amount = (
row["personal_self_payment"]
* liability["personal_self_ratio"]
* Decimal("0.01")
)
# 个人自付可理算金额
non_medical_adjustable_amount = (
row["non_medical_payment"]
* liability["non_medical_ratio"]
* Decimal("0.01")
)
# 合理可理算金额
reasonable_adjustable_amount = (
row["reasonable_amount"]
* liability["reasonable_ratio"]
* Decimal("0.01")
)
# 理算金额
adjustment_amount = max(
Decimal("0.00"),
min(
remaining_adjustable_amount,
remaining_amount, remaining_amount,
adjustment_amount, adjustable_amount := (
(
personal_self_adjustable_amount
+ non_medical_adjustable_amount
+ reasonable_adjustable_amount
).quantize(
Decimal("0.00"),
rounding=ROUND_HALF_UP,
)
), # 可理算金额
),
) )
# 初始化票据理算记录 # 若理算金额大于0则新增保额扣减记录
adjustment = { if adjustment_amount > Decimal("0.00"):
"liability": liability["liability"], # 理赔责任名称 masterdata.add_coverage_change(
"type": row["就诊类型"], person_policy_guid=liability["person_policy_guid"],
"amount": row["合理金额"], before_change_amount=remaining_amount,
"payable": 0.0, change_amount=adjustment_amount,
} )
return adjustments receipt_adjustments.append(
{
"person_policy": liability["person_policy"], # 个单号
"liability": liability["liability"], # 理赔责任名称
"personal_self_payment": row[
"personal_self_payment"
], # 个人自费金额
"personal_self_ratio": liability[
"personal_self_ratio"
], # 个人自费比例
"personal_self_adjustable_amount": personal_self_adjustable_amount, # 个人自费可理算金额
"non_medical_payment": row["non_medical_payment"], # 个人自付金额
"non_medical_ratio": liability["non_medical_ratio"], # 个人自付比例
"non_medical_adjustable_amount": non_medical_adjustable_amount, # 个人自付可理算金额
"reasonable_amount": row["reasonable_amount"], # 合理可理算金额
"reasonable_ratio": liability["reasonable_ratio"], # 合理部分比例
"reasonable_adjustable_amount": reasonable_adjustable_amount, # 合理可理算金额
"adjustment_amount": adjustment_amount, # 理算金额
"adjustment_explanation": f"""
1应理算金额{remaining_adjustable_amount:.2f}
2个单余额{remaining_amount:.2f}
3可理算金额{adjustable_amount:.2f}其中
1个人自费可理算金额{personal_self_adjustable_amount:.2f}={row['personal_self_payment']:.2f}*{liability['personal_self_ratio']:.2f}%
2个人自付可理算金额{non_medical_adjustable_amount:.2f}={row['non_medical_payment']:.2f}*{liability['non_medical_ratio']:.2f}%
3合理部分可理算金额{reasonable_adjustable_amount:.2f}={row['reasonable_amount']:.2f}*{liability['reasonable_ratio']:.2f}%
4理算金额{adjustment_amount:.2f}即上述应理算金额个人余额和可理算金额的最小值
""".replace(
"\n", ""
).replace(
" ", ""
), # 理算说明
}
)
remaining_adjustable_amount -= adjustment_amount
# 若剩余可理算金额小于等于0则跳出循环
if remaining_adjustable_amount <= Decimal("0.00"):
break
if not receipt_adjustments:
receipt_adjustments.append(
{
"person_policy": None, # 个单号
"liability": None, # 理赔责任名称
"personal_self_payment": None, # 个人自费金额
"personal_self_ratio": None, # 个人自费比例
"personal_self_adjustable_amount": None, # 个人自费可理算金额
"non_medical_payment": None, # 个人自付金额
"non_medical_ratio": None, # 个人自付比例
"non_medical_adjustable_amount": None, # 个人自付可理算金额
"reasonable_amount": None, # 合理可理算金额
"reasonable_ratio": None, # 合理部分比例
"reasonable_adjustable_amount": None, # 合理可理算金额
"adjustment_amount": Decimal("0.00"), # 理赔责任理算金额
"adjustment_explanation": "票据不予理算", # 理算说明
}
)
return receipt_adjustments

View File

@ -1,14 +1,15 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""通用模块""" """通用模块"""
import sys
from pathlib import Path from pathlib import Path
import sys
from masterdata import MasterData from masterdata import MasterData
sys.path.append(Path(__file__).parent.parent.as_posix()) sys.path.append(Path(__file__).parent.parent.as_posix())
from utils.rules_engine import RulesEngine from utils.rules_engine import RulesEngine
# 实例化主数据 # 实例化主数据
masterdata = MasterData(database=Path(__file__).parent / "database.db") masterdata = MasterData(database=Path(__file__).parent / "database.db")

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -3,27 +3,27 @@
影像件处理模块 影像件处理模块
""" """
import json
import re
import sys
from base64 import b64encode from base64 import b64encode
from datetime import datetime from datetime import datetime
from decimal import ROUND_HALF_UP, Decimal from decimal import Decimal, ROUND_HALF_UP
from hashlib import md5 from hashlib import md5
import json
from pathlib import Path from pathlib import Path
import re
import sys
from typing import Any, Dict, List, Optional, Tuple from typing import Any, Dict, List, Optional, Tuple
import cv2 import cv2
import numpy
import pandas
from common import masterdata, rules_engine
from fuzzywuzzy import fuzz from fuzzywuzzy import fuzz
from jionlp import parse_location from jionlp import parse_location
import numpy
import pandas
from utils.authenticator import Authenticator from common import masterdata, rules_engine
from utils.request import Request
sys.path.append(Path(__file__).parent.parent.as_posix()) sys.path.append(Path(__file__).parent.parent.as_posix())
from utils.authenticator import Authenticator
from utils.request import Request
# 实例化认证器 # 实例化认证器
@ -139,12 +139,10 @@ def image_read(
:return: 影像件图像数组 :return: 影像件图像数组
""" """
try: try:
with open(image_path, "rb") as file: # 先使用读取影像件,再解码为单通道灰度图数组对象
image_bytes = file.read() # 读取影像件字节流
# 先将影像件字节流转为 numpy.ndarray 对象,再解码为单通道灰度图数组对象
image_ndarray = cv2.imdecode( image_ndarray = cv2.imdecode(
buf=numpy.frombuffer(image_bytes, numpy.uint8), flags=cv2.IMREAD_GRAYSCALE buf=numpy.fromfile(file=image_path, dtype=numpy.uint8),
flags=cv2.IMREAD_GRAYSCALE,
) )
if image_ndarray is None: if image_ndarray is None:
raise RuntimeError(f"影像件不存在") raise RuntimeError(f"影像件不存在")
@ -600,7 +598,9 @@ def receipt_recognize(
"token": authenticator.get_token(servicer="szkt"), # 获取深圳快瞳访问令牌 "token": authenticator.get_token(servicer="szkt"), # 获取深圳快瞳访问令牌
"imgBase64": f"data:image/{image["image_format"].lstrip(".")};base64,{image["image_base64"]}", # 将影像件格式和BASE64编码嵌入数据统一资源标识符 "imgBase64": f"data:image/{image["image_format"].lstrip(".")};base64,{image["image_base64"]}", # 将影像件格式和BASE64编码嵌入数据统一资源标识符
}, },
guid=md5(string=(url + image["image_guid"]).encode("utf-8")).hexdigest().upper(), guid=md5(string=(url + image["image_guid"]).encode("utf-8"))
.hexdigest()
.upper(),
) )
# 若查验状态为真票或红票则直接整合至赔案档案 # 若查验状态为真票或红票则直接整合至赔案档案
if response.get("status") == 200 and response.get("code") == 10000: if response.get("status") == 200 and response.get("code") == 10000:

View File

@ -10,7 +10,6 @@ from pathlib import Path
from case import case_adjust from case import case_adjust
from image import image_classify, image_recognize from image import image_classify, image_recognize
from jinja2 import Environment, FileSystemLoader
if __name__ == "__main__": if __name__ == "__main__":
# 初始化文件路径 # 初始化文件路径
@ -20,27 +19,18 @@ if __name__ == "__main__":
folder_path = file_path / "directory" folder_path = file_path / "directory"
folder_path.mkdir(parents=True, exist_ok=True) # 若文件夹路径不存在则创建 folder_path.mkdir(parents=True, exist_ok=True) # 若文件夹路径不存在则创建
# 实例化JINJA2环境
environment = Environment(loader=FileSystemLoader(file_path))
# 添加DATE过滤器
environment.filters["date"] = lambda date: (
date.strftime("%Y-%m-%d") if date else "长期"
)
# 加载赔案档案模版
template = environment.get_template("template.html")
# 遍历文件夹中赔案文件夹并创建赔案档案 # 遍历文件夹中赔案文件夹并创建赔案档案
for case_path in [x for x in folder_path.iterdir() if x.is_dir()]: for case_path in [x for x in folder_path.iterdir() if x.is_dir()]:
# 初始化赔案档案推送至TPA时保险公司会提保险分公司名称、报案时间和影像件等TPA签收后生成赔案号 # 初始化赔案档案推送至TPA时保险公司会提保险分公司名称、报案时间和影像件等TPA签收后生成赔案号
dossier = { dossier = {
"report_layer": { "report_layer": {
"report_time": datetime(
2025, 7, 25, 12, 0, 0
), # 指定报案时间,默认为 datetime对象
"case_number": case_path.stem, # 默认为赔案文件夹名称 "case_number": case_path.stem, # 默认为赔案文件夹名称
"insurer_company": ( "insurer_company": (
insurer_company := "中银保险有限公司苏州分公司" insurer_company := "中银保险有限公司苏州分公司"
), # 默认为中银保险有限公司苏州分公司 ), # 默认为中银保险有限公司苏州分公司
"report_time": datetime(
2025, 7, 25, 12, 0, 0
), # 指定报案时间,默认为 datetime对象
}, # 报案层 }, # 报案层
"images_layer": [], # 影像件层 "images_layer": [], # 影像件层
"insured_person_layer": {}, # 出险人层 "insured_person_layer": {}, # 出险人层

View File

@ -3,11 +3,12 @@
主数据模块 主数据模块
""" """
import sys
from datetime import datetime from datetime import datetime
from decimal import ROUND_HALF_UP, Decimal from decimal import Decimal, ROUND_HALF_UP
from hashlib import md5
from pathlib import Path from pathlib import Path
from typing import Any, Dict, List, Optional import sys
from typing import Any, Dict, List
sys.path.append(Path(__file__).parent.parent.as_posix()) sys.path.append(Path(__file__).parent.parent.as_posix())
from utils.sqlite import SQLite from utils.sqlite import SQLite
@ -104,8 +105,6 @@ class MasterData(SQLite):
non_medical_ratio TEXT NOT NULL, non_medical_ratio TEXT NOT NULL,
--合理理算比例 --合理理算比例
reasonable_ratio TEXT NOT NULL, reasonable_ratio TEXT NOT NULL,
--理赔保单唯一标识
claim_policy_guid TEXT NOT NULL,
--个单唯一标识 --个单唯一标识
person_policy_guid TEXT NOT NULL person_policy_guid TEXT NOT NULL
) )
@ -128,8 +127,8 @@ class MasterData(SQLite):
after_change_amount TEXT NOT NULL, after_change_amount TEXT NOT NULL,
--变动时间 --变动时间
change_time TEXT NOT NULL, change_time TEXT NOT NULL,
--变动保单唯一标识 --单唯一标识
change_policy_guid TEXT NOT NULL person_policy_guid TEXT NOT NULL
) )
""" """
) )
@ -200,7 +199,7 @@ class MasterData(SQLite):
liabilities.personal_self_ratio, liabilities.personal_self_ratio,
liabilities.non_medical_ratio, liabilities.non_medical_ratio,
liabilities.reasonable_ratio, liabilities.reasonable_ratio,
liabilities.claim_policy_guid liabilities.person_policy_guid
FROM insured_persons FROM insured_persons
INNER JOIN person_policies INNER JOIN person_policies
ON insured_persons.person_policy_guid = person_policies.guid ON insured_persons.person_policy_guid = person_policies.guid
@ -212,10 +211,10 @@ class MasterData(SQLite):
INNER JOIN liabilities INNER JOIN liabilities
ON person_policies.guid = liabilities.person_policy_guid ON person_policies.guid = liabilities.person_policy_guid
INNER JOIN coverage_changes INNER JOIN coverage_changes
ON liabilities.claim_policy_guid = coverage_changes.change_policy_guid ON liabilities.person_policy_guid = coverage_changes.person_policy_guid
AND coverage_changes.change_time = (SELECT MAX(change_time) AND coverage_changes.change_time = (SELECT MAX(change_time)
FROM coverage_changes FROM coverage_changes
WHERE liabilities.claim_policy_guid = change_policy_guid) WHERE liabilities.person_policy_guid = person_policy_guid)
WHERE group_policies.insurer_company = ? WHERE group_policies.insurer_company = ?
AND insured_persons.insured_person = ? AND insured_persons.insured_person = ?
AND insured_persons.identity_type = ? AND insured_persons.identity_type = ?
@ -312,11 +311,11 @@ class MasterData(SQLite):
def query_remaining_amount( def query_remaining_amount(
self, self,
policy_guid: str, person_policy_guid: str,
) -> Decimal: ) -> Decimal:
""" """
根据变动保单唯一标识查询最新一条保额变动记录的变动后金额 根据单唯一标识查询最新一条保额变动记录的变动后金额
:param policy_guid: 变动保单唯一标识 :param person_policy_guid: 单唯一标识
:return: 变动后金额 :return: 变动后金额
""" """
try: try:
@ -325,11 +324,11 @@ class MasterData(SQLite):
sql=""" sql="""
SELECT after_change_amount SELECT after_change_amount
FROM coverage_changes FROM coverage_changes
WHERE change_policy_guid = ? WHERE person_policy_guid = ?
ORDER BY change_time DESC ORDER BY change_time DESC
LIMIT 1; LIMIT 1;
""", """,
parameters=(policy_guid,), parameters=(person_policy_guid,),
) )
if not result: if not result:
raise RuntimeError("查无数据") raise RuntimeError("查无数据")
@ -341,3 +340,63 @@ class MasterData(SQLite):
except Exception as exception: except Exception as exception:
raise RuntimeError(f"{str(exception)}") from exception raise RuntimeError(f"{str(exception)}") from exception
def add_coverage_change(
self,
person_policy_guid: str,
before_change_amount: Decimal,
change_amount: Decimal,
) -> None:
"""
新增保额扣减记录
:param person_policy_guid: 个单唯一标识
:param before_change_amount: 变动前金额
:param change_amount: 变动金额
:return:
"""
if before_change_amount != self.query_remaining_amount(
person_policy_guid=person_policy_guid,
):
raise ValueError("变动前金额不等于最新一条保额变动记录的变动后金额")
# 变动后金额
after_change_amount = (before_change_amount - change_amount).quantize(
Decimal("0.00"),
rounding=ROUND_HALF_UP,
)
if after_change_amount < Decimal("0.00"):
raise ValueError("变动后金额小于0")
# 当前时间
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
# 构建保额变动唯一标识
guid = (
md5(
string=f"{person_policy_guid} 保额扣减 {before_change_amount:.2f} {change_amount:.2f} {after_change_amount:.2f} {current_time}".encode(
"utf-8"
)
)
.hexdigest()
.upper()
)
with self:
if not self.execute(
sql="""
INSERT INTO coverage_changes
(guid, change_type, before_change_amount, change_amount, after_change_amount, change_time, person_policy_guid)
VALUES
(?, ?, ?, ?, ?, ?, ?)
""",
parameters=(
guid,
"保额扣减",
f"{before_change_amount:.2f}",
f"{change_amount:.2f}",
f"{after_change_amount:.2f}",
current_time,
person_policy_guid,
),
):
raise RuntimeError("新增保额扣减记录发生异常")

View File

@ -1,8 +1,8 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="zh-CN"> <html lang="zh-CN">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>赔案档案</title> <title>赔案档案</title>
<style> <style>
:root { :root {
@ -70,11 +70,12 @@
--color-text-secondary: var(--gray-8); --color-text-secondary: var(--gray-8);
--color-border: var(--gray-3); --color-border: var(--gray-3);
--color-bg: var(--gray-1); --color-bg: var(--gray-1);
--color-bg-secondary: #FFFFFF; --color-bg-secondary: #ffffff;
--border-radius-small: 4px; --border-radius-small: 4px;
--border-radius-medium: 6px; --border-radius-medium: 6px;
--border-radius-large: 8px; --border-radius-large: 8px;
--font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif; --font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
"Helvetica Neue", Arial, "Noto Sans", sans-serif;
--box-shadow: 0 4px 10px rgba(0, 0, 0, 0.04); --box-shadow: 0 4px 10px rgba(0, 0, 0, 0.04);
--box-shadow-hover: 0 8px 20px rgba(0, 0, 0, 0.08); --box-shadow-hover: 0 8px 20px rgba(0, 0, 0, 0.08);
--spacing-xs: 4px; --spacing-xs: 4px;
@ -263,12 +264,12 @@
color: var(--color-text-secondary); color: var(--color-text-secondary);
} }
.invoice-examination { .invoice-verification {
display: flex; display: flex;
align-items: center; align-items: center;
} }
.examination-tag { .verification-tag {
padding: 6px 12px; padding: 6px 12px;
border-radius: 50px; border-radius: 50px;
font-weight: 600; font-weight: 600;
@ -277,19 +278,19 @@
border: 1px solid; border: 1px solid;
} }
.examination-tag.valid { .verification-tag.valid {
background: var(--green-1); background: var(--green-1);
color: var(--green-7); color: var(--green-7);
border-color: var(--green-3); border-color: var(--green-3);
} }
.examination-tag.suspicious { .verification-tag.suspicious {
background: var(--orange-1); background: var(--orange-1);
color: var(--orange-7); color: var(--orange-7);
border-color: var(--orange-3); border-color: var(--orange-3);
} }
.examination-tag.invalid { .verification-tag.invalid {
background: var(--red-1); background: var(--red-1);
color: var(--red-7); color: var(--red-7);
border-color: var(--red-3); border-color: var(--red-3);
@ -398,15 +399,19 @@
} }
} }
</style> </style>
</head> </head>
<body> <body>
<div class="container"> <div class="container">
<header> <header>
<div class="header-content"> <div class="header-content">
<div> <div>
<h1>赔案档案</h1> <h1>赔案档案</h1>
<div class="header-info"> <div class="header-info">
<p>赔案编号: {{ dossier.赔案层.赔案编号 }} | 保险总公司: {{ dossier.赔案层.保险总公司 }}</p> <p>
赔案编号: {{ dossier.report_layer.case_number }} | 保险分公司:
{{ dossier.report_layer.insurer_company }} | 报案时间: {{
dossier.report_layer.report_time | DateTime }}
</p>
</div> </div>
</div> </div>
</div> </div>
@ -417,21 +422,19 @@
<table> <table>
<thead> <thead>
<tr> <tr>
<th>影像件序号</th> <th>影像件唯一标识</th>
<th>影像件编号</th>
<th>影像件名称</th> <th>影像件名称</th>
<th>已分类(含旋正)</th>
<th>影像件类型</th> <th>影像件类型</th>
<th>已识别</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for image in dossier.影像件层 %} {% for image in dossier.images_layer %}
<tr> <tr>
<td>{{ image.影像件序号 }}</td> <td>{{ image.image_guid }}</td>
<td>{{ image.影像件名称 }}</td> <td>{{ image.image_index }}</td>
<td>{{ image.已分类 }}</td> <td>{{ image.image_name }}</td>
<td>{{ image.影像件类型 }}</td> <td>{{ image.image_type }}</td>
<td>{{ image.已识别 }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
@ -442,154 +445,246 @@
<h2>赔案层</h2> <h2>赔案层</h2>
<div class="card-container"> <div class="card-container">
<div class="card"> <div class="card">
<h3>申请人信息</h3> <h3>出险人(被保险人)信息</h3>
<div class="info-grid"> <div class="info-grid">
<div class="info-item">
<div class="info-label">与被保险人关系</div>
<div class="info-value">{{ dossier.赔案层.申请人信息.与被保险人关系 }}</div>
</div>
<div class="info-item"> <div class="info-item">
<div class="info-label">姓名</div> <div class="info-label">姓名</div>
<div class="info-value">{{ dossier.赔案层.申请人信息.姓名 }}</div> <div class="info-value">
{{ dossier.insured_person_layer.insured_person }}
</div>
</div> </div>
<div class="info-item"> <div class="info-item">
<div class="info-label">证件类型</div> <div class="info-label">证件类型</div>
<div class="info-value">{{ dossier.赔案层.申请人信息.证件类型 }}</div> <div class="info-value">
{{ dossier.insured_person_layer.identity_type }}
</div>
</div> </div>
<div class="info-item"> <div class="info-item">
<div class="info-label">证件号码</div> <div class="info-label">证件号码</div>
<div class="info-value">{{ dossier.赔案层.申请人信息.证件号码 }}</div> <div class="info-value">
{{ dossier.insured_person_layer.identity_number }}
</div>
</div> </div>
<div class="info-item"> <div class="info-item">
<div class="info-label">证件有效期</div> <div class="info-label">证件有效期</div>
<div class="info-value">{{ dossier.赔案层.申请人信息.证件有效期起 | date }} 至 {{ <div class="info-value">
dossier.赔案层.申请人信息.证件有效期止 | date }} {{ dossier.insured_person_layer.commencement_date | DateTime
}} 至 {{ dossier.insured_person_layer.termination_date |
DateTime }}
</div> </div>
</div> </div>
<div class="info-item"> <div class="info-item">
<div class="info-label">性别</div> <div class="info-label">性别</div>
<div class="info-value">{{ dossier.赔案层.申请人信息.性别 }}</div> <div class="info-value">
{{ dossier.insured_person_layer.gender }}
</div> </div>
</div>
<div class="info-item"> <div class="info-item">
<div class="info-label">出生</div> <div class="info-label">出生</div>
<div class="info-value">{{ dossier.赔案层.申请人信息.出生 | date }} | {{ <div class="info-value">
dossier.赔案层.申请人信息.年龄 }}岁 {{ dossier.insured_person_layer.birth_date | DateTime }} | {{
dossier.insured_person_layer.age }}岁
</div> </div>
</div> </div>
<div class="info-item"> <div class="info-item">
<div class="info-label">手机号</div> <div class="info-label">手机号</div>
<div class="info-value">{{ dossier.赔案层.申请人信息.手机号 }}</div> <div class="info-value">
{{ dossier.insured_person_layer.phone_number }}
</div>
</div> </div>
<div class="info-item"> <div class="info-item">
<div class="info-label">住址</div> <div class="info-label">住址</div>
<div class="info-value">{{ dossier.赔案层.申请人信息.省 }} {{ dossier.赔案层.申请人信息.地 }} {{ <div class="info-value">
dossier.赔案层.申请人信息.县 }} {{ dossier.insured_person_layer.province }} {{
dossier.insured_person_layer.city }} {{
dossier.insured_person_layer.district }}
</div>
<div class="info-value">
{{ dossier.insured_person_layer.detailed_address }}
</div> </div>
<div class="info-value">{{ dossier.赔案层.申请人信息.详细地址 }}</div>
</div> </div>
</div> </div>
</div> </div>
<div class="card"> <div class="card">
<h3>受益人信息</h3> <h3>领款信息</h3>
<div class="info-grid"> <div class="info-grid">
<div class="info-item">
<div class="info-label">与被保险人关系</div>
<div class="info-value">{{ dossier.赔案层.受益人信息.与被保险人关系 }}</div>
</div>
<div class="info-item"> <div class="info-item">
<div class="info-label">户名</div> <div class="info-label">户名</div>
<div class="info-value">{{ dossier.赔案层.受益人信息.户名 }}</div> <div class="info-value">
{{ dossier.insured_person_layer.account }}
</div>
</div> </div>
<div class="info-item"> <div class="info-item">
<div class="info-label">开户银行</div> <div class="info-label">开户银行</div>
<div class="info-value">{{ dossier.赔案层.受益人信息.开户银行 }}</div> <div class="info-value">
{{ dossier.insured_person_layer.account_bank }}
</div>
</div> </div>
<div class="info-item"> <div class="info-item">
<div class="info-label">银行账</div> <div class="info-label"></div>
<div class="info-value">{{ dossier.赔案层.受益人信息.银行账号 }}</div> <div class="info-value">
</div> {{ dossier.insured_person_layer.account_number }}
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="card">
<h3>在保个单</h3>
<table>
<thead>
<tr>
<th>团单号</th>
<th>保险分公司名称</th>
<th>被保险人姓名</th>
<th>主被保险人</th>
<th>与主被保险人关系</th>
<th>保险期</th>
<th>理赔责任名称</th>
</tr>
</thead>
<tbody>
{% for liability in dossier.liabilities_layer %}
<tr>
<td>{{ liability.group_policy }}</td>
<td>{{ liability.insurer_company }}</td>
<td>{{ liability.insured_person }}</td>
<td>{{ liability.master_insured_person }}</td>
<td>{{ liability.relationship }}</td>
<td>
{{ liability.commencement_date | DateTime }} 至 {{
liability.termination_date | DateTime }}
</td>
<td>{{ liability.liability }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<div class="section"> <div class="section">
<h2>发票层</h2> <h2></h2>
{% for invoice in dossier.发票层 %} {% for receipt in dossier.receipts_layer %}
<div class="invoice-card"> <div class="invoice-card">
<div class="invoice-header"> <div class="invoice-header">
<div class="invoice-number-container"> <div class="invoice-number-container">
<div class="invoice-number">{{ invoice.票据类型 }} | {{ invoice.票据号码 }}</div> <div class="invoice-number">{{ receipt.receipt_number }}</div>
<span class="invoice-reference">关联影像件序号: {{ invoice.关联影像件序号 }}</span> <span class="invoice-reference"
>关联影像件序号: {{ receipt.image_index }}</span
>
</div> </div>
<div class="invoice-examination"> <div class="invoice-verification">
{% if invoice.查验状态 == '真票' %} {% if receipt.verification == '真票' %}
<span class="examination-tag valid">{{ invoice.查验状态 }}</span> <span class="verification-tag valid"
{% elif invoice.查验状态 == '无法查验' %} >{{ receipt.verification }}</span
<span class="examination-tag suspicious">{{ invoice.查验状态 }}</span> >
{% elif receipt.verification == '无法查验' %}
<span class="verification-tag suspicious"
>{{ receipt.verification }}</span
>
{% else %} {% else %}
<span class="examination-tag invalid">{{ invoice.查验状态 }}</span> <span class="verification-tag invalid"
>{{ receipt.verification }}</span
>
{% endif %} {% endif %}
</div> </div>
</div> </div>
<div class="invoice-details"> <div class="invoice-details">
<div class="detail-item"> <div class="detail-item">
<div class="detail-label">就诊人</div> <div class="detail-label">出险</div>
<div class="detail-value">{{ invoice.就诊人 }}</div> <div class="detail-value">{{ receipt.payer }}</div>
</div> </div>
<div class="detail-item"> <div class="detail-item">
<div class="detail-label">票据代码</div> <div class="detail-label">票据代码</div>
<div class="detail-value">{{ invoice.票据代码 }}</div> <div class="detail-value">{{ receipt.code }}</div>
</div> </div>
<div class="detail-item"> <div class="detail-item">
<div class="detail-label">校验码后六位</div> <div class="detail-label">校验码后六位</div>
<div class="detail-value">{{ invoice.校验码后六位 }}</div> <div class="detail-value">{{ receipt.verification_code }}</div>
</div> </div>
<div class="detail-item"> <div class="detail-item">
<div class="detail-label">开票日期</div> <div class="detail-label">开票日期</div>
<div class="detail-value">{{ invoice.开票日期 | date }}</div> <div class="detail-value">{{ receipt.date | DateTime }}</div>
</div> </div>
<div class="detail-item"> <div class="detail-item">
<div class="detail-label">票据金额</div> <div class="detail-label">票据金额</div>
<div class="detail-value">{{ invoice.票据金额 }}元</div> <div class="detail-value">{{ receipt.amount }}元</div>
</div> </div>
<div class="detail-item"> <div class="detail-item">
<div class="detail-label">就诊类型</div> <div class="detail-label">出险事故</div>
<div class="detail-value">{{ invoice.就诊类型 }}</div> <div class="detail-value">{{ receipt.accident }}</div>
</div> </div>
<div class="detail-item"> <div class="detail-item">
<div class="detail-label">医药机构</div> <div class="detail-label">购药及就医机构</div>
<div class="detail-value">{{ invoice.医药机构 }}</div> <div class="detail-value">
{{ receipt.institution }} | {{ receipt.institution_type }}
</div>
</div> </div>
<div class="detail-item"> <div class="detail-item">
<div class="detail-label">推定疾病</div> <div class="detail-label">医疗诊断</div>
<div class="detail-value">{{ invoice.推定疾病 }}</div> <div class="detail-value">{{ receipt.diagnosis }}</div>
</div> </div>
</div> </div>
<table> <table>
<thead> <thead>
<tr> <tr>
<th>大项</th> <th>类别</th>
<th>小项</th> <th>药品/医疗服务</th>
<th>数量</th> <th>数量</th>
<th>金额</th> <th>金额</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for item in invoice.项目 %} {% for item in receipt.items %}
<tr> <tr>
<td>{{ item.大项 }}</td> <td>{{ item.category }}</td>
<td>{{ item.小项 }}</td> <td>{{ item.medicine }}</td>
<td>{{ item.数量 }}</td> <td>{{ item.quantity }}</td>
<td>{{ item.金额 }}元</td> <td>{{ item.amount }}元</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
<div class="amount-total">总金额: {{ invoice.票据金额 }}元</div>
<table>
<thead>
<tr>
<th>个人自费可理算金额</th>
<th>个人自付可理算金额</th>
<th>合理可理算金额</th>
<th>理算金额</th>
</tr>
</thead>
<tbody>
{% for adjustment in receipt.adjustments %}
<tr>
<td>
{{ adjustment.personal_self_adjustable_amount }} = {{
adjustment.personal_self_payment }} * {{
adjustment.personal_self_ratio }} %
</td>
<td>
{{ adjustment.non_medical_adjustable_amount }} = {{
adjustment.non_medical_payment }} * {{
adjustment.non_medical_ratio }} %
</td>
<td>
{{ adjustment.reasonable_adjustable_amount }} = {{
adjustment.reasonable_amount }} * {{
adjustment.reasonable_ratio }} %
</td>
<td>{{ adjustment.adjustment_amount }}元</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="amount-total">总金额: {{ receipt.amount }}元</div>
</div> </div>
{% endfor %} {% endfor %}
</div> </div>
@ -597,6 +692,6 @@
<footer> <footer>
<p>@liubiren.cloud</p> <p>@liubiren.cloud</p>
</footer> </footer>
</div> </div>
</body> </body>
</html> </html>