fix(top): fix

This commit is contained in:
2026-03-19 18:03:41 +08:00
parent a6c83ef3f6
commit de91f1c9d8
4 changed files with 233 additions and 141 deletions

View File

@@ -1600,7 +1600,12 @@ const PaperContainer = (
)?.select_mode
switch (select_mode) {
case 2:
obj[key] = (value as string).split(",")
obj[key] = Array.isArray(value)
? value
: (value as string)
.split(",")
.map((item) => item.trim())
.filter(Boolean)
return
default:
obj[key] = value as string

View File

@@ -1423,16 +1423,97 @@ const TopTools = (
},
})
const getPresetFormValues = useCallback(
(
operationId: string,
values: Record<string, string | string[] | undefined> = {}
) => {
const schema = getOperationSchema(operationId)
if (!schema?.sub_attributes_describe?.length) return {}
const nextValues: Record<string, string | string[]> = {}
schema.sub_attributes_describe.forEach((item) => {
const currentValue = values[item.chinese_name]
if (
currentValue === undefined ||
currentValue === null ||
currentValue === ""
)
return
if (item.select_mode === 2) {
nextValues[item.chinese_name] = Array.isArray(currentValue)
? currentValue
: currentValue
.split(",")
.map((value) => value.trim())
.filter(Boolean)
return
}
nextValues[item.chinese_name] = Array.isArray(currentValue)
? currentValue[0] || ""
: currentValue
})
return nextValues
},
[getOperationSchema]
)
const getPresetStoreValues = useCallback(
(operationId: string, values: Record<string, any> = {}) => {
const schema = getOperationSchema(operationId)
if (!schema?.sub_attributes_describe?.length) return {}
const nextValues: Record<string, string> = {}
schema.sub_attributes_describe.forEach((item) => {
const currentValue = values[item.chinese_name]
if (
currentValue === undefined ||
currentValue === null ||
currentValue === ""
)
return
if (item.select_mode === 2) {
nextValues[item.chinese_name] = Array.isArray(currentValue)
? currentValue.join(",")
: currentValue
return
}
nextValues[item.chinese_name] = Array.isArray(currentValue)
? currentValue[0] || ""
: currentValue
})
return nextValues
},
[getOperationSchema]
)
useEffect(() => {
let operationSchema = getOperationSchema(activeOperation)
if (operationSchema?.label_class && subAttrPresetShow) {
form.setFieldValue(
"sub_attributes",
subAttributes[operationSchema?.label_class] || {}
getPresetFormValues(
activeOperation,
subAttributes[operationSchema?.label_class] || {}
)
)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [activeOperation, getOperationSchema, subAttributes, subAttrPresetShow])
}, [
activeOperation,
getOperationSchema,
getPresetFormValues,
subAttributes,
subAttrPresetShow,
])
useEffect(() => {
usePaperStore.getState().polygonTool?.emit("keydown", { key: "escape" })
@@ -1441,115 +1522,110 @@ const TopTools = (
usePaperStore.getState().pointTool?.emit("keydown", { key: "escape" })
}, [activeOperation, mode])
const subAttrForm = useMemo(() => {
let operationSchema = getOperationSchema(activeOperation)
const operationSchema = getOperationSchema(activeOperation)
return (
<Box w={256}>
<Flex
justify="space-between"
align="center"
pb={4}
mb={8}
style={{
borderBottom:
"1px solid light-dark(var(--mantine-color-gray-4), var(--mantine-color-dark-4))",
fontWeight: 700,
}}>
<Box>
<Text span c="blue">
{`${getOperationSchema(activeOperation)?.label_class}`}
</Text>
<Text span size="sm" ml={4}>
</Text>
</Box>
<Flex>
<Button
variant="transparent"
size="xs"
onClick={async () => {
const { hasErrors } = form.validate()
if (hasErrors) return
if (operationSchema?.label_class)
setsubAttributes(
operationSchema?.label_class,
form.values.sub_attributes
)
// setSubAttrPresetShow(false);
}}>
</Button>
<Button
variant="transparent"
size="xs"
onClick={() => {
form.reset()
if (operationSchema?.label_class)
setsubAttributes(operationSchema?.label_class, {})
// setSubAttrPresetShow(false);
}}>
</Button>
</Flex>
</Flex>
<ScrollArea.Autosize mah={300}>
<Stack gap="xs">
{operationSchema?.sub_attributes_describe.map((item) => {
if (item.select_mode === 0) {
return (
<TextInput
key={item.chinese_name}
label={item.chinese_name}
placeholder={`请输入${item.chinese_name}`}
size="xs"
{...form.getInputProps(
`sub_attributes.${item.chinese_name}`
)}
/>
const subAttrForm = (
<Box w={256}>
<Flex
justify="space-between"
align="center"
pb={4}
mb={8}
style={{
borderBottom:
"1px solid light-dark(var(--mantine-color-gray-4), var(--mantine-color-dark-4))",
fontWeight: 700,
}}>
<Box>
<Text span c="blue">
{`${operationSchema?.label_class || ""}`}
</Text>
<Text span size="sm" ml={4}>
</Text>
</Box>
<Flex>
<Button
variant="transparent"
size="xs"
onClick={async () => {
const { hasErrors } = form.validate()
if (hasErrors) return
if (operationSchema?.label_class) {
const nextPresetValues = getPresetStoreValues(
activeOperation,
safeClone(form.values.sub_attributes || {})
)
} else if (item.select_mode === 1) {
return (
<Radio.Group
key={item.chinese_name}
label={item.chinese_name}
size="xs"
{...form.getInputProps(
`sub_attributes.${item.chinese_name}`
)}>
<Group mt="xs" gap="xs">
{item.optional_item.map((option) => (
<Radio key={option} value={option} label={option} />
))}
</Group>
</Radio.Group>
)
} else if (item.select_mode === 2) {
return (
<Checkbox.Group
key={item.chinese_name}
label={item.chinese_name}
size="xs"
{...form.getInputProps(
`sub_attributes.${item.chinese_name}`
)}>
<Group mt="xs" gap="xs">
{item.optional_item.map((option) => (
<Checkbox key={option} value={option} label={option} />
))}
</Group>
</Checkbox.Group>
)
} else {
return null
setsubAttributes(operationSchema.label_class, nextPresetValues)
}
})}
</Stack>
</ScrollArea.Autosize>
</Box>
)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [activeOperation, getOperationSchema, setsubAttributes])
}}>
</Button>
<Button
variant="transparent"
size="xs"
onClick={() => {
form.reset()
if (operationSchema?.label_class)
setsubAttributes(operationSchema.label_class, {})
}}>
</Button>
</Flex>
</Flex>
<ScrollArea.Autosize mah={300}>
<Stack gap="xs">
{operationSchema?.sub_attributes_describe.map((item) => {
if (item.select_mode === 0) {
return (
<TextInput
key={item.chinese_name}
label={item.chinese_name}
placeholder={`请输入${item.chinese_name}`}
size="xs"
{...form.getInputProps(`sub_attributes.${item.chinese_name}`)}
/>
)
} else if (item.select_mode === 1) {
return (
<Radio.Group
key={item.chinese_name}
label={item.chinese_name}
size="xs"
{...form.getInputProps(
`sub_attributes.${item.chinese_name}`
)}>
<Group mt="xs" gap="xs">
{item.optional_item.map((option) => (
<Radio key={option} value={option} label={option} />
))}
</Group>
</Radio.Group>
)
} else if (item.select_mode === 2) {
return (
<Checkbox.Group
key={item.chinese_name}
label={item.chinese_name}
size="xs"
{...form.getInputProps(
`sub_attributes.${item.chinese_name}`
)}>
<Group mt="xs" gap="xs">
{item.optional_item.map((option) => (
<Checkbox key={option} value={option} label={option} />
))}
</Group>
</Checkbox.Group>
)
} else {
return null
}
})}
</Stack>
</ScrollArea.Autosize>
</Box>
)
useImperativeHandle(ref, () => ({
handleSave,
@@ -2047,28 +2123,39 @@ const TopTools = (
{renderOperationIcon(getOperationSchema(activeOperation))}
</Button>
<Popover
position="bottom"
position="bottom-start"
zIndex={49}
shadow="md"
width={280}
opened={
getOperationSchema(activeOperation)?.sub_attributes_describe
?.length
? subAttrPresetShow
: false
}>
!!operationSchema?.sub_attributes_describe?.length &&
subAttrPresetShow
}
onChange={setSubAttrPresetShow}>
<Popover.Target>
<ActionIcon
variant="transparent"
c="var(--mantine-color-text)"
style={{ width: "auto", display: "flex" }}
<UnstyledButton
onClick={() => {
if (!operationSchema?.sub_attributes_describe?.length) return
setSubAttrPresetShow(!subAttrPresetShow)
}}
style={{
display: "flex",
alignItems: "center",
gap: 4,
borderRadius: 6,
padding: "2px 4px",
cursor: operationSchema?.sub_attributes_describe?.length
? "pointer"
: "default",
opacity: operationSchema?.sub_attributes_describe?.length
? 1
: 0.6,
}}>
{renderOperationIcon(getOperationSchema(activeOperation))}
<Text span size="xs" style={{ width: "max-content" }} ml={4}>
{getOperationSchema(activeOperation)?.label_class || ""}
{renderOperationIcon(operationSchema)}
<Text span size="xs" style={{ width: "max-content" }}>
{operationSchema?.label_class || ""}
</Text>
</ActionIcon>
</UnstyledButton>
</Popover.Target>
<Popover.Dropdown>{subAttrForm}</Popover.Dropdown>
</Popover>

View File

@@ -2866,9 +2866,8 @@ export const usePaperStore = create<PaperState>((set) => ({
useTopToolsStore.getState().activeOperation
)
let label_class = category?.label_class || ""
let subAttr = Object.assign(
{},
useTopToolsStore.getState().subAttributes[label_class]
let subAttr = safeClone(
useTopToolsStore.getState().subAttributes[label_class] || {}
)
// 镂空或分割的多边形存值
@@ -3352,9 +3351,8 @@ export const usePaperStore = create<PaperState>((set) => ({
useTopToolsStore.getState().activeOperation
)
let label_class = category?.label_class || ""
let subAttr = Object.assign(
{},
useTopToolsStore.getState().subAttributes[label_class]
let subAttr = safeClone(
useTopToolsStore.getState().subAttributes[label_class] || {}
)
useLabelStore
.getState()
@@ -3623,9 +3621,8 @@ export const usePaperStore = create<PaperState>((set) => ({
useTopToolsStore.getState().activeOperation
)
let label_class = category?.label_class || ""
let subAttr = Object.assign(
{},
useTopToolsStore.getState().subAttributes[label_class]
let subAttr = safeClone(
useTopToolsStore.getState().subAttributes[label_class] || {}
)
// 多线段存值
@@ -3998,9 +3995,8 @@ export const usePaperStore = create<PaperState>((set) => ({
useTopToolsStore.getState().activeOperation
)
let label_class = category?.label_class || ""
let subAttr = Object.assign(
{},
useTopToolsStore.getState().subAttributes[label_class]
let subAttr = safeClone(
useTopToolsStore.getState().subAttributes[label_class] || {}
)
// 存值

View File

@@ -4,6 +4,7 @@ import { persist } from "zustand/middleware"
import { usePaperStore } from "./usePaperStore"
import { useObjectStore } from "./store"
import { useBottomToolsStore } from "./useBottomToolsStore"
import { safeClone } from "./utils/clone"
interface TopToolsState {
// 标注页面是否仅查看
@@ -59,10 +60,13 @@ interface TopToolsState {
subAttributes: {
// key: label_class
[key: string]: {
[key: string]: string
[key: string]: string | string[]
}
}
setsubAttributes: (key: string, val: { [key: string]: string }) => void
setsubAttributes: (
key: string,
val: { [key: string]: string | string[] }
) => void
objectOperations: Project.LabelSchemaList[]
setObjectOperations: (val: Project.LabelSchemaList[]) => void
needBackup: boolean
@@ -219,10 +223,10 @@ export const useTopToolsStore = create<TopToolsState>()(
setsubAttributes: (key, val) =>
set((state: TopToolsState) => ({
...state,
subAttributes: Object.assign(
useTopToolsStore.getState().subAttributes,
{ [key]: val }
),
subAttributes: {
...state.subAttributes,
[key]: safeClone(val),
},
})),
objectOperations: initialTopToolsState.objectOperations,
setObjectOperations: (val) =>