fix(admin): 课程包编辑页问题修复
- 封面回显与保存:使用 getFileUrl 统一处理,修复 watch 逻辑 - 课程介绍/排课参考/环创建设回显:修复 API 字段映射和解析 - 测评内容 JSON 格式:新增 parseAssessmentDataForDisplay 前后端统一 - 保存后跳转列表:修复新建/编辑流程的 router.replace - 表单校验:导入课、集体课、领域课各必填一条,下一步时校验 - 保存按钮:修复 @click 将 event 误传为 isDraft 导致不跳转 - Lesson API:updateLesson/updateStep 传入正确的 courseId Made-with: Cursor
This commit is contained in:
parent
36b8621060
commit
877acf33b8
@ -211,11 +211,18 @@ export const fileApi = {
|
||||
|
||||
/**
|
||||
* 获取文件URL
|
||||
* 支持:完整 OSS URL、以 / 开头的路径、相对路径
|
||||
*/
|
||||
getFileUrl: (filePath: string): string => {
|
||||
// filePath 格式: /uploads/courses/covers/xxx.png
|
||||
// 直接返回相对路径,由 nginx 或后端静态服务处理
|
||||
return filePath;
|
||||
getFileUrl: (filePath: string | null | undefined): string => {
|
||||
if (!filePath) return '';
|
||||
if (filePath.startsWith('http://') || filePath.startsWith('https://')) {
|
||||
return filePath;
|
||||
}
|
||||
const SERVER_BASE = import.meta.env.VITE_SERVER_BASE_URL || '/api';
|
||||
if (filePath.startsWith('/')) {
|
||||
return `${SERVER_BASE}${filePath}`;
|
||||
}
|
||||
return `${SERVER_BASE}/uploads/${filePath}`;
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@ -105,8 +105,8 @@ export function createLesson(courseId: number, data: CreateLessonData) {
|
||||
}
|
||||
|
||||
// 更新课程
|
||||
export function updateLesson(lessonId: number, data: Partial<CreateLessonData>) {
|
||||
return http.put(`/v1/admin/courses/0/lessons/${lessonId}`, data);
|
||||
export function updateLesson(courseId: number, lessonId: number, data: Partial<CreateLessonData>) {
|
||||
return http.put(`/v1/admin/courses/${courseId}/lessons/${lessonId}`, data);
|
||||
}
|
||||
|
||||
// 删除课程
|
||||
@ -132,8 +132,8 @@ export function createStep(courseId: number, lessonId: number, data: CreateStepD
|
||||
}
|
||||
|
||||
// 更新环节
|
||||
export function updateStep(stepId: number, data: Partial<CreateStepData>) {
|
||||
return http.put(`/v1/admin/courses/0/lessons/steps/${stepId}`, data);
|
||||
export function updateStep(courseId: number, stepId: number, data: Partial<CreateStepData>) {
|
||||
return http.put(`/v1/admin/courses/${courseId}/lessons/steps/${stepId}`, data);
|
||||
}
|
||||
|
||||
// 删除环节
|
||||
|
||||
@ -126,7 +126,7 @@ import { ref, reactive, watch, onMounted } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { PlusOutlined } from '@ant-design/icons-vue';
|
||||
import { getThemeList } from '@/api/theme';
|
||||
import { uploadFile } from '@/api/file';
|
||||
import { uploadFile, getFileUrl } from '@/api/file';
|
||||
import type { Theme } from '@/api/theme';
|
||||
|
||||
interface BasicInfoData {
|
||||
@ -206,19 +206,16 @@ watch(
|
||||
if (newVal) {
|
||||
Object.assign(formData, newVal);
|
||||
|
||||
// 处理封面图片
|
||||
if (newVal.coverImagePath && coverImages.value.length === 0) {
|
||||
// 构建正确的图片URL
|
||||
let imageUrl = newVal.coverImagePath;
|
||||
if (!imageUrl.startsWith('http') && !imageUrl.startsWith('/uploads') && !imageUrl.includes('/uploads/')) {
|
||||
imageUrl = `/uploads/${imageUrl}`;
|
||||
}
|
||||
// 处理封面图片回显
|
||||
if (newVal.coverImagePath) {
|
||||
coverImages.value = [{
|
||||
uid: '-1',
|
||||
name: 'cover',
|
||||
status: 'done',
|
||||
url: imageUrl,
|
||||
url: getFileUrl(newVal.coverImagePath),
|
||||
}];
|
||||
} else {
|
||||
coverImages.value = [];
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -255,16 +252,11 @@ const beforeCoverUpload = async (file: any) => {
|
||||
try {
|
||||
const result = await uploadFile(file, 'cover');
|
||||
formData.coverImagePath = result.filePath;
|
||||
// 构建正确的图片URL - 后端返回的filePath已经包含完整路径
|
||||
let imageUrl = result.filePath;
|
||||
if (!imageUrl.startsWith('http') && !imageUrl.startsWith('/uploads') && !imageUrl.includes('/uploads/')) {
|
||||
imageUrl = `/uploads/${imageUrl}`;
|
||||
}
|
||||
coverImages.value = [{
|
||||
uid: file.uid,
|
||||
name: file.name,
|
||||
status: 'done',
|
||||
url: imageUrl,
|
||||
url: getFileUrl(result.filePath),
|
||||
}];
|
||||
handleChange();
|
||||
message.success('封面上传成功');
|
||||
|
||||
@ -133,17 +133,20 @@ const tableData = ref<ScheduleRow[]>([]);
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
try {
|
||||
const parsed = JSON.parse(newVal);
|
||||
tableData.value = parsed.map((row: any, index: number) => ({
|
||||
...row,
|
||||
key: row.key || `row_${index}`,
|
||||
}));
|
||||
} catch (e) {
|
||||
console.error('解析排课数据失败', e);
|
||||
tableData.value = [];
|
||||
}
|
||||
if (!newVal || typeof newVal !== 'string') {
|
||||
tableData.value = [];
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const parsed = JSON.parse(newVal);
|
||||
const rows = Array.isArray(parsed) ? parsed : [];
|
||||
tableData.value = rows.map((row: any, index: number) => ({
|
||||
...row,
|
||||
key: row.key || `row_${index}`,
|
||||
}));
|
||||
} catch (e) {
|
||||
console.error('解析排课数据失败', e);
|
||||
tableData.value = [];
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
|
||||
@ -60,6 +60,7 @@ import { PlusOutlined } from '@ant-design/icons-vue';
|
||||
import LessonConfigPanel from '@/components/course/LessonConfigPanel.vue';
|
||||
import type { LessonData } from '@/components/course/LessonConfigPanel.vue';
|
||||
import { getLessonByType, createLesson, updateLesson, deleteLesson as deleteLessonApi } from '@/api/lesson';
|
||||
import { parseAssessmentDataForDisplay } from '@/utils/assessmentData';
|
||||
|
||||
interface Props {
|
||||
courseId: number;
|
||||
@ -100,7 +101,7 @@ const fetchLesson = async () => {
|
||||
preparation: lesson.preparation || '',
|
||||
extension: lesson.extension || '',
|
||||
reflection: lesson.reflection || '',
|
||||
assessmentData: lesson.assessmentData || '',
|
||||
assessmentData: parseAssessmentDataForDisplay(lesson.assessmentData),
|
||||
useTemplate: lesson.useTemplate || false,
|
||||
steps: lesson.steps || [],
|
||||
isNew: false,
|
||||
@ -159,10 +160,10 @@ const handleLessonChange = () => {
|
||||
emit('change');
|
||||
};
|
||||
|
||||
// 验证:若配置了导入课,则通过 formRules 校验
|
||||
// 验证:导入课为必填,至少配置一条
|
||||
const validate = async () => {
|
||||
if (!lessonData.value) {
|
||||
return { valid: true, errors: [] as string[], warnings: ['未配置导入课'] };
|
||||
return { valid: false, errors: ['请配置导入课(至少一条)'] };
|
||||
}
|
||||
return configPanelRef.value?.validate() ?? { valid: true, errors: [] as string[] };
|
||||
};
|
||||
|
||||
@ -60,6 +60,7 @@ import { PlusOutlined } from '@ant-design/icons-vue';
|
||||
import LessonConfigPanel from '@/components/course/LessonConfigPanel.vue';
|
||||
import type { LessonData } from '@/components/course/LessonConfigPanel.vue';
|
||||
import { getLessonByType, createLesson as createLessonApi, updateLesson, deleteLesson as deleteLessonApi } from '@/api/lesson';
|
||||
import { parseAssessmentDataForDisplay } from '@/utils/assessmentData';
|
||||
|
||||
interface Props {
|
||||
courseId: number;
|
||||
@ -101,7 +102,7 @@ const fetchLesson = async () => {
|
||||
preparation: lesson.preparation || '',
|
||||
extension: lesson.extension || '',
|
||||
reflection: lesson.reflection || '',
|
||||
assessmentData: lesson.assessmentData || '',
|
||||
assessmentData: parseAssessmentDataForDisplay(lesson.assessmentData),
|
||||
useTemplate: lesson.useTemplate || false,
|
||||
steps: lesson.steps || [],
|
||||
isNew: false,
|
||||
@ -160,10 +161,10 @@ const handleLessonChange = () => {
|
||||
emit('change');
|
||||
};
|
||||
|
||||
// 验证:若配置了集体课,则通过 formRules 校验
|
||||
// 验证:集体课为必填,至少配置一条
|
||||
const validate = async () => {
|
||||
if (!lessonData.value) {
|
||||
return { valid: true, errors: [] as string[], warnings: ['未配置集体课'] };
|
||||
return { valid: false, errors: ['请配置集体课(至少一条)'] };
|
||||
}
|
||||
return configPanelRef.value?.validate() ?? { valid: true, errors: [] as string[] };
|
||||
};
|
||||
|
||||
@ -93,6 +93,7 @@ import {
|
||||
import LessonConfigPanel from '@/components/course/LessonConfigPanel.vue';
|
||||
import type { LessonData } from '@/components/course/LessonConfigPanel.vue';
|
||||
import { getLessonList, createLesson, updateLesson, deleteLesson } from '@/api/lesson';
|
||||
import { parseAssessmentDataForDisplay } from '@/utils/assessmentData';
|
||||
|
||||
interface DomainConfig {
|
||||
type: string;
|
||||
@ -204,7 +205,7 @@ const fetchLessons = async () => {
|
||||
preparation: lesson.preparation || '',
|
||||
extension: lesson.extension || '',
|
||||
reflection: lesson.reflection || '',
|
||||
assessmentData: lesson.assessmentData || '',
|
||||
assessmentData: parseAssessmentDataForDisplay(lesson.assessmentData),
|
||||
useTemplate: lesson.useTemplate || false,
|
||||
steps: lesson.steps || [],
|
||||
isNew: false,
|
||||
@ -266,8 +267,13 @@ const handleLessonChange = () => {
|
||||
emit('change');
|
||||
};
|
||||
|
||||
// 验证:若启用某领域,则通过 formRules 校验各领域
|
||||
// 验证:领域课为必填,至少配置一条,且已启用的领域需通过 formRules 校验
|
||||
const validate = async () => {
|
||||
const saveData = getSaveData();
|
||||
if (!saveData || saveData.length === 0) {
|
||||
return { valid: false, errors: ['请配置领域课(至少一条)'] };
|
||||
}
|
||||
|
||||
const enabledDomains = domains.filter((d) => d.enabled);
|
||||
const allErrors: string[] = [];
|
||||
|
||||
|
||||
19
reading-platform-frontend/src/utils/assessmentData.ts
Normal file
19
reading-platform-frontend/src/utils/assessmentData.ts
Normal file
@ -0,0 +1,19 @@
|
||||
/**
|
||||
* 测评内容(assessmentData)前后端格式统一
|
||||
* 后端将纯文本存储为 JSON 字符串(如 "核心内容"),加载时需解析为明文展示
|
||||
*/
|
||||
export function parseAssessmentDataForDisplay(value: string | null | undefined): string {
|
||||
if (value == null || value === '') return '';
|
||||
const trimmed = value.trim();
|
||||
if (!trimmed) return '';
|
||||
// 若是 JSON 字符串格式(如 "核心内容"),解析后返回明文
|
||||
if (trimmed.startsWith('"') && trimmed.endsWith('"')) {
|
||||
try {
|
||||
const parsed = JSON.parse(trimmed);
|
||||
return typeof parsed === 'string' ? parsed : trimmed;
|
||||
} catch {
|
||||
return trimmed;
|
||||
}
|
||||
}
|
||||
return trimmed;
|
||||
}
|
||||
@ -1,21 +1,13 @@
|
||||
<template>
|
||||
<div class="course-edit-view">
|
||||
<div class="sticky-header">
|
||||
<a-page-header
|
||||
:title="isEdit ? '编辑课程包' : '创建课程包'"
|
||||
@back="() => router.back()"
|
||||
>
|
||||
<a-page-header :title="isEdit ? '编辑课程包' : '创建课程包'" @back="() => router.back()">
|
||||
<template #extra>
|
||||
<a-space>
|
||||
<a-button @click="handleSaveDraft" :loading="saving">保存草稿</a-button>
|
||||
<a-button v-if="currentStep > 0" @click="prevStep">上一步</a-button>
|
||||
<a-button v-if="currentStep < 6" type="primary" @click="nextStep">下一步</a-button>
|
||||
<a-button
|
||||
v-if="currentStep === 6"
|
||||
type="primary"
|
||||
:loading="saving"
|
||||
@click="handleSave"
|
||||
>
|
||||
<a-button v-if="currentStep === 6" type="primary" :loading="saving" @click="() => handleSave(false)">
|
||||
{{ isEdit ? '保存' : '创建' }}
|
||||
</a-button>
|
||||
<a-button v-else-if="isEdit" type="primary" @click="handleSaveAndSubmit" :loading="saving">
|
||||
@ -48,62 +40,32 @@
|
||||
<!-- 步骤内容 -->
|
||||
<div class="step-content">
|
||||
<!-- 步骤1:基本信息 -->
|
||||
<Step1BasicInfo
|
||||
v-show="currentStep === 0"
|
||||
ref="step1Ref"
|
||||
v-model="formData.basic"
|
||||
@change="handleDataChange"
|
||||
/>
|
||||
<Step1BasicInfo v-show="currentStep === 0" ref="step1Ref" v-model="formData.basic"
|
||||
@change="handleDataChange" />
|
||||
|
||||
<!-- 步骤2:课程介绍 -->
|
||||
<Step2CourseIntro
|
||||
v-show="currentStep === 1"
|
||||
ref="step2Ref"
|
||||
v-model="formData.intro"
|
||||
@change="handleDataChange"
|
||||
/>
|
||||
<Step2CourseIntro v-show="currentStep === 1" ref="step2Ref" v-model="formData.intro"
|
||||
@change="handleDataChange" />
|
||||
|
||||
<!-- 步骤3:排课参考 -->
|
||||
<Step3ScheduleRef
|
||||
v-show="currentStep === 2"
|
||||
ref="step3Ref"
|
||||
v-model="formData.scheduleRefData"
|
||||
@change="handleDataChange"
|
||||
/>
|
||||
<Step3ScheduleRef v-show="currentStep === 2" ref="step3Ref" v-model="formData.scheduleRefData"
|
||||
@change="handleDataChange" />
|
||||
|
||||
<!-- 步骤4:导入课 -->
|
||||
<Step4IntroLesson
|
||||
v-show="currentStep === 3"
|
||||
ref="step4Ref"
|
||||
:course-id="courseId"
|
||||
@change="handleDataChange"
|
||||
/>
|
||||
<Step4IntroLesson v-show="currentStep === 3" ref="step4Ref" :course-id="courseId"
|
||||
@change="handleDataChange" />
|
||||
|
||||
<!-- 步骤5:集体课 -->
|
||||
<Step5CollectiveLesson
|
||||
v-show="currentStep === 4"
|
||||
ref="step5Ref"
|
||||
:course-id="courseId"
|
||||
:course-name="formData.basic.name"
|
||||
@change="handleDataChange"
|
||||
/>
|
||||
<Step5CollectiveLesson v-show="currentStep === 4" ref="step5Ref" :course-id="courseId"
|
||||
:course-name="formData.basic.name" @change="handleDataChange" />
|
||||
|
||||
<!-- 步骤6:领域课 -->
|
||||
<Step6DomainLessons
|
||||
v-show="currentStep === 5"
|
||||
ref="step6Ref"
|
||||
:course-id="courseId"
|
||||
:course-name="formData.basic.name"
|
||||
@change="handleDataChange"
|
||||
/>
|
||||
<Step6DomainLessons v-show="currentStep === 5" ref="step6Ref" :course-id="courseId"
|
||||
:course-name="formData.basic.name" @change="handleDataChange" />
|
||||
|
||||
<!-- 步骤7:环创建设 -->
|
||||
<Step7Environment
|
||||
v-show="currentStep === 6"
|
||||
ref="step7Ref"
|
||||
v-model="formData.environmentConstruction"
|
||||
@change="handleDataChange"
|
||||
/>
|
||||
<Step7Environment v-show="currentStep === 6" ref="step7Ref" v-model="formData.environmentConstruction"
|
||||
@change="handleDataChange" />
|
||||
</div>
|
||||
</a-card>
|
||||
</a-spin>
|
||||
@ -231,8 +193,8 @@ const fetchCourseDetail = async () => {
|
||||
formData.basic.grades = Array.isArray(course.gradeTags) ? course.gradeTags : (course.gradeTags ? JSON.parse(course.gradeTags) : []);
|
||||
formData.basic.pictureBookName = course.pictureBookName || '';
|
||||
formData.basic.coreContent = course.coreContent || '';
|
||||
formData.basic.duration = course.duration || 25;
|
||||
formData.basic.domainTags = course.domainTags ? JSON.parse(course.domainTags) : [];
|
||||
formData.basic.duration = course.durationMinutes ?? course.duration ?? 25;
|
||||
formData.basic.domainTags = Array.isArray(course.domainTags) ? course.domainTags : (course.domainTags ? JSON.parse(course.domainTags || '[]') : []);
|
||||
formData.basic.coverImagePath = course.coverImagePath || '';
|
||||
|
||||
// 课程介绍
|
||||
@ -280,18 +242,26 @@ const nextStep = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
// 校验:导入课、集体课、领域课至少配置一种
|
||||
const validateAtLeastOneLesson = (): boolean => {
|
||||
// 校验:导入课、集体课、领域课各必填一条
|
||||
const validateAllThreeLessons = (): boolean => {
|
||||
const hasIntro = !!step4Ref.value?.lessonData;
|
||||
const hasCollective = !!step5Ref.value?.lessonData;
|
||||
const domainData = step6Ref.value?.getSaveData?.() || [];
|
||||
const hasDomain = Array.isArray(domainData) && domainData.length > 0;
|
||||
|
||||
if (hasIntro || hasCollective || hasDomain) {
|
||||
return true;
|
||||
if (!hasIntro) {
|
||||
message.warning('请配置导入课(至少一节)');
|
||||
return false;
|
||||
}
|
||||
message.warning('请至少配置一种课程:导入课、集体课或领域课(至少完成一个领域)');
|
||||
return false;
|
||||
if (!hasCollective) {
|
||||
message.warning('请配置集体课(至少一节)');
|
||||
return false;
|
||||
}
|
||||
if (!hasDomain) {
|
||||
message.warning('请配置领域课(至少一节)');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
// 验证当前步骤(覆盖全部 7 步)
|
||||
@ -308,9 +278,9 @@ const validateCurrentStep = async (): Promise<boolean> => {
|
||||
];
|
||||
const ref = stepRefs[step]?.value;
|
||||
if (!ref?.validate) {
|
||||
// 步骤 5(领域课)、步骤 6(环创建设)需额外校验「至少一种课程」
|
||||
// 步骤 5(领域课)、步骤 6(环创建设)需额外校验「导入课、集体课、领域课各必填一条」
|
||||
if (step === 5 || step === 6) {
|
||||
return validateAtLeastOneLesson();
|
||||
return validateAllThreeLessons();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -321,9 +291,9 @@ const validateCurrentStep = async (): Promise<boolean> => {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 步骤 5(领域课)、步骤 6(环创建设)需额外校验「至少一种课程」
|
||||
// 步骤 5(领域课)、步骤 6(环创建设)需额外校验「导入课、集体课、领域课各必填一条」
|
||||
if (step === 5 || step === 6) {
|
||||
return validateAtLeastOneLesson();
|
||||
return validateAllThreeLessons();
|
||||
}
|
||||
return true;
|
||||
};
|
||||
@ -384,13 +354,7 @@ const handleSave = async (isDraft = false) => {
|
||||
console.log('Course updated successfully');
|
||||
} else {
|
||||
const res = await createCourse(courseData) as any;
|
||||
console.log('🔍 创建课程返回结果:', JSON.stringify(res, null, 2));
|
||||
savedCourseId = res?.id || res?.data?.id; // 响应拦截器已返回 data.data,但也兼容直接返回完整响应
|
||||
console.log('Course created with ID:', savedCourseId);
|
||||
// 更新路由以支持后续保存
|
||||
if (savedCourseId) {
|
||||
router.replace(`/admin/packages/${savedCourseId}/edit`);
|
||||
}
|
||||
savedCourseId = res?.id ?? res?.data?.id; // 响应拦截器已返回 data.data,但也兼容直接返回完整响应
|
||||
}
|
||||
|
||||
if (!savedCourseId) {
|
||||
@ -433,18 +397,10 @@ const handleSave = async (isDraft = false) => {
|
||||
// 继续保存其他内容,不中断
|
||||
}
|
||||
|
||||
console.log('✅ 所有课程数据保存完成,准备显示成功提示...');
|
||||
message.success(isDraft ? '草稿保存成功' : (isEdit.value ? '保存成功' : '创建成功'));
|
||||
console.log('✅ 成功提示已显示,准备跳转...');
|
||||
|
||||
if (!isDraft) {
|
||||
console.log('🚀 准备跳转到课程列表页面...');
|
||||
console.log('🚀 isDraft =', isDraft, ', isEdit =', isEdit.value);
|
||||
// 确保所有异步操作完成后再跳转
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
console.log('🚀 即将执行 router.push 跳转...');
|
||||
await router.push('/admin/packages');
|
||||
console.log('✅ 已执行 router.push 跳转');
|
||||
await router.replace('/admin/packages');
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('Save failed:', error);
|
||||
@ -457,7 +413,8 @@ const handleSave = async (isDraft = false) => {
|
||||
};
|
||||
|
||||
// 保存单个课程
|
||||
const saveLesson = async (courseId: number, lessonData: any, lessonType: string) => {
|
||||
const saveLesson = async (courseId: number | string, lessonData: any, lessonType: string) => {
|
||||
const cid = Number(courseId);
|
||||
if (!lessonData) {
|
||||
console.log('No lesson data to save for type:', lessonType);
|
||||
return;
|
||||
@ -486,15 +443,10 @@ const saveLesson = async (courseId: number, lessonData: any, lessonType: string)
|
||||
|
||||
try {
|
||||
if (lessonData.isNew || !lessonData.id) {
|
||||
// 创建新课程
|
||||
console.log('Creating new lesson:', lessonType);
|
||||
const res = await createLesson(courseId, lessonPayload) as any;
|
||||
const res = await createLesson(cid, lessonPayload) as any;
|
||||
lessonId = res.data?.id || res.id;
|
||||
console.log('Lesson created with ID:', lessonId);
|
||||
} else {
|
||||
// 更新现有课程
|
||||
console.log('Updating lesson:', lessonId);
|
||||
await updateLesson(lessonData.id, lessonPayload);
|
||||
await updateLesson(cid, lessonData.id, lessonPayload);
|
||||
}
|
||||
|
||||
// 保存教学环节
|
||||
@ -509,9 +461,9 @@ const saveLesson = async (courseId: number, lessonData: any, lessonType: string)
|
||||
|
||||
try {
|
||||
if (step.isNew || !step.id) {
|
||||
await createStep(courseId, lessonId, stepPayload);
|
||||
await createStep(cid, lessonId, stepPayload);
|
||||
} else {
|
||||
await updateStep(step.id, stepPayload);
|
||||
await updateStep(cid, step.id, stepPayload);
|
||||
}
|
||||
} catch (stepError: any) {
|
||||
console.error('Failed to save step:', stepError);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user