first commit
This commit is contained in:
7
.dockerignore
Normal file
7
.dockerignore
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
.git/
|
||||||
|
.venv/
|
||||||
|
uploads/
|
||||||
|
jobs/
|
||||||
|
|
||||||
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
.venv/
|
||||||
|
jobs/
|
||||||
|
uploads/
|
||||||
|
|
||||||
16
Dockerfile
Normal file
16
Dockerfile
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
FROM python:3.12-slim
|
||||||
|
|
||||||
|
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||||
|
PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY requirements.txt .
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
COPY app ./app
|
||||||
|
|
||||||
|
EXPOSE 8000
|
||||||
|
|
||||||
|
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||||
|
|
||||||
33
README.md
Normal file
33
README.md
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# HIS_Sur_Data_Deal
|
||||||
|
|
||||||
|
网页端检测数据处理工具。上传 `待处理检测数据.zip` 后,服务会自动识别 V1/V2 数据结构,调用原处理脚本生成 Excel,并返回结果压缩包。
|
||||||
|
|
||||||
|
## 本地运行
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install -r requirements.txt
|
||||||
|
uvicorn app.main:app --host 0.0.0.0 --port 8000
|
||||||
|
```
|
||||||
|
|
||||||
|
访问 `http://localhost:8000`。
|
||||||
|
|
||||||
|
## Docker 构建与运行
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker build -t his-sur-data-deal .
|
||||||
|
docker run --rm -p 8000:8000 his-sur-data-deal
|
||||||
|
```
|
||||||
|
|
||||||
|
## 推送镜像示例
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker tag his-sur-data-deal 192.168.31.5:5002/admin/his-sur-data-deal:latest
|
||||||
|
docker push 192.168.31.5:5002/admin/his-sur-data-deal:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
## 数据模式
|
||||||
|
|
||||||
|
V1:zip 解压后包含 `Patients_info.csv`、`Tests_List`、`Tests_Detail_List`,输出一个汇总 Excel。
|
||||||
|
|
||||||
|
V2:zip 解压后包含 `Patients_info.csv`,并按患者目录分别保存检测汇总和具体检测,输出多个患者 Excel。
|
||||||
|
|
||||||
1
app/__init__.py
Normal file
1
app/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
244
app/main.py
Normal file
244
app/main.py
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
import html
|
||||||
|
import shutil
|
||||||
|
import tempfile
|
||||||
|
import uuid
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from fastapi import FastAPI, File, Form, HTTPException, UploadFile
|
||||||
|
from fastapi.responses import FileResponse, HTMLResponse
|
||||||
|
|
||||||
|
from .processor import ProcessingError, run_processing
|
||||||
|
|
||||||
|
|
||||||
|
APP_ROOT = Path(__file__).resolve().parent
|
||||||
|
WORK_ROOT = Path(tempfile.gettempdir()) / "his_sur_data_deal_jobs"
|
||||||
|
WORK_ROOT.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
app = FastAPI(title="检测数据处理")
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/", response_class=HTMLResponse)
|
||||||
|
def index() -> str:
|
||||||
|
return """
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>检测数据处理</title>
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
color-scheme: light;
|
||||||
|
--bg: #f6f7f9;
|
||||||
|
--panel: #ffffff;
|
||||||
|
--text: #1f2937;
|
||||||
|
--muted: #64748b;
|
||||||
|
--line: #d7dde5;
|
||||||
|
--primary: #146c5c;
|
||||||
|
--primary-dark: #0f574b;
|
||||||
|
--danger: #b42318;
|
||||||
|
}
|
||||||
|
* { box-sizing: border-box; }
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
min-height: 100vh;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Microsoft YaHei", sans-serif;
|
||||||
|
background: var(--bg);
|
||||||
|
color: var(--text);
|
||||||
|
}
|
||||||
|
.shell {
|
||||||
|
width: min(960px, calc(100vw - 32px));
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 36px 0;
|
||||||
|
}
|
||||||
|
header {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 24px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 28px;
|
||||||
|
line-height: 1.2;
|
||||||
|
font-weight: 750;
|
||||||
|
letter-spacing: 0;
|
||||||
|
}
|
||||||
|
.sub {
|
||||||
|
margin-top: 8px;
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.panel {
|
||||||
|
background: var(--panel);
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 24px;
|
||||||
|
box-shadow: 0 10px 26px rgba(17, 24, 39, 0.06);
|
||||||
|
}
|
||||||
|
form {
|
||||||
|
display: grid;
|
||||||
|
gap: 18px;
|
||||||
|
}
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 650;
|
||||||
|
}
|
||||||
|
input[type="file"], select, input[type="text"] {
|
||||||
|
width: 100%;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 11px 12px;
|
||||||
|
font: inherit;
|
||||||
|
background: #fff;
|
||||||
|
color: var(--text);
|
||||||
|
}
|
||||||
|
.grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 14px;
|
||||||
|
}
|
||||||
|
.checks {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 16px;
|
||||||
|
color: var(--text);
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.checks label {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
margin: 0;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
width: fit-content;
|
||||||
|
min-width: 148px;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 12px 18px;
|
||||||
|
background: var(--primary);
|
||||||
|
color: #fff;
|
||||||
|
font: inherit;
|
||||||
|
font-weight: 700;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
button:hover { background: var(--primary-dark); }
|
||||||
|
.note {
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.6;
|
||||||
|
margin-top: 18px;
|
||||||
|
border-top: 1px solid var(--line);
|
||||||
|
padding-top: 16px;
|
||||||
|
}
|
||||||
|
.error {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
color: var(--danger);
|
||||||
|
font-weight: 650;
|
||||||
|
}
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
header { display: block; }
|
||||||
|
.grid { grid-template-columns: 1fr; }
|
||||||
|
button { width: 100%; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<main class="shell">
|
||||||
|
<header>
|
||||||
|
<div>
|
||||||
|
<h1>检测数据处理</h1>
|
||||||
|
<div class="sub">上传“待处理检测数据.zip”,处理完成后自动下载结果压缩包。</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<section class="panel">
|
||||||
|
<form action="/process" method="post" enctype="multipart/form-data">
|
||||||
|
<div>
|
||||||
|
<label for="file">待处理检测数据.zip</label>
|
||||||
|
<input id="file" name="file" type="file" accept=".zip,application/zip" required>
|
||||||
|
</div>
|
||||||
|
<div class="grid">
|
||||||
|
<div>
|
||||||
|
<label for="mode">处理模式</label>
|
||||||
|
<select id="mode" name="mode">
|
||||||
|
<option value="auto">自动识别</option>
|
||||||
|
<option value="v1">V1 整批汇总</option>
|
||||||
|
<option value="v2">V2 单患者文件</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="data_type">患者编号类型</label>
|
||||||
|
<select id="data_type" name="data_type">
|
||||||
|
<option value="pat_no">患者号 pat_no</option>
|
||||||
|
<option value="zhuyuanhao">住院号 zhuyuanhao</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="result_name">结果文件名</label>
|
||||||
|
<input id="result_name" name="result_name" type="text" value="Result">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="checks">
|
||||||
|
<label><input type="checkbox" name="show_not_match" value="true" checked> 输出未匹配内容</label>
|
||||||
|
<label><input type="checkbox" name="show_all_infos" value="true"> 输出全部检测记录</label>
|
||||||
|
</div>
|
||||||
|
<button type="submit">开始处理</button>
|
||||||
|
</form>
|
||||||
|
<div class="note">V1 适用于含有 Patients_info.csv、Tests_List、Tests_Detail_List 的批量数据;V2 适用于每个患者单独目录的数据。</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@app.post("/process")
|
||||||
|
async def process(
|
||||||
|
file: UploadFile = File(...),
|
||||||
|
mode: str = Form("auto"),
|
||||||
|
data_type: str = Form("pat_no"),
|
||||||
|
result_name: str = Form("Result"),
|
||||||
|
show_not_match: str | None = Form(None),
|
||||||
|
show_all_infos: str | None = Form(None),
|
||||||
|
) -> FileResponse:
|
||||||
|
if not file.filename or not file.filename.lower().endswith(".zip"):
|
||||||
|
raise HTTPException(status_code=400, detail="请上传 zip 文件。")
|
||||||
|
|
||||||
|
job_dir = WORK_ROOT / uuid.uuid4().hex
|
||||||
|
job_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
upload_path = job_dir / "input.zip"
|
||||||
|
try:
|
||||||
|
with upload_path.open("wb") as out:
|
||||||
|
shutil.copyfileobj(file.file, out)
|
||||||
|
|
||||||
|
result_zip = run_processing(
|
||||||
|
zip_path=upload_path,
|
||||||
|
job_dir=job_dir,
|
||||||
|
mode=mode,
|
||||||
|
data_type=data_type,
|
||||||
|
result_name=result_name,
|
||||||
|
show_not_match=show_not_match == "true",
|
||||||
|
show_all_infos=show_all_infos == "true",
|
||||||
|
)
|
||||||
|
except ProcessingError as exc:
|
||||||
|
safe_detail = html.escape(str(exc))
|
||||||
|
raise HTTPException(status_code=400, detail=safe_detail) from exc
|
||||||
|
except Exception as exc:
|
||||||
|
raise HTTPException(status_code=500, detail=f"处理失败:{exc}") from exc
|
||||||
|
|
||||||
|
return FileResponse(
|
||||||
|
result_zip,
|
||||||
|
media_type="application/zip",
|
||||||
|
filename="检测数据处理结果.zip",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/health")
|
||||||
|
def health() -> dict[str, str]:
|
||||||
|
return {"status": "ok"}
|
||||||
|
|
||||||
181
app/processor.py
Normal file
181
app/processor.py
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import zipfile
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
PROCESSOR_DIR = Path(__file__).resolve().parent / "processors"
|
||||||
|
|
||||||
|
|
||||||
|
class ProcessingError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def run_processing(
|
||||||
|
zip_path: Path,
|
||||||
|
job_dir: Path,
|
||||||
|
mode: str,
|
||||||
|
data_type: str,
|
||||||
|
result_name: str,
|
||||||
|
show_not_match: bool,
|
||||||
|
show_all_infos: bool,
|
||||||
|
) -> Path:
|
||||||
|
if mode not in {"auto", "v1", "v2"}:
|
||||||
|
raise ProcessingError("处理模式不正确。")
|
||||||
|
if data_type not in {"pat_no", "zhuyuanhao"}:
|
||||||
|
raise ProcessingError("患者编号类型不正确。")
|
||||||
|
|
||||||
|
extract_dir = job_dir / "input"
|
||||||
|
output_dir = job_dir / "output"
|
||||||
|
extract_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
output_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
_safe_extract(zip_path, extract_dir)
|
||||||
|
data_dir = _find_data_root(extract_dir)
|
||||||
|
selected_mode = _detect_mode(data_dir) if mode == "auto" else mode
|
||||||
|
|
||||||
|
clean_name = _clean_result_name(result_name)
|
||||||
|
if selected_mode == "v1":
|
||||||
|
result_path = output_dir / f"{clean_name}.xlsx"
|
||||||
|
cmd = [
|
||||||
|
sys.executable,
|
||||||
|
str(PROCESSOR_DIR / "V1-ALL_convert_Lab_Test_data.py"),
|
||||||
|
str(data_dir),
|
||||||
|
str(result_path),
|
||||||
|
str(show_not_match),
|
||||||
|
str(show_all_infos),
|
||||||
|
data_type,
|
||||||
|
]
|
||||||
|
elif selected_mode == "v2":
|
||||||
|
cmd = [
|
||||||
|
sys.executable,
|
||||||
|
str(PROCESSOR_DIR / "V2-Every_Pat_File_convert_Lab_Test_data.py"),
|
||||||
|
"--file_dir",
|
||||||
|
str(data_dir),
|
||||||
|
"--result_save_file_name",
|
||||||
|
clean_name,
|
||||||
|
"--show_not_match",
|
||||||
|
str(show_not_match),
|
||||||
|
"--show_all_infos",
|
||||||
|
str(show_all_infos),
|
||||||
|
"--data_type",
|
||||||
|
data_type,
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
raise ProcessingError("无法识别数据目录结构,请手动选择 V1 或 V2。")
|
||||||
|
|
||||||
|
env = os.environ.copy()
|
||||||
|
env["PYTHONUTF8"] = "1"
|
||||||
|
env["PYTHONIOENCODING"] = "utf-8"
|
||||||
|
|
||||||
|
completed = subprocess.run(
|
||||||
|
cmd,
|
||||||
|
cwd=PROCESSOR_DIR,
|
||||||
|
env=env,
|
||||||
|
text=True,
|
||||||
|
encoding="utf-8",
|
||||||
|
errors="replace",
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.STDOUT,
|
||||||
|
timeout=60 * 30,
|
||||||
|
)
|
||||||
|
|
||||||
|
log_path = output_dir / "process.log"
|
||||||
|
log_path.write_text(
|
||||||
|
"mode=" + selected_mode + "\n\n" + completed.stdout,
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
if completed.returncode != 0:
|
||||||
|
raise ProcessingError(f"处理脚本退出码 {completed.returncode}。\n{completed.stdout[-4000:]}")
|
||||||
|
|
||||||
|
if selected_mode == "v2":
|
||||||
|
_collect_v2_outputs(data_dir, output_dir)
|
||||||
|
_collect_logs(data_dir, output_dir)
|
||||||
|
|
||||||
|
xlsx_files = list(output_dir.rglob("*.xlsx"))
|
||||||
|
if not xlsx_files:
|
||||||
|
raise ProcessingError("处理完成但没有生成 Excel 文件,请检查数据结构和 process.log。")
|
||||||
|
|
||||||
|
result_zip = job_dir / "result.zip"
|
||||||
|
with zipfile.ZipFile(result_zip, "w", compression=zipfile.ZIP_DEFLATED) as zf:
|
||||||
|
for path in output_dir.rglob("*"):
|
||||||
|
if path.is_file():
|
||||||
|
zf.write(path, path.relative_to(output_dir))
|
||||||
|
return result_zip
|
||||||
|
|
||||||
|
|
||||||
|
def _safe_extract(zip_path: Path, target_dir: Path) -> None:
|
||||||
|
try:
|
||||||
|
with zipfile.ZipFile(zip_path) as zf:
|
||||||
|
for member in zf.infolist():
|
||||||
|
destination = (target_dir / member.filename).resolve()
|
||||||
|
if not str(destination).startswith(str(target_dir.resolve())):
|
||||||
|
raise ProcessingError("zip 中包含不安全路径。")
|
||||||
|
zf.extractall(target_dir)
|
||||||
|
except zipfile.BadZipFile as exc:
|
||||||
|
raise ProcessingError("zip 文件无法解压。") from exc
|
||||||
|
|
||||||
|
|
||||||
|
def _find_data_root(extract_dir: Path) -> Path:
|
||||||
|
candidates = [extract_dir]
|
||||||
|
children = [p for p in extract_dir.iterdir() if p.is_dir()]
|
||||||
|
if len(children) == 1 and not any(p.is_file() for p in extract_dir.iterdir()):
|
||||||
|
candidates.insert(0, children[0])
|
||||||
|
|
||||||
|
for candidate in candidates:
|
||||||
|
if (candidate / "Patients_info.csv").exists():
|
||||||
|
return candidate
|
||||||
|
|
||||||
|
for path in extract_dir.rglob("Patients_info.csv"):
|
||||||
|
return path.parent
|
||||||
|
|
||||||
|
raise ProcessingError("未找到 Patients_info.csv。")
|
||||||
|
|
||||||
|
|
||||||
|
def _detect_mode(data_dir: Path) -> str:
|
||||||
|
if (data_dir / "Tests_List").is_dir() and (data_dir / "Tests_Detail_List").is_dir():
|
||||||
|
return "v1"
|
||||||
|
|
||||||
|
patient_dirs = [p for p in data_dir.iterdir() if p.is_dir()]
|
||||||
|
for patient_dir in patient_dirs:
|
||||||
|
names = {p.name for p in patient_dir.iterdir()}
|
||||||
|
has_summary = any(name.endswith("_检测汇总.csv") for name in names)
|
||||||
|
has_detail_dir = any(name.endswith("_具体检测") and (patient_dir / name).is_dir() for name in names)
|
||||||
|
if has_summary and has_detail_dir:
|
||||||
|
return "v2"
|
||||||
|
|
||||||
|
raise ProcessingError("无法自动识别 V1/V2 数据结构。")
|
||||||
|
|
||||||
|
|
||||||
|
def _clean_result_name(result_name: str) -> str:
|
||||||
|
name = (result_name or "Result").strip()
|
||||||
|
if name.lower().endswith(".xlsx"):
|
||||||
|
name = name[:-5]
|
||||||
|
forbidden = '<>:"/\\|?*'
|
||||||
|
name = "".join("_" if ch in forbidden else ch for ch in name).strip(" .")
|
||||||
|
return name or "Result"
|
||||||
|
|
||||||
|
|
||||||
|
def _collect_v2_outputs(data_dir: Path, output_dir: Path) -> None:
|
||||||
|
v2_dir = output_dir / "V2患者结果"
|
||||||
|
v2_dir.mkdir(exist_ok=True)
|
||||||
|
for path in data_dir.rglob("*.xlsx"):
|
||||||
|
if path.is_file():
|
||||||
|
target = v2_dir / path.name
|
||||||
|
if target.exists():
|
||||||
|
target = v2_dir / f"{path.parent.name}_{path.name}"
|
||||||
|
shutil.copy2(path, target)
|
||||||
|
|
||||||
|
|
||||||
|
def _collect_logs(data_dir: Path, output_dir: Path) -> None:
|
||||||
|
logs_dir = output_dir / "logs"
|
||||||
|
for pattern in ("*.txt", "error.txt", "Error.txt"):
|
||||||
|
for path in data_dir.rglob(pattern):
|
||||||
|
if path.is_file():
|
||||||
|
logs_dir.mkdir(exist_ok=True)
|
||||||
|
relative = path.relative_to(data_dir)
|
||||||
|
target = logs_dir / relative
|
||||||
|
target.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
shutil.copy2(path, target)
|
||||||
364
app/processors/V1-ALL_convert_Lab_Test_data.py
Normal file
364
app/processors/V1-ALL_convert_Lab_Test_data.py
Normal file
@@ -0,0 +1,364 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: UTF-8 -*-
|
||||||
|
import csv, sys, os, copy, re
|
||||||
|
import os.path as osp
|
||||||
|
from openpyxl import Workbook, load_workbook
|
||||||
|
|
||||||
|
# 向特定excel的sheet中添加内容
|
||||||
|
workbook = None # 全局变量,初始值为 None
|
||||||
|
file_path_g = None
|
||||||
|
def add_content_to_excel(file_path, sheet_name, content):
|
||||||
|
global workbook, file_path_g # 声明 workbook 为全局变量
|
||||||
|
# 如果改换工作路径且workbook不为空
|
||||||
|
if file_path_g != file_path and not (workbook is None):
|
||||||
|
# 保存工作簿
|
||||||
|
workbook.save(file_path_g)
|
||||||
|
print("保存Excel工作表在:", file_path_g)
|
||||||
|
elif file_path_g != file_path:
|
||||||
|
try:
|
||||||
|
# 尝试加载现有的工作簿
|
||||||
|
workbook = load_workbook(file_path)
|
||||||
|
except FileNotFoundError:
|
||||||
|
# 如果文件不存在,则创建一个新的工作簿
|
||||||
|
workbook = Workbook()
|
||||||
|
file_path_g = file_path
|
||||||
|
|
||||||
|
if sheet_name not in workbook.sheetnames:
|
||||||
|
# 如果工作表不存在,则创建一个新的工作表
|
||||||
|
workbook.create_sheet(sheet_name)
|
||||||
|
|
||||||
|
# 选择指定的工作表
|
||||||
|
sheet = workbook[sheet_name]
|
||||||
|
|
||||||
|
# 向工作表添加内容
|
||||||
|
# 检查列表的第一个元素
|
||||||
|
if isinstance(content, list) and content and isinstance(content[0], list):
|
||||||
|
# "二维列表"
|
||||||
|
for row in content:
|
||||||
|
sheet.append(row)
|
||||||
|
elif isinstance(content, list):
|
||||||
|
# "一维列表"
|
||||||
|
sheet.append(content)
|
||||||
|
elif isinstance(content, str):
|
||||||
|
# "字符串"
|
||||||
|
sheet.append([content])
|
||||||
|
else:
|
||||||
|
print('add_content_to_excel输入参数为', content, '其不是列表、字符串')
|
||||||
|
|
||||||
|
def save_excel():
|
||||||
|
global workbook, file_path_g
|
||||||
|
if not (workbook is None):
|
||||||
|
# 保存工作簿
|
||||||
|
print("Excel工作表保存在:", file_path_g)
|
||||||
|
workbook.save(file_path_g)
|
||||||
|
|
||||||
|
# 自定义数据
|
||||||
|
# 1.数据所在路径
|
||||||
|
file_dir = sys.argv[1]
|
||||||
|
# 2.文件保存路径
|
||||||
|
result_save_pth = sys.argv[2] # osp.join(file_dir, 'Result.xlsx') #
|
||||||
|
# 3.是否输出不匹配内容
|
||||||
|
show_not_match = sys.argv[3]
|
||||||
|
# 4. 数据类型:pat_no / zhuyuanhao
|
||||||
|
data_type = sys.argv[5]
|
||||||
|
|
||||||
|
if (show_not_match.lower() == 'true'):
|
||||||
|
show_not_match = True
|
||||||
|
else:
|
||||||
|
show_not_match = False
|
||||||
|
# 4.是否输出全部信息(包括全无项)
|
||||||
|
show_all_infos = sys.argv[4]
|
||||||
|
if (show_all_infos.lower() == 'true'):
|
||||||
|
show_all_infos = True
|
||||||
|
else:
|
||||||
|
show_all_infos = False
|
||||||
|
|
||||||
|
####### 生成信息 #######
|
||||||
|
# Patients_info文件的路径
|
||||||
|
Patients_info_pth = osp.join(file_dir, 'Patients_info.csv')
|
||||||
|
# Tests_List目录的路径
|
||||||
|
patno_dir = osp.join(file_dir, 'Tests_List')
|
||||||
|
# Tests_List目录的路径
|
||||||
|
Patient_detail_infos_dir = osp.join(file_dir, 'Tests_Detail_List')
|
||||||
|
RED = '\033[91m'
|
||||||
|
RESET = '\033[0m'
|
||||||
|
error_dir = osp.join(file_dir, 'error.txt')
|
||||||
|
|
||||||
|
# 输出错误函数
|
||||||
|
def Error(output_str="Error:", error_dir=error_dir):
|
||||||
|
# 打开 error.txt 文件并写入字符串
|
||||||
|
with open(error_dir, "a+") as file:
|
||||||
|
# 将字符串输出到标准错误流 sys.stderr
|
||||||
|
file.write(output_str+'\n')
|
||||||
|
print(RED+output_str+RESET)
|
||||||
|
|
||||||
|
# 判断字符串是否匹配正则表达式
|
||||||
|
def match_re(string, pattern):
|
||||||
|
# 使用 str() 强制转换,防止出现 None 或数字导致的报错
|
||||||
|
if re.match(str(pattern), str(string)):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 1.删除Error文件
|
||||||
|
if os.path.exists(error_dir):
|
||||||
|
os.remove(error_dir)
|
||||||
|
print("删除Error文件:", error_dir)
|
||||||
|
|
||||||
|
# 2.打开Patients_info.csv文件,遍历出所有有效患者
|
||||||
|
with open(Patients_info_pth, "r", encoding='utf-8-sig') as file:
|
||||||
|
reader_ = csv.DictReader(file)
|
||||||
|
reader_Patients_info = []
|
||||||
|
for r in reader_:
|
||||||
|
reader_Patients_info.append(r)
|
||||||
|
# 读取pat_no列数据
|
||||||
|
if data_type == "pat_no":
|
||||||
|
pat_no_col = [f"{int(row['pat_no']):010}" for row in reader_Patients_info]
|
||||||
|
elif data_type == "zhuyuanhao":
|
||||||
|
pat_no_col = [f"{row['pat_no']}" for row in reader_Patients_info]
|
||||||
|
else:
|
||||||
|
print("数据类型需要为pat_no或zhuyuanhao")
|
||||||
|
pat_no_col = list(set(pat_no_col)) # 去除数组中重复内容
|
||||||
|
|
||||||
|
# *** 注意: TODO for循环和list的remove相冲突,因此深拷贝原有元素
|
||||||
|
# 遍历所有pat_no,查看pat_no中是否有对应文件
|
||||||
|
pat_no_col_ = copy.deepcopy(pat_no_col)
|
||||||
|
for i in range(len(pat_no_col_)):
|
||||||
|
pat_no = pat_no_col_[i]
|
||||||
|
# 查看Tests_List目录下是否有对应的文件
|
||||||
|
file_path = osp.join(patno_dir, pat_no+'.csv')
|
||||||
|
if not osp.exists(file_path):
|
||||||
|
# 去除对应元素并报错
|
||||||
|
pat_no_col.remove(pat_no)
|
||||||
|
Error(f"{pat_no}.csv 在 {patno_dir} 中不存在")
|
||||||
|
|
||||||
|
# 遍历所有pat_no,查看Patient_detail_infos中是否有对应文件
|
||||||
|
pat_no_col_ = copy.deepcopy(pat_no_col)
|
||||||
|
for i in range(len(pat_no_col_)):
|
||||||
|
pat_no = pat_no_col_[i]
|
||||||
|
# 查看Patient_detail_infos目录下是否有对应的文件夹
|
||||||
|
file_path = osp.join(Patient_detail_infos_dir, pat_no)
|
||||||
|
if not osp.exists(file_path):
|
||||||
|
pat_no_col.remove(pat_no)
|
||||||
|
Error(f"{pat_no} 文件夹在 {Patient_detail_infos_dir} 中不存在")
|
||||||
|
|
||||||
|
print("有效可处理患者数为:", len(pat_no_col), f"\n无效数据已存储至{error_dir}中了")
|
||||||
|
|
||||||
|
# 3.遍历所有患者打开patno文件夹中的patno.csv
|
||||||
|
# 获取患者头部信息(提取于Patients_info.csv)
|
||||||
|
Front_line = {'姓名':'pat_name', '住院号':'pat_no'}
|
||||||
|
# 获取患者检测基本信息(提取于patno文件夹)
|
||||||
|
Basic_line = {'采样时间': 'sampled_dt', '检测原因':'req_reason'}
|
||||||
|
# 所有检测具体信息(提取于Patient_detail_infos文件夹)
|
||||||
|
# 一个检查包括:检测rptunitids、检查名(自主命名)、检查项、检查结果所在列、存放结果dict
|
||||||
|
#{'test_rptunitid':[str(X), str(X)], 'test_check_name':'XXX', 'test_check_list':["XXX", "XXX", ], 'test_check_list_all':["XXX", "XXX", ], 'test_result_col_name':"result_str"},
|
||||||
|
ALL_tests = [# 血细胞 # (1):血细胞分析+五分类;(2):血细胞分析+五分类;(4):血细胞五分类+CRP;东院区:(106):血细胞分析+五分类
|
||||||
|
{'test_rptunitid':[str(1), str(2), str(4), str(106)], 'test_check_name':'血细胞', 'test_check_list':["血红蛋白", "红细胞压积", "平均红细胞体积", "平均血红蛋白含量", "平均血红蛋白浓度", "红细胞宽度-CV值", "红细胞宽度-SD值", "血小板计数", "血小板分布宽度", "平均血小板体积", "大血小板比率", "血小板压积", "淋巴细胞计数", "单核细胞计数", "中性粒细胞计数", "嗜酸细胞计数", "嗜碱细胞计数", "淋巴细胞百分比", "单核细胞百分比", "中性粒细胞百分比", "嗜酸细胞百分比", "嗜碱细胞百分比", "白细胞计数", "红细胞计数", "CRP检验=====", "C反应蛋白", "超敏CRP", ], 'test_check_list_all':["血红蛋白", "红细胞压积", "平均红细胞体积", "平均血红蛋白含量", "平均血红蛋白浓度", "红细胞宽度-CV值", "红细胞宽度-SD值", "血小板计数", "血小板分布宽度", "平均血小板体积", "大血小板比率", "血小板压积", "淋巴细胞计数", "单核细胞计数", "中性粒细胞计数", "嗜酸细胞计数", "嗜碱细胞计数", "淋巴细胞百分比", "单核细胞百分比", "中性粒细胞百分比", "嗜酸细胞百分比", ["嗜碱细胞百分比", "嗜碱细胞%"], ["白细胞计数", "白细胞"], "红细胞计数", "CRP检验=====", "C反应蛋白", ["超敏CRP", "超敏C反应蛋白"], ], 'test_result_col_name':"result_str"},
|
||||||
|
# 凝血 # (3):凝血六项;(110):东院区;(90):凝血和血小板功能监测
|
||||||
|
{'test_rptunitid':[str(3), str(110),str(90)], 'test_check_name':'凝血', 'test_check_list':["凝血酶原时间", "凝血酶原活动度", "血浆凝血酶原时间比值", "凝血酶原国际标准化比值", "活化部分凝血活酶时间", "活化部分凝血活酶比值", "凝血酶时间", "凝血酶时间比值", "纤维蛋白原含量", "D-二聚体测定", "纤维蛋白原降解产物", "凝血酶生成时间","凝血速率","血小板功能"],\
|
||||||
|
'test_check_list_all':["凝血酶原时间*", ["凝血酶原活动度", r"凝血酶原活度\(%\)"], ["凝血酶原比值", "血浆凝血酶原时间比值"], ["凝血酶原标准化比值", "凝血酶原国际标准化比值"], ["活化部分凝血活酶时间*", "活化部分凝血酶时间*"], "活化部分凝血活酶比值", "凝血酶时间", "凝血酶时间比值", "纤维蛋白原含量", [r"D-二聚体\(sysmex\)", "D-二聚体测定*"], [r"纤维蛋白\(原\)降解产物", "纤维蛋白原降解产物"], "凝血酶生成时间","凝血速率","血小板功能"], 'test_result_col_name':"result_str"},
|
||||||
|
# 肝功 # (5):平诊肝功十四项+平诊电解质八项+平诊肾功七项;(20)急诊肝功十二项_急诊肾功五项[复]_急诊电解质七项[复];东院区:(108):传染性指标检测八项
|
||||||
|
{'test_rptunitid':[str(5), str(20), str(108)], 'test_check_name':'肝功', 'test_check_list':["谷草转氨酶", "谷丙转氨酶", "谷草/谷丙", "碱性磷酸酶", "γ谷氨酰氨转肽酶", "总胆红素", "直接胆红素", "间接胆红素", "胆碱脂酶", "总胆固醇", "总蛋白", "白蛋白", "球蛋白", "白球比", "总胆汁酸", "a-L-岩藻糖苷酶", "前白蛋白", "超氧化物歧化酶", "尿素", "肌酐", "胱抑素C", "葡萄糖", "尿酸", "钾", "钠", "氯", "磷", "钙", "镁", "二氧化碳结合率", "离子间隙", "糖化白蛋白", "视黄醇结合蛋白", "eGFR(CKD-EPI)", "a-l岩藻糖苷酶", "超氧化物歧化酶", "eGFR(MDRD)", r"eGFR单位ml/min/1.73m^2", "8597", "乳酸测定", "乳酸脱氢酶", "羟丁酸脱氢酶", "肌酸激酶", "肌酸激酶同工酶", "载脂蛋白A", "载脂蛋白B", "载脂蛋白E", "脂蛋白(a)", "缺血修饰白蛋白", "甘油三酯", "高密度脂蛋白", "低密度脂蛋白", ], \
|
||||||
|
'test_check_list_all':["谷草转氨酶", "谷丙转氨酶", "谷草/谷丙", "碱性磷酸酶", ["γ谷氨酰氨转肽酶", "γ-谷氨酰转肽酶"], "总胆红素", "直接胆红素", "间接胆红素", "胆碱脂酶", "总胆固醇", "总蛋白", "白蛋白", "球蛋白", "白球比", "总胆汁酸", "a-L-岩藻糖苷酶", "前白蛋白", "超氧化物歧化酶", "尿素", "肌酐", "胱抑素C", "葡萄糖", "尿酸", "钾", "钠", "氯", "磷", "钙", "镁", "二氧化碳结合率", "离子间隙", "糖化白蛋白", "视黄醇结合蛋白", r"eGFR\(CKD-EPI\)", "a-l岩藻糖苷酶", "超氧化物歧化酶", r"eGFR\(MDRD\)", r"eGFR单位ml/min/1.73m\^2", "8597", "乳酸测定", "乳酸脱氢酶", "羟丁酸脱氢酶", "肌酸激酶", "肌酸激酶同工酶", "载脂蛋白A", "载脂蛋白B", "载脂蛋白E", "脂蛋白(a)", "缺血修饰白蛋白", "甘油三酯", "高密度脂蛋白", "低密度脂蛋白", ], 'test_result_col_name':"result_str"},
|
||||||
|
# 各类肿瘤标志物 # (6):各类肿瘤标志物,e.g.肿瘤标志物肺癌六项[复]、肿瘤标志物十项(男);东院区:(108):肿瘤标志物肺癌六项[复]
|
||||||
|
{'test_rptunitid':[str(6), str(108)], 'test_check_name':'各类肿瘤标志物', 'test_check_list':["胃泌素释放肽前体(罗氏)", "鳞状上皮细胞癌抗原(罗氏)", "癌胚抗原", "甲胎蛋白", "糖类抗原125", "糖类抗原199", "糖类抗原724", "细胞角蛋白19片段", "神经元特异性烯醇化酶测定", "总前列腺特异性抗原", "游离前列腺抗原", "游离/总", "糖类抗原153","人附睾蛋白","绝经前 ROMA","绝经后 ROMA","铁蛋白","叶酸","维生素B12","高尔基体蛋白73测定","胃蛋白酶原Ⅰ","胃蛋白酶原Ⅱ","胃蛋白酶原Ⅰ/Ⅱ","降钙素","甲状腺球蛋白"],\
|
||||||
|
'test_check_list_all':[r"胃泌素释放肽前体\(罗氏\)", ["鳞状上皮细胞癌相关抗原", r"鳞状上皮细胞癌抗原\(罗氏\)"], "癌胚抗原", "甲胎蛋白", "糖类抗原125", "糖类抗原199", "糖类抗原724", "细胞角蛋白19片段", "神经元特异性烯醇化酶测定", "总前列腺特异性抗原", "游离前列腺抗原", "游离/总", "糖类抗原153","人附睾蛋白","绝经前 ROMA","绝经后 ROMA","铁蛋白","叶酸","维生素B12","高尔基体蛋白73测定","胃蛋白酶原Ⅰ","胃蛋白酶原Ⅱ","胃蛋白酶原Ⅰ/Ⅱ","降钙素","甲状腺球蛋白"], 'test_result_col_name':"result_str"},
|
||||||
|
# 七抗 # (10):肺癌七种自身抗体检测
|
||||||
|
{'test_rptunitid':str(10), 'test_check_name':'七抗', 'test_check_list':["p53自身抗体", "PGP9.5自身抗体", "SOX2自身抗体", "GAGE7自身抗体", "GBU4-5自身抗体", "MAGE A1自身抗体", "CAGE自身抗体", ], 'test_check_list_all':["p53自身抗体", "PGP9.5自身抗体", "SOX2自身抗体", "GAGE7自身抗体", "GBU4-5自身抗体", "MAGE A1自身抗体", "CAGE自身抗体", ], 'test_result_col_name':"result_str"},
|
||||||
|
# 传染指标 # (52):传染指标八项-急诊;(53):传染性指标检测八项[复];东院区:(108):传染性指标检测八项[复]
|
||||||
|
{'test_rptunitid':[str(52), str(53), str(108)], 'test_check_name':'传染指标', 'test_check_list':["乙肝表面抗原定量", "乙肝表面抗体定量", "乙肝e抗原", "乙肝e抗体", "乙肝核心抗体", "丙型肝炎抗体", "梅毒螺旋体抗体", "人类免疫缺陷病毒", ], 'test_check_list_all':["乙肝表面抗原定量", "乙肝表面抗体定量", "乙肝e抗原", "乙肝e抗体", "乙肝核心抗体", "丙型肝炎抗体", ["螺旋体特异抗体", "梅毒螺旋体抗体"], ["人免疫缺陷病毒", "人类免疫缺陷病毒"], ], 'test_result_col_name':"result_str"},
|
||||||
|
# 血气分析+生化分析 # (16):血气分析+生化六项[复]/血气分析3, (49):血气分析+生化六项[复], (50):血气分析+生化五项[复], (73/74):血气分析+生化十项[复], (89):血气分析+生化六项[复], (112):血气分析/血气分析+生化七项[复], (158):血气分析+生化六项[复];(42):血气分析+生化六项[复]
|
||||||
|
{'test_rptunitid':[str(16), str(49), str(50), str(73), str(74), str(89), str(112), str(158),str(42)], 'test_check_name':'血气分析+生化分析', 'test_check_list':["体温", "吸氧流量", "酸碱度", "氧分压", "二氧化碳分压", "二氧化碳总量", "红细胞压积", "总血红蛋白", "氧饱和度", "Na+钠离子浓度", "钾离子浓度", "钙离子浓度", "氯离子浓度", "标准离子钙", "氢离子浓度", "酸碱度计算值", "PCO2分压计算值", "p氧分压计算值", "pO2(A-a)(T)_r", "pO2(a/A)(T)_r", "呼吸指数计算值", "pO2(T)/FIO2_r", "氢离子浓度", "HCO3-act_r", "HCO3-std_r", "BE(ecf)_r", "血液缓冲碱", "ctCO2", "pO2(A-a)_r", "pO2(a/A)_r", "呼吸指数", "氧和指数", "阴离子间隙", "渗透压", "血糖", "乳酸", "实际碳酸氢盐", "标准碳酸氢盐", "实际碱剩余", "标准碱剩余", "细胞外液剩余碱","氧合血红蛋白","一氧化碳血红蛋白", "还原血红蛋白","高铁血红蛋白", "总胆红素", "A-aDO2", "pAO2", "paO2/pAO2", "50%饱和度氧分压", "动脉血氧含量", "肺泡动脉氧分压差", "动脉氧分压与肺泡氧分压之比", "pCO2(T)", "pO2(T)", "PH(T)", "吸氧浓度","平均肺泡氧分压"],\
|
||||||
|
'test_check_list_all':["体温", "吸氧流量", "酸碱度", "氧分压", "二氧化碳分压", "二氧化碳总量", "红细胞压积", "总血红蛋白", "氧饱和度", ["Na\+钠离子浓度", "钠离子"], ["钾离子浓度","钾离子"], ["钙离子浓度","钙离子"], ["氯离子浓度","氯离子"], ["标准离子钙","PH=7.4的钙"], "氢离子浓度", "酸碱度计算值", "PCO2分压计算值", "p氧分压计算值", r"pO2\(A-a\)\(T\)_r", r"pO2\(a/A\)\(T\)_r", "呼吸指数计算值", r"pO2\(T\)/FIO2_r", "氢离子浓度", "HCO3-act_r", "HCO3-std_r", r"BE\(ecf\)_r", "血液缓冲碱", "ctCO2", r"pO2\(A-a\)_r", r"pO2\(a/A\)_r", "呼吸指数", "氧和指数", "阴离子间隙", "渗透压", "血糖", "乳酸", ["实际碳酸氢盐","血浆碳酸氢盐浓度"], "标准碳酸氢盐", ["血液剩余碱","实际碱剩余"], "标准碱剩余", "细胞外液剩余碱","氧合血红蛋白","一氧化碳血红蛋白", "还原血红蛋白","高铁血红蛋白", "总胆红素", "A-aDO2", "pAO2", "paO2/pAO2", "50%饱和度氧分压", "动脉血氧含量", "肺泡动脉氧分压差", "动脉氧分压与肺泡氧分压之比", r"pCO2\(T\)", r"pO2\(T\)", r"PH\(T\)", "吸氧浓度","平均肺泡氧分压"], 'test_result_col_name':"result_str"},
|
||||||
|
# 感染指标 # (77)/(92)/(113)/(126)/(77)/(82)/:新型冠状病毒核酸检测[复]; (75):新型冠状病毒抗体; (25):新冠核酸检测[复]/乙肝病毒DNA含量/结核杆菌定量测定;str(121)/str(37):一般细菌涂片检查;str(111):乙型肝炎DNA定量测定;str(29):免疫8项;str(34):内毒素+D葡聚糖测定,str(38)/(116):红细胞沉降率测定;str(36):结核Xpert鉴定及耐药[复];str(10):结核感染T细胞检测;str(24):自身抗体谱测定(18项);str(23):血清肌钙蛋白I测定
|
||||||
|
{'test_rptunitid':[str(77),str(25),str(92),str(113),str(126),str(75),str(77),str(82),str(30),str(121),str(37),str(111),str(29),str(34),str(38),str(116),str(36),str(10),str(23)], 'test_check_name':'感染指标', 'test_check_list':["新型冠状病毒抗体IgG","新型冠状病毒抗体IgM", "新型冠状病毒核酸检测","新型冠状病毒核酸混检", "乙肝病毒DNA含量","结核杆菌定量测定", "EB病毒定量测定","巨细胞病毒定量测定","白细胞","上皮细胞","革兰氏阳性球菌","革兰氏阴性球菌","革兰氏阴性球杆菌","革兰氏阳性杆菌","革兰氏阴性杆菌","真菌菌丝" ,"真菌孢子","抗酸染色", "HPV6","HPV11","抗链球菌溶血素O定量测定","KAP轻链","LAM轻链","免疫球蛋白IgE","免疫球蛋白G","免疫球蛋白M","免疫球蛋白A","补体C3","补体C4","类风湿因子","C反应蛋白","G-脂多糖","1-3-β-D葡聚糖","抗心磷脂IgG抗体","EB病毒核心抗原IgG抗体","EB病毒衣壳抗原IgG抗体","EB病毒早期抗原IgM抗体","EB病毒衣壳抗原IgM抗体","红细胞沉降率测定","降钙素原",r"淋巴细胞培养+干扰素\(基础水平N\)",r"结核杆菌γ干扰素释放试验\(T-N\)",r"结核杆菌阳性对照反应\(M-N\)",r"结核杆菌特异性细胞免疫反应提示", "抗dsDNA抗体","抗核小体抗体","抗组蛋白抗体","抗SmD1抗体","抗PCNA抗体","抗核糖体P蛋白测定","抗SSA/Ro60kD抗体","抗SSA/Ro52kD抗体","抗ssb抗体","抗CENPB抗体","抗Scl-70抗体","抗U1-snRNP抗体","抗Jo-1抗体","抗PM-Scl抗体","抗Ku抗体","抗AMA-M2抗体","抗Mi-2抗体",r"抗核抗体\(1:80\)","高敏肌钙蛋白I" ],\
|
||||||
|
'test_check_list_all':["新型冠状病毒抗体IgG","新型冠状病毒抗体IgM",["新型冠状病毒核酸检测", "新型冠状病毒核酸快速检测"], r"新型冠状病毒核酸检测\(混检\)",["乙肝病毒DNA含量","乙型肝炎病毒DNA定量"],"结核杆菌定量测定", "EB病毒定量测定","巨细胞病毒定量测定","白细胞","上皮细胞",["革兰氏阳性球菌","革兰阳性球菌"],["革兰阴性球菌","革兰氏阴性球菌"],"革兰氏阴性球杆菌",["革兰阳性杆菌","革兰氏阳性杆菌"],["革兰阴性杆菌","革兰氏阴性杆菌"],"真菌菌丝","真菌孢子","抗酸染色","HPV6","HPV11","抗链球菌溶血素O定量测定","KAP轻链","LAM轻链","免疫球蛋白IgE","免疫球蛋白G","免疫球蛋白M","免疫球蛋白A","补体C3","补体C4","类风湿因子","C反应蛋白","G-脂多糖","1-3-β-D葡聚糖","抗心磷脂IgG抗体","EB病毒核心抗原IgG抗体","EB病毒衣壳抗原IgG抗体","EB病毒早期抗原IgM抗体","EB病毒衣壳抗原IgM抗体","红细胞沉降率测定","降钙素原",r"淋巴细胞培养+干扰素\(基础水平N\)",r"结核杆菌γ干扰素释放试验\(T-N\)",r"结核杆菌阳性对照反应\(M-N\)",r"结核杆菌特异性细胞免疫反应提示","抗dsDNA抗体","抗核小体抗体","抗组蛋白抗体","抗SmD1抗体","抗PCNA抗体","抗核糖体P蛋白测定","抗SSA/Ro60kD抗体","抗SSA/Ro52kD抗体","抗ssb抗体","抗CENPB抗体","抗Scl-70抗体","抗U1-snRNP抗体","抗Jo-1抗体","抗PM-Scl抗体","抗Ku抗体","抗AMA-M2抗体","抗Mi-2抗体",r"抗核抗体\(1:80\)","高敏肌钙蛋白I"], 'test_result_col_name':"result_str"},
|
||||||
|
# 基因检测指标 # (41):CYP2C19基因检测[复]
|
||||||
|
{'test_rptunitid':[str(41)], 'test_check_name':'基因检测指标', 'test_check_list':[r"GG_681GG\)",r"GG_681GA\)",r"GA_681GG\)",r"GG_681AA\)",r"AA_681GG\)",r"GA_681GA\)" ],\
|
||||||
|
'test_check_list_all':[r"\*1/\*1\(636", r"\*1/\*2\(636",r"\*1/\*3\(636", r"\*2/\*2\(636",r"\*3/\*3\(636", r"\*2/\*3\(636", ], 'test_result_col_name':"result_ref"},
|
||||||
|
# 心衰系列 # str(20):B型前脑尿钠肽, str(16):B型前脑尿钠肽检测(Pro-BN_降钙素原检;str(108):B型尿钠肽检测(BNP)
|
||||||
|
{'test_rptunitid':[str(20),str(16)], 'test_check_name':'心衰系列', 'test_check_list':['B型前脑尿钠肽','高敏肌钙蛋白T'],\
|
||||||
|
'test_check_list_all':['B型前脑尿钠肽','高敏肌钙蛋白T'], 'test_result_col_name':"result_str"},
|
||||||
|
# 普通指标 # str(79),str(51):卡式血型鉴定;str(12):肝纤维化指标(五项);str(22)/(33):胃液常规检查;str(161):甲功五项(化学发光法)[复]
|
||||||
|
{'test_rptunitid':[str(79),str(51),str(12),str(22),str(33),str(161)], 'test_check_name':'普通指标', 'test_check_list':['ABO正定型','ABO反定型','ABO血型',r'Rh\(D\)血型','TPO过氧化物酶自身抗体','T4甲状腺素','T3三碘甲腺原氨酸','FT4游离甲状腺素','FT3游离三碘甲腺原氨酸','h-TSH促甲状腺激素','TGAB甲状腺球蛋白抗体','TMAB甲状腺微粒体抗体','隐血'],\
|
||||||
|
'test_check_list_all':['ABO正定型','ABO反定型','ABO血型',r'Rh\(D\)血型','TPO过氧化物酶自身抗体','T4甲状腺素','T3三碘甲腺原氨酸','FT4游离甲状腺素','FT3游离三碘甲腺原氨酸','h-TSH促甲状腺激素','TGAB甲状腺球蛋白抗体','TMAB甲状腺微粒体抗体','隐血'], 'test_result_col_name':"result_str"},
|
||||||
|
# 免疫系列 # str(14):'促甲状腺素受体抗体测定
|
||||||
|
{'test_rptunitid':[str(14)], 'test_check_name':'免疫系列', 'test_check_list':['甲状腺球蛋白','促甲状腺激素','血清甲状腺素','血清三碘甲状原氨酸','血清游离甲状腺素','血清游离三碘甲状原氨酸','抗甲状腺球蛋白抗体','抗甲状腺过氧化物酶抗体'],\
|
||||||
|
'test_check_list_all':['甲状腺球蛋白','促甲状腺激素','血清甲状腺素','血清三碘甲状原氨酸','血清游离甲状腺素','血清游离三碘甲状原氨酸','抗甲状腺球蛋白抗体','抗甲状腺过氧化物酶抗体'], 'test_result_col_name':"result_str"},
|
||||||
|
# 特殊指标 # str(10):血管内皮生长因子检测;str(46):
|
||||||
|
{'test_rptunitid':[str(10)], 'test_check_name':'特殊指标', 'test_check_list':['血管内皮生长因子_血管内皮生长因子检测',r'Th1/Th2/Th17亚群十二项细胞因子_白介素\(IL\)检测\(IL-1β\)',r'白介素(IL)检测\(IL-2\)',r'白介素(IL)检测\(IL-4\)',r'白介素(IL)检测\(IL-5\)',r'白介素(IL)检测\(IL-6\)',r'白介素(IL)检测\(IL-8\)',r'白介素(IL)检测\(IL-10\)',r'白介素(IL)检测\(IL-12p\)',r'白介素(IL)检测\(IL-17\)',r'干扰素(IFN)测定\(IFN-α\)',r'干扰素(IFN)测定\(IFN-γ\)',r'肿瘤坏死因子测定'],\
|
||||||
|
'test_check_list_all':['血管内皮生长因子检测',r'白介素\(IL\)检测\(IL-1β\)',r'白介素(IL)检测\(IL-2\)',r'白介素(IL)检测\(IL-4\)',r'白介素(IL)检测\(IL-5\)',r'白介素(IL)检测\(IL-6\)',r'白介素(IL)检测\(IL-8\)',r'白介素(IL)检测\(IL-10\)',r'白介素(IL)检测\(IL-12p\)',r'白介素(IL)检测\(IL-17\)',r'干扰素(IFN)测定\(IFN-α\)',r'干扰素(IFN)测定\(IFN-γ\)',r'肿瘤坏死因子测定',], 'test_result_col_name':"result_str"},
|
||||||
|
# 内分泌代谢系列 # str(12):尿β2-MG;str(7):尿液儿茶酚胺测定八项[复];str(7):抗中性粒细胞胞浆抗体测定(ANC;
|
||||||
|
{'test_rptunitid':[str(12),str(7),str(17),str(161)], 'test_check_name':'内分泌代谢系列', 'test_check_list':['尿β2-MG','游离肾上腺素','游离去甲肾上腺素','游离多巴胺','游离甲氧基肾上腺素','游离甲氧基去甲肾上腺素','游离3-甲氧基酪胺','尿香草扁桃酸','高香草酸','24小时尿(体液)量','尿24小时游离肾上腺素','尿24小时游离去甲肾上腺素','尿24小时游离多巴胺','尿24小时游离甲氧基肾上腺素','尿24小时游离甲氧基去甲肾上腺素','尿24小时游离3-甲氧基酪胺','尿24小时香草扁桃酸','尿24小时高香草酸', 'cANCA','pANCA','抗蛋白酶3抗体','抗髓过氧化物酶抗体','ANA','非典型性ANCA','*MPO标准品1','*MPO标准品2','*MPO标准品3','*PR3标准品1','*PR3标准品2','*PR3标准品3'],\
|
||||||
|
'test_check_list_all':['尿β2-MG','游离肾上腺素','游离去甲肾上腺素','游离多巴胺','游离甲氧基肾上腺素','游离甲氧基去甲肾上腺素','游离3-甲氧基酪胺','尿香草扁桃酸','高香草酸','24小时尿(体液)量','尿24小时游离肾上腺素','尿24小时游离去甲肾上腺素','尿24小时游离多巴胺','尿24小时游离甲氧基肾上腺素','尿24小时游离甲氧基去甲肾上腺素','尿24小时游离3-甲氧基酪胺','尿24小时香草扁桃酸','尿24小时高香草酸','cANCA','pANCA','抗蛋白酶3抗体','抗髓过氧化物酶抗体','ANA','非典型性ANCA',r'\*MPO标准品1',r'\*MPO标准品2',r'\*MPO标准品3',r'\*PR3标准品1',r'\*PR3标准品2',r'\*PR3标准品3'], 'test_result_col_name':"result_str"},
|
||||||
|
# 用药指导 # str(78):用药指导基因检测他汀类药物两项
|
||||||
|
{'test_rptunitid':[str(78),str(40)], 'test_check_name':'用药指导', 'test_check_list':[r'VKORC1\(1639G>A\)',r'CYP2C9*3\(1075A>C\)',r'ALDH2\(1510G>A\)',r'ApoE\(526',r'SLCO1B1*5\(521'],\
|
||||||
|
'test_check_list_all':[r'VKORC1\(1639G>A\)',r'CYP2C9*3\(1075A>C\)',r'ALDH2\(1510G>A\)',r'ApoE\(526',r'SLCO1B1*5\(521'], 'test_result_col_name':"result_str"},
|
||||||
|
]
|
||||||
|
|
||||||
|
# 生成基本存储信息文件
|
||||||
|
# 如果有文件则将其删除
|
||||||
|
if os.path.exists(result_save_pth):
|
||||||
|
os.remove(result_save_pth)
|
||||||
|
# 生成抬头信息
|
||||||
|
front_content=[] # 抬头个人信息
|
||||||
|
for front in Front_line:
|
||||||
|
front_content.append(front)
|
||||||
|
# 生成basic存储信息
|
||||||
|
basic_content=[] # basic个人信息
|
||||||
|
for basic in Basic_line:
|
||||||
|
basic_content.append(basic)
|
||||||
|
# 生成各个检测sheet:head+basic+items+[not_match]
|
||||||
|
for test in ALL_tests: # 各项检测信息
|
||||||
|
# 生成未匹配检查内容
|
||||||
|
if show_not_match == True:
|
||||||
|
add_content_to_excel(result_save_pth, test['test_check_name'], front_content + basic_content + test["test_check_list"] + ['未匹配检测内容'])
|
||||||
|
else:
|
||||||
|
add_content_to_excel(result_save_pth, test['test_check_name'], front_content + basic_content + test["test_check_list"])
|
||||||
|
|
||||||
|
|
||||||
|
####### 获取所有患者头部信息(Front_line) #######
|
||||||
|
front_line_data = []
|
||||||
|
# 遍历所有患者(pat_no)
|
||||||
|
for row in reader_Patients_info:
|
||||||
|
data = {}
|
||||||
|
for item in Front_line:
|
||||||
|
if Front_line[item] == 'pat_no':
|
||||||
|
if data_type == "pat_no":
|
||||||
|
data[Front_line[item]] = f"{int(row['pat_no']):010}"
|
||||||
|
elif data_type == "zhuyuanhao":
|
||||||
|
data[Front_line[item]] = f"{row['pat_no']}"
|
||||||
|
else:
|
||||||
|
data[Front_line[item]] = row[Front_line[item]]
|
||||||
|
front_line_data.append(data)
|
||||||
|
# 将字典转换为元组,并放入集合中去重
|
||||||
|
front_line_data = set(tuple(sorted(d.items())) for d in front_line_data)
|
||||||
|
# 将去重后的元组转换回字典,并放入新的列表
|
||||||
|
front_line_data = [dict(t) for t in front_line_data]
|
||||||
|
|
||||||
|
####### 获取所有患者检测信息(base_line,pat_no/pato_no.csv) #######
|
||||||
|
# 遍历所有患者(pat_no)
|
||||||
|
for pat_no in pat_no_col:
|
||||||
|
# 信息头生成
|
||||||
|
excel_head = []
|
||||||
|
for d in front_line_data:
|
||||||
|
if d["pat_no"] == pat_no:
|
||||||
|
for item in Front_line:
|
||||||
|
excel_head.append(d[Front_line[item]])
|
||||||
|
break
|
||||||
|
# 如果头文件为空
|
||||||
|
if excel_head == []:
|
||||||
|
Error(str(pat_no)+"的excel_head为空")
|
||||||
|
exit()
|
||||||
|
print("__处理患者头为__:", excel_head)
|
||||||
|
# 遍历所有rptunitid
|
||||||
|
for test in ALL_tests:
|
||||||
|
# 特定检查rptunitid
|
||||||
|
test_rptunitid = test['test_rptunitid']
|
||||||
|
if not isinstance(test_rptunitid, list) and not isinstance(test_rptunitid, tuple):
|
||||||
|
test_rptunitid = [test_rptunitid]
|
||||||
|
# 检查名
|
||||||
|
test_check_name = test['test_check_name']
|
||||||
|
# 检查项
|
||||||
|
test_check_list_all = test['test_check_list_all']
|
||||||
|
# 检查项_名
|
||||||
|
test_check_list = test['test_check_list']
|
||||||
|
if len(test_check_list_all) != len(test_check_list):
|
||||||
|
Error("test_check_list_all长度和test_check_list不同")
|
||||||
|
print(f"test_check_list_all:{test_check_list_all}\ntest_check_list:{test_check_list}")
|
||||||
|
exit()
|
||||||
|
# 检查结果所在列的列名
|
||||||
|
test_result_col_name = test['test_result_col_name']
|
||||||
|
# 存放检查结果的dict
|
||||||
|
test_check_result = {}
|
||||||
|
|
||||||
|
print("获取患者 ", test_check_name, " 检查结果")
|
||||||
|
|
||||||
|
### 打开patno/pat_no.csv文件获取更详细信息 ###
|
||||||
|
with open(osp.join(patno_dir, pat_no+'.csv'), "r", encoding='utf-8-sig') as file:
|
||||||
|
reader = csv.DictReader(file) # 读取文件
|
||||||
|
# 汇总特定检查行
|
||||||
|
test_rptunitid_rows = [ row for row in reader if row['rptunitid'] in test_rptunitid ]
|
||||||
|
print("患者检查 ", test_check_name, "次数为", len(test_rptunitid_rows))
|
||||||
|
|
||||||
|
# 遍历所有特定检查行,提取关键信息
|
||||||
|
rows_not_match = [] # 每一行内不匹配的内容
|
||||||
|
for i in range(len(test_rptunitid_rows)):
|
||||||
|
print("处理患者第", i+1, "次检查")
|
||||||
|
row_1 = test_rptunitid_rows[i]
|
||||||
|
sampled_dt = row_1['sampled_dt'] # 获取时间信息
|
||||||
|
###### basic信息头生成 ######
|
||||||
|
excel_basic = []
|
||||||
|
for item in Basic_line:
|
||||||
|
excel_basic.append(row_1[Basic_line[item]])
|
||||||
|
|
||||||
|
### 打开Patient_detail_infos/pat_no/文件 ###,获取特定检查文件存储路径
|
||||||
|
if data_type == "zhuyuanhao":
|
||||||
|
row_file_path = os.path.join(Patient_detail_infos_dir, pat_no, 'None' + "_" + row_1['reporttype'] + "_" + row_1['rptunitid'] + "_" + row_1['reportid'].replace("_","-") + "_" + row_1['rechkdt'].replace(" ","-").replace(":","-").replace("_","-") +".csv")
|
||||||
|
elif data_type == "pat_no":
|
||||||
|
row_file_path = os.path.join(Patient_detail_infos_dir, pat_no, pat_no + "_" + row_1['reporttype'] + "_" + row_1['rptunitid'] + "_" + row_1['reportid'].replace("_","-") + "_" + row_1['rechkdt'].replace(" ","-").replace(":","-").replace("_","-") +".csv")
|
||||||
|
with open(row_file_path, "r") as row_file:
|
||||||
|
row_reader_ = csv.DictReader(row_file) # 读取文件,迭代器只能读取一次
|
||||||
|
row_reader = []
|
||||||
|
for r in row_reader_:
|
||||||
|
row_reader.append(r)
|
||||||
|
# 寻找所有检查项的值
|
||||||
|
match = False # 检测内容中是否含有检测项目
|
||||||
|
rows_not_match = [] # 每一行内不匹配的内容
|
||||||
|
# 遍历所有行,查看对应检查结果
|
||||||
|
for row_2 in row_reader:
|
||||||
|
row_test_name_exist = False
|
||||||
|
row_test_name = row_2['rpt_itemname']
|
||||||
|
# 遍历所有待检查项
|
||||||
|
for j in range(len(test_check_list_all)):
|
||||||
|
# 检查项名称
|
||||||
|
test_result_name = test_check_list[j]
|
||||||
|
# 遍历所有完整版检查项目
|
||||||
|
test_checks = test_check_list_all[j]
|
||||||
|
if isinstance(test_checks, str):
|
||||||
|
test_checks = [test_checks]
|
||||||
|
for test_check in test_checks:
|
||||||
|
# print(test_check, row_2['rpt_itemname'],"___")
|
||||||
|
if match_re(row_test_name, test_check):# test_check == row_test_name: # 检测项目属于其中
|
||||||
|
match = True
|
||||||
|
row_test_name_exist = True
|
||||||
|
# temp临时存储变量,如果其为'.',则结果变为'None'
|
||||||
|
temp = row_2[test_result_col_name]
|
||||||
|
if (temp == '.' or temp == '') :
|
||||||
|
temp = 'None'
|
||||||
|
test_check_result[test_result_name] = temp
|
||||||
|
break
|
||||||
|
# 如果结果中存在row_test_name_exist的话,退出循环
|
||||||
|
if row_test_name_exist == True:
|
||||||
|
break
|
||||||
|
# 如果没有row_test_name_exist的话,将信息加入行信息中
|
||||||
|
if row_test_name_exist == False:
|
||||||
|
rows_not_match.append(row_test_name)
|
||||||
|
|
||||||
|
# 如果没有寻找到对应test_check_result的话,设置为Not_Find
|
||||||
|
for test_result_name in test_check_list:
|
||||||
|
if not test_result_name in test_check_result:
|
||||||
|
test_check_result[test_result_name] = 'Not_Find'
|
||||||
|
|
||||||
|
# 如果没有检测到相匹配内容,且不输出所有信息,continue
|
||||||
|
if (match == False and show_all_infos == False):
|
||||||
|
continue
|
||||||
|
# 进行进一步操作 ing...
|
||||||
|
|
||||||
|
|
||||||
|
# 抽取结果格式转换
|
||||||
|
excel_fromat_result = []
|
||||||
|
for test_item in test['test_check_list']:
|
||||||
|
excel_fromat_result.append(test_check_result[test_item])
|
||||||
|
# print("输出结果:", excel_fromat_result)
|
||||||
|
if show_not_match == True:
|
||||||
|
add_content_to_excel(result_save_pth, test['test_check_name'], excel_head + excel_basic + excel_fromat_result + rows_not_match)
|
||||||
|
else:
|
||||||
|
add_content_to_excel(result_save_pth, test['test_check_name'], excel_head + excel_basic + excel_fromat_result)
|
||||||
|
|
||||||
|
# 每处理一个患者数据,保存相关信息
|
||||||
|
save_excel()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
325
app/processors/V2-Every_Pat_File_convert_Lab_Test_data.py
Normal file
325
app/processors/V2-Every_Pat_File_convert_Lab_Test_data.py
Normal file
@@ -0,0 +1,325 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: UTF-8 -*-
|
||||||
|
import csv, sys, os, copy, re, argparse
|
||||||
|
import os.path as osp
|
||||||
|
from openpyxl import Workbook, load_workbook
|
||||||
|
from V2_Data import Front_line, Basic_line, ALL_tests
|
||||||
|
|
||||||
|
# 向特定excel的sheet中添加内容
|
||||||
|
workbook = None # 全局变量,初始值为 None
|
||||||
|
file_path_g = None
|
||||||
|
def add_content_to_excel(file_path, sheet_name, content):
|
||||||
|
global workbook, file_path_g # 声明 workbook 为全局变量
|
||||||
|
# 如果改换工作路径且workbook不为空
|
||||||
|
if file_path_g != file_path and not (workbook is None):
|
||||||
|
# 保存工作簿
|
||||||
|
workbook.save(file_path_g)
|
||||||
|
print("保存Excel工作表在:", file_path_g)
|
||||||
|
elif file_path_g != file_path:
|
||||||
|
try:
|
||||||
|
# 尝试加载现有的工作簿
|
||||||
|
workbook = load_workbook(file_path)
|
||||||
|
except FileNotFoundError:
|
||||||
|
# 如果文件不存在,则创建一个新的工作簿
|
||||||
|
workbook = Workbook()
|
||||||
|
file_path_g = file_path
|
||||||
|
|
||||||
|
if sheet_name not in workbook.sheetnames:
|
||||||
|
# 如果工作表不存在,则创建一个新的工作表
|
||||||
|
workbook.create_sheet(sheet_name)
|
||||||
|
|
||||||
|
# 选择指定的工作表
|
||||||
|
sheet = workbook[sheet_name]
|
||||||
|
|
||||||
|
# 向工作表添加内容
|
||||||
|
# 检查列表的第一个元素
|
||||||
|
if isinstance(content, list) and content and isinstance(content[0], list):
|
||||||
|
# "二维列表"
|
||||||
|
for row in content:
|
||||||
|
sheet.append(row)
|
||||||
|
elif isinstance(content, list):
|
||||||
|
# "一维列表"
|
||||||
|
sheet.append(content)
|
||||||
|
elif isinstance(content, str):
|
||||||
|
# "字符串"
|
||||||
|
sheet.append([content])
|
||||||
|
else:
|
||||||
|
print('add_content_to_excel输入参数为', content, '其不是列表、字符串')
|
||||||
|
|
||||||
|
def save_excel():
|
||||||
|
global workbook, file_path_g
|
||||||
|
if not (workbook is None):
|
||||||
|
# 保存工作簿
|
||||||
|
print("Excel工作表保存在:", file_path_g)
|
||||||
|
workbook.save(file_path_g)
|
||||||
|
|
||||||
|
# 判断字符串是否匹配正则表达式
|
||||||
|
def match_re(string, pattern):
|
||||||
|
if re.match(pattern, string):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 输出错误函数
|
||||||
|
def Error(output_str="Error:", error_dir="Error.txt"):
|
||||||
|
# 打开 error.txt 文件并写入字符串
|
||||||
|
with open(error_dir, "a+", encoding="utf-8-sig") as file:
|
||||||
|
# 将字符串输出到标准错误流 sys.stderr
|
||||||
|
file.write(output_str+'\n')
|
||||||
|
RED = '\033[91m'
|
||||||
|
RESET = '\033[0m'
|
||||||
|
print(RED+output_str+RESET)
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description='数据处理脚本参数解析')
|
||||||
|
# 1. 数据文件夹所在路径
|
||||||
|
parser.add_argument('--file_dir', type=str, required=True, help='数据文件夹所在路径')
|
||||||
|
# 2. 最终结果保存文件名
|
||||||
|
parser.add_argument('--result_save_file_name', type=str, required=True, help='最终结果保存文件名')
|
||||||
|
# 3. 是否输出不匹配内容【True/False】
|
||||||
|
parser.add_argument('--show_not_match', type=str, choices=['True', 'False'], required=True, help='是否输出不匹配内容')
|
||||||
|
# 4. 是否输出全部信息(包括全无项)【True/False】
|
||||||
|
parser.add_argument('--show_all_infos', type=str, choices=['True', 'False'], required=True, help='是否输出全部信息(包括全无项)')
|
||||||
|
# 5. 患者数据类型【pat_no / zhuyuanhao】
|
||||||
|
parser.add_argument('--data_type', type=str, choices=['pat_no', 'zhuyuanhao'], required=True, help='患者数据类型')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# 1.获取参数
|
||||||
|
file_dir = args.file_dir
|
||||||
|
result_save_file_name = args.result_save_file_name
|
||||||
|
data_type = args.data_type
|
||||||
|
# 将布尔类型的字符串转换为布尔值
|
||||||
|
show_not_match = args.show_not_match == 'True'
|
||||||
|
show_all_infos = args.show_all_infos == 'True'
|
||||||
|
|
||||||
|
# 2.1. 打开Patients_info.csv文件,遍历出所有有效患者
|
||||||
|
|
||||||
|
Patients_info_pth = osp.join(file_dir, 'Patients_info.csv')
|
||||||
|
# 检查文件是否存在
|
||||||
|
if not os.path.exists(Patients_info_pth):
|
||||||
|
print(f"{Patients_info_pth}不存在,请将 Patients_info.csv 移动到文件夹中")
|
||||||
|
sys.exit(1) # 退出程序
|
||||||
|
with open(Patients_info_pth, "r", encoding="utf-8-sig") as file:
|
||||||
|
reader_ = csv.DictReader(file)
|
||||||
|
reader_Patients_info = []
|
||||||
|
for r in reader_:
|
||||||
|
reader_Patients_info.append(r)
|
||||||
|
# 读取pat_no列数据
|
||||||
|
if data_type == "pat_no":
|
||||||
|
pat_no_col = [f"{int(row['pat_no']):010}" for row in reader_Patients_info]
|
||||||
|
elif data_type == "zhuyuanhao":
|
||||||
|
pat_no_col = [f"{row['pat_no']}" for row in reader_Patients_info]
|
||||||
|
else:
|
||||||
|
print("数据类型需要为pat_no或zhuyuanhao")
|
||||||
|
pat_no_col = list(set(pat_no_col)) # 去除数组中重复内容
|
||||||
|
|
||||||
|
# 2.2. 获取所有患者头部信息(Front_line)
|
||||||
|
front_line_data = []
|
||||||
|
# 遍历所有患者(pat_no)
|
||||||
|
for row in reader_Patients_info:
|
||||||
|
data = {}
|
||||||
|
for item in Front_line:
|
||||||
|
if Front_line[item] == 'pat_no':
|
||||||
|
if data_type == "pat_no":
|
||||||
|
data[Front_line[item]] = f"{int(row['pat_no']):010}"
|
||||||
|
elif data_type == "zhuyuanhao":
|
||||||
|
data[Front_line[item]] = f"{row['pat_no']}"
|
||||||
|
else:
|
||||||
|
data[Front_line[item]] = row[Front_line[item]]
|
||||||
|
front_line_data.append(data)
|
||||||
|
# 将字典转换为元组,并放入集合中去重
|
||||||
|
front_line_data = set(tuple(sorted(d.items())) for d in front_line_data)
|
||||||
|
# 将去重后的元组转换回字典,并放入新的列表
|
||||||
|
front_line_data = [dict(t) for t in front_line_data]
|
||||||
|
|
||||||
|
# 3. 生成信息
|
||||||
|
for pat_no in os.listdir(file_dir): # 遍历 file_dir 下的所有文件和文件夹
|
||||||
|
|
||||||
|
# 向特定excel的sheet中添加内容
|
||||||
|
workbook = None # 全局变量,初始值为 None
|
||||||
|
file_path_g = None
|
||||||
|
|
||||||
|
# 获取文件夹的完整路径
|
||||||
|
pat_file_dir = os.path.join(file_dir, pat_no) # 获取完整路径
|
||||||
|
result_save_pth = osp.join(pat_file_dir, pat_no+"_"+result_save_file_name+".xlsx")
|
||||||
|
|
||||||
|
if os.path.isdir(pat_file_dir): # 判断是否是文件夹
|
||||||
|
print(f"处理文件夹: {pat_file_dir}")
|
||||||
|
If_continue = False
|
||||||
|
# Tests_List目录的路径
|
||||||
|
patno_pth = osp.join(pat_file_dir, pat_no+"_检测汇总.csv")
|
||||||
|
if not osp.exists(patno_pth):
|
||||||
|
Error(f"{pat_no+'_检测汇总.csv'} 在 {pat_no} 文件夹中不存在", error_dir=osp.join(pat_file_dir, f"{pat_no+'_检测汇总.csv'} 在文件夹中不存在.txt"))
|
||||||
|
If_continue = True
|
||||||
|
# Tests_List目录的路径
|
||||||
|
Patient_detail_infos_dir = osp.join(pat_file_dir, pat_no+'_具体检测')
|
||||||
|
if not osp.exists(Patient_detail_infos_dir):
|
||||||
|
Error(f"{pat_no+'_具体检测'} 在 {pat_no} 文件夹中不存在", error_dir=osp.join(pat_file_dir, f"{pat_no+'_具体检测.csv'} 在文件夹中不存在.txt"))
|
||||||
|
If_continue = True
|
||||||
|
RED = '\033[91m'
|
||||||
|
RESET = '\033[0m'
|
||||||
|
if If_continue == True:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
print("")
|
||||||
|
print(f"※当前住院号为:{pat_no}")
|
||||||
|
|
||||||
|
# 删除Error文件
|
||||||
|
error_dir=osp.join(pat_file_dir, "Error.txt")
|
||||||
|
if os.path.exists(error_dir):
|
||||||
|
os.remove(error_dir)
|
||||||
|
print("删除Error文件:", error_dir)
|
||||||
|
|
||||||
|
# 生成基本存储信息文件
|
||||||
|
# 如果有文件则将其删除
|
||||||
|
if os.path.exists(result_save_pth):
|
||||||
|
os.remove(result_save_pth)
|
||||||
|
# 生成抬头信息
|
||||||
|
front_content=[] # 抬头个人信息
|
||||||
|
for front in Front_line:
|
||||||
|
front_content.append(front)
|
||||||
|
# 生成basic存储信息
|
||||||
|
basic_content=[] # basic个人信息
|
||||||
|
for basic in Basic_line:
|
||||||
|
basic_content.append(basic)
|
||||||
|
# 生成各个检测sheet:head+basic+items+[not_match]
|
||||||
|
for test in ALL_tests: # 各项检测信息
|
||||||
|
# 生成未匹配检查内容
|
||||||
|
if show_not_match == True:
|
||||||
|
add_content_to_excel(result_save_pth, test['test_check_name'], front_content + basic_content + test["test_check_list"] + ['未匹配检测内容'])
|
||||||
|
else:
|
||||||
|
add_content_to_excel(result_save_pth, test['test_check_name'], front_content + basic_content + test["test_check_list"])
|
||||||
|
|
||||||
|
# 信息头生成
|
||||||
|
excel_head = []
|
||||||
|
for d in front_line_data:
|
||||||
|
if d["pat_no"] == pat_no:
|
||||||
|
for item in Front_line:
|
||||||
|
excel_head.append(d[Front_line[item]])
|
||||||
|
break
|
||||||
|
# 如果头文件为空
|
||||||
|
if excel_head == []:
|
||||||
|
Error(str(pat_no)+"的excel_head为空", error_dir=osp.join(pat_file_dir, "Error.txt"))
|
||||||
|
exit()
|
||||||
|
|
||||||
|
# 读取pat_no列数据
|
||||||
|
if data_type == "pat_no":
|
||||||
|
pat_no = f"{int(pat_no):010}"
|
||||||
|
elif data_type == "zhuyuanhao":
|
||||||
|
pat_no = f"{pat_no}"
|
||||||
|
else:
|
||||||
|
print("数据类型需要为pat_no或zhuyuanhao")
|
||||||
|
|
||||||
|
####### 获取所有患者检测信息(base_line,pat_no/pato_no.csv) #######
|
||||||
|
# 遍历所有患者(pat_no)
|
||||||
|
|
||||||
|
# 遍历所有rptunitid
|
||||||
|
for test in ALL_tests:
|
||||||
|
# 特定检查rptunitid
|
||||||
|
test_rptunitid = test['test_rptunitid']
|
||||||
|
if not isinstance(test_rptunitid, list) and not isinstance(test_rptunitid, tuple):
|
||||||
|
test_rptunitid = [test_rptunitid]
|
||||||
|
# 检查名
|
||||||
|
test_check_name = test['test_check_name']
|
||||||
|
# 检查项
|
||||||
|
test_check_list_all = test['test_check_list_all']
|
||||||
|
# 检查项_名
|
||||||
|
test_check_list = test['test_check_list']
|
||||||
|
if len(test_check_list_all) != len(test_check_list):
|
||||||
|
Error("test_check_list_all长度和test_check_list不同", error_dir=osp.join(pat_file_dir, "Error.txt"))
|
||||||
|
print(f"test_check_list_all:{test_check_list_all}\ntest_check_list:{test_check_list}")
|
||||||
|
exit()
|
||||||
|
# 检查结果所在列的列名
|
||||||
|
test_result_col_name = test['test_result_col_name']
|
||||||
|
# 存放检查结果的dict
|
||||||
|
test_check_result = {}
|
||||||
|
|
||||||
|
print("获取患者 ", test_check_name, " 检查结果")
|
||||||
|
|
||||||
|
### 打开patno/pat_no.csv文件获取更详细信息 ###
|
||||||
|
with open(patno_pth, "r", encoding="utf-8-sig") as file:
|
||||||
|
reader = csv.DictReader(file) # 读取文件
|
||||||
|
# 汇总特定检查行
|
||||||
|
test_rptunitid_rows = [ row for row in reader if row['rptunitid'] in test_rptunitid ]
|
||||||
|
print("患者检查 ", test_check_name, "次数为", len(test_rptunitid_rows))
|
||||||
|
|
||||||
|
# 遍历所有特定检查行,提取关键信息
|
||||||
|
rows_not_match = [] # 每一行内不匹配的内容
|
||||||
|
for i in range(len(test_rptunitid_rows)):
|
||||||
|
print("处理患者第", i+1, "次检查")
|
||||||
|
row_1 = test_rptunitid_rows[i]
|
||||||
|
sampled_dt = row_1['sampled_dt'] # 获取时间信息
|
||||||
|
###### basic信息头生成 ######
|
||||||
|
excel_basic = []
|
||||||
|
for item in Basic_line:
|
||||||
|
excel_basic.append(row_1[Basic_line[item]])
|
||||||
|
|
||||||
|
### 打开Patient_detail_infos/pat_no/文件 ###,获取特定检查文件存储路径
|
||||||
|
if data_type == "zhuyuanhao":
|
||||||
|
row_file_path = os.path.join(Patient_detail_infos_dir, 'None' + "_" + row_1['reporttype'] + "_" + row_1['rptunitid'] + "_" + row_1['reportid'].replace("_","-") + "_" + row_1['rechkdt'].replace(" ","-").replace(":","-").replace("_","-") +".csv")
|
||||||
|
elif data_type == "pat_no":
|
||||||
|
row_file_path = os.path.join(Patient_detail_infos_dir, pat_no + "_" + row_1['reporttype'] + "_" + row_1['rptunitid'] + "_" + row_1['reportid'].replace("_","-") + "_" + row_1['rechkdt'].replace(" ","-").replace(":","-").replace("_","-") +".csv")
|
||||||
|
with open(row_file_path, "r", encoding="utf-8-sig") as row_file:
|
||||||
|
row_reader_ = csv.DictReader(row_file) # 读取文件,迭代器只能读取一次
|
||||||
|
row_reader = []
|
||||||
|
for r in row_reader_:
|
||||||
|
row_reader.append(r)
|
||||||
|
# 寻找所有检查项的值
|
||||||
|
match = False # 检测内容中是否含有检测项目
|
||||||
|
rows_not_match = [] # 每一行内不匹配的内容
|
||||||
|
# 遍历所有行,查看对应检查结果
|
||||||
|
for row_2 in row_reader:
|
||||||
|
row_test_name_exist = False
|
||||||
|
row_test_name = row_2['rpt_itemname']
|
||||||
|
# 遍历所有待检查项
|
||||||
|
for j in range(len(test_check_list_all)):
|
||||||
|
# 检查项名称
|
||||||
|
test_result_name = test_check_list[j]
|
||||||
|
# 遍历所有完整版检查项目
|
||||||
|
test_checks = test_check_list_all[j]
|
||||||
|
if isinstance(test_checks, str):
|
||||||
|
test_checks = [test_checks]
|
||||||
|
for test_check in test_checks:
|
||||||
|
# print(test_check, row_2['rpt_itemname'],"___")
|
||||||
|
if match_re(row_test_name, test_check):# test_check == row_test_name: # 检测项目属于其中
|
||||||
|
match = True
|
||||||
|
row_test_name_exist = True
|
||||||
|
# temp临时存储变量,如果其为'.',则结果变为'None'
|
||||||
|
temp = row_2[test_result_col_name]
|
||||||
|
if (temp == '.' or temp == '') :
|
||||||
|
temp = 'None'
|
||||||
|
test_check_result[test_result_name] = temp
|
||||||
|
break
|
||||||
|
# 如果结果中存在row_test_name_exist的话,退出循环
|
||||||
|
if row_test_name_exist == True:
|
||||||
|
break
|
||||||
|
# 如果没有row_test_name_exist的话,将信息加入行信息中
|
||||||
|
if row_test_name_exist == False:
|
||||||
|
rows_not_match.append(row_test_name)
|
||||||
|
|
||||||
|
# 如果没有寻找到对应test_check_result的话,设置为Not_Find
|
||||||
|
for test_result_name in test_check_list:
|
||||||
|
if not test_result_name in test_check_result:
|
||||||
|
test_check_result[test_result_name] = 'Not_Find'
|
||||||
|
|
||||||
|
# 如果没有检测到相匹配内容,且不输出所有信息,continue
|
||||||
|
if (match == False and show_all_infos == False):
|
||||||
|
continue
|
||||||
|
# 进行进一步操作 ing...
|
||||||
|
|
||||||
|
|
||||||
|
# 抽取结果格式转换
|
||||||
|
excel_fromat_result = []
|
||||||
|
for test_item in test['test_check_list']:
|
||||||
|
excel_fromat_result.append(test_check_result[test_item])
|
||||||
|
# print("输出结果:", excel_fromat_result)
|
||||||
|
if show_not_match == True:
|
||||||
|
add_content_to_excel(result_save_pth, test['test_check_name'], excel_head + excel_basic + excel_fromat_result + rows_not_match)
|
||||||
|
else:
|
||||||
|
add_content_to_excel(result_save_pth, test['test_check_name'], excel_head + excel_basic + excel_fromat_result)
|
||||||
|
|
||||||
|
# 每处理一个患者数据,保存相关信息
|
||||||
|
save_excel()
|
||||||
54
app/processors/V2_Data.py
Normal file
54
app/processors/V2_Data.py
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
global Front_line
|
||||||
|
global Basic_line
|
||||||
|
global ALL_tests
|
||||||
|
# 3.遍历所有患者打开patno文件夹中的patno.csv
|
||||||
|
# 获取患者头部信息(提取于Patients_info.csv)
|
||||||
|
Front_line = {'姓名':'pat_name', '住院号':'pat_no'}
|
||||||
|
# 获取患者检测基本信息(提取于patno文件夹)
|
||||||
|
Basic_line = {'采样时间': 'sampled_dt', '检测原因':'req_reason'}
|
||||||
|
# 所有检测具体信息(提取于Patient_detail_infos文件夹)
|
||||||
|
# 一个检查包括:检测rptunitids、检查名(自主命名)、检查项、检查结果所在列、存放结果dict
|
||||||
|
#{'test_rptunitid':[str(X), str(X)], 'test_check_name':'XXX', 'test_check_list':["XXX", "XXX", ], 'test_check_list_all':["XXX", "XXX", ], 'test_result_col_name':"result_str"},
|
||||||
|
ALL_tests = [# 血细胞 # (1):血细胞分析+五分类;(2):血细胞分析+五分类;(4):血细胞五分类+CRP;东院区:(106):血细胞分析+五分类
|
||||||
|
{'test_rptunitid':[str(1), str(2), str(4), str(106)], 'test_check_name':'血细胞', 'test_check_list':["血红蛋白", "红细胞压积", "平均红细胞体积", "平均血红蛋白含量", "平均血红蛋白浓度", "红细胞宽度-CV值", "红细胞宽度-SD值", "血小板计数", "血小板分布宽度", "平均血小板体积", "大血小板比率", "血小板压积", "淋巴细胞计数", "单核细胞计数", "中性粒细胞计数", "嗜酸细胞计数", "嗜碱细胞计数", "淋巴细胞百分比", "单核细胞百分比", "中性粒细胞百分比", "嗜酸细胞百分比", "嗜碱细胞百分比", "白细胞计数", "红细胞计数", "CRP检验=====", "C反应蛋白", "超敏CRP", ], 'test_check_list_all':["血红蛋白", "红细胞压积", "平均红细胞体积", "平均血红蛋白含量", "平均血红蛋白浓度", "红细胞宽度-CV值", "红细胞宽度-SD值", "血小板计数", "血小板分布宽度", "平均血小板体积", "大血小板比率", "血小板压积", "淋巴细胞计数", "单核细胞计数", "中性粒细胞计数", "嗜酸细胞计数", "嗜碱细胞计数", "淋巴细胞百分比", "单核细胞百分比", "中性粒细胞百分比", "嗜酸细胞百分比", ["嗜碱细胞百分比", "嗜碱细胞%"], ["白细胞计数", "白细胞"], "红细胞计数", "CRP检验=====", "C反应蛋白", ["超敏CRP", "超敏C反应蛋白"], ], 'test_result_col_name':"result_str"},
|
||||||
|
# 凝血 # (3):凝血六项;(110):东院区;(90):凝血和血小板功能监测
|
||||||
|
{'test_rptunitid':[str(3), str(110),str(90)], 'test_check_name':'凝血', 'test_check_list':["凝血酶原时间", "凝血酶原活动度", "血浆凝血酶原时间比值", "凝血酶原国际标准化比值", "活化部分凝血活酶时间", "活化部分凝血活酶比值", "凝血酶时间", "凝血酶时间比值", "纤维蛋白原含量", "D-二聚体测定", "纤维蛋白原降解产物", "凝血酶生成时间","凝血速率","血小板功能"],\
|
||||||
|
'test_check_list_all':["凝血酶原时间*", ["凝血酶原活动度", r"凝血酶原活度\(%\)"], ["凝血酶原比值", "血浆凝血酶原时间比值"], ["凝血酶原标准化比值", "凝血酶原国际标准化比值"], ["活化部分凝血活酶时间*", "活化部分凝血酶时间*"], "活化部分凝血活酶比值", "凝血酶时间", "凝血酶时间比值", "纤维蛋白原含量", [r"D-二聚体\(sysmex\)", "D-二聚体测定*"], [r"纤维蛋白\(原\)降解产物", "纤维蛋白原降解产物"], "凝血酶生成时间","凝血速率","血小板功能"], 'test_result_col_name':"result_str"},
|
||||||
|
# 肝功 # (5):平诊肝功十四项+平诊电解质八项+平诊肾功七项;(20)急诊肝功十二项_急诊肾功五项[复]_急诊电解质七项[复];东院区:(108):传染性指标检测八项
|
||||||
|
{'test_rptunitid':[str(5), str(20), str(108)], 'test_check_name':'肝功', 'test_check_list':["谷草转氨酶", "谷丙转氨酶", "谷草/谷丙", "碱性磷酸酶", "γ谷氨酰氨转肽酶", "总胆红素", "直接胆红素", "间接胆红素", "胆碱脂酶", "总胆固醇", "总蛋白", "白蛋白", "球蛋白", "白球比", "总胆汁酸", "a-L-岩藻糖苷酶", "前白蛋白", "超氧化物歧化酶", "尿素", "肌酐", "胱抑素C", "葡萄糖", "尿酸", "钾", "钠", "氯", "磷", "钙", "镁", "二氧化碳结合率", "离子间隙", "糖化白蛋白", "视黄醇结合蛋白", "eGFR(CKD-EPI)", "a-l岩藻糖苷酶", "超氧化物歧化酶", "eGFR(MDRD)", r"eGFR单位ml/min/1.73m^2", "8597", "乳酸测定", "乳酸脱氢酶", "羟丁酸脱氢酶", "肌酸激酶", "肌酸激酶同工酶", "载脂蛋白A", "载脂蛋白B", "载脂蛋白E", "脂蛋白(a)", "缺血修饰白蛋白", "甘油三酯", "高密度脂蛋白", "低密度脂蛋白", ], \
|
||||||
|
'test_check_list_all':["谷草转氨酶", "谷丙转氨酶", "谷草/谷丙", "碱性磷酸酶", ["γ谷氨酰氨转肽酶", "γ-谷氨酰转肽酶"], "总胆红素", "直接胆红素", "间接胆红素", "胆碱脂酶", "总胆固醇", "总蛋白", "白蛋白", "球蛋白", "白球比", "总胆汁酸", "a-L-岩藻糖苷酶", "前白蛋白", "超氧化物歧化酶", "尿素", "肌酐", "胱抑素C", "葡萄糖", "尿酸", "钾", "钠", "氯", "磷", "钙", "镁", "二氧化碳结合率", "离子间隙", "糖化白蛋白", "视黄醇结合蛋白", r"eGFR\(CKD-EPI\)", "a-l岩藻糖苷酶", "超氧化物歧化酶", r"eGFR\(MDRD\)", r"eGFR单位ml/min/1.73m\^2", "8597", "乳酸测定", "乳酸脱氢酶", "羟丁酸脱氢酶", "肌酸激酶", "肌酸激酶同工酶", "载脂蛋白A", "载脂蛋白B", "载脂蛋白E", "脂蛋白(a)", "缺血修饰白蛋白", "甘油三酯", "高密度脂蛋白", "低密度脂蛋白", ], 'test_result_col_name':"result_str"},
|
||||||
|
# 各类肿瘤标志物 # (6):各类肿瘤标志物,e.g.肿瘤标志物肺癌六项[复]、肿瘤标志物十项(男);东院区:(108):肿瘤标志物肺癌六项[复]
|
||||||
|
{'test_rptunitid':[str(6), str(108)], 'test_check_name':'各类肿瘤标志物', 'test_check_list':["胃泌素释放肽前体(罗氏)", "鳞状上皮细胞癌抗原(罗氏)", "癌胚抗原", "甲胎蛋白", "糖类抗原125", "糖类抗原199", "糖类抗原724", "细胞角蛋白19片段", "神经元特异性烯醇化酶测定", "总前列腺特异性抗原", "游离前列腺抗原", "游离/总", "糖类抗原153","人附睾蛋白","绝经前 ROMA","绝经后 ROMA","铁蛋白","叶酸","维生素B12","高尔基体蛋白73测定","胃蛋白酶原Ⅰ","胃蛋白酶原Ⅱ","胃蛋白酶原Ⅰ/Ⅱ","降钙素","甲状腺球蛋白"],\
|
||||||
|
'test_check_list_all':[r"胃泌素释放肽前体\(罗氏\)", ["鳞状上皮细胞癌相关抗原", r"鳞状上皮细胞癌抗原\(罗氏\)"], "癌胚抗原", "甲胎蛋白", "糖类抗原125", "糖类抗原199", "糖类抗原724", "细胞角蛋白19片段", "神经元特异性烯醇化酶测定", "总前列腺特异性抗原", "游离前列腺抗原", "游离/总", "糖类抗原153","人附睾蛋白","绝经前 ROMA","绝经后 ROMA","铁蛋白","叶酸","维生素B12","高尔基体蛋白73测定","胃蛋白酶原Ⅰ","胃蛋白酶原Ⅱ","胃蛋白酶原Ⅰ/Ⅱ","降钙素","甲状腺球蛋白"], 'test_result_col_name':"result_str"},
|
||||||
|
# 七抗 # (10):肺癌七种自身抗体检测
|
||||||
|
{'test_rptunitid':str(10), 'test_check_name':'七抗', 'test_check_list':["p53自身抗体", "PGP9.5自身抗体", "SOX2自身抗体", "GAGE7自身抗体", "GBU4-5自身抗体", "MAGE A1自身抗体", "CAGE自身抗体", ], 'test_check_list_all':["p53自身抗体", "PGP9.5自身抗体", "SOX2自身抗体", "GAGE7自身抗体", "GBU4-5自身抗体", "MAGE A1自身抗体", "CAGE自身抗体", ], 'test_result_col_name':"result_str"},
|
||||||
|
# 传染指标 # (52):传染指标八项-急诊;(53):传染性指标检测八项[复];(23):传染性指标检测八项[复];东院区:(108):传染性指标检测八项[复]
|
||||||
|
{'test_rptunitid':[str(52), str(53), str(108), str(23)], 'test_check_name':'传染指标', 'test_check_list':["乙肝表面抗原定量", "乙肝表面抗体定量", "乙肝e抗原", "乙肝e抗体", "乙肝核心抗体", "丙型肝炎抗体", "梅毒螺旋体抗体", "人类免疫缺陷病毒", ], 'test_check_list_all':["乙肝表面抗原定量", "乙肝表面抗体定量", "乙肝e抗原", "乙肝e抗体", "乙肝核心抗体", "丙型肝炎抗体", ["螺旋体特异抗体", "梅毒螺旋体抗体"], ["人免疫缺陷病毒", "人类免疫缺陷病毒"], ], 'test_result_col_name':"result_str"},
|
||||||
|
# 血气分析+生化分析 # (16):血气分析+生化六项[复]/血气分析3, (49):血气分析+生化六项[复], (50):血气分析+生化五项[复], (73/74):血气分析+生化十项[复], (89):血气分析+生化六项[复], (112):血气分析/血气分析+生化七项[复], (158):血气分析+生化六项[复];(42):血气分析+生化六项[复]
|
||||||
|
{'test_rptunitid':[str(16), str(49), str(50), str(73), str(74), str(89), str(112), str(158),str(42)], 'test_check_name':'血气分析+生化分析', 'test_check_list':["体温", "吸氧流量", "酸碱度", "氧分压", "二氧化碳分压", "二氧化碳总量", "红细胞压积", "总血红蛋白", "氧饱和度", "Na+钠离子浓度", "钾离子浓度", "钙离子浓度", "氯离子浓度", "标准离子钙", "氢离子浓度", "酸碱度计算值", "PCO2分压计算值", "p氧分压计算值", "pO2(A-a)(T)_r", "pO2(a/A)(T)_r", "呼吸指数计算值", "pO2(T)/FIO2_r", "氢离子浓度", "HCO3-act_r", "HCO3-std_r", "BE(ecf)_r", "血液缓冲碱", "ctCO2", "pO2(A-a)_r", "pO2(a/A)_r", "呼吸指数", "氧和指数", "阴离子间隙", "渗透压", "血糖", "乳酸", "实际碳酸氢盐", "标准碳酸氢盐", "实际碱剩余", "标准碱剩余", "细胞外液剩余碱","氧合血红蛋白","一氧化碳血红蛋白", "还原血红蛋白","高铁血红蛋白", "总胆红素", "A-aDO2", "pAO2", "paO2/pAO2", "50%饱和度氧分压", "动脉血氧含量", "肺泡动脉氧分压差", "动脉氧分压与肺泡氧分压之比", "pCO2(T)", "pO2(T)", "PH(T)", "吸氧浓度","平均肺泡氧分压"],\
|
||||||
|
'test_check_list_all':["体温", "吸氧流量", "酸碱度", "氧分压", "二氧化碳分压", "二氧化碳总量", "红细胞压积", "总血红蛋白", "氧饱和度", ["Na\+钠离子浓度", "钠离子"], ["钾离子浓度","钾离子"], ["钙离子浓度","钙离子"], ["氯离子浓度","氯离子"], ["标准离子钙","PH=7.4的钙"], "氢离子浓度", "酸碱度计算值", "PCO2分压计算值", "p氧分压计算值", r"pO2\(A-a\)\(T\)_r", r"pO2\(a/A\)\(T\)_r", "呼吸指数计算值", r"pO2\(T\)/FIO2_r", "氢离子浓度", "HCO3-act_r", "HCO3-std_r", r"BE\(ecf\)_r", "血液缓冲碱", "ctCO2", r"pO2\(A-a\)_r", r"pO2\(a/A\)_r", "呼吸指数", "氧和指数", "阴离子间隙", "渗透压", "血糖", "乳酸", ["实际碳酸氢盐","血浆碳酸氢盐浓度"], "标准碳酸氢盐", ["血液剩余碱","实际碱剩余"], "标准碱剩余", "细胞外液剩余碱","氧合血红蛋白","一氧化碳血红蛋白", "还原血红蛋白","高铁血红蛋白", "总胆红素", "A-aDO2", "pAO2", "paO2/pAO2", "50%饱和度氧分压", "动脉血氧含量", "肺泡动脉氧分压差", "动脉氧分压与肺泡氧分压之比", r"pCO2\(T\)", r"pO2\(T\)", r"PH\(T\)", "吸氧浓度","平均肺泡氧分压"], 'test_result_col_name':"result_str"},
|
||||||
|
# 感染指标 # (77)/(92)/(113)/(126)/(77)/(82)/:新型冠状病毒核酸检测[复]; (75):新型冠状病毒抗体; (25):新冠核酸检测[复]/乙肝病毒DNA含量/结核杆菌定量测定;str(121)/str(37):一般细菌涂片检查;str(111):乙型肝炎DNA定量测定;str(29):免疫8项;str(34):内毒素+D葡聚糖测定,str(38)/(116):红细胞沉降率测定;str(36):结核Xpert鉴定及耐药[复];str(10):结核感染T细胞检测;str(24):自身抗体谱测定(18项);str(23):血清肌钙蛋白I测定
|
||||||
|
{'test_rptunitid':[str(77),str(25),str(92),str(113),str(126),str(75),str(77),str(82),str(30),str(121),str(37),str(111),str(29),str(34),str(38),str(116),str(36),str(10)], 'test_check_name':'感染指标', 'test_check_list':["新型冠状病毒抗体IgG","新型冠状病毒抗体IgM", "新型冠状病毒核酸检测","新型冠状病毒核酸混检", "乙肝病毒DNA含量","结核杆菌定量测定", "EB病毒定量测定","巨细胞病毒定量测定","白细胞","上皮细胞","革兰氏阳性球菌","革兰氏阴性球菌","革兰氏阴性球杆菌","革兰氏阳性杆菌","革兰氏阴性杆菌","真菌菌丝" ,"真菌孢子","抗酸染色", "HPV6","HPV11","抗链球菌溶血素O定量测定","KAP轻链","LAM轻链","免疫球蛋白IgE","免疫球蛋白G","免疫球蛋白M","免疫球蛋白A","补体C3","补体C4","类风湿因子","C反应蛋白","G-脂多糖","1-3-β-D葡聚糖","抗心磷脂IgG抗体","EB病毒核心抗原IgG抗体","EB病毒衣壳抗原IgG抗体","EB病毒早期抗原IgM抗体","EB病毒衣壳抗原IgM抗体","红细胞沉降率测定","降钙素原",r"淋巴细胞培养+干扰素\(基础水平N\)",r"结核杆菌γ干扰素释放试验\(T-N\)",r"结核杆菌阳性对照反应\(M-N\)",r"结核杆菌特异性细胞免疫反应提示", "抗dsDNA抗体","抗核小体抗体","抗组蛋白抗体","抗SmD1抗体","抗PCNA抗体","抗核糖体P蛋白测定","抗SSA/Ro60kD抗体","抗SSA/Ro52kD抗体","抗ssb抗体","抗CENPB抗体","抗Scl-70抗体","抗U1-snRNP抗体","抗Jo-1抗体","抗PM-Scl抗体","抗Ku抗体","抗AMA-M2抗体","抗Mi-2抗体",r"抗核抗体\(1:80\)","高敏肌钙蛋白I" ],\
|
||||||
|
'test_check_list_all':["新型冠状病毒抗体IgG","新型冠状病毒抗体IgM",["新型冠状病毒核酸检测", "新型冠状病毒核酸快速检测"], r"新型冠状病毒核酸检测\(混检\)",["乙肝病毒DNA含量","乙型肝炎病毒DNA定量"],"结核杆菌定量测定", "EB病毒定量测定","巨细胞病毒定量测定","白细胞","上皮细胞",["革兰氏阳性球菌","革兰阳性球菌"],["革兰阴性球菌","革兰氏阴性球菌"],"革兰氏阴性球杆菌",["革兰阳性杆菌","革兰氏阳性杆菌"],["革兰阴性杆菌","革兰氏阴性杆菌"],"真菌菌丝","真菌孢子","抗酸染色","HPV6","HPV11","抗链球菌溶血素O定量测定","KAP轻链","LAM轻链","免疫球蛋白IgE","免疫球蛋白G","免疫球蛋白M","免疫球蛋白A","补体C3","补体C4","类风湿因子","C反应蛋白","G-脂多糖","1-3-β-D葡聚糖","抗心磷脂IgG抗体","EB病毒核心抗原IgG抗体","EB病毒衣壳抗原IgG抗体","EB病毒早期抗原IgM抗体","EB病毒衣壳抗原IgM抗体","红细胞沉降率测定","降钙素原",r"淋巴细胞培养+干扰素\(基础水平N\)",r"结核杆菌γ干扰素释放试验\(T-N\)",r"结核杆菌阳性对照反应\(M-N\)",r"结核杆菌特异性细胞免疫反应提示","抗dsDNA抗体","抗核小体抗体","抗组蛋白抗体","抗SmD1抗体","抗PCNA抗体","抗核糖体P蛋白测定","抗SSA/Ro60kD抗体","抗SSA/Ro52kD抗体","抗ssb抗体","抗CENPB抗体","抗Scl-70抗体","抗U1-snRNP抗体","抗Jo-1抗体","抗PM-Scl抗体","抗Ku抗体","抗AMA-M2抗体","抗Mi-2抗体",r"抗核抗体\(1:80\)","高敏肌钙蛋白I"], 'test_result_col_name':"result_str"},
|
||||||
|
# 基因检测指标 # (41):CYP2C19基因检测[复]
|
||||||
|
{'test_rptunitid':[str(41)], 'test_check_name':'基因检测指标', 'test_check_list':[r"GG_681GG\)",r"GG_681GA\)",r"GA_681GG\)",r"GG_681AA\)",r"AA_681GG\)",r"GA_681GA\)" ],\
|
||||||
|
'test_check_list_all':[r"\*1/\*1\(636", r"\*1/\*2\(636",r"\*1/\*3\(636", r"\*2/\*2\(636",r"\*3/\*3\(636", r"\*2/\*3\(636", ], 'test_result_col_name':"result_ref"},
|
||||||
|
# 心衰系列 # str(20):B型前脑尿钠肽, str(16):B型前脑尿钠肽检测(Pro-BN_降钙素原检;str(108):B型尿钠肽检测(BNP)
|
||||||
|
{'test_rptunitid':[str(20),str(16)], 'test_check_name':'心衰系列', 'test_check_list':['B型前脑尿钠肽','高敏肌钙蛋白T'],\
|
||||||
|
'test_check_list_all':['B型前脑尿钠肽','高敏肌钙蛋白T'], 'test_result_col_name':"result_str"},
|
||||||
|
# 普通指标 # str(79),str(51):卡式血型鉴定;str(12):肝纤维化指标(五项);str(22)/(33):胃液常规检查;str(161):甲功五项(化学发光法)[复]
|
||||||
|
{'test_rptunitid':[str(79),str(51),str(12),str(22),str(33),str(161)], 'test_check_name':'普通指标', 'test_check_list':['ABO正定型','ABO反定型','ABO血型',r'Rh\(D\)血型','TPO过氧化物酶自身抗体','T4甲状腺素','T3三碘甲腺原氨酸','FT4游离甲状腺素','FT3游离三碘甲腺原氨酸','h-TSH促甲状腺激素','TGAB甲状腺球蛋白抗体','TMAB甲状腺微粒体抗体','隐血'],\
|
||||||
|
'test_check_list_all':['ABO正定型','ABO反定型','ABO血型',r'Rh\(D\)血型','TPO过氧化物酶自身抗体','T4甲状腺素','T3三碘甲腺原氨酸','FT4游离甲状腺素','FT3游离三碘甲腺原氨酸','h-TSH促甲状腺激素','TGAB甲状腺球蛋白抗体','TMAB甲状腺微粒体抗体','隐血'], 'test_result_col_name':"result_str"},
|
||||||
|
# 免疫系列 # str(14):'促甲状腺素受体抗体测定
|
||||||
|
{'test_rptunitid':[str(14)], 'test_check_name':'免疫系列', 'test_check_list':['甲状腺球蛋白','促甲状腺激素','血清甲状腺素','血清三碘甲状原氨酸','血清游离甲状腺素','血清游离三碘甲状原氨酸','抗甲状腺球蛋白抗体','抗甲状腺过氧化物酶抗体'],\
|
||||||
|
'test_check_list_all':['甲状腺球蛋白','促甲状腺激素','血清甲状腺素','血清三碘甲状原氨酸','血清游离甲状腺素','血清游离三碘甲状原氨酸','抗甲状腺球蛋白抗体','抗甲状腺过氧化物酶抗体'], 'test_result_col_name':"result_str"},
|
||||||
|
# 特殊指标 # str(10):血管内皮生长因子检测;str(46):
|
||||||
|
{'test_rptunitid':[str(10)], 'test_check_name':'特殊指标', 'test_check_list':['血管内皮生长因子_血管内皮生长因子检测',r'Th1/Th2/Th17亚群十二项细胞因子_白介素\(IL\)检测\(IL-1β\)',r'白介素(IL)检测\(IL-2\)',r'白介素(IL)检测\(IL-4\)',r'白介素(IL)检测\(IL-5\)',r'白介素(IL)检测\(IL-6\)',r'白介素(IL)检测\(IL-8\)',r'白介素(IL)检测\(IL-10\)',r'白介素(IL)检测\(IL-12p\)',r'白介素(IL)检测\(IL-17\)',r'干扰素(IFN)测定\(IFN-α\)',r'干扰素(IFN)测定\(IFN-γ\)',r'肿瘤坏死因子测定'],\
|
||||||
|
'test_check_list_all':['血管内皮生长因子检测',r'白介素\(IL\)检测\(IL-1β\)',r'白介素(IL)检测\(IL-2\)',r'白介素(IL)检测\(IL-4\)',r'白介素(IL)检测\(IL-5\)',r'白介素(IL)检测\(IL-6\)',r'白介素(IL)检测\(IL-8\)',r'白介素(IL)检测\(IL-10\)',r'白介素(IL)检测\(IL-12p\)',r'白介素(IL)检测\(IL-17\)',r'干扰素(IFN)测定\(IFN-α\)',r'干扰素(IFN)测定\(IFN-γ\)',r'肿瘤坏死因子测定',], 'test_result_col_name':"result_str"},
|
||||||
|
# 内分泌代谢系列 # str(12):尿β2-MG;str(7):尿液儿茶酚胺测定八项[复];str(7):抗中性粒细胞胞浆抗体测定(ANC;
|
||||||
|
{'test_rptunitid':[str(12),str(7),str(17),str(161)], 'test_check_name':'内分泌代谢系列', 'test_check_list':['尿β2-MG','游离肾上腺素','游离去甲肾上腺素','游离多巴胺','游离甲氧基肾上腺素','游离甲氧基去甲肾上腺素','游离3-甲氧基酪胺','尿香草扁桃酸','高香草酸','24小时尿(体液)量','尿24小时游离肾上腺素','尿24小时游离去甲肾上腺素','尿24小时游离多巴胺','尿24小时游离甲氧基肾上腺素','尿24小时游离甲氧基去甲肾上腺素','尿24小时游离3-甲氧基酪胺','尿24小时香草扁桃酸','尿24小时高香草酸', 'cANCA','pANCA','抗蛋白酶3抗体','抗髓过氧化物酶抗体','ANA','非典型性ANCA','*MPO标准品1','*MPO标准品2','*MPO标准品3','*PR3标准品1','*PR3标准品2','*PR3标准品3'],\
|
||||||
|
'test_check_list_all':['尿β2-MG','游离肾上腺素','游离去甲肾上腺素','游离多巴胺','游离甲氧基肾上腺素','游离甲氧基去甲肾上腺素','游离3-甲氧基酪胺','尿香草扁桃酸','高香草酸','24小时尿(体液)量','尿24小时游离肾上腺素','尿24小时游离去甲肾上腺素','尿24小时游离多巴胺','尿24小时游离甲氧基肾上腺素','尿24小时游离甲氧基去甲肾上腺素','尿24小时游离3-甲氧基酪胺','尿24小时香草扁桃酸','尿24小时高香草酸','cANCA','pANCA','抗蛋白酶3抗体','抗髓过氧化物酶抗体','ANA','非典型性ANCA',r'\*MPO标准品1',r'\*MPO标准品2',r'\*MPO标准品3',r'\*PR3标准品1',r'\*PR3标准品2',r'\*PR3标准品3'], 'test_result_col_name':"result_str"},
|
||||||
|
# 用药指导 # str(78):用药指导基因检测他汀类药物两项
|
||||||
|
{'test_rptunitid':[str(78),str(40)], 'test_check_name':'用药指导', 'test_check_list':[r'VKORC1\(1639G>A\)',r'CYP2C9*3\(1075A>C\)',r'ALDH2\(1510G>A\)',r'ApoE\(526',r'SLCO1B1*5\(521'],\
|
||||||
|
'test_check_list_all':[r'VKORC1\(1639G>A\)',r'CYP2C9*3\(1075A>C\)',r'ALDH2\(1510G>A\)',r'ApoE\(526',r'SLCO1B1*5\(521'], 'test_result_col_name':"result_str"},
|
||||||
|
]
|
||||||
5
requirements.txt
Normal file
5
requirements.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
fastapi==0.115.6
|
||||||
|
uvicorn[standard]==0.34.0
|
||||||
|
python-multipart==0.0.20
|
||||||
|
openpyxl==3.1.5
|
||||||
|
|
||||||
Reference in New Issue
Block a user