ken_nogi/Pleasanter/.claude/js/site-scripts/健康診断管理/apply-508971-columns-to-513156.js
Kenichiro NOGI bd6a605539 健康診断管理システムのn8nワークフロー設計ドキュメントとPleasanter操作スクリプトを追加
n8nに構築済みのHC-SUB/HC-WP/HC-WAワークフロー設計・実装計画・エクスポートJSONを
Pleasanter/健康診断管理/docs/n8n/に集約管理。508971/513156のColumns/Styles/Summaries
反映用ワンショットスクリプトも合わせて追加。worktree-healthcheck-survey-botブランチを
mainへfast-forward mergeし、.claude/worktrees/はgit管理対象外に追加。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 09:02:14 +09:00

141 lines
6.0 KiB
JavaScript

// 健康診断管理 SiteId 513156(実施年度-集計): site-508971_社員別健康診断管理のNum061~071/081~091の
// Column設定(LabelText/ControlType/NoWrap/Min/Max/Description)をそのまま複製して新規追加し、
// 508971のStyles(Id1:基本スタイル調整→Id2:数値エリア調整の順)も複製して適用するワンショットスクリプト。
// EditorColumnHash.General(Num061~091)は画面上で追加済みのため変更しない。updatesite(Mode:full)を使う。
// --execute指定時のみ実際に送信、指定なければプレビュー(送信Body・diff)のみ出力。
"use strict";
const fs = require("fs");
const path = require("path");
const { findSiteDir, newModifyDir } = require("../../site-paths.js");
const PROJECT_NAME = "健康診断管理";
const ENV = "production";
const SRC_SITE_ID = 508971;
const DST_SITE_ID = 513156;
const DST_SITE_NAME = "実施年度-集計";
const REQUEST_LABEL = "apply-508971-num-columns-and-styles";
const NUM_COLUMN_NAMES = [
"Num061", "Num062", "Num063", "Num064", "Num065", "Num066", "Num067", "Num068", "Num069", "Num070", "Num071",
"Num081", "Num082", "Num083", "Num084", "Num085", "Num086", "Num087", "Num088", "Num089", "Num090", "Num091",
];
const REPO_ROOT = path.join(__dirname, "..", "..", "..", "..");
const PROJECT_ROOT = path.join(REPO_ROOT, PROJECT_NAME);
const CONFIGS_DIR = path.join(PROJECT_ROOT, "configs", ENV);
function loadServerConfig() {
const configPath = path.join(REPO_ROOT, `config_${ENV}.json`);
const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
if (!config.BaseUrl || !config.ApiKey) {
console.error(`[エラー] ${configPath} に BaseUrl / ApiKey を設定してください。`);
process.exit(1);
}
return config;
}
function loadLatest(siteId) {
const siteDir = findSiteDir(CONFIGS_DIR, siteId);
if (!siteDir) {
console.error(`[エラー] configs/${ENV}/site-${siteId}_* が見つかりません。先にget-site-config.jsを実行してください。`);
process.exit(1);
}
const p = path.join(siteDir, "sitesettings", `site-${siteId}_latest.json`);
const raw = JSON.parse(fs.readFileSync(p, "utf-8"));
return { current: raw.Response.Data, siteDir, rawText: fs.readFileSync(p, "utf-8") };
}
function buildDesiredSiteSettings(srcCurrent, dstCurrent) {
const settings = JSON.parse(JSON.stringify(dstCurrent.SiteSettings));
const addedColumns = [];
for (const name of NUM_COLUMN_NAMES) {
if (settings.Columns.some((c) => c.ColumnName === name)) {
console.error(`[エラー] 移行先Columns内に${name}が既に存在します(重複追加防止のため中断)。`);
process.exit(1);
}
const src = srcCurrent.SiteSettings.Columns.find((c) => c.ColumnName === name);
if (!src) {
console.error(`[エラー] 移行元(508971)Columns内に${name}が見つかりません。`);
process.exit(1);
}
const col = JSON.parse(JSON.stringify(src));
settings.Columns.push(col);
addedColumns.push(col);
}
// Styles: 508971のId1(基本スタイル調整)→Id2(数値エリア調整)の順で複製
const srcStyles = srcCurrent.SiteSettings.Styles || [];
const style1 = srcStyles.find((s) => s.Id === 1);
const style2 = srcStyles.find((s) => s.Id === 2);
if (!style1 || !style2) {
console.error("[エラー] 移行元(508971)にStyle Id1/Id2が見つかりません。");
process.exit(1);
}
settings.Styles = [
{ ...style1 },
{ ...style2 },
];
// Links省略厳禁(全置換のため既存値をそのまま含める。移行先に元々設定が無ければ空配列)
settings.Links = dstCurrent.SiteSettings.Links || [];
return { settings, addedColumns };
}
function buildUpdateBody(apiKey, current, desiredSettings) {
return {
ApiVersion: "1.1",
ApiKey: apiKey,
SiteId: DST_SITE_ID,
Title: current.Title,
ReferenceType: current.ReferenceType,
ParentId: current.ParentId,
InheritPermission: current.InheritPermission,
SiteSettings: desiredSettings,
};
}
const execute = process.argv.includes("--execute");
const server = loadServerConfig();
(async () => {
const { current: srcCurrent } = loadLatest(SRC_SITE_ID);
const { current: dstCurrent, siteDir: dstSiteDir, rawText: dstRawText } = loadLatest(DST_SITE_ID);
const { settings: desiredSettings, addedColumns } = buildDesiredSiteSettings(srcCurrent, dstCurrent);
const body = buildUpdateBody(server.ApiKey, dstCurrent, desiredSettings);
const modifyDir = newModifyDir(dstSiteDir, REQUEST_LABEL);
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
fs.writeFileSync(path.join(modifyDir, `before_site-${DST_SITE_ID}_latest.json`), dstRawText, "utf-8");
const updatedPath = path.join(modifyDir, `site-${DST_SITE_ID}_updated_${timestamp}.json`);
fs.writeFileSync(updatedPath, JSON.stringify(body, null, 2), "utf-8");
console.log(`\n==== SiteId ${DST_SITE_ID} (${DST_SITE_NAME}) ====`);
console.log("追加するColumns(508971から複製):");
for (const c of addedColumns) console.log(` - ${c.ColumnName}: ${c.LabelText}`);
console.log("適用するStyles(508971から複製、順序: Id1→Id2):");
for (const s of desiredSettings.Styles) console.log(` - Id${s.Id}: ${s.Title}`);
console.log(`\nColumns件数: 変更前${dstCurrent.SiteSettings.Columns.length} → 変更後${desiredSettings.Columns.length}`);
console.log(`プレビュー保存先: ${updatedPath}`);
if (!execute) {
console.log("\n(--execute 未指定のためプレビューのみ。送信していません)");
return;
}
const url = `${server.BaseUrl}api/items/${DST_SITE_ID}/updatesite`;
console.log(`送信先: ${url}`);
const res = await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
});
const json = await res.json();
console.log(`[結果] HTTP ${res.status}:`, JSON.stringify(json));
const resultPath = path.join(modifyDir, `site-${DST_SITE_ID}_result_${timestamp}.json`);
fs.writeFileSync(resultPath, JSON.stringify(json, null, 2), "utf-8");
})();