完成五人团队正式内用最小收口(07-18-small-team-internal-readiness)
这个提交包含在:
@@ -27,6 +27,7 @@ import { isApiError } from "../api/types";
|
||||
import { useAuth } from "../auth/AuthContext";
|
||||
import { hasAnyPermission, hasPermission } from "../auth/permissions";
|
||||
import { DateTextInput } from "../components/common/DateTextInput";
|
||||
import { useUnsavedChangesGuard } from "../components/common/UnsavedChangesGuard";
|
||||
import { StatusBadge } from "../components/common/StatusBadge";
|
||||
import { TableSkeleton } from "../components/common/TableSkeleton";
|
||||
import {
|
||||
@@ -233,6 +234,7 @@ export function AssetRegistryPage() {
|
||||
const [selectedAssetId, setSelectedAssetId] = useState(searchParams.get("id") ?? "");
|
||||
const [isCreatingAsset, setIsCreatingAsset] = useState(false);
|
||||
const [assetForm, setAssetForm] = useState(initialAssetForm);
|
||||
const [savedAssetFormSignature, setSavedAssetFormSignature] = useState(() => JSON.stringify(initialAssetForm()));
|
||||
const [assetFormError, setAssetFormError] = useState("");
|
||||
const [movementEmployeeId, setMovementEmployeeId] = useState("");
|
||||
const [movementLocation, setMovementLocation] = useState("");
|
||||
@@ -331,7 +333,7 @@ export function AssetRegistryPage() {
|
||||
return;
|
||||
}
|
||||
const asset = assetDetailQuery.data.asset;
|
||||
setAssetForm({
|
||||
const nextAssetForm = {
|
||||
name: asset.name,
|
||||
assetType: asset.assetType,
|
||||
sensitivityLevel: asset.sensitivityLevel,
|
||||
@@ -355,7 +357,9 @@ export function AssetRegistryPage() {
|
||||
expiresAt: asset.expiresAt ?? "",
|
||||
activatedAt: asset.activatedAt ?? "",
|
||||
retiredAt: asset.retiredAt ?? "",
|
||||
});
|
||||
};
|
||||
setAssetForm(nextAssetForm);
|
||||
setSavedAssetFormSignature(JSON.stringify(nextAssetForm));
|
||||
setMovementEmployeeId("");
|
||||
setMovementLocation(asset.location ?? "");
|
||||
setMovementNote("");
|
||||
@@ -379,6 +383,10 @@ export function AssetRegistryPage() {
|
||||
|
||||
const currentAsset = assetDetailQuery.data?.asset ?? null;
|
||||
const canEditCurrent = canManage && (isCreatingAsset || currentAsset?.permissions.canEdit);
|
||||
const runGuarded = useUnsavedChangesGuard(
|
||||
Boolean(isCreatingAsset || selectedAssetId) && Boolean(canEditCurrent) && JSON.stringify(assetForm) !== savedAssetFormSignature,
|
||||
"资产表单",
|
||||
);
|
||||
const hasAdvancedAssetFilters = Boolean(
|
||||
sensitivityFilter ||
|
||||
categoryFilter ||
|
||||
@@ -404,10 +412,14 @@ export function AssetRegistryPage() {
|
||||
}
|
||||
|
||||
function resetAssetEditor() {
|
||||
setIsCreatingAsset(true);
|
||||
setSelectedAssetId("");
|
||||
setAssetForm(initialAssetForm());
|
||||
setAssetFormError("");
|
||||
runGuarded(() => {
|
||||
const nextAssetForm = initialAssetForm();
|
||||
setIsCreatingAsset(true);
|
||||
setSelectedAssetId("");
|
||||
setAssetForm(nextAssetForm);
|
||||
setSavedAssetFormSignature(JSON.stringify(nextAssetForm));
|
||||
setAssetFormError("");
|
||||
});
|
||||
}
|
||||
|
||||
function parseAssetMetadata() {
|
||||
@@ -555,6 +567,7 @@ export function AssetRegistryPage() {
|
||||
queryClient.invalidateQueries({ queryKey: ["assets", "detail"] }),
|
||||
]);
|
||||
setAssetFormError("");
|
||||
setSavedAssetFormSignature(JSON.stringify(assetForm));
|
||||
setSelectedAssetId(data.asset.id);
|
||||
setIsCreatingAsset(false);
|
||||
toast.success(isCreatingAsset ? "资产卡片已创建" : "资产卡片已更新");
|
||||
@@ -711,15 +724,19 @@ export function AssetRegistryPage() {
|
||||
});
|
||||
}, [assetItems]);
|
||||
const selectAsset = (assetId: string) => {
|
||||
setIsCreatingAsset(false);
|
||||
setSelectedAssetId(assetId);
|
||||
runGuarded(() => {
|
||||
setIsCreatingAsset(false);
|
||||
setSelectedAssetId(assetId);
|
||||
});
|
||||
};
|
||||
const returnToAssetList = () => {
|
||||
setIsCreatingAsset(false);
|
||||
setSelectedAssetId("");
|
||||
const next = new URLSearchParams(searchParams);
|
||||
next.delete("id");
|
||||
setSearchParams(next, { replace: true });
|
||||
runGuarded(() => {
|
||||
setIsCreatingAsset(false);
|
||||
setSelectedAssetId("");
|
||||
const next = new URLSearchParams(searchParams);
|
||||
next.delete("id");
|
||||
setSearchParams(next, { replace: true });
|
||||
});
|
||||
};
|
||||
const isAssetDetailMode = isCreatingAsset || Boolean(selectedAssetId);
|
||||
|
||||
|
||||
在新工单中引用
屏蔽一个用户