ken_nogi/Pleasanter/.claude/js/site-scripts/NEXTGROUP経営計画/rotate-tabs-507570.js
Kenichiro NOGI ce58cb4be4 初回コミット: dev配下(NodeSrv/Pleasanter等)をGitea管理下に統合
GitHub(nextgroup2706/ken_nogi)は今後使わず自社Gitea運用に切替え。
NodeSrvは旧リポジトリの履歴を破棄しファイルのみ統合(Dokploy用サービスアカウントは
別途mygit-admin/NodeSrv.gitに履歴あり)。notepmエクスポート(12GB)とPleasanter
インストーラzip(208MB)はサイズが大きいため.gitignoreで除外。

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

131 lines
5.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* rotate-tabs-507570.js
* ------------------------------------------------------------
* SiteId 507570事業計画v2専用のワンオフスクリプト。
* 期首を4月→10月に変更したことに伴い、画面タブ「1Q/2Q/3Q/4Q」Tabs配列のラベルはそのまま
* 割り当てられている中身EditorColumnHashの_Tab-1〜_Tab-4配列をローテーションする。
*
* 変更前: _Tab-1(1Q)=4-6月, _Tab-2(2Q)=7-9月, _Tab-3(3Q)=10-12月, _Tab-4(4Q)=1-3月
* 変更後: _Tab-1(1Q)=10-12月, _Tab-2(2Q)=1-3月, _Tab-3(3Q)=4-6月, _Tab-4(4Q)=7-9月
* 新1Q=旧3Q、新2Q=旧4Q、新3Q=旧1Q、新4Q=旧2Qの中身をそのまま入れ替えるだけ。
* Section Id等も含めて配列ごと移動するので、タブ内の受注/着工/完成セクション構造は保持される)
*
* SiteSettings.Linksは省略厳禁のため、取得済み生JSONをそのままベースにコピーし、
* EditorColumnHashのみ差し替える。Permissionsは対象サイト自身が実体を持つ
* InheritPermission === SiteId自身ためそのまま含める。
*
* 使い方:
* node rotate-tabs-507570.js … プレビューのみ(差分表示、送信なし)
* node rotate-tabs-507570.js --execute … 実際にupdatesiteへ送信
* ------------------------------------------------------------
*/
const fs = require("fs");
const path = require("path");
const https = require("https");
const PROJECT_NAME = "NEXTGROUP経営計画";
const ENV = "production";
const SITE_ID = 507570;
const REPO_ROOT = path.join(__dirname, "..", "..", "..", "..");
const baseDir = path.join(REPO_ROOT, PROJECT_NAME);
const siteDir = path.join(baseDir, "configs", ENV, `site-${SITE_ID}_事業計画v2`);
const latestJsonPath = path.join(siteDir, "sitesettings", `site-${SITE_ID}_latest.json`);
const modifyDir = path.join(siteDir, "modify", "rotate-tabs");
const configPath = path.join(REPO_ROOT, `config_${ENV}.json`);
const serverConfig = JSON.parse(fs.readFileSync(configPath, "utf-8"));
const execute = process.argv.includes("--execute");
const raw = JSON.parse(fs.readFileSync(latestJsonPath, "utf-8"));
const data = raw.Response.Data;
const ss = data.SiteSettings;
const eh = ss.EditorColumnHash;
const before = {
"_Tab-1": eh["_Tab-1"],
"_Tab-2": eh["_Tab-2"],
"_Tab-3": eh["_Tab-3"],
"_Tab-4": eh["_Tab-4"],
};
const newEh = {
...eh,
"_Tab-1": before["_Tab-3"], // 1Q <- 旧3Q(10-12月)
"_Tab-2": before["_Tab-4"], // 2Q <- 旧4Q(1-3月)
"_Tab-3": before["_Tab-1"], // 3Q <- 旧1Q(4-6月)
"_Tab-4": before["_Tab-2"], // 4Q <- 旧2Q(7-9月)
};
console.log("========================================");
console.log(" タブ内容ローテーション(プレビュー)");
console.log("========================================");
console.log(`SiteId: ${SITE_ID}\n`);
for (const key of ["_Tab-1", "_Tab-2", "_Tab-3", "_Tab-4"]) {
const descBefore = before[key].filter((x) => typeof x === "string" && x.startsWith("Description")).slice(0, 3);
const descAfter = newEh[key].filter((x) => typeof x === "string" && x.startsWith("Description")).slice(0, 3);
console.log(`${key}: [${descBefore.join(",")}...] -> [${descAfter.join(",")}...]`);
}
const body = {
ApiVersion: serverConfig.ApiVersion || "1.1",
ApiKey: serverConfig.ApiKey,
SiteId: SITE_ID,
Title: data.Title,
ReferenceType: data.ReferenceType,
ParentId: data.ParentId,
InheritPermission: data.InheritPermission,
Permissions: data.Permissions,
SiteSettings: {
...ss,
EditorColumnHash: newEh,
},
};
fs.mkdirSync(modifyDir, { recursive: true });
const ts = new Date().toISOString().replace(/[:.]/g, "-");
const beforeSnapshotPath = path.join(modifyDir, `before_site-${SITE_ID}_latest_${ts}.json`);
const previewPath = path.join(modifyDir, `site-${SITE_ID}_rotate_tabs_preview_${ts}.json`);
fs.writeFileSync(beforeSnapshotPath, JSON.stringify(raw, null, 2));
fs.writeFileSync(previewPath, JSON.stringify({ ...body, ApiKey: "***masked***" }, null, 2));
console.log(`\n[OK] 変更前スナップショット保存: ${beforeSnapshotPath}`);
console.log(`[OK] 送信予定内容(APIキーマスク)保存: ${previewPath}`);
if (!execute) {
console.log("\n[注意] --execute が指定されていないため、送信は行っていません。");
console.log("内容を確認の上、問題なければ次を実行してください: node rotate-tabs-507570.js --execute");
process.exit(0);
}
console.log("\n実際に送信しますupdatesite...");
const url = new URL(`${serverConfig.BaseUrl}/api/items/${SITE_ID}/updatesite`);
const payload = JSON.stringify(body);
const req = https.request(
{
hostname: url.hostname,
path: url.pathname,
method: "POST",
headers: {
"Content-Type": "application/json",
"Content-Length": Buffer.byteLength(payload),
},
},
(res) => {
let chunks = "";
res.on("data", (c) => (chunks += c));
res.on("end", () => {
console.log(`HTTP ${res.statusCode}`);
console.log(chunks);
const resultPath = path.join(modifyDir, `site-${SITE_ID}_rotate_tabs_result_${ts}.json`);
fs.writeFileSync(resultPath, chunks);
console.log(`[OK] 応答を保存しました: ${resultPath}`);
});
}
);
req.on("error", (e) => console.error("[エラー]", e));
req.write(payload);
req.end();