统一菜单命名并移除剩余台账工具(05-31-unified-menu-remove-ledger-tools-wave2)

这个提交包含在:
2026-05-31 15:06:26 +08:00
父节点 46fa609961
当前提交 43efc9ea08
共修改 47 个文件,包含 498 行新增和 358 行删除
+63 -66
查看文件
@@ -82,7 +82,7 @@ export function ProjectsPage() {
const [targetEndAt, setTargetEndAt] = useState("");
const [isConfidential, setIsConfidential] = useState(false);
const [showTrialData, setShowTrialData] = useState(false);
const [showLedgerTools, setShowLedgerTools] = useState(false);
const [showCreatePanel, setShowCreatePanel] = useState(false);
const listQuery = useQuery({
queryKey: ["projects", "list", status, mine, q],
@@ -181,79 +181,76 @@ export function ProjectsPage() {
actions={
<div className="flex gap-2">
<Button asChild variant="secondary" type="button">
<Link to="/contracts-registry">合同台账</Link>
<Link to="/contracts-registry">合同</Link>
</Button>
<Button type="button" variant={showLedgerTools ? "default" : "secondary"} onClick={() => setShowLedgerTools((value) => !value)}>
台账工具
<Button type="button" variant={showTrialData ? "default" : "secondary"} onClick={() => setShowTrialData((value) => !value)}>
{showTrialData ? "隐藏测试数据" : "显示测试数据"}
</Button>
{canManageProjects ? (
<Button type="button" variant={showCreatePanel ? "default" : "secondary"} onClick={() => setShowCreatePanel((value) => !value)}>
新建项目
</Button>
) : null}
</div>
}
/>
{showLedgerTools ? (
<SectionPanel title="台账工具">
{showCreatePanel ? (
<SectionPanel title="新建项目">
<div className="space-y-4">
{!canManageProjects ? (
<div className="text-sm text-zinc-500">你当前只有查看权限,项目创建入口仅对老板 / 管理员 / 项目管理角色开放。</div>
) : (
<>
<div className="grid gap-3 md:grid-cols-2">
<div className="space-y-2">
<Label>项目名称</Label>
<Input value={name} onChange={(event) => setName(event.target.value)} placeholder="例如:深圳某客户现场实施" />
</div>
<div className="space-y-2">
<Label>客户名称</Label>
<Input value={clientName} onChange={(event) => setClientName(event.target.value)} placeholder="客户全称" />
</div>
<div className="space-y-2">
<Label>客户简称</Label>
<Input value={clientAlias} onChange={(event) => setClientAlias(event.target.value)} placeholder="可选" />
</div>
<div className="space-y-2">
<Label>项目经理</Label>
<select className="select-std" value={managerEmployeeId} onChange={(event) => setManagerEmployeeId(event.target.value)}>
<option value="">未指定</option>
{managerCandidates.map((item) => (
<option key={item.id} value={item.id}>
{item.name} · {item.employeeNo}
</option>
))}
</select>
</div>
</div>
<div className="grid gap-3 md:grid-cols-2">
<div className="space-y-2">
<Label>开始日期</Label>
<DateTextInput value={startsAt} onChange={(event) => setStartsAt(event.target.value)} />
</div>
<div className="space-y-2">
<Label>目标完成</Label>
<DateTextInput value={targetEndAt} onChange={(event) => setTargetEndAt(event.target.value)} />
</div>
</div>
<div className="space-y-2">
<Label>项目摘要</Label>
<Textarea value={summary} onChange={(event) => setSummary(event.target.value)} placeholder="填项目目标、交付范围、关键约束" />
</div>
<label className="flex items-center gap-2 text-sm text-zinc-700">
<input type="checkbox" checked={isConfidential} onChange={(event) => setIsConfidential(event.target.checked)} />
项目含涉密内容(正文与附件继续离线保存)
</label>
</>
)}
<div className="grid gap-3 md:grid-cols-2">
<div className="space-y-2">
<Label>项目名称</Label>
<Input value={name} onChange={(event) => setName(event.target.value)} placeholder="例如:深圳某客户现场实施" />
</div>
<div className="space-y-2">
<Label>客户名称</Label>
<Input value={clientName} onChange={(event) => setClientName(event.target.value)} placeholder="客户全称" />
</div>
<div className="space-y-2">
<Label>客户简称</Label>
<Input value={clientAlias} onChange={(event) => setClientAlias(event.target.value)} placeholder="可选" />
</div>
<div className="space-y-2">
<Label>项目经理</Label>
<select className="select-std" value={managerEmployeeId} onChange={(event) => setManagerEmployeeId(event.target.value)}>
<option value="">未指定</option>
{managerCandidates.map((item) => (
<option key={item.id} value={item.id}>
{item.name} · {item.employeeNo}
</option>
))}
</select>
</div>
</div>
<div className="grid gap-3 md:grid-cols-2">
<div className="space-y-2">
<Label>开始日期</Label>
<DateTextInput value={startsAt} onChange={(event) => setStartsAt(event.target.value)} />
</div>
<div className="space-y-2">
<Label>目标完成</Label>
<DateTextInput value={targetEndAt} onChange={(event) => setTargetEndAt(event.target.value)} />
</div>
</div>
<div className="space-y-2">
<Label>项目摘要</Label>
<Textarea value={summary} onChange={(event) => setSummary(event.target.value)} placeholder="填项目目标、交付范围、关键约束" />
</div>
<label className="flex items-center gap-2 text-sm text-zinc-700">
<input type="checkbox" checked={isConfidential} onChange={(event) => setIsConfidential(event.target.checked)} />
项目含涉密内容(正文与附件继续离线保存)
</label>
<div className="flex flex-wrap gap-2">
{canManageProjects ? (
<Button
type="button"
disabled={createMutation.isPending || !name.trim() || !clientName.trim()}
onClick={() => createMutation.mutate()}
>
{createMutation.isPending ? "创建中..." : "创建项目"}
</Button>
) : null}
<Button type="button" variant={showTrialData ? "default" : "secondary"} onClick={() => setShowTrialData((value) => !value)}>
{showTrialData ? "隐藏测试数据" : "显示测试数据"}
<Button
type="button"
disabled={createMutation.isPending || !name.trim() || !clientName.trim()}
onClick={() => createMutation.mutate()}
>
{createMutation.isPending ? "创建中..." : "创建项目"}
</Button>
<Button type="button" variant="secondary" onClick={() => setShowCreatePanel(false)}>
取消
</Button>
</div>
</div>