
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
2024-11-19
2024-11-19
<template>
<div class="title-box flex justify-between mb40">
<p class="title">문제 조회</p>
</div>
<div class="content-t">
<div class="board-wrap">
<div class="gd-col2 ">
<div class="flex align-center mb20">
<label for="" class="title2">카테고리</label>
<select v-model="selectedSearchOption" class="mr10 data-wrap">
<option value="1">듣기 이해력(LC)</option>
<option value="2">독해 이해력(RC)</option>
<option value="4">쓰기(WT)</option>
<option value="5">말하기(SP)</option>
<option value="3">그외(ETC)</option>
</select>
</div>
<div class="flex align-center mb20">
<label for="" class="title2">문제 유형</label>
<select v-model="selectedSearchOption2" class="mr10 data-wrap">
<option v-for="prblmT in problemType" :key="prblmT.prblm_type_id" :value="prblmT">
{{ prblmT.prblm_type_nm }}
</option>
</select>
</div>
<div class="flex align-center">
<label for="" class="title2">지문</label>
<select name="" id="" v-model="book_id" @change="fetchUnits" class="mr10">
<option value="" disabled>교재를 선택하세요</option>
<option v-for="book in books" :key="book.book_id" :value="book.book_id">
{{ book.book_nm }}
</option>
</select>
<select name="" id="" v-model="unit_id" @change="fetchTexts" class="mr10">
<option value="" disabled>단원을 선택하세요</option>
<option v-for="unit in units" :key="unit.unitId" :value="unit.unitId">
{{ unit.unitName }}
</option>
</select>
<select v-model="text_id" class="mr10 data-wrap">
<option value="" disabled>지문을 선택하세요</option>
<option v-for="text in texts" :key="text.textId" :value="text.textId">
{{ text.textTtl }}
</option>
</select>
</div>
</div>
<div class="flex align-center mb20 mt40">
<label for="" class="title2">문제 배점</label>
<input type="text" class="data-wrap" v-model="prblm_scr">
</div>
<div class="flex align-center mb20">
<label for="" class="title2">내용</label>
<textarea name="" id="" class="data-wrap" v-model="prblm_expln"></textarea>
</div>
<div class="flex align-center mb20">
<label for="" class="title2">힌트</label>
<input type="text" class="data-wrap" v-model="prblm_hint">
</div>
<div class="flex align-center ">
<label for="file" class="title2">첨부파일</label>
<div v-for="(data, index) in mainfile" :key="index">
<label>{{ data.fileNm }}</label>
</div>
<input type="file" ref="fileInput" @change="handleFileUpload" multiple />
</div>
<hr>
<div v-if="selectedSearchOption2.prblm_type_cls === '5지선다'">
<!--5지선다-->
<div class="gd-col2 " v-for="i in 5" :key="i">
<div>
<div class="flex align-center mb20 mr40">
<label :for="'answer' + i" class="title2">답{{ i }}</label>
<input :id="'answer' + i" type="text" class="data-wrap"
v-model="prblmDetail.answers[i].text" />
</div>
<div class="flex align-center mb20">
<label :for="'correct' + i" class="title2">정답여부</label>
<input :id="'correct' + i" type="checkbox" class="ui-checkbox"
:checked="prblmDetail.correctIndex === i" @change="setCorrectAnswer(i, 5)" />
</div>
</div>
<div class="flex align-center mb20">
<label :for="'file' + i" class="title2">첨부파일</label>
<div v-if="prblmDetail.answers[i] && prblmDetail.answers[i].fileInfo"
v-for="(data, index) in prblmDetail.answers[i].fileInfo" :key="index">
<label>{{ data.fileNm }}</label>
</div>
<input type="file" :ref="'fileInput' + i" @change="handleDetailFileUpload(i)" multiple />
</div>
</div>
</div>
<div v-else-if="selectedSearchOption2.prblm_type_cls === '4지선다'">
<!--4지선다-->
<div class="gd-col2 " v-for="i in 4" :key="i">
<div>
<div class="flex align-center mb20 mr40">
<label :for="'answer' + i" class="title2">답{{ i }}</label>
<input :id="'answer' + i" type="text" class="data-wrap"
v-model="prblmDetail.answers[i].text" />
</div>
<div class="flex align-center mb20">
<label :for="'correct' + i" class="title2">정답여부</label>
<input :id="'correct' + i" type="checkbox" class="ui-checkbox"
:checked="prblmDetail.correctIndex === i" @change="setCorrectAnswer(i, 4)" />
</div>
</div>
<div class="flex align-center mb20">
<label :for="'file' + i" class="title2">첨부파일</label>
<div v-if="prblmDetail.answers[i] && prblmDetail.answers[i].fileInfo"
v-for="(data, index) in prblmDetail.answers[i].fileInfo" :key="index">
<label>{{ data.fileNm }}</label>
</div>
<input type="file" :ref="'fileInput' + i" @change="handleDetailFileUpload(i)" multiple />
</div>
</div>
</div>
<div v-else-if="selectedSearchOption2.prblm_type_cls === '3지선다'">
<!--3지선다-->
<div class="gd-col2 " v-for="i in 3" :key="i">
<div>
<div class="flex align-center mb20 mr40">
<label :for="'answer' + i" class="title2">답{{ i }}</label>
<input :id="'answer' + i" type="text" class="data-wrap"
v-model="prblmDetail.answers[i].text" />
</div>
<div class="flex align-center mb20">
<label :for="'correct' + i" class="title2">정답여부</label>
<input :id="'correct' + i" type="checkbox" class="ui-checkbox"
:checked="prblmDetail.correctIndex === i" @change="setCorrectAnswer(i, 3)" />
</div>
</div>
<div class="flex align-center mb20">
<label :for="'file' + i" class="title2">첨부파일</label>
<div v-if="prblmDetail.answers[i] && prblmDetail.answers[i].fileInfo"
v-for="(data, index) in prblmDetail.answers[i].fileInfo" :key="index">
<label>{{ data.fileNm }}</label>
</div>
<input type="file" :ref="'fileInput' + i" @change="handleDetailFileUpload(i)" multiple />
</div>
</div>
</div>
<div v-else-if="selectedSearchOption2.prblm_type_cls === '2지선다'">
<!--2지선다-->
<div class="gd-col2 " v-for="i in 2" :key="i">
<div>
<div class="flex align-center mb20 mr40">
<label :for="'answer' + i" class="title2">답{{ i }}</label>
<input :id="'answer' + i" type="text" class="data-wrap"
v-model="prblmDetail.answers[i].text" />
</div>
<div class="flex align-center mb20">
<label :for="'correct' + i" class="title2">정답여부</label>
<input :id="'correct' + i" type="checkbox" class="ui-checkbox"
:checked="prblmDetail.correctIndex === i" @change="setCorrectAnswer(i, 2)" />
</div>
</div>
<div class="flex align-center mb20">
<label :for="'file' + i" class="title2">첨부파일</label>
<div v-if="prblmDetail.answers[i] && prblmDetail.answers[i].fileInfo"
v-for="(data, index) in prblmDetail.answers[i].fileInfo" :key="index">
<label>{{ data.fileNm }}</label>
</div>
<input type="file" :ref="'fileInput' + i" @change="handleDetailFileUpload(i)" multiple />
</div>
</div>
</div>
<div v-else-if="selectedSearchOption2.prblm_type_cls === 'OX 문제'">
<!-- OX 문제 -->
<div class="flex align-center mb20">
<label for="" class="title2">답</label>
<select v-model="prblmDetail.answers[1].text" class="mr10 data-wrap">
<option value="O">O</option>
<option value="X">X</option>
</select>
</div>
<div class="flex align-center mb20">
<label class="title2">첨부파일</label>
<div v-if="prblmDetail.answers[1] && prblmDetail.answers[1].fileInfo"
v-for="(data, index) in prblmDetail.answers[1].fileInfo" :key="index">
<label>{{ data.fileNm }}</label>
</div>
<input type="file" ref="fileInput1" @change="handleDetailFileUpload(1)" multiple />
</div>
</div>
<div v-else-if="selectedSearchOption2.prblm_type_cls === '서술형'">
<!-- 서술형 -->
<div class="gd-col2">
<div class="flex align-center mb20">
<label for="" class="title2">답</label>
<input type="text" class="data-wrap" v-model="prblmDetail.answers[1].text">
</div>
<div class="flex align-center mb20">
<label class="title2">첨부파일</label>
<div v-if="prblmDetail.answers[1] && prblmDetail.answers[1].fileInfo"
v-for="(data, index) in prblmDetail.answers[1].fileInfo" :key="index">
<label>{{ data.fileNm }}</label>
</div>
<input type="file" ref="fileInput1" @change="handleDetailFileUpload(1)" multiple />
</div>
</div>
</div>
<div class="flex align-center mb20">
<label for="" class="title2">해설</label>
<textarea name="" id="" class="data-wrap" v-model="prblm_cmmt"></textarea>
</div>
<hr>
<div class="flex align-center mb20 mt40">
<label for="" class="title2">문제 지표 1</label>
<input type="text" class="data-wrap" v-model="prblm_mtr1">
</div>
<div class="flex align-center mb20 mt40">
<label for="" class="title2">문제 지표 2</label>
<input type="text" class="data-wrap" v-model="prblm_mtr2">
</div>
<div class="flex align-center mb20 mt40">
<label for="" class="title2">문제 지표 3</label>
<input type="text" class="data-wrap" v-model="prblm_mtr3">
</div>
<div class="flex align-center mb20 mt40">
<label for="" class="title2">문제 지표 4</label>
<input type="text" class="data-wrap" v-model="prblm_mtr4">
</div>
<div class="flex align-center mb20 mt40">
<label for="" class="title2">문제 지표 5</label>
<input type="text" class="data-wrap" v-model="prblm_mtr5">
</div>
<div class="flex align-center mb20 mt40">
<label for="" class="title2">문제 지표 6</label>
<input type="text" class="data-wrap" v-model="prblm_mtr6">
</div>
</div>
<div class="flex justify-between mt50">
<button type="button" title="글쓰기" class="new-btn" @click="goToPage('QuestionList')">
목록
</button>
<div class="flex">
<button type="button" title="글쓰기" class="new-btn mr10" @click="deletePost">
삭제
</button>
<button type="button" title="글쓰기" class="new-btn" @click="submitForm">
수정
</button>
</div>
</div>
</div>
</template>
<script>
import SvgIcon from '@jamescoyle/vue-icon';
import { mdiMagnify } from '@mdi/js';
import axios from 'axios';
export default {
data() {
return {
mdiMagnify: mdiMagnify,
selectedTab: 'tab1',
prblm: {},
dataList: [],
problemDetail: [],
problemType: [],
selectedSearchOption: '',
selectedSearchOption2: {
},
book_id: '',
unit_id: '',
text_id: '',
prblm_scr: '',
prblm_expln: '',
prblm_hint: '',
prblm_cmmt: '',
prblm_mtr1: '',
prblm_mtr2: '',
prblm_mtr3: '',
prblm_mtr4: '',
prblm_mtr5: '',
prblm_mtr6: '',
file_mng_id: '',
prblmDetail: {
answers: {
1: { text: '', isCorrect: 'Y', fileMngId: null, fileInfo: '' },
2: { text: '', isCorrect: 'N', fileMngId: null, fileInfo: '' },
3: { text: '', isCorrect: 'N', fileMngId: null, fileInfo: '' },
4: { text: '', isCorrect: 'N', fileMngId: null, fileInfo: '' },
5: { text: '', isCorrect: 'N', fileMngId: null, fileInfo: '' },
},
correctIndex: 1, // 정답으로 선택된 답의 인덱스
},
books: [],
units: [],
texts: [],
mainfile: null,
selectedFiles: {},
}
},
methods: {
goToPage(page) {
this.$router.push({ name: page });
},
handleFileUpload(e) {
this.file = e.target.files;
},
handleDetailFileUpload(index) {
const files = this.$refs['fileInput' + index][0].files;
this.selectedFiles[index] = files;
},
// 문제 정보 가져오기
async problemSearch() {
try {
const vm = this;
vm.prblm = JSON.parse(sessionStorage.getItem("selectQuestionList"));
const res = await axios({
url: "problem/problemInfo.json",
method: "post",
headers: {
"Content-Type": "application/json; charset=UTF-8",
},
data: {
prblmId: vm.prblm.prblmId,
},
});
console.log("problem - response : ", res.data);
vm.dataList = res.data.problem;
vm.problemDetail = res.data.problemDetail;
vm.problemDetail.sort((a, b) => {
return a.prblmDtlId.localeCompare(b.prblmDtlId);
});
vm.selectedSearchOption = vm.dataList.prblmCtgryId;
vm.selectedSearchOption2.prblm_type_id = vm.dataList.prblmTypeId;
vm.selectedSearchOption2.prblm_type_cls = vm.dataList.prblmTypeCls;
vm.selectedSearchOption2.prblm_type_nm = vm.dataList.prblmTypeNm;
vm.book_id = vm.dataList.bookId;
vm.unit_id = vm.dataList.unitId;
vm.text_id = vm.dataList.textId;
vm.prblm_scr = vm.dataList.prblmScr;
vm.prblm_expln = vm.dataList.prblmExpln;
vm.prblm_hint = vm.dataList.prblmHint;
vm.prblm_cmmt = vm.dataList.prblmCmmt;
vm.prblm_mtr1 = vm.dataList.prblmMtr1;
vm.prblm_mtr2 = vm.dataList.prblmMtr2;
vm.prblm_mtr3 = vm.dataList.prblmMtr3;
vm.prblm_mtr4 = vm.dataList.prblmMtr4;
vm.prblm_mtr5 = vm.dataList.prblmMtr5;
vm.prblm_mtr6 = vm.dataList.prblmMtr6;
vm.file_mng_id = vm.dataList.fileMngId;
if (vm.problemDetail.length > 0) {
vm.prblmDetail.answers = {};
for (let index = 0; index < vm.problemDetail.length; index++) {
const detail = vm.problemDetail[index];
let fileInfo = null;
if (detail.fileMngId) {
fileInfo = await vm.findFile(detail.fileMngId);
}
vm.prblmDetail.answers[index + 1] = {
prblmDtlId: detail.prblmDtlId,
text: detail.prblmDtlExpln,
isCorrect: detail.prblmYn === 'Y' ? 'Y' : 'N',
fileMngId: detail.fileMngId || null,
fileInfo: fileInfo || null,
};
}
vm.prblmDetail.correctIndex = vm.problemDetail.findIndex(detail => detail.prblmYn === 'Y') + 1;
}
if (vm.file_mng_id) {
vm.mainfile = await vm.findFile(vm.file_mng_id);
}
} catch (error) {
console.log("problem - error : ", error);
}
},
// 문제 수정
async submitForm() {
// 필요한 모든 필드를 검사합니다.
if (!this.selectedSearchOption) {
alert("카테고리를 지정해 주세요.");
return;
}
if (!this.selectedSearchOption2.prblm_type_id) {
alert("문제 유형을 지정해 주세요.");
return;
}
if (!this.prblm_scr) {
alert("문제 배점을 입력해 주세요.");
return;
}
if (!this.prblm_expln) {
alert("문제 내용을 입력해 주세요.");
return;
}
const payload = {
prblmId: this.dataList.prblmId,
prblmCtgryId: this.selectedSearchOption, // 카테고리
prblmTypeId: this.selectedSearchOption2.prblm_type_id, // 문제 유형
prblmScr: this.prblm_scr, // 문제 배점
prblmExpln: this.prblm_expln, // 내용
prblmHint: this.prblm_hint, // 힌트
prblmCmmt: this.prblm_cmmt, // 해설
textId: this.text_id, // 지문 아이디
unitId: this.unit_id, // 단원 아이디
bookId: this.book_id, // 교재 아이디
// userId: this.user_id, // 유저 아이디
userId: 'USID_000000000000004', // 유저 아이디
prblmMtr1: this.prblm_mtr1, // 문제 지표
prblmMtr2: this.prblm_mtr2,
prblmMtr3: this.prblm_mtr3,
prblmMtr4: this.prblm_mtr4,
prblmMtr5: this.prblm_mtr5,
prblmMtr6: this.prblm_mtr6,
fileMngId: this.file_mng_id // 첨부파일 ID
};
if (this.file && this.file.length > 0) {
// 파일 업로드를 수행하고, 결과로 얻은 fileMngId를 payload에 추가합니다.
const fileMngId = await this.uploadFiles(this.file);
payload.fileMngId = fileMngId;
}
try {
const response = await axios.post('/problem/updateProblem.json', payload);
console.log('성공:', response.data);
const problemDetails = await this.prepareProblemDetails();
await this.submitDetailForm(problemDetails);
alert('문제가 성공적으로 수정되었습니다.');
this.goToPage('QuestionList');
} catch (error) {
console.error('오류:', error);
// 오류 처리 로직 추가
}
},
// 문제 상세 업데이트
async submitDetailForm(problemDetails) {
try {
const response = await axios.post('/problem/updateProblemDetail.json', problemDetails);
console.log('성공:', response.data);
} catch (error) {
console.error('오류:', error);
// 오류 처리 로직 추가
}
},
// 상세 정보 세팅하기
async prepareProblemDetails() {
const details = [];
const answers = this.prblmDetail.answers;
let answerCount = 0;
if (this.selectedSearchOption2.prblm_type_cls === '5지선다') {
answerCount = 5;
} else if (this.selectedSearchOption2.prblm_type_cls === '4지선다') {
answerCount = 4;
} else if (this.selectedSearchOption2.prblm_type_cls === '3지선다') {
answerCount = 3;
} else if (this.selectedSearchOption2.prblm_type_cls === '2지선다') {
answerCount = 2;
} else {
answerCount = 1;
}
for (let i = 1; i <= answerCount; i++) {
if (this.selectedFiles[i] && this.selectedFiles[i].length > 0) {
const uploadedFileMngId = await this.uploadFiles(this.selectedFiles[i]);
answers[i].fileMngId = uploadedFileMngId; // 파일 매니지 ID 저장
}
details.push({
prblmDtlId: answers[i].prblmDtlId,
prblmDtlExpln: answers[i].text || '',
prblmYn: this.selectedSearchOption2.prblm_type_cls === '서술형' ||
this.selectedSearchOption2.prblm_type_cls === 'OX 문제' ? 'Y' : answers[i].isCorrect, // 서술형 및 OX 문제의 경우 항상 'Y'
fileMngId: answers[i].fileMngId,
});
}
return details;
},
setCorrectAnswer(index, size) {
this.prblmDetail.correctIndex = index;
// 선택된 인덱스의 답만 'Y'로 설정하고, 나머지는 'N'으로 설정
for (let i = 1; i <= size; i++) {
this.prblmDetail.answers[i].isCorrect = i === index ? 'Y' : 'N';
}
},
resetPrblmDetail() {
this.prblmDetail = {
answers: {
1: { text: '', isCorrect: 'Y', fileMngId: null, fileInfo: '' },
2: { text: '', isCorrect: 'N', fileMngId: null, fileInfo: '' },
3: { text: '', isCorrect: 'N', fileMngId: null, fileInfo: '' },
4: { text: '', isCorrect: 'N', fileMngId: null, fileInfo: '' },
5: { text: '', isCorrect: 'N', fileMngId: null, fileInfo: '' },
},
correctIndex: 1,
};
this.selectedFiles = {};
},
// 문제 삭제
deletePost() {
const result = confirm('문제를 삭제 하시겠습니까?')
if (result) {
} else {
alert("삭제를 취소했습니다")
return;
}
axios.post("/problem/deleteProblem.json", { prblmId: this.dataList.prblmId }, {
headers: {
"Content-Type": "application/json; charset=UTF-8",
}
})
.then(response => {
this.goToPage('QuestionList');
})
.catch(error => {
console.error("Error deleting post:", error);
alert("문제 삭제에 오류가 발생했습니다.");
});
},
// 파일 업로드 메서드
async uploadFiles(files) {
if (!files || files.length === 0) {
return null;
}
const formData = new FormData();
for (let i = 0; i < files.length; i++) {
formData.append("files", files[i]);
}
try {
const response = await axios.post("http://165.229.169.113:9080/file/upload.json", formData, {
headers: {
"Content-Type": "multipart/form-data",
},
});
return response.data.fileMngId; // 파일 매니지 ID 반환
} catch (error) {
console.error("파일 업로드 오류:", error);
throw new Error("파일 업로드에 실패했습니다.");
}
},
// 교재 정보 가져오기
fetchBooks() {
axios({
url: "/book/findAll.json",
method: "post",
headers: {
"Content-Type": "application/json; charset=UTF-8",
},
})
.then(response => {
console.log(response.data)
this.books = response.data;
this.text_id = '';
})
.catch(error => {
console.error("fetchBooks - error: ", error);
alert("교재 목록을 불러오는 중 오류가 발생했습니다.");
});
},
// 단원 정보 가져오기
fetchUnits() {
if (!this.book_id) return;
axios({
url: "/unit/unitList.json",
method: "post",
headers: {
"Content-Type": "application/json; charset=UTF-8",
},
data: {
"bookId": this.book_id
},
})
.then(response => {
this.units = response.data;
this.text_id = '';
})
.catch(error => {
console.error("fetchUnits - error: ", error);
alert("단원 목록을 불러오는 중 오류가 발생했습니다.");
});
},
// 지문 정보 가져오기
fetchTexts() {
axios({
url: "/text/textSearch.json",
method: "post",
headers: {
"Content-Type": "application/json; charset=UTF-8",
},
data: {
"unitId": this.unit_id
},
})
.then(response => {
this.texts = response.data.list;
})
.catch(error => {
console.error("fetchTexts - error: ", error);
alert("지문 목록을 불러오는 중 오류가 발생했습니다.");
});
},
// 업로드한 파일 정보 가져오기
async findFile(fileMngId) {
try {
const response = await axios({
url: "/file/find.json",
method: "post",
headers: {
"Content-Type": "application/json; charset=UTF-8",
},
data: {
file_mng_id: fileMngId,
},
});
if (response.data && response.data.list) {
return response.data.list; // 파일 정보를 반환
} else {
console.error("파일 정보를 가져오는 데 실패했습니다: ", response.data);
return [];
}
} catch (error) {
console.log("result - error : ", error);
return [];
}
},
// 문제 유형 정보 가져오기
selectProblemType() {
axios({
url: "/problem/selectType.json",
method: "post",
headers: {
"Content-Type": "application/json; charset=UTF-8",
},
})
.then(response => {
this.problemType = response.data;
})
.catch(error => {
console.error("selectProblemType - error: ", error);
});
},
},
watch: {
selectedSearchOption2(newVal, oldVal) {
if (newVal !== oldVal) {
this.resetPrblmDetail();
}
}
},
computed: {
},
components: {
SvgIcon
},
mounted() {
let prblm = JSON.parse(sessionStorage.getItem("selectQuestionList"));
this.book_id = prblm.bookId;
this.unit_id = prblm.unitId;
this.fetchBooks();
this.fetchUnits();
this.fetchTexts();
this.selectProblemType();
this.problemSearch();
}
}
</script>
<style scoped>
.ui-checkbox {
width: 30px;
height: 30px;
}
</style>