This commit is contained in:
zlwu committed 2026-07-26 21:06:09 +08:00
1 parent 70bdd820ce
commit bede140d12
988 files changed
+692310 -775910

No files matched your search

-143
View File
@@ -1,143 +0,0 @@
"""MinIO 附件 URL 规范化(数据迁移共用)。
背景
----
CRM / 地磅 / 报销与 shanxia2.0 共用同一 MinIO(bucket 默认 ``ruoyi``),
物理对象无需复制。旧 CRM ``sys_oss.url`` 存的是带域名的绝对 URL(含历史
``47.99.164.66:20004``、``121.43.228.102:9000`` 等),门户 ``sys_oss.url`` 与
业务表字段存 **相对 object key**(如 ``2025/10/08/xxx.png``)。
旧表 ``sys_oss.file_name`` 通常已是 object key,与 ``url`` 中的路径一致,
解析失败时可优先回退 ``file_name``。
报销 ``bx_attachment.file_path`` 本身即为相对路径(如 ``bx/2026-05-19/...``),
可直接写入目标库。
"""
from __future__ import annotations
from typing import Iterable, Optional
from urllib.parse import unquote, urlparse
DEFAULT_BUCKET = "ruoyi"
# 历史绝对 URL 前缀(域名/网关变更);匹配时去掉前缀得到 object key
LEGACY_URL_PREFIXES = (
"http://47.99.164.66:20004/ruoyi/",
"https://47.99.164.66:20004/ruoyi/",
"http://121.43.228.102:9000/ruoyi/",
"https://121.43.228.102:9000/ruoyi/",
"http://www.chengyantek.cn:20004/ruoyi/",
"https://www.chengyantek.cn:20004/ruoyi/",
"http://www.chengyantek.cn/ruoyi/",
"https://www.chengyantek.cn/ruoyi/",
"http://www.chengyantek.cn/zkxw/",
"https://www.chengyantek.cn/zkxw/",
)
def strip_url_query(raw: str) -> str:
"""去掉预签名 query(``?X-Amz-...``)。"""
value = (raw or "").strip()
if not value:
return ""
return value.split("?", 1)[0].strip()
def _strip_legacy_prefix(url: str) -> Optional[str]:
normalized = strip_url_query(url)
for prefix in LEGACY_URL_PREFIXES:
if normalized.startswith(prefix):
return normalized[len(prefix) :].lstrip("/")
return None
def extract_minio_object_key(
raw_url: Optional[str],
*,
bucket: str = DEFAULT_BUCKET,
file_name_fallback: Optional[str] = None,
) -> str:
"""将绝对/相对 URL 规范为 MinIO object key(不含 bucket)。"""
url = strip_url_query(raw_url or "")
if not url:
fallback = (file_name_fallback or "").strip().lstrip("/")
return fallback
legacy = _strip_legacy_prefix(url)
if legacy:
return legacy
if url.startswith("http://") or url.startswith("https://"):
parsed = urlparse(url)
path = unquote((parsed.path or "").lstrip("/"))
bucket_prefix = f"{bucket}/"
if path.startswith(bucket_prefix):
return path[len(bucket_prefix) :]
# 少数 URL 路径不含 bucket 段
return path
return url.lstrip("/")
def normalize_oss_storage_url(
url: Optional[str],
file_name: Optional[str] = None,
*,
bucket: str = DEFAULT_BUCKET,
) -> str:
"""迁移 CRM ``sys_oss`` 行:``url`` + ``file_name`` → 门户相对路径。"""
from_url = extract_minio_object_key(url, bucket=bucket)
if from_url:
return from_url
return (file_name or "").strip().lstrip("/")
def join_relative_urls(urls: Iterable[str]) -> str:
"""逗号拼接相对路径(去空、去重保序)。"""
seen = set()
parts: list[str] = []
for item in urls:
key = (item or "").strip().lstrip("/")
if not key or key in seen:
continue
seen.add(key)
parts.append(key)
return ",".join(parts)
def resolve_oss_id_csv(
oss_id_csv: Optional[str],
oss_id_to_relative_url: dict[str, str],
) -> str:
"""业务表 OSS ID 串 → 相对 URL 串(用于客户证照、跟进附件等)。"""
if not oss_id_csv:
return ""
urls: list[str] = []
for token in str(oss_id_csv).split(","):
oss_id = token.strip()
if not oss_id:
continue
mapped = oss_id_to_relative_url.get(oss_id)
if mapped:
urls.append(mapped)
return join_relative_urls(urls)
if __name__ == "__main__":
samples = [
(
"http://47.99.164.66:20004/ruoyi/2025/10/08/5ac0966ab3a74eadab571ce0bb3b441a.png",
"2025/10/08/5ac0966ab3a74eadab571ce0bb3b441a.png",
),
(
"http://121.43.228.102:9000/ruoyi/2025/11/01/0048348b3d6c439f99db454c8c05e59a.gif?X-Amz-Algorithm=AWS4",
"2025/11/01/0048348b3d6c439f99db454c8c05e59a.gif",
),
("2025/10/17/d601338282a44cf092bf68afe1aef239.jpeg", "2025/10/17/d601338282a44cf092bf68afe1aef239.jpeg"),
("bx/2026-05-19/4ca4ffbeb7fc4e22913936d0860b2e2d.png", "bx/2026-05-19/4ca4ffbeb7fc4e22913936d0860b2e2d.png"),
]
for raw, expected in samples:
got = extract_minio_object_key(raw)
assert got == expected, f"{raw!r} -> {got!r}, want {expected!r}"
print("minio_url self-check ok")