Commit a3dfaf51 authored by David Yang's avatar David Yang

feat: 批量导入

parent 5ac06b5a
No preview for this file type
No preview for this file type
...@@ -233,16 +233,13 @@ export default function ProjectManagerLayout() { ...@@ -233,16 +233,13 @@ export default function ProjectManagerLayout() {
sidebarCollapsed ? 'justify-center' : 'gap-3 px-1', sidebarCollapsed ? 'justify-center' : 'gap-3 px-1',
)} )}
> >
{sidebarCollapsed ? (
<img <img
src={sidebarCollapsed ? xyLogoSmall : xyLogo} src={xyLogoSmall}
alt="XY Logo" alt="XY Logo"
className={clsx( className="h-9 w-auto max-w-[52px] shrink-0 object-contain"
'shrink-0 object-contain',
sidebarCollapsed
? 'h-9 w-auto max-w-[52px]'
: 'h-5 w-auto max-w-[128px]',
)}
/> />
) : null}
{!sidebarCollapsed ? ( {!sidebarCollapsed ? (
<h1 className="truncate text-sm font-semibold tracking-[0.02em] text-white/95"> <h1 className="truncate text-sm font-semibold tracking-[0.02em] text-white/95">
{APP_NAME} {APP_NAME}
......
...@@ -1488,7 +1488,7 @@ export default function ResourceBookingPage() { ...@@ -1488,7 +1488,7 @@ export default function ResourceBookingPage() {
<DialogBody> <DialogBody>
<div className="space-y-6"> <div className="space-y-6">
<div className="rounded-[24px] border border-sky-100 bg-sky-50 px-4 py-3 text-sm text-sky-700"> <div className="rounded-[24px] border border-sky-100 bg-sky-50 px-4 py-3 text-sm text-sky-700">
当前共选中 {selectedCount} 份材料,批量修改会写回 `am_material.metadata`。 当前共选中 {selectedCount} 份材料,批量修改会同步更新你勾选的字段。
</div> </div>
<FormSection <FormSection
...@@ -1513,7 +1513,7 @@ export default function ResourceBookingPage() { ...@@ -1513,7 +1513,7 @@ export default function ResourceBookingPage() {
批量更新来源应用 批量更新来源应用
</div> </div>
<div data-slot="description" className="text-sm text-zinc-500"> <div data-slot="description" className="text-sm text-zinc-500">
对应 `metadata.source_app`。 勾选后可统一覆盖所有已选材料的来源应用。
</div> </div>
</div> </div>
</CheckboxField> </CheckboxField>
...@@ -1548,7 +1548,7 @@ export default function ResourceBookingPage() { ...@@ -1548,7 +1548,7 @@ export default function ResourceBookingPage() {
批量更新材料分类 批量更新材料分类
</div> </div>
<div data-slot="description" className="text-sm text-zinc-500"> <div data-slot="description" className="text-sm text-zinc-500">
对应 `metadata.archive_category`。 勾选后可统一覆盖所有已选材料的材料分类。
</div> </div>
</div> </div>
</CheckboxField> </CheckboxField>
...@@ -1583,7 +1583,7 @@ export default function ResourceBookingPage() { ...@@ -1583,7 +1583,7 @@ export default function ResourceBookingPage() {
批量更新提供部门 批量更新提供部门
</div> </div>
<div data-slot="description" className="text-sm text-zinc-500"> <div data-slot="description" className="text-sm text-zinc-500">
对应 `metadata.provide_department`。 勾选后可统一覆盖所有已选材料的提供部门。
</div> </div>
</div> </div>
</CheckboxField> </CheckboxField>
...@@ -1617,7 +1617,7 @@ export default function ResourceBookingPage() { ...@@ -1617,7 +1617,7 @@ export default function ResourceBookingPage() {
批量更新提供时间 批量更新提供时间
</div> </div>
<div data-slot="description" className="text-sm text-zinc-500"> <div data-slot="description" className="text-sm text-zinc-500">
提交时会统一转换为 ISO 8601 字符串。 保存后会自动转换为标准时间格式。
</div> </div>
</div> </div>
</CheckboxField> </CheckboxField>
...@@ -1660,7 +1660,7 @@ export default function ResourceBookingPage() { ...@@ -1660,7 +1660,7 @@ export default function ResourceBookingPage() {
批量更新是否涉密 批量更新是否涉密
</div> </div>
<div data-slot="description" className="text-sm text-zinc-500"> <div data-slot="description" className="text-sm text-zinc-500">
勾选后,将下面的值统一写入 `is_confidential`。 勾选后,会将下面的值统一应用到所有已选材料。
</div> </div>
</div> </div>
</CheckboxField> </CheckboxField>
...@@ -1700,7 +1700,7 @@ export default function ResourceBookingPage() { ...@@ -1700,7 +1700,7 @@ export default function ResourceBookingPage() {
批量更新是否审计部材料 批量更新是否审计部材料
</div> </div>
<div data-slot="description" className="text-sm text-zinc-500"> <div data-slot="description" className="text-sm text-zinc-500">
勾选后,将下面的值统一写入 `is_audit_dept_material`。 勾选后,会将下面的值统一应用到所有已选材料。
</div> </div>
</div> </div>
</CheckboxField> </CheckboxField>
...@@ -1758,7 +1758,7 @@ export default function ResourceBookingPage() { ...@@ -1758,7 +1758,7 @@ export default function ResourceBookingPage() {
> >
<DialogTitle>批量打标签</DialogTitle> <DialogTitle>批量打标签</DialogTitle>
<DialogDescription> <DialogDescription>
为当前勾选材料统一写入同一个标签值,提交时会覆盖原 `metadata.tag`。 为当前勾选材料统一设置同一个标签值,提交后会覆盖原标签。
</DialogDescription> </DialogDescription>
<DialogBody> <DialogBody>
<div className="space-y-5"> <div className="space-y-5">
...@@ -1803,7 +1803,7 @@ export default function ResourceBookingPage() { ...@@ -1803,7 +1803,7 @@ export default function ResourceBookingPage() {
<Dialog open={isUploadOpen} onClose={handleUploadDialogClose} size="3xl"> <Dialog open={isUploadOpen} onClose={handleUploadDialogClose} size="3xl">
<DialogTitle>上传材料</DialogTitle> <DialogTitle>上传材料</DialogTitle>
<DialogDescription> <DialogDescription>
创建页已按最新对象文档补齐字段,上传完成后会统一写入 `am_material.metadata`。 创建页已按最新对象文档补齐字段,上传完成后会统一保存到材料档案。
</DialogDescription> </DialogDescription>
<DialogBody> <DialogBody>
<div className="space-y-6"> <div className="space-y-6">
......
...@@ -128,7 +128,7 @@ function ChartPanel({ option, className = '', emptyText = '暂无图表数据' } ...@@ -128,7 +128,7 @@ function ChartPanel({ option, className = '', emptyText = '暂无图表数据' }
option={option} option={option}
notMerge notMerge
lazyUpdate lazyUpdate
className={clsx('h-[320px] w-full', className)} className={clsx('min-h-[280px] w-full', className)}
/> />
); );
} }
...@@ -604,63 +604,18 @@ export default function ResourceStatPage() { ...@@ -604,63 +604,18 @@ export default function ResourceStatPage() {
</Panel> </Panel>
</div> </div>
<div className="grid gap-6 xl:grid-cols-[1.1fr_0.9fr]">
<Panel className="p-6">
<SectionHeader
title="最近上传"
description="快速浏览最近进入材料池的文件,便于发现异常命名、来源遗漏或归档不完整的情况。"
/>
<div className="space-y-3">
{dashboard.recentMaterials.length > 0 ? (
dashboard.recentMaterials.map((item) => (
<div
key={item.id}
className="flex flex-col gap-3 rounded-[24px] border border-zinc-200 bg-zinc-50/70 px-4 py-4 sm:flex-row sm:items-center sm:justify-between"
>
<div className="min-w-0">
<div className="flex flex-wrap items-center gap-2">
<div className="truncate text-sm font-semibold text-zinc-950 sm:text-base">
{item.materialTitle}
</div>
<TagPill>{item.archiveCategory}</TagPill>
{item.tag ? <TagPill>{item.tag}</TagPill> : null}
</div>
<div className="mt-2 text-sm text-zinc-500">
{item.sourceAppLabel} · {item.uploaderLabel} · {item.fileSizeLabel}
</div>
<div className="mt-2 flex flex-wrap gap-2">
{item.isConfidential ? <TagPill tone="amber">涉密</TagPill> : null}
{item.isAuditDeptMaterial ? (
<TagPill tone="emerald">审计部材料</TagPill>
) : null}
{item.provideDepartment ? (
<TagPill>{item.provideDepartment}</TagPill>
) : null}
{item.tag ? <TagPill>{item.tag}</TagPill> : null}
</div>
</div>
<div className="text-sm text-zinc-500">{formatDateTime(item.uploadedAt)}</div>
</div>
))
) : (
<div className="text-sm text-zinc-400">暂无最近上传材料</div>
)}
</div>
</Panel>
<div className="space-y-6">
<Panel className="p-6"> <Panel className="p-6">
<SectionHeader <SectionHeader
title="提供与合规" title="提供与合规"
description="根据最新字段快速看清提供信息补录进度,以及涉密、审计部材料的标记情况。" description="根据最新字段快速看清提供信息补录进度,以及涉密、审计部材料的标记情况。"
/> />
<div className="grid gap-4 lg:grid-cols-[1.15fr_0.85fr]"> <div className="grid gap-5 xl:grid-cols-[minmax(0,1.15fr)_minmax(20rem,0.85fr)] xl:items-stretch">
<ChartPanel <ChartPanel
option={governanceOption} option={governanceOption}
className="h-[300px]" className="h-[320px] sm:h-[340px] xl:h-[360px]"
emptyText="暂无提供与合规数据" emptyText="暂无提供与合规数据"
/> />
<div className="space-y-3"> <div className="grid gap-3 sm:grid-cols-2 xl:grid-cols-1">
<div className="rounded-[22px] border border-zinc-200 bg-zinc-50/80 px-4 py-4"> <div className="rounded-[22px] border border-zinc-200 bg-zinc-50/80 px-4 py-4">
<div className="text-sm text-zinc-500">已补齐提供信息</div> <div className="text-sm text-zinc-500">已补齐提供信息</div>
<div className="mt-2 text-2xl font-semibold text-zinc-950"> <div className="mt-2 text-2xl font-semibold text-zinc-950">
...@@ -688,21 +643,63 @@ export default function ResourceStatPage() { ...@@ -688,21 +643,63 @@ export default function ResourceStatPage() {
)} )}
</div> </div>
</div> </div>
<div className="rounded-[22px] border border-dashed border-zinc-200 bg-zinc-50/70 px-4 py-4 text-sm text-zinc-600 sm:col-span-2 xl:col-span-1">
图表外圈表示提供信息补录情况,内圈用于区分涉密材料、审计部材料与其它材料,便于先看合规密度,再判断是否需要回到归档页补录。
</div>
</div> </div>
</div> </div>
<div className="mt-4 flex flex-wrap gap-2"> <div className="mt-4 flex flex-wrap gap-2">
<TagPill tone="amber">涉密 {dashboard.confidentialCount}</TagPill> <TagPill tone="amber">涉密 {dashboard.confidentialCount}</TagPill>
<TagPill tone="emerald"> <TagPill tone="emerald">审计部材料 {dashboard.auditDeptCount}</TagPill>
审计部材料 {dashboard.auditDeptCount}
</TagPill>
</div> </div>
</Panel>
<div className="mt-5 rounded-[22px] border border-dashed border-zinc-200 bg-zinc-50/70 px-4 py-4 text-sm text-zinc-600"> <div className="grid gap-6 xl:grid-cols-[1.1fr_0.9fr]">
图表外圈表示提供信息补录情况,内圈用于区分涉密材料、审计部材料与其它材料,便于先看合规密度,再判断是否需要回到归档页补录。 <Panel className="p-6">
<SectionHeader
title="最近上传"
description="快速浏览最近进入材料池的文件,便于发现异常命名、来源遗漏或归档不完整的情况。"
/>
<div className="space-y-3">
{dashboard.recentMaterials.length > 0 ? (
dashboard.recentMaterials.map((item) => (
<div
key={item.id}
className="flex flex-col gap-3 rounded-[24px] border border-zinc-200 bg-zinc-50/70 px-4 py-4 sm:flex-row sm:items-center sm:justify-between"
>
<div className="min-w-0">
<div className="flex flex-wrap items-center gap-2">
<div className="truncate text-sm font-semibold text-zinc-950 sm:text-base">
{item.materialTitle}
</div>
<TagPill>{item.archiveCategory}</TagPill>
{item.tag ? <TagPill>{item.tag}</TagPill> : null}
</div>
<div className="mt-2 text-sm text-zinc-500">
{item.sourceAppLabel} · {item.uploaderLabel} · {item.fileSizeLabel}
</div>
<div className="mt-2 flex flex-wrap gap-2">
{item.isConfidential ? <TagPill tone="amber">涉密</TagPill> : null}
{item.isAuditDeptMaterial ? (
<TagPill tone="emerald">审计部材料</TagPill>
) : null}
{item.provideDepartment ? (
<TagPill>{item.provideDepartment}</TagPill>
) : null}
{item.tag ? <TagPill>{item.tag}</TagPill> : null}
</div>
</div>
<div className="text-sm text-zinc-500">{formatDateTime(item.uploadedAt)}</div>
</div>
))
) : (
<div className="text-sm text-zinc-400">暂无最近上传材料</div>
)}
</div> </div>
</Panel> </Panel>
<div className="space-y-6">
<Panel className="p-6"> <Panel className="p-6">
<SectionHeader <SectionHeader
title="待完善清单" title="待完善清单"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment