question-form.vue 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. <template>
  2. <el-form
  3. ref="form"
  4. :model="innerValue"
  5. :rules="rules"
  6. label-width="100px"
  7. class="question-form"
  8. :disabled="isView"
  9. >
  10. <el-form-item label="序号:" prop="sort">
  11. <el-input v-model="innerValue.sort" placeholder="请输入序号" />
  12. </el-form-item>
  13. <el-form-item label="试题内容:" prop="content">
  14. <el-input
  15. v-model="innerValue.content"
  16. type="textarea"
  17. :rows="4"
  18. placeholder="请输入内容(500字以内)"
  19. />
  20. </el-form-item>
  21. <el-form-item label="试题类型:" prop="type">
  22. <el-select
  23. v-model="innerValue.type"
  24. placeholder="请选择试题类型"
  25. style="width: 160px"
  26. @change="handleTypeChange"
  27. >
  28. <el-option
  29. v-for="item in typeOptions"
  30. :key="item.value"
  31. :label="item.label"
  32. :value="item.value"
  33. />
  34. </el-select>
  35. <el-button
  36. type="primary"
  37. size="small"
  38. plain
  39. style="margin-left: 10px"
  40. @click="handleUploadImage"
  41. >上传图片</el-button
  42. >
  43. <span class="upload-tip">试题图片上传</span>
  44. </el-form-item>
  45. <el-form-item label="专业类别:" prop="category">
  46. <el-select
  47. v-model="innerValue.category"
  48. placeholder="请选择专业类别"
  49. style="width: 160px"
  50. >
  51. <el-option
  52. v-for="item in categoryOptions"
  53. :key="item.value"
  54. :label="item.label"
  55. :value="item.value"
  56. />
  57. </el-select>
  58. </el-form-item>
  59. <el-form-item label="试题分数:" prop="score">
  60. <el-input v-model="innerValue.score" placeholder="请输入试题分数" />
  61. </el-form-item>
  62. <!-- 选项 -->
  63. <el-form-item
  64. v-if="
  65. innerValue.type === '1' ||
  66. innerValue.type === '2' ||
  67. innerValue.type === '3'
  68. "
  69. label="选项:"
  70. prop="options"
  71. >
  72. <div class="option-list">
  73. <div
  74. v-for="(item, index) in innerValue.options"
  75. :key="index"
  76. class="option-item"
  77. >
  78. <el-radio
  79. v-if="innerValue.type === '1' || innerValue.type === '3'"
  80. v-model="innerValue.rightAnswer"
  81. :label="item.key"
  82. class="option-radio"
  83. />
  84. <el-checkbox
  85. v-else
  86. v-model="innerValue.rightAnswers"
  87. :label="item.key"
  88. class="option-checkbox"
  89. />
  90. <!-- <span class="option-key">{{ item.key }}</span> -->
  91. <el-input
  92. v-model="item.content"
  93. placeholder="请输入选项(100字以内)"
  94. class="option-input"
  95. />
  96. <el-button
  97. type="text"
  98. size="small"
  99. @click="handleUploadOptionImage(index)"
  100. >上传图片</el-button
  101. >
  102. <el-button
  103. v-if="innerValue.type !== '3' && innerValue.options.length > 2"
  104. type="text"
  105. class="danger-text"
  106. size="small"
  107. @click="handleDeleteOption(index)"
  108. >删除选项</el-button
  109. >
  110. </div>
  111. <el-button
  112. v-if="innerValue.type !== '3'"
  113. type="text"
  114. size="small"
  115. @click="handleAddOption"
  116. >+ 添加选项</el-button
  117. >
  118. </div>
  119. </el-form-item>
  120. <el-form-item label="题目详解:" prop="analysis">
  121. <el-input
  122. v-model="innerValue.analysis"
  123. type="textarea"
  124. :rows="4"
  125. placeholder="请输入内容(500字以内)"
  126. />
  127. </el-form-item>
  128. </el-form>
  129. </template>
  130. <script>
  131. const typeOptions = [
  132. { label: '单选题', value: '1' },
  133. { label: '多选题', value: '2' },
  134. { label: '判断题', value: '3' },
  135. { label: '问答题', value: '4' }
  136. ];
  137. const categoryOptions = [
  138. { label: '计算机类', value: '1' },
  139. { label: '安全生产', value: '2' },
  140. { label: '职业健康', value: '3' },
  141. { label: '环境保护', value: '4' }
  142. ];
  143. export default {
  144. props: {
  145. value: {
  146. type: Object,
  147. default: () => ({})
  148. },
  149. isView: {
  150. type: Boolean,
  151. default: false
  152. }
  153. },
  154. data() {
  155. return {
  156. typeOptions,
  157. categoryOptions,
  158. rules: {
  159. content: [
  160. { required: true, message: '请输入试题内容', trigger: 'blur' }
  161. ],
  162. type: [
  163. { required: true, message: '请选择试题类型', trigger: 'change' }
  164. ],
  165. category: [
  166. { required: true, message: '请选择专业类别', trigger: 'change' }
  167. ],
  168. score: [
  169. { required: true, message: '请输入试题分数', trigger: 'blur' }
  170. ],
  171. options: [
  172. {
  173. validator: (rule, value, callback) => {
  174. if (this.innerValue.type === '2') {
  175. if (!this.innerValue.rightAnswers.length) {
  176. callback(new Error('请选择正确答案'));
  177. return;
  178. }
  179. } else if (
  180. this.innerValue.type === '1' ||
  181. this.innerValue.type === '3'
  182. ) {
  183. if (!this.innerValue.rightAnswer) {
  184. callback(new Error('请选择正确答案'));
  185. return;
  186. }
  187. }
  188. callback();
  189. },
  190. trigger: 'change'
  191. }
  192. ]
  193. }
  194. };
  195. },
  196. computed: {
  197. innerValue: {
  198. get() {
  199. return this.value || {};
  200. },
  201. set(val) {
  202. this.$emit('input', val);
  203. }
  204. }
  205. },
  206. methods: {
  207. handleTypeChange(val) {
  208. if (val === '1' || val === '2') {
  209. this.innerValue.options = [
  210. { key: 'A', content: '' },
  211. { key: 'B', content: '' },
  212. { key: 'C', content: '' },
  213. { key: 'D', content: '' }
  214. ];
  215. this.innerValue.rightAnswer = '';
  216. this.innerValue.rightAnswers = [];
  217. } else if (val === '3') {
  218. this.innerValue.options = [
  219. { key: 'A', content: '正确' },
  220. { key: 'B', content: '错误' }
  221. ];
  222. this.innerValue.rightAnswer = '';
  223. this.innerValue.rightAnswers = [];
  224. } else if (val === '4') {
  225. this.innerValue.options = [];
  226. this.innerValue.rightAnswer = '';
  227. this.innerValue.rightAnswers = [];
  228. }
  229. },
  230. handleUploadImage() {
  231. // TODO: 试题图片上传
  232. this.$message.info('试题图片上传待接入');
  233. },
  234. handleUploadOptionImage(index) {
  235. // TODO: 选项图片上传
  236. this.$message.info('选项图片上传待接入:' + index);
  237. },
  238. handleAddOption() {
  239. if (this.innerValue.type === '3') {
  240. this.$message.warning('判断题不能添加选项');
  241. return;
  242. }
  243. const nextKey = String.fromCharCode(
  244. 65 + this.innerValue.options.length
  245. );
  246. this.innerValue.options.push({ key: nextKey, content: '' });
  247. },
  248. handleDeleteOption(index) {
  249. if (this.innerValue.type === '3') {
  250. this.$message.warning('判断题不能删除选项');
  251. return;
  252. }
  253. if (this.innerValue.options.length <= 2) {
  254. this.$message.warning('至少保留两个选项');
  255. return;
  256. }
  257. this.innerValue.options.splice(index, 1);
  258. this.innerValue.options.forEach((item, idx) => {
  259. item.key = String.fromCharCode(65 + idx);
  260. });
  261. if (this.innerValue.type === '1') {
  262. this.innerValue.rightAnswer = '';
  263. } else {
  264. this.innerValue.rightAnswers = [];
  265. }
  266. },
  267. validate(callback) {
  268. this.$refs.form.validate(callback);
  269. },
  270. clearValidate() {
  271. this.$refs.form && this.$refs.form.clearValidate();
  272. }
  273. }
  274. };
  275. </script>
  276. <style lang="scss" scoped>
  277. .question-form {
  278. padding-top: 10px;
  279. }
  280. .upload-tip {
  281. color: #909399;
  282. font-size: 12px;
  283. margin-left: 10px;
  284. }
  285. .option-list {
  286. .option-item {
  287. display: flex;
  288. align-items: center;
  289. margin-bottom: 10px;
  290. .option-radio,
  291. .option-checkbox {
  292. margin-right: 4px;
  293. }
  294. .option-key {
  295. margin-right: 8px;
  296. font-weight: bold;
  297. min-width: 20px;
  298. }
  299. .option-input {
  300. width: 260px;
  301. margin-right: 10px;
  302. }
  303. }
  304. }
  305. .danger-text {
  306. color: #f56c6c;
  307. }
  308. </style>