fix(top): fix
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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] || {}
|
||||
)
|
||||
|
||||
// 存值
|
||||
|
||||
@@ -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) =>
|
||||
|
||||
Reference in New Issue
Block a user