chore: Storage 初版 — 家庭共享物品管理 (React+TS+Vite+Express+DuckDB)
Build and Deploy / build-image (push) Failing after 2m26s

This commit is contained in:
jif2.zhang
2026-09-26 22:46:15 +08:00
commit 0a6f048c0d
50 changed files with 11073 additions and 0 deletions
+75
View File
@@ -0,0 +1,75 @@
import { useState } from "react";
import Modal from "./Modal";
import { useAppStore } from "../stores/app";
import { transferEntity } from "../api";
import { showToast } from "../lib/toast";
// 跨家庭转移: 将物品/整盒转移到"自己拥有管理权限"的另一个家庭 (决策点 2)
export default function TransferModal({
open, type, entityId, onClose, onDone,
}: {
open: boolean;
type: "item" | "box";
entityId: string;
onClose?: () => void;
onDone?: () => void;
}) {
const sourceFamilyId = useAppStore((s) => s.currentFamilyId);
const families = useAppStore((s) => s.families);
const [dst, setDst] = useState<string>("");
const [loading, setLoading] = useState(false);
if (!open) return null;
const eligible = families.filter((f) => f.id !== sourceFamilyId && f.role === "admin");
const doTransfer = async () => {
if (!dst || !sourceFamilyId) { showToast("请选择目标家庭"); return; }
setLoading(true);
try {
await transferEntity(sourceFamilyId, {
type, entityId, dstFamilyId: dst, dstParentBoxId: null,
});
showToast(`已转移到目标家庭`);
onDone?.();
onClose?.();
} catch (e) {
showToast(String(e));
} finally {
setLoading(false);
}
};
return (
<Modal
open={open}
title={type === "box" ? "转移整个盒子(含全部子盒与物品)" : "转移物品"}
onClose={onClose}
footer={
<div className="modal-actions">
<button className="btn btn-outline" onClick={onClose}>取消</button>
<button className="btn btn-primary" disabled={!dst || loading} onClick={doTransfer}>
{loading ? "转移中..." : "转移"}
</button>
</div>
}
>
{eligible.length === 0 ? (
<p style={{ color: "var(--text-tertiary)", fontSize: 13 }}>没有可转移的家庭(需要你拥有该家庭的管理权限)</p>
) : (
<div className="picker-tree">
{eligible.map((f) => (
<button
key={f.id}
className={"picker-option" + (dst === f.id ? " picker-option-active" : "")}
onClick={() => setDst(f.id)}
>
<span>{f.icon}</span> {f.name}
</button>
))}
</div>
)}
{dst && <p style={{ fontSize: 12, color: "var(--text-secondary)", marginTop: 10 }}>转移后将从当前家庭移除,转移到目标家庭根层。</p>}
</Modal>
);
}