index.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. <template>
  2. <div>
  3. <a class="button is-link" @click="startCreation()"
  4. >新建{{ createTitle }}作业</a
  5. >
  6. <!--新建文档作业模态框-->
  7. <b-modal :active.sync="isCreateModalActive" :width="640" scroll="keep">
  8. <div class="card">
  9. <div class="title">新建{{ createTitle }}作业</div>
  10. <div class="content">
  11. <b-field label="题目名称">
  12. <b-input v-model="problemName"></b-input>
  13. </b-field>
  14. <b-field
  15. label="作业名称"
  16. :type="$v.params.name.$error ? 'is-danger' : ''"
  17. :message="$v.params.name.$error ? '请填写作业名称' : ''"
  18. >
  19. <b-input
  20. placeholder="请填写作业名称"
  21. v-model="$v.params.name.$model"
  22. ></b-input>
  23. </b-field>
  24. <b-field
  25. label="作业描述"
  26. :type="$v.params.description.$error ? 'is-danger' : ''"
  27. :message="$v.params.description.$error ? '请填写作业描述' : ''"
  28. >
  29. <b-input
  30. type="textarea"
  31. placeholder="请填写作业描述"
  32. v-model="$v.params.description.$model"
  33. ></b-input>
  34. </b-field>
  35. <b-field
  36. label="开始时间"
  37. :type="$v.params.startAt.$error ? 'is-danger' : ''"
  38. :message="$v.params.startAt.$error ? '请填写作业开始时间' : ''"
  39. >
  40. <flat-pickr
  41. placeholder="Click to select..."
  42. class="input"
  43. v-model="$v.params.startAt.$model"
  44. :config="startAtConfig"
  45. ></flat-pickr>
  46. </b-field>
  47. <b-field
  48. label="结束时间"
  49. :type="$v.params.endAt.$error ? 'is-danger' : ''"
  50. :message="$v.params.endAt.$error ? '请填写作业结束时间' : ''"
  51. >
  52. <flat-pickr
  53. placeholder="Click to select..."
  54. class="input"
  55. v-model="$v.params.endAt.$model"
  56. :config="endAtConfig"
  57. ></flat-pickr>
  58. </b-field>
  59. <a
  60. class="button is-link"
  61. :class="{ 'is-loading': loadingCreateAssignment }"
  62. @click="createAssignment()"
  63. >
  64. 确认新建
  65. </a>
  66. </div>
  67. </div>
  68. </b-modal>
  69. <!--搜索题目模态框-->
  70. <b-modal :active.sync="isSearchModalActive">
  71. <div class="card">
  72. <div class="title">请先查找题目</div>
  73. <div class="content">
  74. <b-field
  75. :type="$v.searchContent.$error ? 'is-danger' : ''"
  76. :message="$v.params.endAt.$error ? '' : ''"
  77. >
  78. <b-input
  79. placeholder="输入关键字模糊查找"
  80. type="search"
  81. v-model="$v.searchContent.$model"
  82. @keyup.enter.native="search(searchContent)"
  83. expanded
  84. >
  85. </b-input>
  86. <p class="control">
  87. <button
  88. class="button is-link"
  89. :class="{ 'is-loading': loadingSearchQuestions }"
  90. @click="search(searchContent)"
  91. >
  92. 查找
  93. </button>
  94. </p>
  95. </b-field>
  96. </div>
  97. </div>
  98. </b-modal>
  99. <!--题目列表展示框-->
  100. <b-modal :active.sync="isProblemListModalActive">
  101. <b-notification type="is-danger" :active.sync="isServerError">
  102. {{ errorMassage }}
  103. </b-notification>
  104. <div class="card">
  105. <div class="title">选择题目</div>
  106. <div class="content">
  107. <div class="question-list">
  108. <b-table :data="questions" detailed detail-key="id">
  109. <template slot-scope="props">
  110. <b-table-column
  111. field="id"
  112. label="ID"
  113. width="40"
  114. numeric
  115. sortable
  116. >
  117. {{ props.row.id }}
  118. </b-table-column>
  119. <b-table-column label="题目名称">
  120. <a @click="selectAndCreate(props.row)">{{
  121. props.row.name
  122. }}</a>
  123. </b-table-column>
  124. <b-table-column label="题目描述" width="100">
  125. <div class="description">{{ props.row.description }}</div>
  126. </b-table-column>
  127. <b-table-column
  128. field="difficulty"
  129. label="题目难度"
  130. sortable
  131. centered
  132. >
  133. <span
  134. :class="[
  135. 'tag',
  136. `${getDifficultyClass(props.row.difficulty)}`
  137. ]"
  138. >
  139. {{ getDifficultyType(props.row.difficulty) }}
  140. </span>
  141. </b-table-column>
  142. <b-table-column
  143. label="平均时长"
  144. field="expectTime"
  145. sortable
  146. centered
  147. >
  148. {{ props.row.expectTime }}分钟
  149. </b-table-column>
  150. </template>
  151. <template slot="detail" slot-scope="props">
  152. <div>{{ props.row.description }}</div>
  153. </template>
  154. </b-table>
  155. </div>
  156. </div>
  157. </div>
  158. </b-modal>
  159. </div>
  160. </template>
  161. <script>
  162. import { getTeacherKeywordQuestions } from "@/api/question";
  163. import { postDocAssignment } from "@/api/assignment";
  164. import { postCodeAssignment } from "@/api/assignment";
  165. import timeMixins from "@/mixins/time";
  166. import { required } from "vuelidate/lib/validators";
  167. import pathMixins from "@/mixins/path";
  168. import { difficultyType } from "@/data/questionDifficulty";
  169. import { difficultyClass } from "@/data/questionDifficulty";
  170. export default {
  171. props: {
  172. courseId: {
  173. type: String
  174. },
  175. assignType: {
  176. type: Number
  177. }
  178. },
  179. mounted() {
  180. if (this.assignType === 1) {
  181. this.createTitle = "文档";
  182. this.postParam = "DOCUMENT";
  183. } else {
  184. this.createTitle = "代码";
  185. this.postParam = "CODE";
  186. }
  187. },
  188. data() {
  189. return {
  190. params: {
  191. name: null,
  192. description: null,
  193. startAt: null,
  194. endAt: null,
  195. problem: null //题目编号
  196. },
  197. createTitle: "",
  198. postParam: "",
  199. myPromise: null,
  200. problemName: "",
  201. searchContent: "",
  202. questions: [],
  203. isCreateModalActive: false,
  204. isSearchModalActive: false,
  205. isProblemListModalActive: false,
  206. startAtConfig: {
  207. ...this.getDefaultConfig(),
  208. minDate: "today",
  209. maxDate: null
  210. },
  211. endAtConfig: {
  212. ...this.getDefaultConfig(),
  213. minDate: "today",
  214. maxDate: null
  215. },
  216. errorMassage: null,
  217. isServerError: false,
  218. submitting: false,
  219. // 转圈圈
  220. loadingSearchQuestions: false,
  221. loadingCreateAssignment: false
  222. };
  223. },
  224. methods: {
  225. /**
  226. * 准备新建
  227. */
  228. startCreation() {
  229. if (this.submitting) return;
  230. this.isSearchModalActive = true;
  231. },
  232. /**
  233. * 搜索题目
  234. */
  235. search(content) {
  236. if (this.submitting) return;
  237. this.isServerError = false;
  238. this.$v.searchContent.$touch();
  239. if (!this.$v.searchContent.$invalid) {
  240. this.loadingSearchQuestions = true;
  241. this.submitting = true;
  242. try {
  243. getTeacherKeywordQuestions(content).then(res => {
  244. this.questions = res.data;
  245. this.isSearchModalActive = false;
  246. this.loadingSearchQuestions = false;
  247. this.isProblemListModalActive = true;
  248. });
  249. } catch (e) {
  250. this.errorMassage = e.message;
  251. this.isServerError = true;
  252. } finally {
  253. this.submitting = false;
  254. }
  255. }
  256. },
  257. selectAndCreate(problem) {
  258. this.params.problem = problem.id;
  259. this.problemName = problem.name;
  260. this.isProblemListModalActive = false;
  261. this.isCreateModalActive = true;
  262. },
  263. /**
  264. * 确认新建
  265. */
  266. createAssignment() {
  267. if (this.submitting) return;
  268. this.$v.params.$touch();
  269. if (!this.$v.params.$invalid) {
  270. this.loadingCreateAssignment = true;
  271. this.submitting = true;
  272. this.params["type"] = this.postParam;
  273. this.parseParams();
  274. if (this.assignType === 1) {
  275. // 文档作业
  276. this.myPromise = postDocAssignment(
  277. this.params,
  278. parseInt(this.courseId)
  279. );
  280. } else {
  281. // 代码作业
  282. this.myPromise = postCodeAssignment(
  283. this.params,
  284. parseInt(this.courseId)
  285. );
  286. }
  287. this.myPromise.then(res => {
  288. //创建成功
  289. this.isCreateModalActive = false;
  290. if (res.code === 0) {
  291. if (this.assignType === 1) {
  292. this.$router.push({
  293. path: `${this.prefix}/review?documentHwId=${res.data.id}`
  294. });
  295. }
  296. this.$emit("sendCreatedAssignment", res.data);
  297. this.loadingCreateAssignment = false;
  298. } else {
  299. //创建失败
  300. this.isCreateModalActive = false;
  301. this.loadingCreateAssignment = false;
  302. this.$dialog.alert({
  303. title: "创建失败",
  304. message: res.message,
  305. type: "is-danger",
  306. hasIcon: true
  307. });
  308. }
  309. });
  310. this.submitting = false;
  311. }
  312. },
  313. getDifficultyType(level) {
  314. return difficultyType(level);
  315. },
  316. getDifficultyClass(level) {
  317. return difficultyClass(level);
  318. },
  319. parseParams() {
  320. this.params.startAt = parseInt(this.params.startAt);
  321. this.params.endAt = parseInt(this.params.endAt);
  322. }
  323. },
  324. mixins: [timeMixins, pathMixins],
  325. validations: {
  326. params: {
  327. name: {
  328. required
  329. },
  330. description: {
  331. required
  332. },
  333. startAt: {
  334. required
  335. },
  336. endAt: {
  337. required
  338. }
  339. },
  340. searchContent: {
  341. required
  342. }
  343. },
  344. watch: {
  345. isCreateModalActive(newValue) {
  346. if (newValue === false) {
  347. this.$v.params.$reset();
  348. }
  349. },
  350. isSearchModalActive(newValue) {
  351. if (newValue === false) {
  352. this.$v.searchContent.$reset();
  353. }
  354. }
  355. }
  356. };
  357. </script>
  358. <style lang="scss" scoped>
  359. .card {
  360. text-align: left;
  361. padding: 30px;
  362. .title {
  363. font-size: 1.25rem;
  364. small {
  365. color: gray;
  366. font-size: 1rem;
  367. }
  368. }
  369. .content {
  370. a {
  371. margin-top: 30px;
  372. width: 100%;
  373. }
  374. }
  375. }
  376. .description {
  377. overflow: hidden;
  378. text-overflow: ellipsis;
  379. -webkit-box-orient: vertical;
  380. -webkit-line-clamp: 1;
  381. word-wrap: break-word;
  382. word-break: break-all;
  383. display: -webkit-box;
  384. }
  385. </style>