feat: click 照護頁 - 代辦事項的 table row 可顯示 forge 該床位的 popover
This commit is contained in:
parent
1834af24c9
commit
3a6b61db1d
@ -460,6 +460,28 @@ const {
|
||||
__staticDevices,
|
||||
} = useForgeSprite();
|
||||
|
||||
// === Date 工具 ===
|
||||
function __fmtYMD(d) {
|
||||
const y = d.getFullYear();
|
||||
const m = String(d.getMonth() + 1).padStart(2, "0");
|
||||
const day = String(d.getDate()).padStart(2, "0");
|
||||
return `${y}/${m}/${day}`;
|
||||
}
|
||||
|
||||
// 依床位與索引產生「穩定且分散」的入住日期(不會落到未來)
|
||||
function seededStartTime(bedKey, idx = 0) {
|
||||
const n = parseInt(String(bedKey).replace("-", ""), 10) || 0;
|
||||
const base = new Date(2024, 0, 1); // 2024/01/01
|
||||
const offset = (n * 13 + idx * 17) % 540; // 約 18 個月範圍
|
||||
let d = new Date(base.getTime() + offset * 86400000);
|
||||
const today = new Date();
|
||||
if (d > today) {
|
||||
const back = (n % 60) + 10; // 至少往回 10 天
|
||||
d = new Date(today.getTime() - back * 86400000);
|
||||
}
|
||||
return __fmtYMD(d);
|
||||
}
|
||||
|
||||
/** ===================== 常數 / 主題色 ===================== */
|
||||
const FLOOR_DBIDS = { "1F": null, "2F": null };
|
||||
const BRAND_RED = "#FF8678"; // 女(佔床)
|
||||
@ -486,6 +508,7 @@ function loadResidentStore() {
|
||||
return new Map();
|
||||
}
|
||||
}
|
||||
|
||||
function saveResidentStore(map) {
|
||||
try {
|
||||
localStorage.setItem(
|
||||
@ -521,7 +544,7 @@ function ensureResidentFor(bedKey, genderHint) {
|
||||
residentsName: fixed.name,
|
||||
residentsSex: fixed.sex || genderHint || "男",
|
||||
residentsAge: fixed.age ?? 78,
|
||||
startTime: fixed.startTime ?? "2023/01/15",
|
||||
startTime: fixed.startTime ?? "2025/01/01",
|
||||
healthStatus: fixed.healthStatus ?? "一般",
|
||||
medicationStatus: fixed.medicationStatus ?? "規律服藥",
|
||||
specialEvent: fixed.specialEvent ?? "-",
|
||||
@ -532,14 +555,14 @@ function ensureResidentFor(bedKey, genderHint) {
|
||||
return rec;
|
||||
}
|
||||
|
||||
// 🧰 再看 localStorage(沒有寫死表才用舊值;補齊性別)
|
||||
// 再看 localStorage(沒有寫死表才用舊值;補齊性別)
|
||||
const existed = RESIDENT_BY_BED.get(key);
|
||||
if (existed) {
|
||||
if (!existed.residentsSex && genderHint) existed.residentsSex = genderHint;
|
||||
return existed;
|
||||
}
|
||||
|
||||
// 🆘 最後備援(真的沒定義到的床位)
|
||||
// 最後備援(真的沒定義到的床位)
|
||||
const g = genderHint === "女" ? "女" : "男";
|
||||
const pool = g === "男" ? NAME_POOL_MALE : NAME_POOL_FEMALE;
|
||||
const idx = hashFNV1a(key) % pool.length;
|
||||
@ -548,7 +571,7 @@ function ensureResidentFor(bedKey, genderHint) {
|
||||
residentsName: pool[idx],
|
||||
residentsSex: g,
|
||||
residentsAge: 78,
|
||||
startTime: "2023/01/15",
|
||||
startTime: seededStartTime(key, idx),
|
||||
healthStatus: "一般",
|
||||
medicationStatus: "規律服藥",
|
||||
specialEvent: "-",
|
||||
@ -1156,6 +1179,49 @@ window.FORGE_API = {
|
||||
},
|
||||
};
|
||||
|
||||
// === 新增:聚焦指定床位並顯示 popover ===
|
||||
window.FORGE_API.focusBed = async function focusBed(bedKey, opts = {}) {
|
||||
try {
|
||||
if (!viewer || !__staticDevices?.length) return false;
|
||||
|
||||
const bed = String(bedKey || "").trim();
|
||||
if (!bed) return false;
|
||||
|
||||
// 確認樓層,必要時切換(1xx→1F,2xx→2F)
|
||||
const targetFloor = bed.charAt(0) === "2" ? "2F" : "1F";
|
||||
if (activeFloor.value !== targetFloor) {
|
||||
await applyFloor(targetFloor);
|
||||
}
|
||||
|
||||
// 找到對應 sprite
|
||||
const dev = __staticDevices.find(
|
||||
(d) => d.bedKey === bed || d.name?.includes(bed)
|
||||
);
|
||||
if (!dev) return false;
|
||||
|
||||
// 讓 popover 篩選顯示到它(selectedInfo 要對上該 sprite 的 status)
|
||||
selectedInfo.value = dev.status; // 'occupied' | 'vacant' | 'hospitalized' | 'leave'
|
||||
soloSpriteId.value = dev.spriteDbId;
|
||||
bringToFrontById(dev.spriteDbId);
|
||||
|
||||
// 重新算 popover 位置
|
||||
rebuildLabelsAfterNextRender();
|
||||
|
||||
// 視角帶到該 sprite(可用 opts.fit=false 關掉)
|
||||
if (opts.fit !== false) {
|
||||
await cardfitToView({
|
||||
forge_dbid: dev.forge_dbid,
|
||||
spriteDbId: dev.spriteDbId,
|
||||
back: 30,
|
||||
});
|
||||
}
|
||||
return true;
|
||||
} catch (err) {
|
||||
console.warn("[FORGE_API.focusBed] failed:", err);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/** ===================== Sprites 顏色規則 ===================== */
|
||||
function spriteColorBy(status, gender) {
|
||||
if (status === "occupied") return gender === "男" ? BRAND_GREEN : BRAND_RED;
|
||||
@ -1508,6 +1574,39 @@ async function onClickFloor(next) {
|
||||
|
||||
/** ===================== 生命週期 ===================== */
|
||||
onMounted(async () => {
|
||||
(function migrateResidentStore() {
|
||||
let changed = false;
|
||||
for (const [k, v] of RESIDENT_BY_BED.entries()) {
|
||||
// 只清理舊備援資料或 startTime 落在 2023/01/15 的
|
||||
if (!v || v.startTime === "2023/01/15") {
|
||||
const fixed = RESIDENTS_BY_BED?.[k];
|
||||
if (fixed) {
|
||||
RESIDENT_BY_BED.set(k, {
|
||||
roomGender: fixed.sex,
|
||||
residentsName: fixed.name,
|
||||
residentsSex: fixed.sex,
|
||||
residentsAge: fixed.age,
|
||||
startTime: fixed.startTime,
|
||||
healthStatus: fixed.healthStatus,
|
||||
medicationStatus: fixed.medicationStatus,
|
||||
specialEvent: fixed.specialEvent,
|
||||
note: fixed.note,
|
||||
});
|
||||
} else {
|
||||
// 沒有寫死表就用新的 seededStartTime
|
||||
const g = v?.residentsSex || "男";
|
||||
RESIDENT_BY_BED.set(k, {
|
||||
...v,
|
||||
startTime: seededStartTime(k, 0),
|
||||
residentsSex: g,
|
||||
});
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (changed) saveResidentStore(RESIDENT_BY_BED);
|
||||
})();
|
||||
|
||||
document.addEventListener("click", onClickOutsideInfo);
|
||||
document.addEventListener("keydown", onKeydownInfo);
|
||||
activeFloor.value = resolveInitialFloor();
|
||||
|
@ -7,6 +7,7 @@
|
||||
* @property {string} medicationStatus
|
||||
* @property {string} specialEvent
|
||||
* @property {string} note
|
||||
*
|
||||
*/
|
||||
|
||||
// ========== 固定姓名池(A 機構床號 74 → 男/女各 37)==========
|
||||
@ -233,6 +234,31 @@ export function ageFromBedKey(key, base = 66) {
|
||||
}
|
||||
|
||||
// ========== 建立固定住民表 ==========
|
||||
// 工具:格式化成 YYYY/MM/DD
|
||||
function fmtYMD(d) {
|
||||
const y = d.getFullYear();
|
||||
const m = String(d.getMonth() + 1).padStart(2, "0");
|
||||
const day = String(d.getDate()).padStart(2, "0");
|
||||
return `${y}/${m}/${day}`;
|
||||
}
|
||||
|
||||
// 工具:依床位與索引產生「穩定且分散」的入住日期
|
||||
// 規則:以 2025/01/01 為起點,往後偏移 0~540 天(約 18 個月)
|
||||
// 若超過今天,會往回扣 (n % 60 + 10) 天,確保不會是未來日期
|
||||
function seededStartTime(bedKey, idx) {
|
||||
const n = parseInt(String(bedKey).replace("-", ""), 10) || 0;
|
||||
const base = new Date(2025, 0, 1); // 2025/01/01
|
||||
const OFFSET_DAYS = (n * 13 + idx * 17) % 540; // 分散 18 個月內
|
||||
let d = new Date(base.getTime() + OFFSET_DAYS * 86400000);
|
||||
|
||||
const today = new Date();
|
||||
if (d > today) {
|
||||
const back = (n % 60) + 10; // 至少退 10 天,最多 ~70 天
|
||||
d = new Date(today.getTime() - back * 86400000);
|
||||
}
|
||||
return fmtYMD(d);
|
||||
}
|
||||
|
||||
function buildFixedResidents(keys, names, sex) {
|
||||
/** @type {Record<string, ResidentFixed>} */
|
||||
const out = {};
|
||||
@ -243,7 +269,7 @@ function buildFixedResidents(keys, names, sex) {
|
||||
sex,
|
||||
age: ageFromBedKey(k, sex === "女" ? 65 : 66),
|
||||
healthStatus: HEALTH_STATUS_POOL[n % HEALTH_STATUS_POOL.length],
|
||||
startTime: "2023/01/15",
|
||||
startTime: seededStartTime(k, i), // ← 用分散演算法產生
|
||||
medicationStatus: "規律服藥",
|
||||
specialEvent: "-",
|
||||
note: "-",
|
||||
@ -559,5 +585,41 @@ export const BASE_FACILITY_DATA = {
|
||||
},
|
||||
};
|
||||
|
||||
// ====== Nursing 待辦:與 Forge 對齊的示範假資料(用 RESIDENTS_BY_BED 反查姓名) ======
|
||||
/** @typedef {{date:string, bed:string, name:string, type:string, desc:string}} NursingTodoSeed */
|
||||
|
||||
export const NURSING_TODOS_SEED = Object.freeze(
|
||||
(() => {
|
||||
const getName = (bed) => RESIDENTS_BY_BED?.[bed]?.name || "-";
|
||||
|
||||
/** @type {NursingTodoSeed[]} */
|
||||
const seeds = [
|
||||
// (a) 你指定的三筆,姓名會由 RESIDENTS_BY_BED 對應床位自動帶入,確保與 Forge 一致
|
||||
{
|
||||
date: "2025/09/21",
|
||||
bed: "201-1",
|
||||
name: getName("201-1"),
|
||||
type: "一般",
|
||||
desc: "轉換床位",
|
||||
},
|
||||
{
|
||||
date: "2025/09/19",
|
||||
bed: "105-1",
|
||||
name: getName("105-1"),
|
||||
type: "一般",
|
||||
desc: "情緒問題、Alb偏低",
|
||||
},
|
||||
{
|
||||
date: "2025/09/20",
|
||||
bed: "207-3",
|
||||
name: getName("207-3"),
|
||||
type: "緊急安置",
|
||||
desc: "適應輔導、衛教需求",
|
||||
},
|
||||
];
|
||||
return seeds;
|
||||
})()
|
||||
);
|
||||
|
||||
// 兼容性輸出(有些檔案以 FACILITY_DATA 讀取)
|
||||
export const FACILITY_DATA = BASE_FACILITY_DATA;
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user