fix(ci): add file

This commit is contained in:
zhangheng
2026-03-28 16:39:27 +08:00
parent 27d47b5692
commit 76bfb30fef
5 changed files with 166 additions and 59 deletions

28
.gitlab-ci.yml Normal file
View File

@@ -0,0 +1,28 @@
stages:
- sync_github
sync_github:
stage: sync_github
tags:
- webfront
image: harbor.cowarobot.cn/softrepo/rust_build:1.94
script:
- echo "代码已合并到 main, 开始执行发布逻辑..."
- |
for i in {1..10}; do
if command -v docker >/dev/null 2>&1 && [ -S /var/run/docker.sock ]; then
echo "Docker is ready!"
break
fi
echo "Waiting for Docker..."
sleep 2
done
- docker info
- echo ${CI_PROJECT_NAME} ${CI_PROJECT_PATH} ${CI_PROJECT_DIR} ${CI_PROJECT_URL} ${CI_COMMIT_SHA}
- echo ${HARBORKEY} | docker login harbor.cowarobot.cn -u 'robot$softpro+cibuild' --password-stdin
- rm -rf ${CI_PROJECT_NAME}
- git clone https://oauth2:glpat-EdU8a_84jpSH2nOlNTkpnW86MQp1OjY1CA.01.0y1rtht99@git.cowarobot.com/${CI_PROJECT_PATH}
- cd ${CI_PROJECT_NAME}
- bash build.sh prod
rules:
- if: $CI_COMMIT_BRANCH == "main"

View File

@@ -1,6 +1,6 @@
export const BASE_LABEL_API = export const BASE_LABEL_API =
process.env.NEXT_PUBLIC_ENV === "production" process.env.NEXT_PUBLIC_ENV === "production"
? "https://label.cowarobot.com" ? "https://label.soft.cowarobot.com"
: process.env.NEXT_PUBLIC_ENV === "staging" : process.env.NEXT_PUBLIC_ENV === "staging"
? "http://172.16.115.128:9110" ? "http://172.16.115.128:9110"
: "https://label.softtest.cowarobot.com" : "https://label.softtest.cowarobot.com"

View File

@@ -16,6 +16,12 @@ import "@mantine/tiptap/styles.css"
export const splitWord = "@1024-" export const splitWord = "@1024-"
const getEditorHtml = (rawValue?: string) => {
if (!rawValue) return ""
const [html] = rawValue.split(splitWord)
return html ?? rawValue
}
interface EditorContainerProps { interface EditorContainerProps {
value: string value: string
onChange: (value: string) => void onChange: (value: string) => void
@@ -41,11 +47,11 @@ const EditorContainer = ({
Image, Image,
Placeholder.configure({ placeholder: "请输入内容..." }), Placeholder.configure({ placeholder: "请输入内容..." }),
], ],
content: value, content: getEditorHtml(value),
editable: !disabled && !isView, editable: !disabled && !isView,
onUpdate: ({ editor }) => { onUpdate: ({ editor }) => {
// Preserve splitWord format const html = getEditorHtml(editor.getHTML())
onChange(`${editor.getHTML()}${splitWord}${editor.getText()}`) onChange(`${html}${splitWord}${editor.getText()}`)
}, },
onFocus: () => { onFocus: () => {
useKeyEventStore.getState().setFocusInput(true) useKeyEventStore.getState().setFocusInput(true)
@@ -63,7 +69,7 @@ const EditorContainer = ({
useEffect(() => { useEffect(() => {
if (!editor) return if (!editor) return
const incomingHtml = value ? value : "<p></p>" const incomingHtml = getEditorHtml(value) || "<p></p>"
if (editor.getHTML() !== incomingHtml) { if (editor.getHTML() !== incomingHtml) {
// Keep editor content in sync with external state, including empty value switch. // Keep editor content in sync with external state, including empty value switch.
editor.commands.setContent(incomingHtml, { emitUpdate: false }) editor.commands.setContent(incomingHtml, { emitUpdate: false })
@@ -91,7 +97,7 @@ const EditorContainer = ({
padding: "4px", padding: "4px",
}}> }}>
<RichTextEditor editor={editor} style={{ border: 0 }}> <RichTextEditor editor={editor} style={{ border: 0 }}>
<RichTextEditor.Toolbar sticky stickyOffset={60}> <RichTextEditor.Toolbar>
<RichTextEditor.ControlsGroup> <RichTextEditor.ControlsGroup>
<RichTextEditor.Bold /> <RichTextEditor.Bold />
<RichTextEditor.Italic /> <RichTextEditor.Italic />

View File

@@ -18,6 +18,7 @@ import { Task } from "../api/task/typing"
import { useBottomToolsStore } from "../useBottomToolsStore" import { useBottomToolsStore } from "../useBottomToolsStore"
import { useDescToolsStore } from "../useDescToolsStore" import { useDescToolsStore } from "../useDescToolsStore"
import { useTopToolsStore } from "../useTopToolsStore" import { useTopToolsStore } from "../useTopToolsStore"
import { safeClone } from "../utils/clone"
import EditorContainer from "./EditorContainer" import EditorContainer from "./EditorContainer"
interface ComponentProps { interface ComponentProps {
@@ -40,23 +41,29 @@ const RightDescTools = ({ taskDetail }: ComponentProps) => {
}) })
const isUpdatingFromStore = useRef(false) const isUpdatingFromStore = useRef(false)
const syncTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
const handleFormUpdate = () => { const setOperationField = (
labelClass: string,
field: string,
value: string | string[]
) => {
const current = ((form.values as any)[labelClass] ?? {}) as Record<
string,
any
>
form.setFieldValue(labelClass, {
...current,
[field]: value,
})
}
const handleFormUpdate = (values: any) => {
if (isUpdatingFromStore.current) return if (isUpdatingFromStore.current) return
const data = form.values as any const currentDescData = safeClone(useDescToolsStore.getState().descData)
let dataMap = new Map()
taskDetail?.data_name.forEach((detail_name) => {
if (detail_name.name[0] !== activeImage) {
if (useDescToolsStore.getState().descData.has(detail_name.name[0])) {
dataMap.set(
detail_name.name[0],
useDescToolsStore.getState().descData.get(detail_name.name[0])
)
}
} else {
const updateMap = new Map() const updateMap = new Map()
Object.entries(data).forEach(([label_class, val]: any) => { Object.entries(values).forEach(([label_class, val]: any) => {
let value = { ...val } let value = { ...val }
if (value.is_correct !== undefined) { if (value.is_correct !== undefined) {
value.is_correct = value.is_correct === "true" value.is_correct = value.is_correct === "true"
@@ -68,18 +75,33 @@ const RightDescTools = ({ taskDetail }: ComponentProps) => {
updateMap.set(label_class, { value: value }) updateMap.set(label_class, { value: value })
} }
}) })
dataMap.set(activeImage, updateMap) currentDescData.set(activeImage, updateMap)
} setDescData(currentDescData)
})
setDescData(dataMap)
} }
useEffect(() => { useEffect(() => {
handleFormUpdate() if (isUpdatingFromStore.current) return
if (syncTimerRef.current) {
clearTimeout(syncTimerRef.current)
}
syncTimerRef.current = setTimeout(() => {
handleFormUpdate(form.values)
syncTimerRef.current = null
}, 180)
return () => {
if (syncTimerRef.current) {
clearTimeout(syncTimerRef.current)
syncTimerRef.current = null
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [form.values]) }, [form.values])
useEffect(() => { useEffect(() => {
if (syncTimerRef.current) {
clearTimeout(syncTimerRef.current)
syncTimerRef.current = null
}
isUpdatingFromStore.current = true isUpdatingFromStore.current = true
form.reset() form.reset()
if (activeImage) { if (activeImage) {
@@ -109,6 +131,10 @@ const RightDescTools = ({ taskDetail }: ComponentProps) => {
useEffect(() => { useEffect(() => {
if (updateDescDataFlag) { if (updateDescDataFlag) {
if (syncTimerRef.current) {
clearTimeout(syncTimerRef.current)
syncTimerRef.current = null
}
isUpdatingFromStore.current = true isUpdatingFromStore.current = true
const formData = useDescToolsStore const formData = useDescToolsStore
.getState() .getState()
@@ -133,6 +159,15 @@ const RightDescTools = ({ taskDetail }: ComponentProps) => {
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [updateDescDataFlag]) }, [updateDescDataFlag])
useEffect(() => {
return () => {
if (syncTimerRef.current) {
clearTimeout(syncTimerRef.current)
syncTimerRef.current = null
}
}
}, [])
return ( return (
<Box h="100%"> <Box h="100%">
<Box <Box
@@ -156,7 +191,9 @@ const RightDescTools = ({ taskDetail }: ComponentProps) => {
activeImage, activeImage,
operation.label_class operation.label_class
) )
const hasComment = currentData?.comment const hasComment =
!!(form.values as any)?.[operation.label_class]?.comment ||
!!currentData?.comment
return ( return (
<Box key={operation.label_class}> <Box key={operation.label_class}>
@@ -171,9 +208,17 @@ const RightDescTools = ({ taskDetail }: ComponentProps) => {
{operation.label_class} {operation.label_class}
</Text> </Text>
<Radio.Group <Radio.Group
{...form.getInputProps( value={
`${operation.label_class}.is_correct` (form.values as any)[operation.label_class]
)} ?.is_correct || ""
}
onChange={(val) => {
setOperationField(
operation.label_class,
"is_correct",
val
)
}}
size="xs"> size="xs">
<Group gap="xs"> <Group gap="xs">
<Radio <Radio
@@ -195,8 +240,9 @@ const RightDescTools = ({ taskDetail }: ComponentProps) => {
variant="subtle" variant="subtle"
size="xs" size="xs"
onClick={() => { onClick={() => {
form.setFieldValue( setOperationField(
`${operation.label_class}.comment`, operation.label_class,
"comment",
"<p></p>" "<p></p>"
) )
}}> }}>
@@ -215,9 +261,18 @@ const RightDescTools = ({ taskDetail }: ComponentProps) => {
placeholder={`请输入${subDesc.chinese_name}`} placeholder={`请输入${subDesc.chinese_name}`}
size="xs" size="xs"
required={!!subDesc.isrequired} required={!!subDesc.isrequired}
{...form.getInputProps( value={
`${operation.label_class}.${subDesc.chinese_name}` (form.values as any)[operation.label_class]?.[
)} subDesc.chinese_name
] || ""
}
onChange={(event) => {
setOperationField(
operation.label_class,
subDesc.chinese_name,
event.currentTarget.value
)
}}
disabled={!!isView} disabled={!!isView}
/> />
) : subDesc.select_mode === 1 ? ( ) : subDesc.select_mode === 1 ? (
@@ -225,9 +280,18 @@ const RightDescTools = ({ taskDetail }: ComponentProps) => {
label={subDesc.chinese_name} label={subDesc.chinese_name}
size="xs" size="xs"
required={!!subDesc.isrequired} required={!!subDesc.isrequired}
{...form.getInputProps( value={
`${operation.label_class}.${subDesc.chinese_name}` (form.values as any)[operation.label_class]?.[
)}> subDesc.chinese_name
] || ""
}
onChange={(val) => {
setOperationField(
operation.label_class,
subDesc.chinese_name,
val
)
}}>
<Group gap="xs" mt={4}> <Group gap="xs" mt={4}>
{subDesc.optional_item.map((option) => ( {subDesc.optional_item.map((option) => (
<Radio <Radio
@@ -244,9 +308,18 @@ const RightDescTools = ({ taskDetail }: ComponentProps) => {
label={subDesc.chinese_name} label={subDesc.chinese_name}
size="xs" size="xs"
required={!!subDesc.isrequired} required={!!subDesc.isrequired}
{...form.getInputProps( value={
`${operation.label_class}.${subDesc.chinese_name}` (form.values as any)[operation.label_class]?.[
)}> subDesc.chinese_name
] || []
}
onChange={(val) => {
setOperationField(
operation.label_class,
subDesc.chinese_name,
val
)
}}>
<Group gap="xs" mt={4}> <Group gap="xs" mt={4}>
{subDesc.optional_item.map((option) => ( {subDesc.optional_item.map((option) => (
<Checkbox <Checkbox
@@ -266,13 +339,11 @@ const RightDescTools = ({ taskDetail }: ComponentProps) => {
<Box mb="xs"> <Box mb="xs">
<EditorContainer <EditorContainer
value={ value={
(form.values as any)[operation.label_class]?.value (form.values as any)[operation.label_class]?.value ||
""
} }
onChange={(val: any) => onChange={(val: any) =>
form.setFieldValue( setOperationField(operation.label_class, "value", val)
`${operation.label_class}.value`,
val
)
} }
/> />
</Box> </Box>
@@ -282,14 +353,16 @@ const RightDescTools = ({ taskDetail }: ComponentProps) => {
<EditorContainer <EditorContainer
color="border-danger" color="border-danger"
value={ value={
(form.values as any)[operation.label_class]?.comment (form.values as any)[operation.label_class]
?.comment || ""
} }
onChange={(val: any) => onChange={(val: any) => {
form.setFieldValue( setOperationField(
`${operation.label_class}.comment`, operation.label_class,
"comment",
val val
) )
} }}
/> />
</Box> </Box>
</> </>

View File

@@ -4,7 +4,7 @@ import { Login } from "./types"
const BASE_PATH = const BASE_PATH =
process.env.NEXT_PUBLIC_ENV === "production" process.env.NEXT_PUBLIC_ENV === "production"
? "https://label.cowarobot.com" ? "https://label.soft.cowarobot.com"
: process.env.NEXT_PUBLIC_ENV === "staging" : process.env.NEXT_PUBLIC_ENV === "staging"
? "http://172.16.115.128:9110" ? "http://172.16.115.128:9110"
: "https://label.softtest.cowarobot.com" : "https://label.softtest.cowarobot.com"