ken_nogi/Pleasanter/.claude/js/site-scripts/新・着工要因システム/apply-9item-phase1-496626.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

249 lines
10 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.

/**
* apply-9item-phase1-496626.js
* ------------------------------------------------------------
* site-496626「新・着工要因(東京)v2」9項目改修のうち、item1,2,3,4,5,6,7,9の
* SiteSettings構造変更Sections/Columns/EditorColumnHash/GridColumns/
* FilterColumns/Aggregations/Links/Summaries/Notificationsをまとめて反映する。
* item8引越し削除+20工程番号リネームは影響範囲が大きく別スクリプトで扱う。
*
* 現在のサイト全体getsiteを取得し、in-memoryで変換した上でupdatesite全体更新
* で送信する。Scripts/Styles/ServerScripts等、この改修で対象外のフィールドは
* 取得した現在値をそのまま使うため変更されない。
*
* 使い方:
* node apply-9item-phase1-496626.js … 差分表示のみ(送信なし)
* node apply-9item-phase1-496626.js --execute … 上記に加えて実際に送信する
* ------------------------------------------------------------
*/
const fs = require("fs");
const path = require("path");
const { findSiteDir, newModifyDir, latestModifyDir } = require("../../site-paths");
const { REPO_ROOT, loadServerConfig } = require("../../resolve-project");
const PROJECT_NAME = "新・着工要因システム";
const ENV = "production";
const SITE_ID = 496626;
const baseDir = path.join(REPO_ROOT, PROJECT_NAME);
const configsDir = path.join(baseDir, "configs", ENV);
const execute = process.argv.includes("--execute");
function loadJson(p) {
return JSON.parse(fs.readFileSync(p, "utf-8"));
}
function maskApiKey(key) {
if (!key) return key;
return key.length > 8 ? key.slice(0, 4) + "****" + key.slice(-4) : "****";
}
function timestamp() {
return new Date().toISOString().replace(/[:.]/g, "-");
}
const config = loadServerConfig(ENV);
const siteDir = findSiteDir(configsDir, SITE_ID);
function transform(ss) {
const log = [];
// ---- item1: ゼロエミ承認 → ゼロエミ交付申請 ----
{
const sec = ss.Sections.find((s) => s.Id === 20);
sec.LabelText = "ゼロエミ交付申請";
const col = ss.Columns.find((c) => c.ColumnName === "Date020");
col.GridLabelText = "ゼロエミ交付申請";
log.push("item1: ゼロエミ承認 -> ゼロエミ交付申請");
}
// ---- item2: 取出有無業者連絡 → 取出業者手配 ----
{
const sec = ss.Sections.find((s) => s.Id === 15);
sec.LabelText = "取出業者手配";
const col = ss.Columns.find((c) => c.ColumnName === "Date015");
col.GridLabelText = "取出業者手配";
log.push("item2: 取出有無業者連絡 -> 取出業者手配");
}
// ---- item5: 物件詳細2 → 補助金項目 ----
{
const col = ss.Columns.find((c) => c.ColumnName === "DescriptionB");
col.LabelText = "補助金項目";
log.push("item5: 物件詳細2 -> 補助金項目");
}
// ---- item6: 一覧からDateD列を非表示 ----
{
const removeDateD = (arr) => {
const idx = arr.indexOf("DateD");
if (idx >= 0) arr.splice(idx, 1);
};
removeDateD(ss.GridColumns);
ss.Views.forEach((v) => {
if (v.GridColumns) removeDateD(v.GridColumns);
});
const colDateD = ss.Columns.find((c) => c.ColumnName === "DateD");
colDateD.GridDesign = "[DateD]\n着工可能:[NumE]\n完成予定:[NumG]";
log.push("item6: DateD列をGridColumns(4箇所)から削除。GridDesignをNumG参照に更新");
}
// ---- item9: 変更・注意点等コメント(DescriptionC)を一覧列から削除 ----
{
const removeDescC = (arr) => {
const idx = arr.indexOf("DescriptionC");
if (idx >= 0) arr.splice(idx, 1);
};
removeDescC(ss.GridColumns);
ss.Views.forEach((v) => {
if (v.GridColumns) removeDescC(v.GridColumns);
});
log.push("item9: DescriptionC列をGridColumns(4箇所)から削除");
}
// ---- item7: NumE/NumF/NumG 再定義 ----
{
const numFIdx = ss.Columns.findIndex((c) => c.ColumnName === "NumF");
ss.Columns[numFIdx].LabelText = "着工可能から完成予定日数";
const numG = { ColumnName: "NumG", LabelText: "契約から完成予定", DefaultInput: "0", Unit: "日" };
ss.Columns.splice(numFIdx + 1, 0, numG);
const genIdx = ss.EditorColumnHash.General.indexOf("NumF");
ss.EditorColumnHash.General.splice(genIdx + 1, 0, "NumG");
log.push("item7: NumF LabelText変更、NumG新規追加(Columns+EditorColumnHash)");
}
// ---- item3: 着工可能日セクション(Id=6)廃止、DateAへ一本化 ----
{
// Columns: DateY, DateZ, ClassY, ClassZ を削除
ss.Columns = ss.Columns.filter(
(c) => !["DateY", "DateZ", "ClassY", "ClassZ"].includes(c.ColumnName)
);
// Sections: Id=6 を削除
ss.Sections = ss.Sections.filter((s) => s.Id !== 6);
// EditorColumnHash.General: _Section-6 と DateY/DateZ/ClassZ/ClassY を削除
// Comments/Title/Class200/Description200 はitem4の処理で一括してSection5末尾へ移設する
ss.EditorColumnHash.General = ss.EditorColumnHash.General.filter(
(t) => !["_Section-6", "DateY", "DateZ", "ClassZ", "ClassY"].includes(t)
);
// DateA を編集可能化読取専用CSSを除去
const colDateA = ss.Columns.find((c) => c.ColumnName === "DateA");
delete colDateA.ExtendedFieldCss;
// FilterColumns / Aggregations / Links / Summaries から ClassZ 関連を削除
ss.FilterColumns = ss.FilterColumns.filter((c) => c !== "ClassZ");
ss.Aggregations = ss.Aggregations.filter((a) => a.GroupBy !== "ClassZ");
ss.Links = ss.Links.filter((l) => l.ColumnName !== "ClassZ");
ss.Summaries = ss.Summaries.filter((s) => s.LinkColumn !== "ClassZ");
// Notifications Id:1着工日更新通知の監視列を DateZ -> DateA に付け替え
// DateZ削除により監視対象が消滅し、通知が永久に発火しなくなるための対応
const notif1 = ss.Notifications.find((n) => n.Id === 1);
if (notif1) {
notif1.MonitorChangesColumns = notif1.MonitorChangesColumns.map((c) =>
c === "DateZ" ? "DateA" : c
);
}
log.push(
"item3: DateY/DateZ/ClassY/ClassZ削除、Section6削除、DateA編集可能化、FilterColumns/Aggregations/Links/Summaries整理、Notification1監視列をDateA化"
);
}
// ---- item4: リードタイム関連情報セクション(Id=7)廃止、Class190-192は存続 ----
{
// Columns: Class113〜Class119 のみ削除Class190〜192は残す
const readtimeCols = ["Class113", "Class114", "Class115", "Class116", "Class117", "Class118", "Class119"];
ss.Columns = ss.Columns.filter((c) => !readtimeCols.includes(c.ColumnName));
// Sections: Id=7 を削除
ss.Sections = ss.Sections.filter((s) => s.Id !== 7);
// EditorColumnHash.General: _Section-7 と Class113〜119 を削除
ss.EditorColumnHash.General = ss.EditorColumnHash.General.filter(
(t) => !["_Section-7", ...readtimeCols].includes(t)
);
// Class190/191/192 を現在の位置から削除し、Section5末尾(DescriptionDの直後)へ移設
ss.EditorColumnHash.General = ss.EditorColumnHash.General.filter(
(t) => !["Class190", "Class191", "Class192"].includes(t)
);
const descDIdx = ss.EditorColumnHash.General.indexOf("DescriptionD");
ss.EditorColumnHash.General.splice(descDIdx + 1, 0, "Class190", "Class191", "Class192");
log.push(
"item4: Class113-119削除、Section7削除、Class190-192をSection5末尾へ移設Notifications3件は宛先存続のため変更なし"
);
}
return log;
}
(async () => {
console.log("[INFO] 現在のサイト情報を取得しています...");
const getUrl = `${config.BaseUrl.replace(/\/+$/, "")}/api/items/${SITE_ID}/getsite`;
const getRes = await fetch(getUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ ApiVersion: config.ApiVersion || "1.1", ApiKey: config.ApiKey }),
});
const getJson = await getRes.json();
if (getJson.StatusCode !== 200) {
console.error("[エラー] getsiteに失敗しました:", JSON.stringify(getJson).slice(0, 500));
process.exit(1);
}
const data = getJson.Response.Data;
console.log(`[OK] 取得しました現在のVer: ${data.Ver}, UpdatedTime: ${data.UpdatedTime}`);
const siteSettings = JSON.parse(JSON.stringify(data.SiteSettings));
console.log("========================================");
console.log(` 9項目改修 Phase1item1,2,3,4,5,6,7,9SiteSettings構造変更updatesite全体更新${execute ? "(実行)" : "(プレビューのみ)"}`);
console.log("========================================");
const log = transform(siteSettings);
log.forEach((l) => console.log(" " + l));
const body = {
ApiVersion: config.ApiVersion || "1.1",
ApiKey: config.ApiKey,
SiteId: SITE_ID,
Title: data.Title,
ReferenceType: data.ReferenceType,
ParentId: data.ParentId,
InheritPermission: data.InheritPermission,
Permissions: data.Permissions,
SiteSettings: siteSettings,
};
const modifyDir = latestModifyDir(siteDir) || newModifyDir(siteDir, "9item-revision");
const ts = timestamp();
const maskedBody = { ...body, ApiKey: maskApiKey(body.ApiKey) };
const previewPath = path.join(modifyDir, `site-${SITE_ID}_phase1_update_preview_${ts}.json`);
fs.writeFileSync(previewPath, JSON.stringify(maskedBody, null, 2), "utf-8");
console.log(`\n[OK] 送信予定内容を保存しました: ${previewPath}`);
if (!execute) {
console.log("\n[注意] --execute が指定されていないため、送信は行っていません。");
console.log("内容を確認の上、問題なければ次を実行してください: node apply-9item-phase1-496626.js --execute");
process.exit(0);
}
console.log("\n実際に送信しますupdatesite...");
const url = `${config.BaseUrl.replace(/\/+$/, "")}/api/items/${SITE_ID}/updatesite`;
const res = await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
});
const text = await res.text();
const resultOutPath = path.join(modifyDir, `site-${SITE_ID}_phase1_update_result_${ts}.json`);
fs.writeFileSync(resultOutPath, text, "utf-8");
console.log(`HTTP ${res.status} ${res.statusText}`);
console.log(`[OK] 応答を保存しました: ${resultOutPath}`);
console.log(text);
})();