From 8798aa9230d56763abe7a6f70ef65f16f333f5c9 Mon Sep 17 00:00:00 2001 From: wkc <978997012@qq.com> Date: Tue, 31 Mar 2026 23:03:14 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4lsfx-mock=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=BA=93=E9=85=8D=E7=BD=AE=E5=B9=B6=E6=9B=B4?= =?UTF-8?q?=E6=96=B0NAS=E9=83=A8=E7=BD=B2=E7=8E=AF=E5=A2=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deploy/deploy-to-nas.sh | 3 ++ deploy/deploy.ps1 | 6 +++ deploy/render_nas_env.py | 47 +++++++++++++++++++ ...31-lsfx-mock-default-db-endpoint-update.md | 23 +++++++++ ...ccount-baseline-audit-column-correction.md | 41 ++++++++++++++++ ...nas-lsfx-mock-db-endpoint-deploy-update.md | 34 ++++++++++++++ lsfx-mock-server/config/settings.py | 6 ++- .../test_abnormal_account_baseline_service.py | 5 ++ lsfx-mock-server/tests/test_settings_sync.py | 9 ++-- tests/deploy/test_deploy_to_nas.py | 7 +++ tests/deploy/test_render_nas_env.py | 37 +++++++++++++++ 11 files changed, 213 insertions(+), 5 deletions(-) create mode 100644 deploy/render_nas_env.py create mode 100644 docs/reports/implementation/2026-03-31-lsfx-mock-default-db-endpoint-update.md create mode 100644 docs/reports/implementation/2026-03-31-lsfx-mock-server-abnormal-account-baseline-audit-column-correction.md create mode 100644 docs/reports/implementation/2026-03-31-nas-lsfx-mock-db-endpoint-deploy-update.md create mode 100644 tests/deploy/test_render_nas_env.py diff --git a/deploy/deploy-to-nas.sh b/deploy/deploy-to-nas.sh index 8ccb167d..c8c3a879 100755 --- a/deploy/deploy-to-nas.sh +++ b/deploy/deploy-to-nas.sh @@ -104,6 +104,9 @@ copy_path "${REPO_ROOT}/ruoyi-ui/dist" "${STAGE_ROOT}/frontend/dist" copy_path "${REPO_ROOT}/docker-compose.yml" "${STAGE_ROOT}/docker-compose.yml" copy_path "${REPO_ROOT}/.env.example" "${STAGE_ROOT}/.env.example" copy_path "${REPO_ROOT}/ruoyi-admin/target/ruoyi-admin.jar" "${STAGE_ROOT}/backend/ruoyi-admin.jar" +python3 "${SCRIPT_DIR}/render_nas_env.py" \ + --template "${REPO_ROOT}/.env.example" \ + --output "${STAGE_ROOT}/.env" echo "[5/5] 上传并远端部署" ensure_paramiko diff --git a/deploy/deploy.ps1 b/deploy/deploy.ps1 index 39177c6c..d089edcf 100644 --- a/deploy/deploy.ps1 +++ b/deploy/deploy.ps1 @@ -95,6 +95,12 @@ Copy-ItemSafe (Join-Path $repoRoot "ruoyi-ui\\dist") (Join-Path $stageRoot "fron Copy-ItemSafe (Join-Path $repoRoot "docker-compose.yml") (Join-Path $stageRoot "docker-compose.yml") Copy-ItemSafe (Join-Path $repoRoot ".env.example") (Join-Path $stageRoot ".env.example") Copy-ItemSafe (Join-Path $repoRoot "ruoyi-admin\\target\\ruoyi-admin.jar") (Join-Path $stageRoot "backend\\ruoyi-admin.jar") +python (Join-Path $scriptDir "render_nas_env.py") ` + --template (Join-Path $repoRoot ".env.example") ` + --output (Join-Path $stageRoot ".env") +if ($LASTEXITCODE -ne 0) { + throw "生成 NAS 部署 .env 失败" +} Write-Host "[5/5] 上传并远端部署" $paramikoCheck = @' diff --git a/deploy/render_nas_env.py b/deploy/render_nas_env.py new file mode 100644 index 00000000..f36256fc --- /dev/null +++ b/deploy/render_nas_env.py @@ -0,0 +1,47 @@ +import argparse +from pathlib import Path + + +NAS_ENV_OVERRIDES = { + "CCDI_DB_HOST": "192.168.0.111", + "CCDI_DB_PORT": "40628", +} + + +def parse_args(): + parser = argparse.ArgumentParser(description="Render NAS deployment .env for CCDI docker compose.") + parser.add_argument("--template", required=True) + parser.add_argument("--output", required=True) + return parser.parse_args() + + +def render_env_text(template_text: str) -> str: + rendered_lines = [] + replaced_keys = set() + + for line in template_text.splitlines(): + key, separator, value = line.partition("=") + if separator and key in NAS_ENV_OVERRIDES: + rendered_lines.append(f"{key}={NAS_ENV_OVERRIDES[key]}") + replaced_keys.add(key) + continue + rendered_lines.append(line) + + for key, value in NAS_ENV_OVERRIDES.items(): + if key not in replaced_keys: + rendered_lines.append(f"{key}={value}") + + return "\n".join(rendered_lines) + "\n" + + +def main(): + args = parse_args() + template_path = Path(args.template) + output_path = Path(args.output) + + template_text = template_path.read_text(encoding="utf-8") + output_path.write_text(render_env_text(template_text), encoding="utf-8") + + +if __name__ == "__main__": + main() diff --git a/docs/reports/implementation/2026-03-31-lsfx-mock-default-db-endpoint-update.md b/docs/reports/implementation/2026-03-31-lsfx-mock-default-db-endpoint-update.md new file mode 100644 index 00000000..1ef1b75e --- /dev/null +++ b/docs/reports/implementation/2026-03-31-lsfx-mock-default-db-endpoint-update.md @@ -0,0 +1,23 @@ +# LSFX Mock Server 默认数据库地址调整实施记录 + +**日期**: 2026-03-31 +**范围**: `lsfx-mock-server` 配置 + +## 1. 调整内容 + +- 在 `lsfx-mock-server/config/settings.py` 中显式固定默认数据库地址: + - `CCDI_DB_HOST = 116.62.17.81` + - `CCDI_DB_PORT = 3307` +- 保持数据库名、用户名、密码继续沿用主工程 `application-dev.yml` 中的默认值读取逻辑 + +## 2. 调整原因 + +此前 `lsfx-mock-server` 的数据库 host/port 默认值隐式跟随 `ruoyi-admin` 的开发配置。虽然当前主工程配置本身也是 `116.62.17.81:3307`,但这种依赖关系不够直接。 + +本次改动后,`lsfx-mock-server` 会在自身配置层明确默认连接到 `116.62.17.81:3307`,避免后续主工程开发配置变化时影响 Mock 服务默认库选择。 + +## 3. 验证范围 + +- `lsfx-mock-server/tests/test_settings_sync.py` + - 校验默认 host/port 固定为 `116.62.17.81:3307` + - 校验数据库名、用户名、密码仍沿用主工程开发配置默认值 diff --git a/docs/reports/implementation/2026-03-31-lsfx-mock-server-abnormal-account-baseline-audit-column-correction.md b/docs/reports/implementation/2026-03-31-lsfx-mock-server-abnormal-account-baseline-audit-column-correction.md new file mode 100644 index 00000000..21c16351 --- /dev/null +++ b/docs/reports/implementation/2026-03-31-lsfx-mock-server-abnormal-account-baseline-audit-column-correction.md @@ -0,0 +1,41 @@ +# LSFX Mock Server 异常账户基线审计字段纠正实施记录 + +**日期**: 2026-03-31 +**范围**: `lsfx-mock-server` 异常账户基线同步链路 + +## 1. 问题说明 + +在前一轮排查中,基于 MCP 表结构结果将 `ccdi_account_info` 的审计列误判为 `created_by`、`updated_by`,并据此调整了异常账户基线 upsert SQL。 + +随后使用 `mysql` 直连 `116.62.17.81:3307/ccdi` 执行: + +- `SHOW COLUMNS FROM ccdi_account_info LIKE 'create_by';` +- `SHOW COLUMNS FROM ccdi_account_info LIKE 'update_by';` +- `SHOW COLUMNS FROM ccdi_account_info;` + +确认真实表结构使用的是 `create_by`、`update_by`。 + +## 2. 本次纠正内容 + +- 修正 `lsfx-mock-server/services/abnormal_account_baseline_service.py` + - upsert 字段改回 `create_by`、`update_by` + - 更新分支改回 `update_by = VALUES(update_by)` +- 修正 `sql/migration/2026-03-31-create-ccdi-account-info-and-abnormal-account-rules.sql` + - `ccdi_account_info` 建表字段改回 `create_by`、`update_by` + - 规则初始化 SQL 的审计字段改回 `create_by` / `update_by` +- 修正 `sql/migration/2026-03-31-add-abnormal-account-rule-test-data.sql` + - `ccdi_account_info` 测试数据插入字段改回 `create_by`、`update_by` +- 修正 `docs/design/2026-03-31-lsfx-mock-server-abnormal-account-baseline-sync-design.md` + - 将设计文档中的账户表审计字段名改回真实库定义 + +## 3. 测试调整 + +- 更新 `lsfx-mock-server/tests/test_abnormal_account_baseline_service.py` + - 锁定 insert SQL 必须包含 `create_by`、`update_by` + - 锁定 upsert update 分支必须写 `update_by = VALUES(update_by)` + +## 4. 结果 + +- 异常账户基线同步 SQL 已与 `116.62.17.81:3307/ccdi` 的真实表结构重新对齐 +- 运行时不会再向不存在的 `created_by`、`updated_by` 字段写值 +- 服务代码、migration、测试数据脚本与设计文档已恢复一致 diff --git a/docs/reports/implementation/2026-03-31-nas-lsfx-mock-db-endpoint-deploy-update.md b/docs/reports/implementation/2026-03-31-nas-lsfx-mock-db-endpoint-deploy-update.md new file mode 100644 index 00000000..aa28ac16 --- /dev/null +++ b/docs/reports/implementation/2026-03-31-nas-lsfx-mock-db-endpoint-deploy-update.md @@ -0,0 +1,34 @@ +# NAS 部署脚本 LSFX Mock 数据库地址调整实施记录 + +**日期**: 2026-03-31 +**范围**: NAS 部署脚本、部署配置 + +## 1. 本次调整 + +- 新增 `deploy/render_nas_env.py` + - 基于根目录 `.env.example` 渲染 NAS 部署专用 `.env` + - 固定输出: + - `CCDI_DB_HOST=192.168.0.111` + - `CCDI_DB_PORT=40628` +- 调整 `deploy/deploy-to-nas.sh` + - 在组装部署目录阶段生成 `${STAGE_ROOT}/.env` +- 调整 `deploy/deploy.ps1` + - 与 Shell 部署入口保持一致,在组装部署目录阶段生成 `${stageRoot}\\.env` + +## 2. 调整目的 + +确保 NAS 部署后的 `lsfx-mock-server` 读取部署包中的 `.env`,从而连接: + +- Host: `192.168.0.111` +- Port: `40628` + +同时保持本地 `docker-compose.yml` 默认值不变,不影响本地开发和手工启动。 + +## 3. 验证范围 + +- `tests/deploy/test_render_nas_env.py` + - 校验渲染后的 `.env` 包含 `CCDI_DB_HOST=192.168.0.111` + - 校验渲染后的 `.env` 包含 `CCDI_DB_PORT=40628` +- `tests/deploy/test_deploy_to_nas.py` + - 校验 `deploy-to-nas.sh` 已接入 `render_nas_env.py` + - 校验部署目录会生成 `${STAGE_ROOT}/.env` diff --git a/lsfx-mock-server/config/settings.py b/lsfx-mock-server/config/settings.py index a2fa65d0..84a47802 100644 --- a/lsfx-mock-server/config/settings.py +++ b/lsfx-mock-server/config/settings.py @@ -26,6 +26,8 @@ def _load_ruoyi_mysql_defaults() -> dict: MYSQL_DEFAULTS = _load_ruoyi_mysql_defaults() +LSFX_DEFAULT_CCDI_DB_HOST = "116.62.17.81" +LSFX_DEFAULT_CCDI_DB_PORT = 3307 class Settings(BaseSettings): @@ -50,8 +52,8 @@ class Settings(BaseSettings): INITIAL_LOG_ID: int = 10000 # 员工库只读配置 - CCDI_DB_HOST: str = MYSQL_DEFAULTS.get("host", "") - CCDI_DB_PORT: int = int(MYSQL_DEFAULTS.get("port", 3306)) + CCDI_DB_HOST: str = LSFX_DEFAULT_CCDI_DB_HOST + CCDI_DB_PORT: int = LSFX_DEFAULT_CCDI_DB_PORT CCDI_DB_NAME: str = MYSQL_DEFAULTS.get("database", "") CCDI_DB_USERNAME: str = MYSQL_DEFAULTS.get("username", "") CCDI_DB_PASSWORD: str = MYSQL_DEFAULTS.get("password", "") diff --git a/lsfx-mock-server/tests/test_abnormal_account_baseline_service.py b/lsfx-mock-server/tests/test_abnormal_account_baseline_service.py index 3ec9599d..3a222710 100644 --- a/lsfx-mock-server/tests/test_abnormal_account_baseline_service.py +++ b/lsfx-mock-server/tests/test_abnormal_account_baseline_service.py @@ -96,6 +96,10 @@ def test_apply_should_insert_new_account_fact_by_account_no(): assert len(fake_connection.executed_sql) == 1 executed = fake_connection.executed_sql[0] assert "INSERT INTO ccdi_account_info" in executed["sql"] + assert "create_by" in executed["sql"] + assert "update_by" in executed["sql"] + assert "created_by" not in executed["sql"] + assert "updated_by" not in executed["sql"] assert executed["params"] == ( "6222000000000001", "DEBIT", @@ -140,6 +144,7 @@ def test_apply_should_update_existing_account_fact_by_account_no(): assert len(fake_connection.executed_sql) == 1 executed = fake_connection.executed_sql[0] assert "ON DUPLICATE KEY UPDATE" in executed["sql"] + assert "update_by = VALUES(update_by)" in executed["sql"] assert executed["params"][0] == "6222000000000001" assert executed["params"][2] == "测试员工结算卡" assert executed["params"][10] == 1 diff --git a/lsfx-mock-server/tests/test_settings_sync.py b/lsfx-mock-server/tests/test_settings_sync.py index 7b2f21c4..b56a1e2c 100644 --- a/lsfx-mock-server/tests/test_settings_sync.py +++ b/lsfx-mock-server/tests/test_settings_sync.py @@ -15,11 +15,14 @@ def test_ruoyi_mysql_defaults_should_follow_application_dev_config(): assert _load_ruoyi_mysql_defaults()["port"] == match.group("port") -def test_settings_should_use_ruoyi_mysql_defaults(): +def test_settings_should_default_to_lsfx_target_mysql_host_and_port(): + assert settings.CCDI_DB_HOST == "116.62.17.81" + assert settings.CCDI_DB_PORT == 3307 + + +def test_settings_should_still_use_ruoyi_mysql_defaults_for_db_name_and_credentials(): defaults = _load_ruoyi_mysql_defaults() - assert settings.CCDI_DB_HOST == defaults["host"] - assert settings.CCDI_DB_PORT == int(defaults["port"]) assert settings.CCDI_DB_NAME == defaults["database"] assert settings.CCDI_DB_USERNAME == defaults["username"] assert settings.CCDI_DB_PASSWORD == defaults["password"] diff --git a/tests/deploy/test_deploy_to_nas.py b/tests/deploy/test_deploy_to_nas.py index fb4d7112..a14ac6bc 100644 --- a/tests/deploy/test_deploy_to_nas.py +++ b/tests/deploy/test_deploy_to_nas.py @@ -43,3 +43,10 @@ def test_sh_dry_run_accepts_override_arguments(): assert "Port: 2222" in result.stdout assert "Username: deploy-user" in result.stdout assert "RemoteRoot: /volume2/custom/app" in result.stdout + + +def test_sh_script_should_render_nas_env_into_stage_package(): + script_text = SCRIPT_PATH.read_text(encoding="utf-8") + + assert 'render_nas_env.py' in script_text + assert '"${STAGE_ROOT}/.env"' in script_text diff --git a/tests/deploy/test_render_nas_env.py b/tests/deploy/test_render_nas_env.py new file mode 100644 index 00000000..384a9a18 --- /dev/null +++ b/tests/deploy/test_render_nas_env.py @@ -0,0 +1,37 @@ +from pathlib import Path +import subprocess +import tempfile + + +REPO_ROOT = Path(__file__).resolve().parents[2] +SCRIPT_PATH = REPO_ROOT / "deploy" / "render_nas_env.py" +ENV_TEMPLATE = REPO_ROOT / ".env.example" + + +def test_render_nas_env_should_generate_lsfx_mock_db_override_file(): + with tempfile.TemporaryDirectory() as tmp_dir: + output_path = Path(tmp_dir) / ".env" + + result = subprocess.run( + [ + "python3", + str(SCRIPT_PATH), + "--template", + str(ENV_TEMPLATE), + "--output", + str(output_path), + ], + cwd=REPO_ROOT, + capture_output=True, + text=True, + ) + + assert result.returncode == 0 + assert output_path.exists() + + env_text = output_path.read_text(encoding="utf-8") + + assert "CCDI_DB_HOST=192.168.0.111" in env_text + assert "CCDI_DB_PORT=40628" in env_text + assert "CCDI_DB_NAME=ccdi" in env_text +