统一业务台账首屏布局(05-30-fix-payment-ledger-layout-consistency)
这个提交包含在:
@@ -187,67 +187,66 @@ export function ProjectsPage() {
|
||||
|
||||
{showLedgerTools ? (
|
||||
<SectionPanel title="台账工具">
|
||||
<div className="grid gap-5 xl:grid-cols-[minmax(0,1fr),260px]">
|
||||
<div>
|
||||
{!canManageProjects ? (
|
||||
<div className="text-sm text-zinc-500">你当前只有查看权限,项目创建入口仅对老板 / 管理员 / 项目管理角色开放。</div>
|
||||
) : (
|
||||
<div className="space-y-4">
|
||||
<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 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>
|
||||
<Textarea value={summary} onChange={(event) => setSummary(event.target.value)} placeholder="填项目目标、交付范围、关键约束" />
|
||||
<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>
|
||||
<label className="flex items-center gap-2 text-sm text-zinc-700">
|
||||
<input type="checkbox" checked={isConfidential} onChange={(event) => setIsConfidential(event.target.checked)} />
|
||||
项目含涉密内容(正文与附件继续离线保存)
|
||||
</label>
|
||||
<Button
|
||||
type="button"
|
||||
disabled={createMutation.isPending || !name.trim() || !clientName.trim()}
|
||||
onClick={() => createMutation.mutate()}
|
||||
>
|
||||
{createMutation.isPending ? "创建中..." : "创建项目"}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="space-y-3 rounded-lg border border-slate-200 bg-slate-50 p-4 text-sm text-slate-600">
|
||||
<div className="font-medium text-slate-900">低频查看</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>
|
||||
|
||||
在新工单中引用
屏蔽一个用户