ken_nogi/Pleasanter/.claude/js/site-scripts/★マスターシート/add-tateuri-link-columns.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

189 lines
7.6 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.

/**
* add-tateuri-link-columns.js
* ------------------------------------------------------------
* 116503「★リードタイム算定」・203147「★工期計算表」に、488755「【開発中】★建売マスターシート」
* への参照カラムを新規追加する。
*
* 経緯: 488755編集画面の要望「リンクは『リードタイム算定』と『工期計算』のみ必要」に対応するため、
* 488755側のEditorColumnHash_Links-116503 / _Links-203147自体は複製元189112から既に
* 引き継がれているが、Pleasanterの双方向リンクは「子サイト側116503/203147が親サイトを
* 参照するColumn」の存在が必須で、これが488755分だけ欠落しているため画面に何も表示されていなかった
* 実機Selenium検証、2026-08-31で確認
*
* 1カラムにつき参照できるサイトは1つまでユーザー確認済みルールのため、既存の189112用カラム
* 116503側=ClassA、203147側=ClassAを流用せず、488755専用の新規カラムを追加する。
*
* 使い方:
* node add-tateuri-link-columns.js --project="★マスターシート" --env=staging
* … 差分表示のみ(送信なし)
* node add-tateuri-link-columns.js --project="★マスターシート" --env=staging --execute
* … 上記に加えて実際に送信する
* ------------------------------------------------------------
*/
const path = require("path");
const fs = require("fs");
const { resolveProjectRoot, loadServerConfig } = require("../../resolve-project");
const { findSiteDir, newModifyDir } = require("../../site-paths");
const { baseDir, env } = resolveProjectRoot();
const execute = process.argv.includes("--execute");
const TARGETS = [
{
siteId: 116503,
newColumnName: "Class001",
labelText: "建売マスターシート",
messageWhenDuplicated: "建売マスターシートに付随できるレコードは1つだけです",
insertAfter: "ClassA",
},
{
siteId: 203147,
newColumnName: "Class011",
labelText: "建売マスターシート",
messageWhenDuplicated: "建売マスターシートに付随できるレコードは1つだけです",
insertAfter: "ClassA",
},
];
const TARGET_SITE_ID_FOR_LINK = 488755;
function maskApiKey(key) {
if (!key) return key;
return key.length > 8 ? key.slice(0, 4) + "****" + key.slice(-4) : "****";
}
async function processSite(target, config) {
const { siteId, newColumnName, labelText, messageWhenDuplicated, insertAfter } = target;
console.log(`\n---- SiteId ${siteId} ----`);
const getUrl = `${config.BaseUrl.replace(/\/+$/, "")}/api/items/${siteId}/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;
const siteSettings = data.SiteSettings;
console.log(`[OK] 取得しました現在のVer: ${data.Ver}, UpdatedTime: ${data.UpdatedTime}`);
let changed = false;
// --- Columns ---
console.log("\n--- Columns ---");
const existingCol = siteSettings.Columns.find((c) => c.ColumnName === newColumnName);
if (existingCol) {
if (existingCol.ChoicesText === `[[${TARGET_SITE_ID_FOR_LINK}]]`) {
console.log(` ${newColumnName}: 既に488755参照カラムとして存在変更なし`);
} else {
console.error(`[エラー] ${newColumnName} は既に別用途で使用中です:`, JSON.stringify(existingCol));
process.exit(1);
}
} else {
const newColumn = {
ColumnName: newColumnName,
LabelText: labelText,
ChoicesText: `[[${TARGET_SITE_ID_FOR_LINK}]]`,
Hide: true,
NoDuplication: true,
MessageWhenDuplicated: messageWhenDuplicated,
FieldCss: "field-wide",
Link: true,
SearchType: "PartialMatch",
};
siteSettings.Columns.push(newColumn);
console.log(` ${newColumnName}: Columns末尾に追加 ->`, JSON.stringify(newColumn));
changed = true;
}
// --- Links ---
console.log("\n--- Links ---");
const hasLink = siteSettings.Links.some(
(l) => l.ColumnName === newColumnName && String(l.SiteId) === String(TARGET_SITE_ID_FOR_LINK)
);
if (hasLink) {
console.log(` 488755参照: 既にLinks設定あり変更なし`);
} else {
siteSettings.Links.push({ ColumnName: newColumnName, SiteId: TARGET_SITE_ID_FOR_LINK });
console.log(` 488755参照: Links末尾に追加 -> { ColumnName: "${newColumnName}", SiteId: ${TARGET_SITE_ID_FOR_LINK} }`);
changed = true;
}
// --- EditorColumnHash.General ---
console.log("\n--- EditorColumnHash.General ---");
const general = siteSettings.EditorColumnHash.General;
if (general.includes(newColumnName)) {
console.log(` ${newColumnName}: 既に配置あり(変更なし)`);
} else {
const idx = general.indexOf(insertAfter);
if (idx === -1) {
console.error(`[エラー] 挿入位置の基準(${insertAfter})が見つかりません`);
process.exit(1);
}
general.splice(idx + 1, 0, newColumnName);
console.log(` ${newColumnName}: ${insertAfter}の直後に挿入 ->`, JSON.stringify(general));
changed = true;
}
if (!changed) {
console.log("\n変更なし。既に対応済みです。");
return { siteId, changed: false };
}
console.log("\n他のSiteSettings他Columns/Processes/GridColumns等・Permissions・Title等は一切変更しません。");
const body = {
ApiVersion: config.ApiVersion || "1.1",
ApiKey: config.ApiKey,
SiteId: siteId,
Title: data.Title,
ReferenceType: data.ReferenceType,
ParentId: data.ParentId,
InheritPermission: data.InheritPermission,
Permissions: data.Permissions,
SiteSettings: siteSettings,
};
const configsDir = path.join(baseDir, "configs", env);
const siteDir = findSiteDir(configsDir, siteId);
const maskedBody = { ...body, ApiKey: maskApiKey(body.ApiKey) };
const ts = new Date().toISOString().replace(/[:.]/g, "-");
if (siteDir) {
const modifyDir = newModifyDir(siteDir, "add-tateuri-link-column");
const previewPath = path.join(modifyDir, `site-${siteId}_preview_${ts}.json`);
fs.writeFileSync(previewPath, JSON.stringify(maskedBody, null, 2), "utf-8");
console.log(`\n[OK] 送信予定内容を保存しました: ${previewPath}`);
}
if (!execute) {
console.log("\n[注意] --execute が指定されていないため、送信は行っていません。");
return { siteId, changed: true, sent: false };
}
console.log("\n実際に送信しますupdatesite...");
const url = `${config.BaseUrl.replace(/\/+$/, "")}/api/items/${siteId}/updatesite`;
const res = await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
});
const text = await res.text();
console.log(`HTTP ${res.status} ${res.statusText}`);
console.log(text);
return { siteId, changed: true, sent: true };
}
(async () => {
const config = loadServerConfig(env);
console.log("========================================");
console.log(` 488755参照カラム追加116503/203147, ${env}${execute ? "(実行)" : "(プレビューのみ)"}`);
console.log("========================================");
for (const target of TARGETS) {
await processSite(target, config);
}
})();