fix(style): fix
This commit is contained in:
@@ -25,3 +25,42 @@ body {
|
|||||||
:-webkit-full-screen::backdrop {
|
:-webkit-full-screen::backdrop {
|
||||||
background: var(--mantine-color-body);
|
background: var(--mantine-color-body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.qa-preview-content {
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: var(--mantine-color-text);
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qa-preview-content p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qa-preview-content h1,
|
||||||
|
.qa-preview-content h2,
|
||||||
|
.qa-preview-content h3,
|
||||||
|
.qa-preview-content h4,
|
||||||
|
.qa-preview-content h5,
|
||||||
|
.qa-preview-content h6 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qa-preview-content ul,
|
||||||
|
.qa-preview-content ol {
|
||||||
|
margin: 0;
|
||||||
|
padding-left: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qa-preview-content pre,
|
||||||
|
.qa-preview-content code {
|
||||||
|
font-size: 12px;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qa-preview-empty {
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
|||||||
@@ -62,14 +62,11 @@ const EditorContainer = ({
|
|||||||
}, [disabled, isView, editor])
|
}, [disabled, isView, editor])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Sync external value changes to editor
|
if (!editor) return
|
||||||
// Check if editor content differs from value to avoid cursor jump and loops
|
const incomingHtml = value ? value : "<p></p>"
|
||||||
if (editor && value && editor.getHTML() !== value) {
|
if (editor.getHTML() !== incomingHtml) {
|
||||||
// Only set content if it's substantially different.
|
// Keep editor content in sync with external state, including empty value switch.
|
||||||
// Note: editor.getHTML() might return different string than value (e.g. attribute order).
|
editor.commands.setContent(incomingHtml, { emitUpdate: false })
|
||||||
// Ideally we should compare content, but string comparison is a basic check.
|
|
||||||
// If value is empty string, we should clear.
|
|
||||||
editor.commands.setContent(value)
|
|
||||||
}
|
}
|
||||||
}, [value, editor])
|
}, [value, editor])
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
Group,
|
Group,
|
||||||
NumberInput,
|
NumberInput,
|
||||||
Radio,
|
Radio,
|
||||||
|
ScrollArea,
|
||||||
Stack,
|
Stack,
|
||||||
Text,
|
Text,
|
||||||
TextInput,
|
TextInput,
|
||||||
@@ -22,10 +23,12 @@ import { ArrowUpIcon, ArrowUpToLineIcon } from "lucide-react"
|
|||||||
import dynamic from "next/dynamic"
|
import dynamic from "next/dynamic"
|
||||||
import {
|
import {
|
||||||
forwardRef,
|
forwardRef,
|
||||||
|
memo,
|
||||||
useCallback,
|
useCallback,
|
||||||
useEffect,
|
useEffect,
|
||||||
useImperativeHandle,
|
useImperativeHandle,
|
||||||
useMemo,
|
useMemo,
|
||||||
|
useRef,
|
||||||
useState,
|
useState,
|
||||||
} from "react"
|
} from "react"
|
||||||
import { getWrongWordList } from "../api/scheme"
|
import { getWrongWordList } from "../api/scheme"
|
||||||
@@ -78,6 +81,46 @@ const ensureStoredValue = (value?: string) => {
|
|||||||
return `${value}${splitWord}${getTextFromHtml(value)}`
|
return `${value}${splitWord}${getTextFromHtml(value)}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hasPreviewContent = (html?: string) => {
|
||||||
|
if (!html) return false
|
||||||
|
if (/<(img|video|audio|iframe|hr)\b/i.test(html)) return true
|
||||||
|
return (
|
||||||
|
html
|
||||||
|
.replace(/<[^>]+>/g, "")
|
||||||
|
.replace(/ /g, " ")
|
||||||
|
.trim().length > 0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const QaPreviewContent = memo(
|
||||||
|
({
|
||||||
|
html,
|
||||||
|
hasContent,
|
||||||
|
emptyText,
|
||||||
|
}: {
|
||||||
|
html: string
|
||||||
|
hasContent: boolean
|
||||||
|
emptyText: string
|
||||||
|
}) => {
|
||||||
|
const parsedContent = useMemo(() => {
|
||||||
|
if (!hasContent) return null
|
||||||
|
return parse(html)
|
||||||
|
}, [hasContent, html])
|
||||||
|
|
||||||
|
if (!hasContent) {
|
||||||
|
return (
|
||||||
|
<Text size="xs" c="dimmed" className="qa-preview-empty">
|
||||||
|
{emptyText}
|
||||||
|
</Text>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return <Box className="qa-preview-content">{parsedContent}</Box>
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
QaPreviewContent.displayName = "QaPreviewContent"
|
||||||
|
|
||||||
const RightQAContent = forwardRef(
|
const RightQAContent = forwardRef(
|
||||||
({ taskDetail }: ComponentProps, ref: React.Ref<unknown>) => {
|
({ taskDetail }: ComponentProps, ref: React.Ref<unknown>) => {
|
||||||
const { isView } = useTopToolsStore()
|
const { isView } = useTopToolsStore()
|
||||||
@@ -112,7 +155,7 @@ const RightQAContent = forwardRef(
|
|||||||
const counts = useMemo(() => {
|
const counts = useMemo(() => {
|
||||||
return countAllTurnsAndQaNumber(activeImage)
|
return countAllTurnsAndQaNumber(activeImage)
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [activeImage, qaData, updateDescDataFlag, countAllTurnsAndQaNumber])
|
}, [activeImage, qaData, countAllTurnsAndQaNumber])
|
||||||
|
|
||||||
const [open, setOpen] = useState({
|
const [open, setOpen] = useState({
|
||||||
status: false,
|
status: false,
|
||||||
@@ -121,13 +164,17 @@ const RightQAContent = forwardRef(
|
|||||||
isEdit: false,
|
isEdit: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const valueSyncTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
||||||
|
|
||||||
// 新增问题
|
// 新增问题
|
||||||
const onClickAdd = (label: string, index: number) => {
|
const onClickAdd = (label: string, index: number) => {
|
||||||
|
flushPendingValueSync()
|
||||||
setOpen({ status: true, label, idx: index, isEdit: false })
|
setOpen({ status: true, label, idx: index, isEdit: false })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 编辑问题名称
|
// 编辑问题名称
|
||||||
const onClickEdit = (label: string, index: number, val: EditFormProps) => {
|
const onClickEdit = (label: string, index: number, val: EditFormProps) => {
|
||||||
|
flushPendingValueSync()
|
||||||
textForm.setValues({
|
textForm.setValues({
|
||||||
question_name: val.question_name,
|
question_name: val.question_name,
|
||||||
value: val.value || "",
|
value: val.value || "",
|
||||||
@@ -140,7 +187,8 @@ const RightQAContent = forwardRef(
|
|||||||
|
|
||||||
const handleFormUpdate = (
|
const handleFormUpdate = (
|
||||||
changeValues: Record<string, any>,
|
changeValues: Record<string, any>,
|
||||||
rawEditorValue?: string
|
rawEditorValue?: string,
|
||||||
|
options?: { notifyFlag?: boolean }
|
||||||
) => {
|
) => {
|
||||||
if (!selectedQuestion) return
|
if (!selectedQuestion) return
|
||||||
const keys = Object.keys(changeValues)
|
const keys = Object.keys(changeValues)
|
||||||
@@ -154,53 +202,84 @@ const RightQAContent = forwardRef(
|
|||||||
? ensureStoredValue(rawEditorValue)
|
? ensureStoredValue(rawEditorValue)
|
||||||
: ensureStoredValue(formData.value)
|
: ensureStoredValue(formData.value)
|
||||||
const { label, type, category } = selectedQuestion
|
const { label, type, category } = selectedQuestion
|
||||||
const currentQaDataArr = currentQaData[category] ?? []
|
|
||||||
let newArr: { [x: string]: any }[] = []
|
|
||||||
currentQaDataArr.forEach((qaObj: QaObj) => {
|
|
||||||
const [question_name, detail] = Object.entries(qaObj)[0]
|
|
||||||
if (question_name === label) {
|
|
||||||
newArr.push({
|
|
||||||
[question_name]: {
|
|
||||||
value: type === "value" ? nextStoredValue : detail.value,
|
|
||||||
id: formData.round,
|
|
||||||
is_pre: detail.is_pre,
|
|
||||||
tag: formData.tag,
|
|
||||||
uid: detail.uid
|
|
||||||
? detail.uid
|
|
||||||
: usePermissionStore.getState().user_id,
|
|
||||||
create_timestamp: detail.create_timestamp
|
|
||||||
? detail.create_timestamp
|
|
||||||
: dayjs().unix(),
|
|
||||||
modify_uid: usePermissionStore.getState().user_id,
|
|
||||||
modify_timestamp: dayjs().unix(),
|
|
||||||
comment: type === "comment" ? nextStoredValue : detail.comment,
|
|
||||||
flag: hasTagChange ? 0 : detail.tag === 2 ? 1 : 0,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
newArr.push(qaObj)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
try {
|
try {
|
||||||
const finalData = safeClone(currentQaData)
|
const latestQaData = useDescToolsStore.getState().qaData
|
||||||
finalData[category] = newArr
|
const latestCurrentQaData =
|
||||||
qaData.set(activeImage, finalData)
|
latestQaData.get(activeImage) ?? latestQaData.get("init") ?? {}
|
||||||
setQaData(new Map(qaData)) // Force update
|
const latestQaDataArr = latestCurrentQaData[category] ?? []
|
||||||
updateFlag(true) // Ensure flag is updated to trigger recalculations if needed
|
let latestNewArr: { [x: string]: any }[] = []
|
||||||
|
latestQaDataArr.forEach((qaObj: QaObj) => {
|
||||||
|
const [question_name, detail] = Object.entries(qaObj)[0]
|
||||||
|
if (question_name === label) {
|
||||||
|
latestNewArr.push({
|
||||||
|
[question_name]: {
|
||||||
|
value: type === "value" ? nextStoredValue : detail.value,
|
||||||
|
id: formData.round,
|
||||||
|
is_pre: detail.is_pre,
|
||||||
|
tag: formData.tag,
|
||||||
|
uid: detail.uid
|
||||||
|
? detail.uid
|
||||||
|
: usePermissionStore.getState().user_id,
|
||||||
|
create_timestamp: detail.create_timestamp
|
||||||
|
? detail.create_timestamp
|
||||||
|
: dayjs().unix(),
|
||||||
|
modify_uid: usePermissionStore.getState().user_id,
|
||||||
|
modify_timestamp: dayjs().unix(),
|
||||||
|
comment: type === "comment" ? nextStoredValue : detail.comment,
|
||||||
|
flag: hasTagChange ? 0 : detail.tag === 2 ? 1 : 0,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
latestNewArr.push(qaObj)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const finalData = safeClone(latestCurrentQaData)
|
||||||
|
finalData[category] = latestNewArr
|
||||||
|
latestQaData.set(activeImage, finalData)
|
||||||
|
setQaData(new Map(latestQaData)) // Force update
|
||||||
|
if (options?.notifyFlag) {
|
||||||
|
updateFlag(true) // Ensure flag is updated to trigger recalculations if needed
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const flushPendingValueSync = () => {
|
||||||
|
if (!valueSyncTimerRef.current) return
|
||||||
|
clearTimeout(valueSyncTimerRef.current)
|
||||||
|
valueSyncTimerRef.current = null
|
||||||
|
handleFormUpdate({ value: form.values.value }, form.values.value)
|
||||||
|
}
|
||||||
|
|
||||||
const onFieldChange = (
|
const onFieldChange = (
|
||||||
field: string,
|
field: string,
|
||||||
value: any,
|
value: any,
|
||||||
rawEditorValue?: string
|
rawEditorValue?: string
|
||||||
) => {
|
) => {
|
||||||
form.setFieldValue(field, value)
|
form.setFieldValue(field, value)
|
||||||
handleFormUpdate({ [field]: value }, rawEditorValue)
|
if (field === "value") {
|
||||||
|
if (valueSyncTimerRef.current) {
|
||||||
|
clearTimeout(valueSyncTimerRef.current)
|
||||||
|
}
|
||||||
|
valueSyncTimerRef.current = setTimeout(() => {
|
||||||
|
handleFormUpdate({ [field]: value }, rawEditorValue)
|
||||||
|
valueSyncTimerRef.current = null
|
||||||
|
}, 180)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
handleFormUpdate({ [field]: value }, rawEditorValue, { notifyFlag: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
if (valueSyncTimerRef.current) {
|
||||||
|
clearTimeout(valueSyncTimerRef.current)
|
||||||
|
valueSyncTimerRef.current = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!selectedQuestion) return
|
if (!selectedQuestion) return
|
||||||
if (
|
if (
|
||||||
@@ -326,16 +405,19 @@ const RightQAContent = forwardRef(
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box h="100%">
|
<Box
|
||||||
<Text
|
h="100%"
|
||||||
size="sm"
|
style={{ display: "flex", flexDirection: "column", minHeight: 0 }}>
|
||||||
fw={600}
|
<Box px="xs" pt="xs" pb={6}>
|
||||||
px="xs"
|
<Text
|
||||||
mb="xs">{`总轮数:${counts.turns}, 总问题数:${counts.question_size},新增单轮数:${counts.new_single_turns},新增多轮数:${counts.new_multiple_turns}`}</Text>
|
size="xs"
|
||||||
<Box
|
fw={500}
|
||||||
|
c="dimmed">{`总轮数:${counts.turns}, 总问题数:${counts.question_size},新增单轮数:${counts.new_single_turns},新增多轮数:${counts.new_multiple_turns}`}</Text>
|
||||||
|
</Box>
|
||||||
|
<ScrollArea
|
||||||
className="qa-tools-container"
|
className="qa-tools-container"
|
||||||
h="calc(100% - 300px)"
|
style={{ flex: 1, minHeight: 0 }}
|
||||||
style={{ overflowY: "auto" }}>
|
px="xs">
|
||||||
<Accordion multiple>
|
<Accordion multiple>
|
||||||
{Object.entries(currentQaData).map(([qaCategory, qaDataArr]) => {
|
{Object.entries(currentQaData).map(([qaCategory, qaDataArr]) => {
|
||||||
const counts = useDescToolsStore
|
const counts = useDescToolsStore
|
||||||
@@ -345,8 +427,9 @@ const RightQAContent = forwardRef(
|
|||||||
<Accordion.Item key={qaCategory} value={qaCategory}>
|
<Accordion.Item key={qaCategory} value={qaCategory}>
|
||||||
<Accordion.Control>
|
<Accordion.Control>
|
||||||
<Text
|
<Text
|
||||||
|
size="sm"
|
||||||
fw={
|
fw={
|
||||||
600
|
500
|
||||||
}>{`${qaCategory} 轮数:${counts.turns},问题数:${counts.question_size}`}</Text>
|
}>{`${qaCategory} 轮数:${counts.turns},问题数:${counts.question_size}`}</Text>
|
||||||
</Accordion.Control>
|
</Accordion.Control>
|
||||||
<Accordion.Panel>
|
<Accordion.Panel>
|
||||||
@@ -357,6 +440,9 @@ const RightQAContent = forwardRef(
|
|||||||
const commentHtmlText = getHtmlFromStoredValue(
|
const commentHtmlText = getHtmlFromStoredValue(
|
||||||
detail.comment
|
detail.comment
|
||||||
)
|
)
|
||||||
|
const hasValueContent = hasPreviewContent(htmlText)
|
||||||
|
const hasCommentContent =
|
||||||
|
hasPreviewContent(commentHtmlText)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
@@ -371,7 +457,9 @@ const RightQAContent = forwardRef(
|
|||||||
}}>
|
}}>
|
||||||
<Flex gap="xs" mb="xs">
|
<Flex gap="xs" mb="xs">
|
||||||
<Flex align="center">
|
<Flex align="center">
|
||||||
<Text>{question_name}</Text>
|
<Text size="sm" fw={500}>
|
||||||
|
{question_name}
|
||||||
|
</Text>
|
||||||
{!detail.is_pre && !isView ? (
|
{!detail.is_pre && !isView ? (
|
||||||
<ActionIcon
|
<ActionIcon
|
||||||
variant="subtle"
|
variant="subtle"
|
||||||
@@ -390,9 +478,13 @@ const RightQAContent = forwardRef(
|
|||||||
</Flex>
|
</Flex>
|
||||||
<Box>
|
<Box>
|
||||||
{detail.tag === 2 ? (
|
{detail.tag === 2 ? (
|
||||||
<Text c="red">错误</Text>
|
<Text size="xs" fw={500} c="red">
|
||||||
|
错误
|
||||||
|
</Text>
|
||||||
) : detail.tag === 1 ? (
|
) : detail.tag === 1 ? (
|
||||||
<Text c="green">正确</Text>
|
<Text size="xs" fw={500} c="green">
|
||||||
|
正确
|
||||||
|
</Text>
|
||||||
) : null}
|
) : null}
|
||||||
</Box>
|
</Box>
|
||||||
</Flex>
|
</Flex>
|
||||||
@@ -400,7 +492,7 @@ const RightQAContent = forwardRef(
|
|||||||
justify="space-between"
|
justify="space-between"
|
||||||
align="center"
|
align="center"
|
||||||
mb="xs">
|
mb="xs">
|
||||||
<Text size="sm">轮次:{detail.id}</Text>
|
<Text size="xs">轮次:{detail.id}</Text>
|
||||||
{!isView ? (
|
{!isView ? (
|
||||||
<Flex gap="xs">
|
<Flex gap="xs">
|
||||||
{!detail.is_pre ? (
|
{!detail.is_pre ? (
|
||||||
@@ -503,22 +595,28 @@ const RightQAContent = forwardRef(
|
|||||||
: "1px solid var(--mantine-color-gray-3)",
|
: "1px solid var(--mantine-color-gray-3)",
|
||||||
borderRadius: "var(--mantine-radius-md)",
|
borderRadius: "var(--mantine-radius-md)",
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
|
minHeight: "40px",
|
||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
flushPendingValueSync()
|
||||||
setSelectedQuestion({
|
setSelectedQuestion({
|
||||||
label: question_name,
|
label: question_name,
|
||||||
value: detail,
|
value: detail,
|
||||||
type: "value",
|
type: "value",
|
||||||
category: qaCategory,
|
category: qaCategory,
|
||||||
})
|
})
|
||||||
console.log("点击批注", htmlText)
|
// console.log("点击批注", htmlText)
|
||||||
form.setValues({
|
form.setValues({
|
||||||
value: htmlText,
|
value: htmlText,
|
||||||
round: detail.id,
|
round: detail.id,
|
||||||
tag: detail.tag,
|
tag: detail.tag,
|
||||||
})
|
})
|
||||||
}}>
|
}}>
|
||||||
{parse(htmlText)}
|
<QaPreviewContent
|
||||||
|
html={htmlText}
|
||||||
|
hasContent={hasValueContent}
|
||||||
|
emptyText="暂无内容"
|
||||||
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
{commentHtmlText ? (
|
{commentHtmlText ? (
|
||||||
<Box
|
<Box
|
||||||
@@ -528,8 +626,10 @@ const RightQAContent = forwardRef(
|
|||||||
"1px solid var(--mantine-color-red-filled)",
|
"1px solid var(--mantine-color-red-filled)",
|
||||||
borderRadius: "var(--mantine-radius-md)",
|
borderRadius: "var(--mantine-radius-md)",
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
|
minHeight: "40px",
|
||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
flushPendingValueSync()
|
||||||
setSelectedQuestion({
|
setSelectedQuestion({
|
||||||
label: question_name,
|
label: question_name,
|
||||||
value: detail,
|
value: detail,
|
||||||
@@ -542,7 +642,11 @@ const RightQAContent = forwardRef(
|
|||||||
tag: detail.tag,
|
tag: detail.tag,
|
||||||
})
|
})
|
||||||
}}>
|
}}>
|
||||||
{parse(commentHtmlText)}
|
<QaPreviewContent
|
||||||
|
html={commentHtmlText}
|
||||||
|
hasContent={hasCommentContent}
|
||||||
|
emptyText="暂无批注内容"
|
||||||
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
) : null}
|
) : null}
|
||||||
</Box>
|
</Box>
|
||||||
@@ -555,49 +659,84 @@ const RightQAContent = forwardRef(
|
|||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</Accordion>
|
</Accordion>
|
||||||
</Box>
|
</ScrollArea>
|
||||||
<Box
|
<Box
|
||||||
style={{ borderTop: "2px solid var(--mantine-color-gray-3)" }}
|
style={{
|
||||||
|
borderTop:
|
||||||
|
"1px solid light-dark(var(--mantine-color-gray-4), var(--mantine-color-dark-4))",
|
||||||
|
flexShrink: 0,
|
||||||
|
}}
|
||||||
pt="sm"
|
pt="sm"
|
||||||
px="sm">
|
px="sm"
|
||||||
|
pb="sm">
|
||||||
<Stack
|
<Stack
|
||||||
gap="xs"
|
gap="xs"
|
||||||
opacity={!isView ? 1 : 0.5}
|
opacity={!isView ? 1 : 0.5}
|
||||||
style={{ pointerEvents: !isView ? "auto" : "none" }}>
|
style={{ pointerEvents: !isView ? "auto" : "none" }}>
|
||||||
<Flex align="center" gap="xs">
|
<Box
|
||||||
<Text fw={600}>问题</Text>
|
p="xs"
|
||||||
<Text>{selectedQuestion?.label || ""}</Text>
|
style={{
|
||||||
</Flex>
|
border:
|
||||||
<Flex align="center" gap="xs">
|
"1px solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-4))",
|
||||||
<Text>轮次</Text>
|
borderRadius: "var(--mantine-radius-md)",
|
||||||
<NumberInput
|
background:
|
||||||
size="xs"
|
"light-dark(var(--mantine-color-gray-0), var(--mantine-color-dark-6))",
|
||||||
min={1}
|
}}>
|
||||||
{...form.getInputProps("round")}
|
<Flex
|
||||||
onChange={(val) => onFieldChange("round", val)}
|
align="flex-end"
|
||||||
disabled={
|
justify="space-between"
|
||||||
!selectedQuestion ||
|
gap="sm"
|
||||||
(selectedQuestion && selectedQuestion.value?.is_pre)
|
wrap="wrap">
|
||||||
}
|
<Box style={{ flex: 1, minWidth: 140 }}>
|
||||||
/>
|
<Text size="xs" c="dimmed">
|
||||||
<Radio.Group
|
当前问题
|
||||||
size="xs"
|
</Text>
|
||||||
{...form.getInputProps("tag")}
|
<Text size="sm" fw={500} truncate="end">
|
||||||
onChange={(val) => onFieldChange("tag", Number(val))}>
|
{selectedQuestion?.label || "未选择问题"}
|
||||||
<Group gap="xs">
|
</Text>
|
||||||
<Radio
|
</Box>
|
||||||
label="正确"
|
<Box w={100}>
|
||||||
value={1}
|
<Text size="xs" c="dimmed" mb={4}>
|
||||||
disabled={!isReview || isView}
|
轮次
|
||||||
|
</Text>
|
||||||
|
<NumberInput
|
||||||
|
size="xs"
|
||||||
|
min={1}
|
||||||
|
{...form.getInputProps("round")}
|
||||||
|
onChange={(val) => onFieldChange("round", val)}
|
||||||
|
disabled={
|
||||||
|
!selectedQuestion ||
|
||||||
|
(selectedQuestion && selectedQuestion.value?.is_pre)
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<Radio
|
</Box>
|
||||||
label="错误"
|
</Flex>
|
||||||
value={2}
|
<Flex align="center" gap="xs" mt="xs">
|
||||||
disabled={!isReview || isView}
|
<Text size="xs" c="dimmed">
|
||||||
/>
|
审核结果
|
||||||
</Group>
|
</Text>
|
||||||
</Radio.Group>
|
<Radio.Group
|
||||||
</Flex>
|
size="xs"
|
||||||
|
{...form.getInputProps("tag")}
|
||||||
|
onChange={(val) => onFieldChange("tag", Number(val))}>
|
||||||
|
<Group gap="xs">
|
||||||
|
<Radio
|
||||||
|
label="正确"
|
||||||
|
value={1}
|
||||||
|
disabled={!isReview || isView}
|
||||||
|
/>
|
||||||
|
<Radio
|
||||||
|
label="错误"
|
||||||
|
value={2}
|
||||||
|
disabled={!isReview || isView}
|
||||||
|
/>
|
||||||
|
</Group>
|
||||||
|
</Radio.Group>
|
||||||
|
</Flex>
|
||||||
|
</Box>
|
||||||
|
<Text size="xs" c="dimmed">
|
||||||
|
内容编辑
|
||||||
|
</Text>
|
||||||
<EditorContainer
|
<EditorContainer
|
||||||
value={form.values.value}
|
value={form.values.value}
|
||||||
onChange={(val: string) =>
|
onChange={(val: string) =>
|
||||||
|
|||||||
Reference in New Issue
Block a user