fix: test
This commit is contained in:
@@ -21,6 +21,18 @@
|
||||
<SvgIcon name="book" :size="20" color="var(--color-thd-gray)" />
|
||||
</template>
|
||||
</TextField>
|
||||
<SelectField
|
||||
v-model="form.termId"
|
||||
name="termId"
|
||||
label="ترم مرتبط"
|
||||
:options="termOptions"
|
||||
option-label="title"
|
||||
option-value="id"
|
||||
:searchable="true"
|
||||
:on-search="searchTerms"
|
||||
:error="errors.termId"
|
||||
@update:model-value="onTermChange"
|
||||
/>
|
||||
<SelectField
|
||||
v-model="form.courseId"
|
||||
name="courseId"
|
||||
@@ -30,6 +42,7 @@
|
||||
option-value="id"
|
||||
:searchable="true"
|
||||
:on-search="searchTemplates"
|
||||
:disabled="!form.termId"
|
||||
:error="errors.courseId"
|
||||
@update:model-value="onCourseChange"
|
||||
/>
|
||||
@@ -77,13 +90,13 @@
|
||||
</div>
|
||||
|
||||
<div class="add-assignment__files">
|
||||
<LineTitleBlock title="فایلهای تکلیف" title-en="Assignment Files" />
|
||||
<FileUploader
|
||||
v-model="attachments"
|
||||
accept=".mp4,.mov,.avi,.mp3,.wav,.jpg,.jpeg,.png,.pdf,.txt,.doc,.docx"
|
||||
:multiple="true"
|
||||
:max-files="10"
|
||||
context="assignment"
|
||||
@select="onAttachmentsSelect"
|
||||
@error="onAttachmentsError"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -117,6 +130,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { toast } from 'vue3-toastify'
|
||||
import useYup from '@/composables/useYup'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import useModal from '@/composables/useModal'
|
||||
@@ -130,9 +144,12 @@ import TextField from '@/components/form/TextField.vue'
|
||||
import SelectField from '@/components/form/SelectField.vue'
|
||||
import LineTitleBlock from '@/components/LineTitleBlock.vue'
|
||||
import FileUploader from '@/components/form/FileUploader.vue'
|
||||
import { objectToFormData } from '@/utils/object-to-formdata'
|
||||
import { useUploadMediaMutation } from '@/services/query/auth'
|
||||
import TextareaField from '@/components/form/TextareaField.vue'
|
||||
import DatePickerField from '@/components/form/DatePickerField.vue'
|
||||
import { assignmentSchema } from '@/features/admin/assignments/schema'
|
||||
import { useAdminTermsListQuery } from '@/services/query/admin-terms'
|
||||
import { useAdminCoursesListQuery } from '@/services/query/admin-courses'
|
||||
import { useAdminSessionsListQuery } from '@/services/query/admin-sessions'
|
||||
import {
|
||||
@@ -158,6 +175,7 @@ const priorityOptions = Object.entries(ASSIGNMENT_PRIORITY).map(([value, label])
|
||||
|
||||
const form = ref({
|
||||
title: '',
|
||||
termId: '',
|
||||
courseId: '',
|
||||
sessionId: '',
|
||||
startDate: '',
|
||||
@@ -172,10 +190,28 @@ const schema = assignmentSchema
|
||||
|
||||
const { validate, validateAt, errors, resetErrors } = useYup(schema)
|
||||
|
||||
const termSearch = ref('')
|
||||
const termFilters = computed(() => ({ title: termSearch.value }))
|
||||
const termPagination = ref({ page: 1, perPage: 100 })
|
||||
const { data: termsResponse } = useAdminTermsListQuery(termFilters, termPagination)
|
||||
const selectedTerm = ref(null)
|
||||
const termOptions = computed(() => {
|
||||
const base = termsResponse.value?.data ?? []
|
||||
if (selectedTerm.value && !base.some((t) => t.id === selectedTerm.value.id)) {
|
||||
return [...base, selectedTerm.value]
|
||||
}
|
||||
return base
|
||||
})
|
||||
|
||||
const templateSearch = ref('')
|
||||
const templateFilters = computed(() => ({ title: templateSearch.value }))
|
||||
const templateFilters = computed(() => ({
|
||||
title: templateSearch.value,
|
||||
termId: form.value.termId || undefined,
|
||||
}))
|
||||
const templatePagination = ref({ page: 1, perPage: 10 })
|
||||
const { data: templatesResponse } = useAdminCoursesListQuery(templateFilters, templatePagination)
|
||||
const { data: templatesResponse } = useAdminCoursesListQuery(templateFilters, templatePagination, {
|
||||
enabled: () => !!form.value.termId,
|
||||
})
|
||||
const selectedTemplate = ref(null)
|
||||
const templateOptions = computed(() => {
|
||||
const base = templatesResponse.value?.data ?? []
|
||||
@@ -203,6 +239,9 @@ const sessionOptions = computed(() => {
|
||||
return base
|
||||
})
|
||||
|
||||
const searchTerms = useDebounce((q) => {
|
||||
termSearch.value = q || ''
|
||||
}, 400)
|
||||
const searchTemplates = useDebounce((q) => {
|
||||
templateSearch.value = q || ''
|
||||
}, 400)
|
||||
@@ -210,37 +249,78 @@ const searchSessions = useDebounce((q) => {
|
||||
sessionSearch.value = q || ''
|
||||
}, 400)
|
||||
|
||||
const onTermChange = (value) => {
|
||||
form.value.termId = value
|
||||
form.value.courseId = ''
|
||||
form.value.sessionId = ''
|
||||
selectedTemplate.value = null
|
||||
selectedSession.value = null
|
||||
}
|
||||
|
||||
const onCourseChange = (value) => {
|
||||
form.value.courseId = value
|
||||
form.value.sessionId = ''
|
||||
selectedSession.value = null
|
||||
}
|
||||
|
||||
const uploadMediaMutation = useUploadMediaMutation()
|
||||
|
||||
const onAttachmentsSelect = async (files) => {
|
||||
for (const file of files) {
|
||||
try {
|
||||
const fd = objectToFormData({ file, purpose: 'homework_file', context: 'homework' })
|
||||
const response = await uploadMediaMutation.mutateAsync(fd)
|
||||
const payload = response?.data ?? response
|
||||
const id = payload?.id ?? payload?.uploadId
|
||||
if (id == null) continue
|
||||
attachments.value = [
|
||||
...attachments.value,
|
||||
{ id, name: file.name, size: file.size, url: payload?.url ?? '' },
|
||||
]
|
||||
} catch {
|
||||
toast.error(`بارگذاری فایل "${file.name}" با خطا مواجه شد.`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const onAttachmentsError = (msg) => toast.error(msg)
|
||||
|
||||
const { data: existingAssignment } = useAdminAssignmentQuery(assignmentId, {
|
||||
enabled: () => !!assignmentId.value,
|
||||
})
|
||||
|
||||
watch(existingAssignment, (assignment) => {
|
||||
if (!assignment) return
|
||||
const tpl = assignment.course
|
||||
const sessionEntity = assignment.session
|
||||
const tpl = sessionEntity?.course || assignment.course
|
||||
const termEntity = tpl?.term || assignment.term
|
||||
const termId = termEntity?.id || tpl?.termId || assignment.termId || ''
|
||||
const priorityValue =
|
||||
assignment.priority ||
|
||||
(typeof assignment.isPriority === 'boolean'
|
||||
? assignment.isPriority
|
||||
? 'mandatory'
|
||||
: 'optional'
|
||||
: 'mandatory')
|
||||
if (termEntity) selectedTerm.value = termEntity
|
||||
if (tpl) selectedTemplate.value = tpl
|
||||
if (sessionEntity) selectedSession.value = sessionEntity
|
||||
form.value = {
|
||||
title: assignment.title || '',
|
||||
courseId: tpl?.id || assignment.courseId || '',
|
||||
termId,
|
||||
courseId: tpl?.id || sessionEntity?.courseId || assignment.courseId || '',
|
||||
sessionId: sessionEntity?.id || assignment.sessionId || '',
|
||||
startDate: assignment.startDate || '',
|
||||
endDate: assignment.endDate || '',
|
||||
priority: assignment.priority || 'mandatory',
|
||||
endDate: assignment.endDate || assignment.deadline || '',
|
||||
priority: priorityValue,
|
||||
description: assignment.description || '',
|
||||
}
|
||||
attachments.value = Array.isArray(assignment.attachments)
|
||||
? assignment.attachments.map((file) => ({
|
||||
id: file.id,
|
||||
name: file.title || `فایل ${file.id}`,
|
||||
url: file.fileUrl || '',
|
||||
type: file.type || 'other',
|
||||
attachments.value = Array.isArray(assignment.media)
|
||||
? assignment.media.map((m) => ({
|
||||
id: m.id,
|
||||
name: m.fileName || `فایل ${m.id}`,
|
||||
size: m.fileSize ?? 0,
|
||||
url: m.url || m.downloadUrl || '',
|
||||
}))
|
||||
: []
|
||||
})
|
||||
@@ -254,13 +334,13 @@ const onSubmit = async (close) => {
|
||||
const { isValid, payload } = await validate(form.value)
|
||||
if (!isValid) return
|
||||
const finalPayload = {
|
||||
...payload,
|
||||
attachments: attachments.value.map((file, index) => ({
|
||||
fileId: file.id,
|
||||
type: file.type || 'other',
|
||||
title: file.name,
|
||||
order: index + 1,
|
||||
})),
|
||||
sessionId: payload.sessionId,
|
||||
title: payload.title,
|
||||
description: payload.description ?? '',
|
||||
deadline: payload.endDate || null,
|
||||
isActive: true,
|
||||
isPriority: payload.priority === 'mandatory',
|
||||
mediaIds: attachments.value.map((file) => file.id).filter((id) => id != null),
|
||||
}
|
||||
if (isEditMode.value) {
|
||||
await updateMutation.mutateAsync({ id: assignmentId.value, payload: finalPayload })
|
||||
|
||||
Reference in New Issue
Block a user