From 76bfb30fefebb5f6f1091ca305d52d999ca0aa9e Mon Sep 17 00:00:00 2001 From: zhangheng Date: Sat, 28 Mar 2026 16:39:27 +0800 Subject: [PATCH] fix(ci): add file --- .gitlab-ci.yml | 28 +++ components/label/api/const.ts | 2 +- .../label/components/EditorContainer.tsx | 16 +- .../label/components/RightDescTools.tsx | 177 +++++++++++++----- components/login/api/index.ts | 2 +- 5 files changed, 166 insertions(+), 59 deletions(-) create mode 100644 .gitlab-ci.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..610a3a5 --- /dev/null +++ b/.gitlab-ci.yml @@ -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" diff --git a/components/label/api/const.ts b/components/label/api/const.ts index 85a96fa..5e1fb07 100644 --- a/components/label/api/const.ts +++ b/components/label/api/const.ts @@ -1,6 +1,6 @@ export const BASE_LABEL_API = process.env.NEXT_PUBLIC_ENV === "production" - ? "https://label.cowarobot.com" + ? "https://label.soft.cowarobot.com" : process.env.NEXT_PUBLIC_ENV === "staging" ? "http://172.16.115.128:9110" : "https://label.softtest.cowarobot.com" diff --git a/components/label/components/EditorContainer.tsx b/components/label/components/EditorContainer.tsx index 7cadec3..89813b1 100644 --- a/components/label/components/EditorContainer.tsx +++ b/components/label/components/EditorContainer.tsx @@ -16,6 +16,12 @@ import "@mantine/tiptap/styles.css" export const splitWord = "@1024-" +const getEditorHtml = (rawValue?: string) => { + if (!rawValue) return "" + const [html] = rawValue.split(splitWord) + return html ?? rawValue +} + interface EditorContainerProps { value: string onChange: (value: string) => void @@ -41,11 +47,11 @@ const EditorContainer = ({ Image, Placeholder.configure({ placeholder: "请输入内容..." }), ], - content: value, + content: getEditorHtml(value), editable: !disabled && !isView, onUpdate: ({ editor }) => { - // Preserve splitWord format - onChange(`${editor.getHTML()}${splitWord}${editor.getText()}`) + const html = getEditorHtml(editor.getHTML()) + onChange(`${html}${splitWord}${editor.getText()}`) }, onFocus: () => { useKeyEventStore.getState().setFocusInput(true) @@ -63,7 +69,7 @@ const EditorContainer = ({ useEffect(() => { if (!editor) return - const incomingHtml = value ? value : "

" + const incomingHtml = getEditorHtml(value) || "

" if (editor.getHTML() !== incomingHtml) { // Keep editor content in sync with external state, including empty value switch. editor.commands.setContent(incomingHtml, { emitUpdate: false }) @@ -91,7 +97,7 @@ const EditorContainer = ({ padding: "4px", }}> - + diff --git a/components/label/components/RightDescTools.tsx b/components/label/components/RightDescTools.tsx index caa8de8..ede4b50 100644 --- a/components/label/components/RightDescTools.tsx +++ b/components/label/components/RightDescTools.tsx @@ -18,6 +18,7 @@ import { Task } from "../api/task/typing" import { useBottomToolsStore } from "../useBottomToolsStore" import { useDescToolsStore } from "../useDescToolsStore" import { useTopToolsStore } from "../useTopToolsStore" +import { safeClone } from "../utils/clone" import EditorContainer from "./EditorContainer" interface ComponentProps { @@ -40,46 +41,67 @@ const RightDescTools = ({ taskDetail }: ComponentProps) => { }) const isUpdatingFromStore = useRef(false) + const syncTimerRef = useRef | 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 - const data = form.values as any - 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]) - ) - } + const currentDescData = safeClone(useDescToolsStore.getState().descData) + const updateMap = new Map() + Object.entries(values).forEach(([label_class, val]: any) => { + let value = { ...val } + if (value.is_correct !== undefined) { + value.is_correct = value.is_correct === "true" + } + const keys = Object.keys(value) + if (keys.includes("value")) { + updateMap.set(label_class, value) } else { - const updateMap = new Map() - Object.entries(data).forEach(([label_class, val]: any) => { - let value = { ...val } - if (value.is_correct !== undefined) { - value.is_correct = value.is_correct === "true" - } - const keys = Object.keys(value) - if (keys.includes("value")) { - updateMap.set(label_class, value) - } else { - updateMap.set(label_class, { value: value }) - } - }) - dataMap.set(activeImage, updateMap) + updateMap.set(label_class, { value: value }) } }) - setDescData(dataMap) + currentDescData.set(activeImage, updateMap) + setDescData(currentDescData) } 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 }, [form.values]) useEffect(() => { + if (syncTimerRef.current) { + clearTimeout(syncTimerRef.current) + syncTimerRef.current = null + } isUpdatingFromStore.current = true form.reset() if (activeImage) { @@ -109,6 +131,10 @@ const RightDescTools = ({ taskDetail }: ComponentProps) => { useEffect(() => { if (updateDescDataFlag) { + if (syncTimerRef.current) { + clearTimeout(syncTimerRef.current) + syncTimerRef.current = null + } isUpdatingFromStore.current = true const formData = useDescToolsStore .getState() @@ -133,6 +159,15 @@ const RightDescTools = ({ taskDetail }: ComponentProps) => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [updateDescDataFlag]) + useEffect(() => { + return () => { + if (syncTimerRef.current) { + clearTimeout(syncTimerRef.current) + syncTimerRef.current = null + } + } + }, []) + return ( { activeImage, operation.label_class ) - const hasComment = currentData?.comment + const hasComment = + !!(form.values as any)?.[operation.label_class]?.comment || + !!currentData?.comment return ( @@ -171,9 +208,17 @@ const RightDescTools = ({ taskDetail }: ComponentProps) => { {operation.label_class} { + setOperationField( + operation.label_class, + "is_correct", + val + ) + }} size="xs"> { variant="subtle" size="xs" onClick={() => { - form.setFieldValue( - `${operation.label_class}.comment`, + setOperationField( + operation.label_class, + "comment", "

" ) }}> @@ -215,9 +261,18 @@ const RightDescTools = ({ taskDetail }: ComponentProps) => { placeholder={`请输入${subDesc.chinese_name}`} size="xs" required={!!subDesc.isrequired} - {...form.getInputProps( - `${operation.label_class}.${subDesc.chinese_name}` - )} + value={ + (form.values as any)[operation.label_class]?.[ + subDesc.chinese_name + ] || "" + } + onChange={(event) => { + setOperationField( + operation.label_class, + subDesc.chinese_name, + event.currentTarget.value + ) + }} disabled={!!isView} /> ) : subDesc.select_mode === 1 ? ( @@ -225,9 +280,18 @@ const RightDescTools = ({ taskDetail }: ComponentProps) => { label={subDesc.chinese_name} size="xs" required={!!subDesc.isrequired} - {...form.getInputProps( - `${operation.label_class}.${subDesc.chinese_name}` - )}> + value={ + (form.values as any)[operation.label_class]?.[ + subDesc.chinese_name + ] || "" + } + onChange={(val) => { + setOperationField( + operation.label_class, + subDesc.chinese_name, + val + ) + }}> {subDesc.optional_item.map((option) => ( { label={subDesc.chinese_name} size="xs" required={!!subDesc.isrequired} - {...form.getInputProps( - `${operation.label_class}.${subDesc.chinese_name}` - )}> + value={ + (form.values as any)[operation.label_class]?.[ + subDesc.chinese_name + ] || [] + } + onChange={(val) => { + setOperationField( + operation.label_class, + subDesc.chinese_name, + val + ) + }}> {subDesc.optional_item.map((option) => ( { - form.setFieldValue( - `${operation.label_class}.value`, - val - ) + setOperationField(operation.label_class, "value", val) } /> @@ -282,14 +353,16 @@ const RightDescTools = ({ taskDetail }: ComponentProps) => { - form.setFieldValue( - `${operation.label_class}.comment`, + onChange={(val: any) => { + setOperationField( + operation.label_class, + "comment", val ) - } + }} />
diff --git a/components/login/api/index.ts b/components/login/api/index.ts index c3d63e8..2075b43 100644 --- a/components/login/api/index.ts +++ b/components/login/api/index.ts @@ -4,7 +4,7 @@ import { Login } from "./types" const BASE_PATH = process.env.NEXT_PUBLIC_ENV === "production" - ? "https://label.cowarobot.com" + ? "https://label.soft.cowarobot.com" : process.env.NEXT_PUBLIC_ENV === "staging" ? "http://172.16.115.128:9110" : "https://label.softtest.cowarobot.com"