Commit b8cdc054 authored by Administrator's avatar Administrator
Browse files

added Story page

parent 1a5a30c9
import apiClient from './index.js'
/**
* 通用的获取所有分页数据的函数
* @param {Function} apiCall - API调用函数
* @param {Object} params - 查询参数
* @returns {Promise<Array>} 所有页面的数据数组
*/
const fetchAllPages = async (apiCall, params = {}) => {
let allData = []
let page = 1
let hasNext = true
console.log('Starting to fetch all pages for API call...')
while (hasNext) {
try {
const currentParams = { ...params, page, page_size: 100 } // 每页100条,减少请求次数
console.log(`Fetching page ${page} with params:`, currentParams)
const response = await apiCall(currentParams)
if (response && response.results) {
// 分页格式响应
allData = [...allData, ...response.results]
hasNext = !!response.next
console.log(`Page ${page}: Got ${response.results.length} items, total so far: ${allData.length}, hasNext: ${hasNext}`)
} else if (Array.isArray(response)) {
// 非分页格式响应(向后兼容)
allData = response
hasNext = false
console.log('Non-paginated response detected, got all data at once:', allData.length, 'items')
} else {
console.log('Unexpected response format, stopping pagination')
hasNext = false
}
page++
// 安全检查:防止无限循环
if (page > 100) {
console.warn('Reached maximum page limit (100), stopping pagination')
break
}
} catch (error) {
console.error(`Error fetching page ${page}:`, error)
throw error
}
}
console.log(`Finished fetching all pages. Total items: ${allData.length}`)
return allData
}
// API端点定义
const apiEndpoints = {
STORIES: {
LIST: '/api/stories/',
DETAIL: (storyId) => `/api/stories/${storyId}/`,
UPDATE: (storyId) => `/api/stories/${storyId}/`,
DELETE: (storyId) => `/api/stories/${storyId}/`
}
}
/**
* 单页API调用函数(内部使用)
* @param {Object} params - 查询参数(包含分页参数)
* @returns {Promise} API响应
*/
const getStoriesPage = async (params = {}) => {
const response = await apiClient.get(apiEndpoints.STORIES.LIST, { params })
return response.data
}
/**
* 获取所有系列任务
* @param {Object} params - 查询参数
* @returns {Promise} 系列任务列表(完整数据,已处理分页)
*/
export const getStories = async (params = {}) => {
try {
// 构建查询参数,过滤掉null和undefined值
const queryParams = {}
Object.entries(params).forEach(([key, value]) => {
if (value !== null && value !== undefined) {
queryParams[key] = value
}
})
console.log('Stories API request params:', queryParams)
// 使用通用分页函数获取所有数据
const allStories = await fetchAllPages(getStoriesPage, queryParams)
console.log('Stories API final result:', {
totalCount: allStories.length,
sampleData: allStories.slice(0, 3) // 显示前3条数据作为样例
})
return allStories
} catch (error) {
console.error('Failed to fetch stories:', error)
throw error
}
}
/**
* 根据ID获取系列任务
* @param {number} storyId - 系列任务ID
* @returns {Promise} 系列任务详情
*/
export const getStoryById = async (storyId) => {
try {
const response = await apiClient.get(apiEndpoints.STORIES.DETAIL(storyId))
console.log('Story detail API response:', response.data)
return response.data
} catch (error) {
console.error('Failed to fetch story detail:', error)
// 提供更详细的错误信息
if (error.response) {
// 服务器响应了错误状态码
throw new Error(`获取系列任务详情失败: ${error.response.status} - ${error.response.statusText}`)
} else if (error.request) {
// 请求已发出但没有收到响应
throw new Error('网络错误: 无法连接到服务器')
} else {
// 其他错误
throw new Error(`请求配置错误: ${error.message}`)
}
}
}
/**
* 创建新的系列任务
* @param {Object} storyData - 系列任务数据
* @returns {Promise} 创建的系列任务
*/
export const createStory = async (storyData) => {
try {
const response = await apiClient.post(apiEndpoints.STORIES.LIST, storyData)
console.log('Create story API response:', response.data)
return response.data
} catch (error) {
console.error('Failed to create story:', error)
// 提供更详细的错误信息
if (error.response) {
// 服务器响应了错误状态码
throw new Error(`创建系列任务失败: ${error.response.status} - ${error.response.statusText}`)
} else if (error.request) {
// 请求已发出但没有收到响应
throw new Error('网络错误: 无法连接到服务器')
} else {
// 其他错误
throw new Error(`请求配置错误: ${error.message}`)
}
}
}
/**
* 更新系列任务
* @param {number} storyId - 系列任务ID
* @param {Object} storyData - 更新的系列任务数据
* @returns {Promise} 更新后的系列任务
*/
export const updateStory = async (storyId, storyData) => {
try {
const response = await apiClient.patch(apiEndpoints.STORIES.UPDATE(storyId), storyData)
console.log('Update story API response:', response.data)
return response.data
} catch (error) {
console.error('Failed to update story:', error)
// 提供更详细的错误信息
if (error.response) {
// 服务器响应了错误状态码
throw new Error(`更新系列任务失败: ${error.response.status} - ${error.response.statusText}`)
} else if (error.request) {
// 请求已发出但没有收到响应
throw new Error('网络错误: 无法连接到服务器')
} else {
// 其他错误
throw new Error(`请求配置错误: ${error.message}`)
}
}
}
/**
* 删除系列任务
* @param {number} storyId - 系列任务ID
* @returns {Promise} 删除结果
*/
export const deleteStory = async (storyId) => {
try {
const response = await apiClient.delete(apiEndpoints.STORIES.DELETE(storyId))
console.log('Delete story API response:', response.data)
return response.data
} catch (error) {
console.error('Failed to delete story:', error)
// 提供更详细的错误信息
if (error.response) {
// 服务器响应了错误状态码
throw new Error(`删除系列任务失败: ${error.response.status} - ${error.response.statusText}`)
} else if (error.request) {
// 请求已发出但没有收到响应
throw new Error('网络错误: 无法连接到服务器')
} else {
// 其他错误
throw new Error(`请求配置错误: ${error.message}`)
}
}
}
......@@ -8,16 +8,23 @@
<v-list-item :title="$t('navigation.welcome.title')" :subtitle="$t('navigation.welcome.subtitle')"></v-list-item>
<v-divider></v-divider>
<v-list v-model:opened="opened">
<v-list v-model:opened="opened" nav>
<template v-for="item in filteredMenu" :key="item.path || item.nameKey">
<!-- 分组(有 children):点击父项仅用于展开,不路由 -->
<v-list-group
v-if="item.children && item.children.length"
:value="item.path"
:prepend-icon="item.mdiIcon"
slim
>
<template #activator="{ props }">
<v-list-item v-bind="props">
<v-list-item
v-bind="props"
:ripple="true"
:disabled="false"
nav
density="comfortable"
>
<v-list-item-title class="text-body-1">{{ $t(item.nameKey) }}</v-list-item-title>
</v-list-item>
</template>
......@@ -30,6 +37,7 @@
:ripple="child.hasRouter"
:disabled="!child.hasRouter"
nav
density="compact"
>
<v-list-item-title class="text-body-1">{{ $t(child.nameKey) }}</v-list-item-title>
</v-list-item>
......@@ -43,13 +51,14 @@
:ripple="item.hasRouter"
:disabled="false"
@click="!item.hasRouter ? noop() : undefined"
nav>
nav
density="comfortable"
>
<v-list-item-title class="text-body-1">{{ $t(item.nameKey) }}</v-list-item-title>
</v-list-item>
</template>
</v-list>
</v-navigation-drawer>
</template>
<script setup>
......@@ -104,4 +113,9 @@ const noop = () => {}
</script>
<style scoped>
/* 使用Vuetify的类来确保一致的外观 */
.v-list-group--activator .v-list-item {
/* 确保分组标题与普通列表项有相同的密度设置 */
--v-list-item-density: -1;
}
</style>
......@@ -34,6 +34,12 @@ export const GLOBAL_MENU_ITEMS = [
path: '/master-data/terms',
mdiIcon: 'mdi-calendar-month-outline',
hasRouter: true
},
{
nameKey: 'navigation.menu.stories',
path: '/master-data/stories',
mdiIcon: 'mdi-book-multiple-outline',
hasRouter: true
}
]
},
......
export default {
pagination: {
itemsPerPage: 'Items per page',
itemsPerPageAll: 'All',
noDataText: 'No data available',
loadingText: 'Loading items...',
pageText: '{0}-{1} of {2}',
rowsPerPageText: 'Rows per page:'
},
actions: {
edit: 'Edit',
delete: 'Delete',
view: 'View'
},
filter: {
search: 'Search',
clear: 'Clear',
apply: 'Apply'
}
}
\ No newline at end of file
......@@ -3,10 +3,12 @@ import buttons from './common/buttons'
import messages from './common/messages'
import status from './common/status'
import validation from './common/validation'
import table from './common/table'
import student from './modules/student'
import subject from './modules/subject'
import term from './modules/term'
import task from './modules/task'
import story from './modules/story'
import auth from './modules/auth'
import navigation from './modules/navigation'
import appHeader from './components/app-header'
......@@ -17,12 +19,14 @@ export default {
buttons,
messages,
status,
validation
validation,
table
},
student,
subject,
term,
task,
story,
auth,
navigation,
components: {
......
......@@ -12,6 +12,7 @@ export default {
students: 'Students',
subjects: 'Subjects',
terms: 'Terms',
stories: 'Story',
tasks: 'Task Management',
dashboard: 'Dashboard',
settings: 'Settings',
......@@ -24,6 +25,7 @@ export default {
students: 'Students',
subjects: 'Subjects',
terms: 'Terms',
stories: 'Story',
tasks: 'Task Management',
profile: 'Profile'
},
......
export default {
title: 'Story',
tableHeader: {
storyId: 'Story ID',
storyName: 'Story Name',
description: 'Description',
studentId: 'Student',
subjectId: 'Subject',
termId: 'Term',
trackedFlag: 'Tracked',
createdBy: 'Created By',
creationDate: 'Creation Date',
lastUpdatedBy: 'Last Updated By',
lastUpdateDate: 'Last Update Date',
actions: 'Actions'
},
form: {
storyName: 'Story Name',
description: 'Description',
studentId: 'Student',
subjectId: 'Subject',
termId: 'Term',
trackedFlag: 'Tracked'
},
dialog: {
create: 'Create Story',
edit: 'Edit Story',
delete: 'Delete Story'
},
button: {
create: 'Create Story',
edit: 'Edit',
delete: 'Delete',
save: 'Save',
cancel: 'Cancel',
confirm: 'Confirm'
},
message: {
createSuccess: 'Story created successfully',
updateSuccess: 'Story updated successfully',
deleteSuccess: 'Story deleted successfully',
createError: 'Failed to create story',
updateError: 'Failed to update story',
deleteError: 'Failed to delete story',
loadError: 'Failed to load stories'
},
deleteConfirm: {
title: 'Delete Story',
message: 'Are you sure you want to delete this story?',
description: 'This action cannot be undone.',
warning: 'This action cannot be undone. Please proceed with caution.',
storyInfo: '{name}'
},
validation: {
storyNameRequired: 'Story name is required',
studentRequired: 'Student is required',
subjectRequired: 'Subject is required',
termRequired: 'Term is required'
},
status: {
tracked: 'Tracked',
notTracked: 'Not Tracked',
enabled: 'Enabled',
disabled: 'Disabled'
}
}
export default {
pagination: {
itemsPerPage: '每页显示',
itemsPerPageAll: '全部',
noDataText: '暂无数据',
loadingText: '加载中...',
pageText: '{0}-{1} 共 {2}',
rowsPerPageText: '每页行数:'
},
actions: {
edit: '编辑',
delete: '删除',
view: '查看'
},
filter: {
search: '搜索',
clear: '清除',
apply: '应用'
}
}
\ No newline at end of file
......@@ -3,10 +3,12 @@ import buttons from './common/buttons'
import messages from './common/messages'
import status from './common/status'
import validation from './common/validation'
import table from './common/table'
import student from './modules/student'
import subject from './modules/subject'
import term from './modules/term'
import task from './modules/task'
import story from './modules/story'
import auth from './modules/auth'
import navigation from './modules/navigation'
import appHeader from './components/app-header'
......@@ -17,12 +19,14 @@ export default {
buttons,
messages,
status,
validation
validation,
table
},
student,
subject,
term,
task,
story,
auth,
navigation,
components: {
......
......@@ -12,6 +12,7 @@ export default {
students: '学生',
subjects: '学科',
terms: '学期',
stories: '系列任务',
tasks: '作业管理',
dashboard: '仪表盘',
settings: '设置',
......@@ -24,6 +25,7 @@ export default {
students: '学生',
subjects: '学科',
terms: '学期',
stories: '系列任务',
tasks: '作业管理',
profile: '个人资料'
},
......
export default {
title: '系列任务',
tableHeader: {
storyId: '系列任务ID',
storyName: '系列任务名称',
description: '描述',
studentId: '学生',
subjectId: '学科',
termId: '学期',
trackedFlag: '跟踪状态',
createdBy: '创建人',
creationDate: '创建日期',
lastUpdatedBy: '最后更新人',
lastUpdateDate: '最后更新日期',
actions: '操作'
},
form: {
storyName: '系列任务名称',
description: '描述',
studentId: '学生',
subjectId: '学科',
termId: '学期',
trackedFlag: '跟踪状态'
},
dialog: {
create: '创建系列任务',
edit: '编辑系列任务',
delete: '删除系列任务'
},
button: {
create: '创建系列任务',
edit: '编辑',
delete: '删除',
save: '保存',
cancel: '取消',
confirm: '确认'
},
message: {
createSuccess: '系列任务创建成功',
updateSuccess: '系列任务更新成功',
deleteSuccess: '系列任务删除成功',
createError: '创建系列任务失败',
updateError: '更新系列任务失败',
deleteError: '删除系列任务失败',
loadError: '加载系列任务失败'
},
deleteConfirm: {
title: '删除系列任务',
message: '确定要删除此系列任务吗?',
description: '此操作无法撤销。',
warning: '此操作无法撤销,请谨慎操作。',
storyInfo: '{name}'
},
validation: {
storyNameRequired: '系列任务名称不能为空',
studentRequired: '学生不能为空',
subjectRequired: '学科不能为空',
termRequired: '学期不能为空'
},
status: {
tracked: '已跟踪',
notTracked: '未跟踪',
enabled: '启用',
disabled: '禁用'
}
}
......@@ -6,6 +6,7 @@ import ProfileView from '../views/ProfileView.vue'
import StudentView from '../views/StudentView.vue'
import SubjectView from '../views/SubjectView.vue'
import TermView from '../views/TermView.vue'
import StoryView from '../views/StoryView.vue'
import TaskView from '../views/TaskView.vue'
const router = createRouter({
......@@ -84,8 +85,7 @@ const router = createRouter({
]
},
},
{
path: '/master-data/terms',
{ path: '/master-data/terms',
name: 'terms',
component: TermView,
meta: {
......@@ -102,6 +102,24 @@ const router = createRouter({
]
},
},
{
path: '/master-data/stories',
name: 'stories',
component: StoryView,
meta: {
requiresAuth: true,
layout: 'default',
title: 'Stories',
breadcrumb: {
key: 'navigation.breadcrumb.stories'
},
breadcrumbPath: [
{ key: 'navigation.breadcrumb.home', to: '/', disabled: false },
{ key: 'navigation.breadcrumb.masterData', to: null, disabled: true },
{ key: 'navigation.breadcrumb.stories', to: '/master-data/stories', disabled: true }
]
},
},
{
path: '/tasks',
name: 'tasks',
......
This diff is collapsed.
......@@ -577,7 +577,7 @@ const saveStudent = async () => {
</div>
</template>
<template v-slot:[`item.enabled`]="{ item }">
<v-chip :color="item.enabled === 'Y' ? 'success' : 'error'" size="small" variant="flat">
<v-chip :color="item.enabled === 'Y' ? 'success' : 'error'" text-color="white" size="small">
{{ item.enabled === 'Y' ? $t('common.status.enabled') : $t('common.status.disabled') }}
</v-chip>
</template>
......@@ -714,6 +714,9 @@ const saveStudent = async () => {
v-model="editForm.enabled"
:label="$t('student.form.enabledStatus')"
color="primary"
:true-value="true"
:false-value="false"
inset
/>
</v-col>
</v-row>
......@@ -871,6 +874,9 @@ const saveStudent = async () => {
v-model="createForm.enabled"
:label="$t('student.form.enabledStatus') + ' *'"
color="primary"
:true-value="true"
:false-value="false"
inset
/>
</v-col>
</v-row>
......
......@@ -390,12 +390,12 @@ const getCalendarColorValue = (colorCode) => {
fixed-header
>
<template v-slot:[`item.enabled_flag`]="{ item }">
<v-chip :color="item.enabled_flag === 'Y' ? 'success' : 'error'" size="small" variant="flat">
<v-chip :color="item.enabled_flag === 'Y' ? 'success' : 'error'" text-color="white" size="small">
{{ item.enabled_flag === 'Y' ? $t('subject.status.enabled') : $t('subject.status.disabled') }}
</v-chip>
</template>
<template v-slot:[`item.primary_flag`]="{ item }">
<v-chip :color="item.primary_flag === 'Y' ? 'primary' : 'default'" size="small" variant="flat">
<v-chip :color="item.primary_flag === 'Y' ? 'primary' : 'default'" text-color="white" size="small">
{{ item.primary_flag === 'Y' ? $t('subject.status.primary') : $t('subject.status.notPrimary') }}
</v-chip>
</template>
......@@ -484,6 +484,7 @@ const getCalendarColorValue = (colorCode) => {
color="primary"
true-value="Y"
false-value="N"
inset
/>
</v-col>
<v-col cols="6">
......@@ -493,6 +494,7 @@ const getCalendarColorValue = (colorCode) => {
color="primary"
true-value="Y"
false-value="N"
inset
/>
</v-col>
</v-row>
......@@ -596,6 +598,7 @@ const getCalendarColorValue = (colorCode) => {
color="primary"
true-value="Y"
false-value="N"
inset
/>
</v-col>
<v-col cols="6">
......@@ -605,6 +608,7 @@ const getCalendarColorValue = (colorCode) => {
color="primary"
true-value="Y"
false-value="N"
inset
/>
</v-col>
</v-row>
......
......@@ -278,7 +278,7 @@
{{ errorMessage }}
</v-alert>
</div>
<v-card-title>
<span>{{ isCreateMode ? $t('task.edit.createTitle') : $t('task.edit.title') }}</span>
<v-spacer />
......@@ -345,7 +345,7 @@
/>
</v-col>
<v-col cols="12" md="6">
<v-text-field
<!-- <v-text-field
v-model="editForm.completion_percent"
:label="$t('task.task.completionPercent') + ' *'"
:placeholder="$t('task.task.completionPercent')"
......@@ -355,7 +355,29 @@
min="0"
max="100"
required
/>
/> -->
<v-slider
v-model="editForm.completion_percent"
:label="$t('task.task.completionPercent') + ' *'"
:min="0"
:max="100"
:step="1"
thumb-label="always"
persistent-hint
:hint="`${editForm.completion_percent}%`"
>
<template #append>
<v-text-field
v-model="editForm.completion_percent"
type="number"
min="0"
max="100"
hide-details
density="compact"
style="width: 80px;"
/>
</template>
</v-slider>
</v-col>
<v-col cols="12" md="6">
<v-text-field
......@@ -598,15 +620,15 @@
{{ errorMessage }}
</v-alert>
</div>
<p class="text-body-1 mb-4">{{ $t('task.messages.deleteConfirmation') }}</p>
<v-card variant="outlined" class="mb-4">
<v-card-item>
<v-card-title>{{ taskToDelete?.task_name }}</v-card-title>
</v-card-item>
</v-card>
<v-alert
type="warning"
variant="tonal"
......@@ -999,7 +1021,7 @@ const onEventClick = async (event) => {
const onDateClick = (date) => {
console.log('onDateClick called with date:', date);
// v-calendar的click:date事件应该传递日期对象,而不是点击事件
// 但如果收到的是点击事件,我们需要处理这种情况
if (date) {
......@@ -1177,7 +1199,7 @@ const openEditDialog = async (task) => {
// 设置为编辑模式
isCreateMode.value = false;
console.log('Setting isCreateMode to false for editing existing task');
// 清理图像缓存
Object.keys(imageCache.value).forEach(key => {
if (imageCache.value[key]) {
......@@ -1185,7 +1207,7 @@ const openEditDialog = async (task) => {
imageCache.value[key] = null;
}
});
// 清理图片删除标记
for (let i = 1; i <= 5; i++) {
const imageKey = `image_0${i}`;
......@@ -1268,7 +1290,7 @@ const openCreateDialog = (date) => {
if (date) {
console.log('date properties:', Object.keys(date));
}
// 清理图像缓存
Object.keys(imageCache.value).forEach(key => {
if (imageCache.value[key]) {
......@@ -1276,7 +1298,7 @@ const openCreateDialog = (date) => {
imageCache.value[key] = null;
}
});
// 清理图片删除标记
for (let i = 1; i <= 5; i++) {
const imageKey = `image_0${i}`;
......@@ -1291,7 +1313,7 @@ const openCreateDialog = (date) => {
// 设置为创建模式
isCreateMode.value = true;
editingTask.value = null;
// 初始化表单数据 - 增强对各种date参数格式的处理
let formattedDate;
try {
......@@ -1331,7 +1353,7 @@ const openCreateDialog = (date) => {
console.warn('Error processing date, using current date:', error);
formattedDate = new Date().toISOString().split('T')[0];
}
editForm.value = {
task_name: '',
task_description: '',
......@@ -1353,7 +1375,7 @@ const openCreateDialog = (date) => {
image_05: null,
image_05_mime_type: null
};
console.log('Creating new task with date:', formattedDate);
editDialog.value = true;
}
......@@ -1362,11 +1384,11 @@ const closeEditDialog = () => {
editDialog.value = false;
editingTask.value = null;
isCreateMode.value = false;
// 清除错误消息状态
isError.value = false;
errorMessage.value = '';
editForm.value = {
task_name: '',
task_description: '',
......@@ -1542,51 +1564,51 @@ const uploadImage = async (index) => {
const input = document.createElement('input');
input.type = 'file';
input.accept = 'image/*'; // 只接受图片文件
// 监听文件选择事件
input.onchange = async (e) => {
const file = e.target.files[0];
if (!file) return;
try {
// 设置加载状态
imageLoading.value[index] = true;
// 读取文件为base64
const reader = new FileReader();
reader.onload = (event) => {
const base64String = event.target.result;
// 更新表单数据
const imageKey = `image_0${index}`;
// 重要:如果之前标记了删除,现在上传新图片,需要取消删除标记
editForm.value[`delete_${imageKey}`] = false;
// 清除旧的图片数据,确保不会有冲突
editForm.value[imageKey] = null;
// 设置新的图片数据
editForm.value[`${imageKey}_mime_type`] = file.type;
editForm.value[`${imageKey}_file_name`] = file.name;
editForm.value[`${imageKey}_base64`] = base64String;
// 更新图片缓存,立即显示上传的图片
if (imageCache.value[index]) {
URL.revokeObjectURL(imageCache.value[index]);
}
imageCache.value[index] = URL.createObjectURL(file);
console.log(`Image ${index} uploaded successfully:`, {
fileName: file.name,
mimeType: file.type,
hasBase64: !!base64String,
deleteFlag: editForm.value[`delete_${imageKey}`]
});
// 重置加载状态
imageLoading.value[index] = false;
};
reader.readAsDataURL(file);
} catch (error) {
console.error(`Failed to upload image ${index}:`, error);
......@@ -1596,12 +1618,12 @@ const uploadImage = async (index) => {
isError.value = false;
errorMessage.value = '';
}, 3000);
// 重置加载状态
imageLoading.value[index] = false;
}
};
// 触发文件选择器
input.click();
};
......@@ -1613,13 +1635,13 @@ const deleteImage = (index) => {
// 更新表单数据,标记为删除
const imageKey = `image_0${index}`;
editForm.value[`delete_${imageKey}`] = true;
// 清除图片缓存
if (imageCache.value[index]) {
URL.revokeObjectURL(imageCache.value[index]);
imageCache.value[index] = null;
}
// 清除其他相关字段
editForm.value[`${imageKey}_mime_type`] = null;
editForm.value[`${imageKey}_file_name`] = null;
......@@ -1714,7 +1736,7 @@ const updateTask = async () => {
isSaving.value = true
try {
console.log('Form data before update/create:', editForm.value)
// 验证必填字段
if (!editForm.value.task_name) {
throw new Error(t('task.validation.nameRequired') || '作业名称不能为空')
......@@ -1750,21 +1772,21 @@ const updateTask = async () => {
end_date: new Date(editForm.value.end_date).toISOString(),
completion_percent: parseInt(editForm.value.completion_percent)
}
// 添加图片上传和删除相关数据
for (let i = 1; i <= 5; i++) {
const imageKey = `image_0${i}`;
// 处理图片上传 - 优先处理上传,因为上传会覆盖删除标记
if (editForm.value[`${imageKey}_base64`]) {
// 如果有新上传的图片,确保删除标记为false
taskData[`delete_${imageKey}`] = false;
// 添加图片数据
taskData[`${imageKey}_mime_type`] = editForm.value[`${imageKey}_mime_type`];
taskData[`${imageKey}_file_name`] = editForm.value[`${imageKey}_file_name`];
taskData[`${imageKey}_base64`] = editForm.value[`${imageKey}_base64`];
console.log(`Sending new image data for ${imageKey}`);
}
// 处理图片删除 - 只有在没有新上传图片的情况下才处理删除
......@@ -1777,13 +1799,13 @@ const updateTask = async () => {
console.log('Sending data:', taskData)
let result;
// 根据模式决定是创建还是更新任务
if (isCreateMode.value) {
// 创建新任务
console.log('Creating new task...');
result = await createTaskAPI(taskData);
// 将新任务添加到任务列表
tasks.value.push(result);
console.log('Task created successfully:', result);
......@@ -1791,7 +1813,7 @@ const updateTask = async () => {
// 更新现有任务
console.log('Updating existing task...');
result = await updateTaskAPI(editingTask.value.task_id, taskData);
// 更新本地列表中的任务
const index = tasks.value.findIndex(t => t.task_id === editingTask.value.task_id);
if (index !== -1) {
......@@ -1808,7 +1830,7 @@ const updateTask = async () => {
errorMessage.value = error.message || (isCreateMode.value ? '创建作业失败' : t('task.messages.updateError'));
isError.value = true;
// 不再使用setTimeout自动清除错误消息,而是让用户手动关闭或在对话框关闭时清除
// 滚动到对话框顶部,确保错误消息可见
setTimeout(() => {
const dialogElement = document.querySelector('.v-dialog--active');
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment