BuildPaperAuto.vue 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. <template>
  2. <div class="build-paper-auto">
  3. <div class="build-step-title">
  4. <h3><span>试卷结构设置</span></h3>
  5. <div>
  6. <el-button
  7. type="primary"
  8. size="small"
  9. icon="el-icon-circle-plus-outline"
  10. @click="addDetail"
  11. >新增大题</el-button
  12. >
  13. </div>
  14. </div>
  15. <el-collapse v-model="activeNames" accordion>
  16. <el-collapse-item
  17. v-for="(detail, index) in details"
  18. :key="detail.id"
  19. :name="detail.id"
  20. >
  21. <div slot="title" class="detail-header">
  22. <h3>{{ index + 1 }}、{{ detail.detailName }}</h3>
  23. <div>
  24. <el-button
  25. size="mini"
  26. type="text"
  27. icon="el-icon-edit"
  28. title="编辑"
  29. @click.stop="editDetail(detail)"
  30. ></el-button>
  31. <el-button
  32. class="btn-danger"
  33. size="mini"
  34. type="text"
  35. icon="el-icon-delete"
  36. title="删除"
  37. @click.stop="removeDetail(index)"
  38. ></el-button>
  39. </div>
  40. </div>
  41. <div v-if="!isAnEmptyRichText(detail.description)" class="detail-desc">
  42. <rich-text :text-json="detail.description"></rich-text>
  43. </div>
  44. <div class="detail-info">
  45. <div>
  46. <p>
  47. <span>题型:</span>
  48. <span>{{ detail.sourceDetailName }}</span>
  49. </p>
  50. <p v-if="detail.selective">
  51. <span>选做题:</span>
  52. <span
  53. :class="{
  54. 'color-danger': detail.questionCount < detail.selectiveCount,
  55. }"
  56. >{{ detail.questionCount }}选{{ detail.selectiveCount }},{{
  57. detail.selectiveRule | selectiveRuleTypeFilter
  58. }}</span
  59. >
  60. </p>
  61. </div>
  62. <div>
  63. <p>
  64. <span>小题数:</span>
  65. <span>{{ detail.questionCount }}</span>
  66. </p>
  67. <p>
  68. <span>总分:</span>
  69. <span>{{ detail.questionCount * detail.score }}</span>
  70. </p>
  71. </div>
  72. </div>
  73. <question-group-struct
  74. :ref="`QuestionStruct${detail.id}`"
  75. :filter-data="{
  76. courseId,
  77. sourceDetailId: detail.sourceDetailId,
  78. }"
  79. :data-source="detail"
  80. @count-change="(val) => structCountChange(val, detail)"
  81. ></question-group-struct>
  82. </el-collapse-item>
  83. </el-collapse>
  84. <!-- ModifyDetailStruct -->
  85. <modify-detail-struct
  86. ref="ModifyDetailStruct"
  87. :detail="curDetail"
  88. @modified="detailModified"
  89. ></modify-detail-struct>
  90. </div>
  91. </template>
  92. <script>
  93. import ModifyDetailStruct from "./ModifyDetailStruct.vue";
  94. import QuestionGroupStruct from "./QuestionGroupStruct.vue";
  95. import { isAnEmptyRichText } from "@/utils/utils";
  96. import { deepCopy } from "@/plugins/utils";
  97. import { omit } from "lodash";
  98. export default {
  99. name: "BuildPaperAuto",
  100. components: {
  101. ModifyDetailStruct,
  102. QuestionGroupStruct,
  103. },
  104. props: {
  105. courseId: {
  106. type: [String, Number],
  107. default: "",
  108. },
  109. detailSource: {
  110. type: Array,
  111. default() {
  112. return [];
  113. },
  114. },
  115. },
  116. data() {
  117. return {
  118. details: [],
  119. curDetail: {},
  120. activeNames: [],
  121. };
  122. },
  123. mounted() {
  124. if (this.detailSource) {
  125. this.details = deepCopy(this.detailSource);
  126. }
  127. },
  128. methods: {
  129. isAnEmptyRichText,
  130. setDetails(details) {
  131. this.details = [];
  132. this.activeNames = [];
  133. this.curDetail = {};
  134. this.$nextTick(() => {
  135. this.details = deepCopy(details);
  136. });
  137. },
  138. addDetail() {
  139. this.curDetail = { courseId: this.courseId };
  140. this.$refs.ModifyDetailStruct.open();
  141. },
  142. editDetail(curDetail) {
  143. this.curDetail = {
  144. ...curDetail,
  145. scorePerQuestion: curDetail.score,
  146. courseId: this.courseId,
  147. };
  148. this.$refs.ModifyDetailStruct.open();
  149. },
  150. async removeDetail(index) {
  151. const confirm = await this.$confirm(`确定要删除当前大题吗?`, "提示", {
  152. type: "warning",
  153. }).catch(() => {});
  154. if (confirm !== "confirm") return;
  155. this.details.splice(index, 1);
  156. },
  157. detailModified(data) {
  158. const index = this.details.findIndex((item) => item.id === data.id);
  159. if (index === -1) {
  160. this.details.push({
  161. ...data,
  162. questionCount: 0,
  163. score: data.scorePerQuestion,
  164. });
  165. if (!this.activeNames.includes(data.id)) this.activeNames.push(data.id);
  166. } else {
  167. this.$set(
  168. this.details,
  169. index,
  170. Object.assign({}, this.details[index], {
  171. ...data,
  172. score: data.scorePerQuestion,
  173. })
  174. );
  175. }
  176. },
  177. structCountChange(val, detail) {
  178. const index = this.details.findIndex((item) => item.id === detail.id);
  179. if (index === -1) return;
  180. this.details[index].questionCount = val;
  181. },
  182. getData() {
  183. let detailInfo = this.details.map((item) => {
  184. const structData =
  185. this.$refs[`QuestionStruct${item.id}`][0].getDataList();
  186. return {
  187. ...omit(item, ["id"]),
  188. ...structData,
  189. };
  190. });
  191. return { detailInfo };
  192. },
  193. validate() {
  194. if (!this.details.length) {
  195. this.$message.error("请设置大题!");
  196. return Promise.reject();
  197. }
  198. let hasNoQuestionDetail = this.details.some(
  199. (detail) => !detail.questionCount
  200. );
  201. if (hasNoQuestionDetail) {
  202. this.$message.error("有大题未设置小题!");
  203. return Promise.reject();
  204. }
  205. let selectiveUnvalid = this.details.some(
  206. (detail) =>
  207. detail.selective && detail.questionCount < detail.selectiveCount
  208. );
  209. if (selectiveUnvalid) {
  210. this.$message.error("有大题设置的小题数小于选做题数!");
  211. return Promise.reject();
  212. }
  213. const { detailInfo } = this.getData();
  214. let hasNoClassifyDetail = detailInfo.some(
  215. (detail) => detail.useClassify && !detail.classifyIdList.length
  216. );
  217. if (hasNoClassifyDetail) {
  218. this.$message.error("有大题指定了文件夹,却未选择文件夹!");
  219. return Promise.reject();
  220. }
  221. return Promise.resolve(true);
  222. },
  223. },
  224. };
  225. </script>