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
<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>