246 lines
10 KiB
JavaScript
246 lines
10 KiB
JavaScript
/**
|
||
* 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 SITE_ID = 496626;
|
||
const baseDir = path.join(__dirname, "..", "..");
|
||
const configsDir = path.join(baseDir, "configs");
|
||
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 = loadJson(path.join(baseDir, "config.json"));
|
||
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項目改修 Phase1(item1,2,3,4,5,6,7,9)SiteSettings構造変更(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);
|
||
})();
|