fix(management/project): task setting
This commit is contained in:
@@ -1,11 +1,31 @@
|
||||
"use client"
|
||||
|
||||
import { projectConfig } from "@/components/label/api/project"
|
||||
import {
|
||||
getProjectAdminList,
|
||||
projectConfig,
|
||||
} from "@/components/label/api/project"
|
||||
import { ProjectDetail } from "@/components/label/api/project/typing"
|
||||
import { useAllUserStore } from "@/components/label/store/auth"
|
||||
import { Button, Group, Paper, Stack, Switch, Text } from "@mantine/core"
|
||||
import {
|
||||
ActionIcon,
|
||||
Collapse,
|
||||
Group,
|
||||
Paper,
|
||||
ScrollArea,
|
||||
SimpleGrid,
|
||||
Stack,
|
||||
Switch,
|
||||
Text,
|
||||
} from "@mantine/core"
|
||||
import { notifications } from "@mantine/notifications"
|
||||
import { useMemo, useState } from "react"
|
||||
import {
|
||||
IconCheck,
|
||||
IconChevronDown,
|
||||
IconChevronRight,
|
||||
IconEdit,
|
||||
IconX,
|
||||
} from "@tabler/icons-react"
|
||||
import { useCallback, useEffect, useMemo, useState } from "react"
|
||||
import AdminUserModal from "./components/AdminUserModal"
|
||||
import LabelSchemeContainer from "./components/LabelSchemeContainer"
|
||||
import NoteRulesTable from "./components/NoteRulesTable"
|
||||
@@ -26,16 +46,55 @@ export default function InfoSettingContainer(props: {
|
||||
const projectId = info?.id ?? -1
|
||||
|
||||
const { userOpts } = useAllUserStore()
|
||||
const userOptions = useMemo(() => {
|
||||
const fallbackUserOptions = useMemo(() => {
|
||||
return userOpts.map((o) => ({ label: o.label, value: String(o.value) }))
|
||||
}, [userOpts])
|
||||
|
||||
const [adminOptions, setAdminOptions] = useState<
|
||||
Array<{ label: string; value: string }>
|
||||
>([])
|
||||
|
||||
const [adminModalOpen, setAdminModalOpen] = useState(false)
|
||||
const [lockingValue, setLockingValue] = useState<boolean>(
|
||||
!!info?.is_lock_object
|
||||
)
|
||||
const [lockingEditValue, setLockingEditValue] = useState<boolean>(
|
||||
!!info?.is_lock_object
|
||||
)
|
||||
const [isLockingEdit, setIsLockingEdit] = useState(false)
|
||||
const [savingLock, setSavingLock] = useState(false)
|
||||
|
||||
const [show, setShow] = useState({
|
||||
process: true,
|
||||
scheme: true,
|
||||
sampling: true,
|
||||
note: true,
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
const v = !!info?.is_lock_object
|
||||
setLockingValue(v)
|
||||
setLockingEditValue(v)
|
||||
setIsLockingEdit(false)
|
||||
}, [info?.is_lock_object])
|
||||
|
||||
const loadAdminOptions = useCallback(async () => {
|
||||
try {
|
||||
const res = await getProjectAdminList()
|
||||
const opts = (res ?? []).map((item) => ({
|
||||
label: item.label,
|
||||
value: String(item.value),
|
||||
}))
|
||||
setAdminOptions(opts)
|
||||
} catch {
|
||||
setAdminOptions([])
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
queueMicrotask(loadAdminOptions)
|
||||
}, [loadAdminOptions])
|
||||
|
||||
const adminText = useMemo(() => {
|
||||
const adminUids = info?.admin_user ?? []
|
||||
const names = adminUids.map((uid) => {
|
||||
@@ -51,13 +110,15 @@ export default function InfoSettingContainer(props: {
|
||||
try {
|
||||
await projectConfig({
|
||||
project_id: projectId,
|
||||
is_lock_object: lockingValue,
|
||||
is_lock_object: lockingEditValue,
|
||||
})
|
||||
notifications.show({
|
||||
color: "green",
|
||||
title: "操作成功",
|
||||
message: "已保存配置",
|
||||
})
|
||||
setLockingValue(lockingEditValue)
|
||||
setIsLockingEdit(false)
|
||||
updateAction()
|
||||
} catch (e) {
|
||||
notifications.show({
|
||||
@@ -70,9 +131,45 @@ export default function InfoSettingContainer(props: {
|
||||
}
|
||||
}
|
||||
|
||||
const sectionTitle = (
|
||||
key: keyof typeof show,
|
||||
title: string,
|
||||
color: "blue" | "orange" | "teal" | "grape"
|
||||
) => {
|
||||
const opened = show[key]
|
||||
return (
|
||||
<Group justify="space-between" wrap="nowrap">
|
||||
<Group gap={8}>
|
||||
<div
|
||||
style={{
|
||||
width: 3,
|
||||
height: 14,
|
||||
borderRadius: 2,
|
||||
backgroundColor: `var(--mantine-color-${color}-6)`,
|
||||
}}
|
||||
/>
|
||||
<Text fw={700}>{title}</Text>
|
||||
</Group>
|
||||
<ActionIcon
|
||||
variant="subtle"
|
||||
color="gray"
|
||||
onClick={() => setShow((s) => ({ ...s, [key]: !opened }))}>
|
||||
{opened ? (
|
||||
<IconChevronDown size={16} />
|
||||
) : (
|
||||
<IconChevronRight size={16} />
|
||||
)}
|
||||
</ActionIcon>
|
||||
</Group>
|
||||
)
|
||||
}
|
||||
|
||||
const finalAdminOptions =
|
||||
adminOptions.length > 0 ? adminOptions : fallbackUserOptions
|
||||
|
||||
return (
|
||||
<>
|
||||
<Stack gap="md" style={{ flex: 1, minHeight: 0 }}>
|
||||
<Stack gap="md" style={{ flex: 1, minHeight: 0 }} w="100%">
|
||||
<Paper
|
||||
withBorder
|
||||
p="sm"
|
||||
@@ -83,74 +180,170 @@ export default function InfoSettingContainer(props: {
|
||||
}}>
|
||||
<Stack gap="sm">
|
||||
<Group justify="space-between" wrap="wrap">
|
||||
<Text fw={700}>基础配置</Text>
|
||||
<Button size="xs" variant="default" onClick={updateAction}>
|
||||
<Text fw={700}>项目配置</Text>
|
||||
<ActionIcon variant="subtle" onClick={updateAction}>
|
||||
<IconEdit size={16} />
|
||||
</ActionIcon>
|
||||
</Group>
|
||||
|
||||
<SimpleGrid cols={{ base: 1, md: 2 }} spacing="sm">
|
||||
<Paper
|
||||
withBorder
|
||||
p="xs"
|
||||
radius="sm"
|
||||
style={{
|
||||
borderColor:
|
||||
"light-dark(var(--mantine-color-gray-4), var(--mantine-color-dark-4))",
|
||||
}}>
|
||||
<Group justify="space-between" wrap="nowrap" align="center">
|
||||
<Stack gap={2} style={{ minWidth: 0 }}>
|
||||
<Text size="sm" fw={600}>
|
||||
项目管理员
|
||||
</Text>
|
||||
<Text
|
||||
size="sm"
|
||||
c="dimmed"
|
||||
style={{
|
||||
maxWidth: 420,
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
whiteSpace: "nowrap",
|
||||
}}>
|
||||
{adminText}
|
||||
</Text>
|
||||
</Stack>
|
||||
<ActionIcon
|
||||
variant="subtle"
|
||||
color="blue"
|
||||
onClick={() => {
|
||||
setAdminModalOpen(true)
|
||||
if (adminOptions.length === 0) {
|
||||
queueMicrotask(loadAdminOptions)
|
||||
}
|
||||
}}>
|
||||
<IconEdit size={16} />
|
||||
</ActionIcon>
|
||||
</Group>
|
||||
</Paper>
|
||||
|
||||
<Paper
|
||||
withBorder
|
||||
p="xs"
|
||||
radius="sm"
|
||||
style={{
|
||||
borderColor:
|
||||
"light-dark(var(--mantine-color-gray-4), var(--mantine-color-dark-4))",
|
||||
}}>
|
||||
<Group justify="space-between" wrap="nowrap" align="center">
|
||||
<Stack gap={2}>
|
||||
<Text size="sm" fw={600}>
|
||||
图片对象锁定
|
||||
</Text>
|
||||
<Text size="sm" c="dimmed">
|
||||
开启后对象可被锁定,避免多人同时标注冲突
|
||||
</Text>
|
||||
</Stack>
|
||||
{isLockingEdit ? (
|
||||
<Group gap={4} wrap="nowrap">
|
||||
<Switch
|
||||
checked={lockingEditValue}
|
||||
onChange={(e) =>
|
||||
setLockingEditValue(e.currentTarget.checked)
|
||||
}
|
||||
/>
|
||||
<ActionIcon
|
||||
variant="subtle"
|
||||
color="gray"
|
||||
onClick={() => {
|
||||
setLockingEditValue(lockingValue)
|
||||
setIsLockingEdit(false)
|
||||
}}>
|
||||
<IconX size={16} />
|
||||
</ActionIcon>
|
||||
<ActionIcon
|
||||
variant="subtle"
|
||||
color="blue"
|
||||
loading={savingLock}
|
||||
onClick={saveLock}>
|
||||
<IconCheck size={16} />
|
||||
</ActionIcon>
|
||||
</Group>
|
||||
) : (
|
||||
<Group gap={8} wrap="nowrap">
|
||||
<Switch checked={lockingValue} readOnly />
|
||||
<ActionIcon
|
||||
variant="subtle"
|
||||
color="blue"
|
||||
onClick={() => setIsLockingEdit(true)}>
|
||||
<IconEdit size={16} />
|
||||
</ActionIcon>
|
||||
</Group>
|
||||
)}
|
||||
</Group>
|
||||
</Paper>
|
||||
</SimpleGrid>
|
||||
|
||||
<Group justify="flex-end">
|
||||
<ActionIcon variant="subtle" onClick={updateAction}>
|
||||
<IconCheck size={16} />
|
||||
</ActionIcon>
|
||||
<Text size="xs" c="dimmed">
|
||||
刷新项目详情
|
||||
</Button>
|
||||
</Group>
|
||||
|
||||
<Group justify="space-between" wrap="wrap">
|
||||
<Stack gap={2}>
|
||||
<Text size="sm" fw={600}>
|
||||
项目管理员
|
||||
</Text>
|
||||
<Text size="sm" c="dimmed">
|
||||
{adminText}
|
||||
</Text>
|
||||
</Stack>
|
||||
<Button
|
||||
size="xs"
|
||||
variant="default"
|
||||
onClick={() => setAdminModalOpen(true)}>
|
||||
编辑
|
||||
</Button>
|
||||
</Group>
|
||||
|
||||
<Group justify="space-between" wrap="wrap">
|
||||
<Stack gap={2}>
|
||||
<Text size="sm" fw={600}>
|
||||
图片对象锁定
|
||||
</Text>
|
||||
<Text size="sm" c="dimmed">
|
||||
开启后对象可被锁定,避免多人同时标注冲突
|
||||
</Text>
|
||||
</Stack>
|
||||
<Group gap="sm">
|
||||
<Switch
|
||||
checked={lockingValue}
|
||||
onChange={(e) => setLockingValue(e.currentTarget.checked)}
|
||||
/>
|
||||
<Button size="xs" loading={savingLock} onClick={saveLock}>
|
||||
保存
|
||||
</Button>
|
||||
</Group>
|
||||
</Text>
|
||||
</Group>
|
||||
</Stack>
|
||||
</Paper>
|
||||
|
||||
<TaskStageTabsContainer
|
||||
projectId={projectId}
|
||||
info={info}
|
||||
userOptions={userOptions}
|
||||
userEnums={userEnums}
|
||||
onUpdatedAction={updateAction}
|
||||
/>
|
||||
<Paper
|
||||
withBorder
|
||||
p="sm"
|
||||
radius="md"
|
||||
style={{
|
||||
borderColor:
|
||||
"light-dark(var(--mantine-color-gray-4), var(--mantine-color-dark-4))",
|
||||
flex: 1,
|
||||
minHeight: 0,
|
||||
}}>
|
||||
<ScrollArea h="100%" type="auto">
|
||||
<Stack gap="sm">
|
||||
{sectionTitle("process", "任务流程", "blue")}
|
||||
<Collapse in={show.process}>
|
||||
<TaskStageTabsContainer
|
||||
projectId={projectId}
|
||||
info={info}
|
||||
userOptions={fallbackUserOptions}
|
||||
userEnums={userEnums}
|
||||
onUpdatedAction={updateAction}
|
||||
/>
|
||||
</Collapse>
|
||||
|
||||
<SamplingPlanContainer
|
||||
projectId={projectId}
|
||||
info={info}
|
||||
onUpdated={updateAction}
|
||||
/>
|
||||
{sectionTitle("scheme", "标注方案", "orange")}
|
||||
<Collapse in={show.scheme}>
|
||||
<LabelSchemeContainer info={info} />
|
||||
</Collapse>
|
||||
|
||||
<LabelSchemeContainer info={info} />
|
||||
{sectionTitle("sampling", "抽检方案", "teal")}
|
||||
<Collapse in={show.sampling}>
|
||||
<SamplingPlanContainer
|
||||
projectId={projectId}
|
||||
info={info}
|
||||
onUpdated={updateAction}
|
||||
/>
|
||||
</Collapse>
|
||||
|
||||
<NoteRulesTable info={info} />
|
||||
{sectionTitle("note", "批注规则", "grape")}
|
||||
<Collapse in={show.note}>
|
||||
<NoteRulesTable info={info} onUpdated={updateAction} />
|
||||
</Collapse>
|
||||
</Stack>
|
||||
</ScrollArea>
|
||||
</Paper>
|
||||
</Stack>
|
||||
|
||||
<AdminUserModal
|
||||
opened={adminModalOpen}
|
||||
value={info?.admin_user ?? []}
|
||||
options={userOptions}
|
||||
options={finalAdminOptions}
|
||||
onCloseAction={async (next) => {
|
||||
setAdminModalOpen(false)
|
||||
if (!next || projectId === -1) return
|
||||
|
||||
Reference in New Issue
Block a user