Course.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  1. <template>
  2. <section element-loading-text="请稍后..." class="content">
  3. <div class="part-box">
  4. <el-form
  5. ref="primaryForm"
  6. class="part-filter-form"
  7. inline
  8. :model="formSearch"
  9. >
  10. <el-form-item label="课程名称">
  11. <el-input v-model="formSearch.name" placeholder="请输入课程名称" />
  12. </el-form-item>
  13. <el-form-item label="课程代码">
  14. <el-input v-model="formSearch.code" placeholder="请输入课程代码" />
  15. </el-form-item>
  16. <el-form-item label="层次">
  17. <el-select v-model="formSearch.level" placeholder="请选择" clearable>
  18. <el-option
  19. v-for="item in levelList"
  20. :key="item.value"
  21. :label="item.label"
  22. :value="item.value"
  23. />
  24. </el-select>
  25. </el-form-item>
  26. <el-form-item>
  27. <el-button type="primary" @click="handleSearchBtn">查询</el-button>
  28. <el-button type="danger" plain @click="resetPrimaryForm">
  29. 重置
  30. </el-button>
  31. </el-form-item>
  32. </el-form>
  33. <!-- <div class="part-box-action">
  34. <div>
  35. <el-button
  36. type="danger"
  37. plain
  38. :disabled="noBatchSelected"
  39. icon="icon icon-play"
  40. @click="deleteByIds"
  41. >删除
  42. </el-button>
  43. <el-button
  44. type="primary"
  45. plain
  46. icon="icon icon-import"
  47. @click="importCourse"
  48. >导入</el-button
  49. >
  50. <el-button
  51. type="primary"
  52. plain
  53. icon="icon icon-export"
  54. :loading="downloading"
  55. @click="exportCourse"
  56. >导出</el-button
  57. >
  58. </div>
  59. <el-button
  60. v-if="authButtons.includes('index_course-add_course')"
  61. type="primary"
  62. icon="icon icon-plus-white"
  63. @click="insertCourse"
  64. >新增</el-button
  65. >
  66. </div> -->
  67. </div>
  68. <div class="part-box">
  69. <div class="icon-btn-group">
  70. <svg-btn
  71. name="xinzeng"
  72. v-if="authButtons.includes('index_course-add_course')"
  73. @click="insertCourse"
  74. >新增</svg-btn
  75. >
  76. <svg-btn name="daoru" @click="importCourse">导入</svg-btn>
  77. <svg-btn name="daochu" @click="exportCourse">导出</svg-btn>
  78. <svg-btn name="shanchu" :disabled="noBatchSelected" @click="deleteByIds"
  79. >删除</svg-btn
  80. >
  81. </div>
  82. <!-- 页面列表 -->
  83. <!-- FIXME: element-ui style bug https://github.com/ElemeFE/element/issues/16167 -->
  84. <el-table :data="tableData" resizable @selection-change="selectChange">
  85. <el-table-column type="selection" width="50" align="center" />
  86. <el-table-column prop="id" label="课程ID" width="80" />
  87. <el-table-column prop="name" label="课程名称" width="180" />
  88. <el-table-column prop="code" label="课程代码" />
  89. <el-table-column label="层次">
  90. <span slot-scope="scope">{{ getLevel(scope.row.level) }}</span>
  91. </el-table-column>
  92. <el-table-column
  93. sortable
  94. prop="updateTime"
  95. label="更新时间"
  96. width="170"
  97. />
  98. <el-table-column label="操作" width="220">
  99. <div slot-scope="scope">
  100. <!-- <el-button
  101. size="mini"
  102. type="primary"
  103. plain
  104. icon="el-icon-share"
  105. @click="relation(scope.row)"
  106. >
  107. 关联专业
  108. </el-button> -->
  109. <el-button
  110. size="medium"
  111. type="text"
  112. class="normal"
  113. @click="editCourse(scope.row)"
  114. >
  115. 编辑
  116. </el-button>
  117. <el-button
  118. size="medium"
  119. type="text"
  120. class="normal"
  121. @click="toKnowledge(scope.row)"
  122. >
  123. 知识点
  124. </el-button>
  125. <el-button
  126. size="medium"
  127. type="text"
  128. class="normal"
  129. @click="deleteById(scope.row)"
  130. >
  131. 删除
  132. </el-button>
  133. </div>
  134. </el-table-column>
  135. </el-table>
  136. <div class="part-page">
  137. <el-pagination
  138. :current-page="currentPage"
  139. :page-size="10"
  140. :page-sizes="[10, 20, 50, 100, 200, 300]"
  141. layout="total, sizes, prev, pager, next, jumper"
  142. :total="total"
  143. @current-change="handleCurrentChange"
  144. @size-change="handleSizeChange"
  145. >
  146. </el-pagination>
  147. </div>
  148. </div>
  149. <!-- 添加或新增课程弹出框 -->
  150. <el-dialog
  151. title="课程"
  152. width="450px"
  153. :visible.sync="courseDialog"
  154. :modal="true"
  155. append-to-body
  156. custom-class="side-dialog"
  157. @close="dialogBeforeClose"
  158. >
  159. <el-form
  160. ref="courseForm"
  161. class="form-tight"
  162. :model="courseForm"
  163. :rules="rules"
  164. label-width="90px"
  165. >
  166. <el-form-item label="课程名称" prop="name">
  167. <el-input
  168. v-model="courseForm.name"
  169. auto-complete="off"
  170. placeholder="请输入课程名称"
  171. />
  172. </el-form-item>
  173. <br />
  174. <el-form-item label="课程代码" prop="code">
  175. <el-input
  176. v-model="courseForm.code"
  177. auto-complete="off"
  178. placeholder="请输入课程代码"
  179. />
  180. </el-form-item>
  181. <br />
  182. <el-form-item label="层次" prop="level">
  183. <el-select v-model="courseForm.level" placeholder="请选择">
  184. <el-option
  185. v-for="item in levelList"
  186. :key="item.value"
  187. :label="item.label"
  188. :value="item.value"
  189. />
  190. </el-select>
  191. </el-form-item>
  192. </el-form>
  193. <div slot="footer">
  194. <el-button type="primary" @click="submitForm">保存</el-button>
  195. <el-button type="danger" plain @click="courseDialog = false"
  196. >取消</el-button
  197. >
  198. </div>
  199. </el-dialog>
  200. <!-- 导入弹窗 -->
  201. <import-file-dialog
  202. ref="ImportCourseDialog"
  203. dialog-title="导入课程"
  204. :template-url="courseTemplateUrl"
  205. :upload-url="uploadCourseUrl"
  206. @uploaded="uploadSuccess"
  207. ></import-file-dialog>
  208. <!-- 导入错误信息列表 -->
  209. <el-dialog title="错误提示" :visible.sync="errDialog" append-to-body>
  210. <div
  211. v-for="errMessage in errMessages"
  212. :key="errMessage.lineNum"
  213. class="text-danger"
  214. >
  215. 第{{ errMessage.lineNum }}行:{{ errMessage.msg }}
  216. </div>
  217. <span slot="footer" class="dialog-footer">
  218. <el-button @click="errDialog = false">确定</el-button>
  219. </span>
  220. </el-dialog>
  221. </section>
  222. </template>
  223. <script>
  224. import { QUESTION_API } from "@/constants/constants.js";
  225. import { ENABLE_TYPE, LEVEL_TYPE } from "../constants/constants.js";
  226. import { mapState, mapGetters } from "vuex";
  227. import { courseExportApi } from "../api";
  228. import { downloadByApi } from "@/plugins/download";
  229. import ImportFileDialog from "@/components/ImportFileDialog.vue";
  230. import SvgBtn from "@/components/SvgBtn.vue";
  231. export default {
  232. name: "Course",
  233. components: { ImportFileDialog, SvgBtn },
  234. data() {
  235. return {
  236. formSearch: {
  237. name: "",
  238. code: "",
  239. enable: "true",
  240. level: "",
  241. },
  242. courseForm: {
  243. id: null,
  244. name: "",
  245. code: "",
  246. level: "ALL",
  247. enable: "true",
  248. },
  249. statusList: ENABLE_TYPE,
  250. levelList: LEVEL_TYPE,
  251. selectedCourseIds: [],
  252. tableData: [],
  253. currentPage: 1,
  254. pageSize: 10,
  255. total: 10,
  256. uploadCourseUrl: `${QUESTION_API}/course/import`,
  257. courseTemplateUrl: `${QUESTION_API}/course/importTemplate`,
  258. uploadHeaders: {},
  259. errMessages: [],
  260. errDialog: false,
  261. courseDialog: false,
  262. relationDialog: false,
  263. downloading: false,
  264. rules: {
  265. name: [
  266. {
  267. required: true,
  268. message: "请输入课程名称",
  269. trigger: "blur",
  270. },
  271. {
  272. max: 30,
  273. message: "课程名称最多30个字符",
  274. trigger: "blur",
  275. },
  276. ],
  277. code: [
  278. {
  279. required: true,
  280. message: "请输入课程代码",
  281. trigger: "blur",
  282. },
  283. {
  284. max: 30,
  285. message: "课程代码最多30个字符",
  286. trigger: "blur",
  287. },
  288. {
  289. pattern: new RegExp(`^[a-zA-Z0-9-_\\s\\[\\]\\(\\)\\{\\}]{1,30}$`),
  290. message: "只能包含字母、数字、括号、空格、下划线和短横线",
  291. trigger: "blur",
  292. },
  293. ],
  294. level: [
  295. {
  296. required: true,
  297. message: "请选择层次",
  298. trigger: "change",
  299. },
  300. ],
  301. status: [
  302. {
  303. required: true,
  304. message: "请选择状态",
  305. trigger: "change",
  306. },
  307. ],
  308. },
  309. };
  310. },
  311. computed: {
  312. ...mapState({
  313. user: (state) => state.user,
  314. }),
  315. ...mapGetters(["authButtons"]),
  316. noBatchSelected() {
  317. return this.selectedCourseIds.length === 0;
  318. },
  319. courseIds() {
  320. var courseIds = "";
  321. for (let courseId of this.selectedCourseIds) {
  322. if (!courseIds) {
  323. courseIds += courseId;
  324. } else {
  325. courseIds += "," + courseId;
  326. }
  327. }
  328. return courseIds;
  329. },
  330. },
  331. //初始化查询
  332. created() {
  333. this.searchForm();
  334. this.uploadHeaders = {
  335. key: this.user.key,
  336. token: this.user.token,
  337. };
  338. },
  339. methods: {
  340. handleSizeChange(val) {
  341. this.pageSize = val;
  342. this.currentPage = 1;
  343. this.searchForm();
  344. },
  345. dialogBeforeClose() {
  346. this.$refs.courseForm.clearValidate();
  347. },
  348. submitAddRelationForm() {
  349. this.$refs.addRelationForm.validate((valid) => {
  350. if (valid) {
  351. var param = new URLSearchParams(this.addRelationForm);
  352. var url = QUESTION_API + "/courseSpeciatlyRelation/add?" + param;
  353. this.$httpWithMsg.post(url, this.speciallyForm).then(() => {
  354. this.$notify({
  355. type: "success",
  356. message: "添加成功!",
  357. });
  358. this.addRelationDialog = false;
  359. });
  360. } else {
  361. console.log("error submit!");
  362. return false;
  363. }
  364. });
  365. },
  366. getTag(status) {
  367. if (status == true) {
  368. return "success";
  369. } else if (status == false) {
  370. return "danger";
  371. }
  372. return status;
  373. },
  374. getLevel(level) {
  375. if (level == "ZSB") {
  376. return "专升本";
  377. } else if (level == "GQZ") {
  378. return "高起专";
  379. } else if (level == "GQB") {
  380. return "高起本";
  381. } else {
  382. return "不限";
  383. }
  384. },
  385. handleSearchBtn() {
  386. this.currentPage = 1;
  387. this.searchForm();
  388. },
  389. searchForm() {
  390. let searchLock = true;
  391. setTimeout(() => {
  392. if (searchLock) {
  393. this.loading = true;
  394. }
  395. }, 500);
  396. var param = new URLSearchParams(this.formSearch);
  397. var url =
  398. QUESTION_API +
  399. "/course/coursePage/" +
  400. this.currentPage +
  401. "/" +
  402. this.pageSize +
  403. "?" +
  404. param;
  405. this.$httpWithMsg
  406. .get(url)
  407. .then((response) => {
  408. this.tableData = response.data.content;
  409. this.total = response.data.totalElements;
  410. })
  411. .finally(() => {
  412. searchLock = false;
  413. this.loading = false;
  414. });
  415. },
  416. handleCurrentChange(val) {
  417. this.currentPage = val;
  418. this.searchForm();
  419. },
  420. selectChange(row) {
  421. this.selectedCourseIds = [];
  422. row.forEach((element) => {
  423. this.selectedCourseIds.push(element.id);
  424. });
  425. console.log(this.selectedCourseIds);
  426. },
  427. //新增
  428. insertCourse() {
  429. this.courseForm.id = null;
  430. this.courseForm.name = null;
  431. this.courseForm.code = null;
  432. this.courseForm.level = "ALL";
  433. this.courseForm.enable = "true";
  434. this.courseDialog = true;
  435. },
  436. //修改
  437. editCourse(row) {
  438. this.courseForm = Object.assign({}, row);
  439. this.courseForm.enable = row.enable ? "true" : "false";
  440. this.courseId = row.id;
  441. this.courseDialog = true;
  442. },
  443. async exportCourse() {
  444. if (this.downloading) return;
  445. this.downloading = true;
  446. const res = await downloadByApi(() => {
  447. return courseExportApi(this.formSearch);
  448. }).catch((e) => {
  449. this.$message.error(e || "下载失败,请重新尝试!");
  450. });
  451. this.downloading = false;
  452. if (!res) return;
  453. this.$message.success("下载成功!");
  454. },
  455. closeCourse() {
  456. this.courseDialog = false;
  457. },
  458. saveRelation() {},
  459. //保存(新增/修改)
  460. submitForm() {
  461. var url = QUESTION_API + "/course";
  462. if (null != this.courseForm.id) {
  463. //修改
  464. this.$refs.courseForm.validate((valid) => {
  465. if (valid) {
  466. this.$httpWithMsg.put(url, this.courseForm).then(() => {
  467. this.$notify({
  468. type: "success",
  469. message: "修改成功!",
  470. });
  471. this.searchForm();
  472. this.resetForm();
  473. this.courseDialog = false;
  474. });
  475. } else {
  476. console.log("error submit!");
  477. return false;
  478. }
  479. });
  480. } else {
  481. this.$refs.courseForm.validate((valid) => {
  482. if (valid) {
  483. this.$httpWithMsg.post(url, this.courseForm).then(() => {
  484. this.$notify({
  485. type: "success",
  486. message: "添加成功",
  487. });
  488. this.searchForm();
  489. this.resetForm();
  490. this.courseDialog = false;
  491. });
  492. } else {
  493. console.log("error submit!");
  494. return false;
  495. }
  496. });
  497. }
  498. },
  499. //重置
  500. resetForm() {
  501. this.$refs.courseForm.resetFields();
  502. },
  503. resetPrimaryForm() {
  504. this.formSearch = {
  505. name: "",
  506. code: "",
  507. enable: "",
  508. level: "",
  509. };
  510. this.$refs.primaryForm.resetFields();
  511. },
  512. //删除单个数据
  513. deleteById(row) {
  514. this.$confirm("是否删除该课程?", "系统通知", {
  515. confirmButtonText: "确定",
  516. cancelButtonText: "取消",
  517. type: "warning",
  518. }).then(() => {
  519. var url = QUESTION_API + "/course/delete";
  520. let temCourseIds = [];
  521. temCourseIds.push(row.id);
  522. this.$httpWithMsg
  523. .post(url, new URLSearchParams({ courseIds: temCourseIds }))
  524. .then(() => {
  525. this.$notify({
  526. type: "success",
  527. message: "删除成功!",
  528. });
  529. this.searchForm();
  530. });
  531. });
  532. },
  533. //知识点
  534. toKnowledge(row) {
  535. this.$router.push({
  536. path: "/questions/property_info/" + row.id,
  537. });
  538. },
  539. //删除多条数据
  540. deleteByIds() {
  541. if (this.selectedCourseIds.length === 0) {
  542. this.$notify({
  543. type: "warning",
  544. message: "请选择要删除的课程",
  545. });
  546. } else {
  547. this.$confirm("确定要删除所选课程吗?", "提示", {
  548. confirmButtonText: "确定",
  549. cancelButtonText: "取消",
  550. type: "error",
  551. }).then(() => {
  552. var url = QUESTION_API + "/course/delete";
  553. this.$httpWithMsg
  554. .post(
  555. url,
  556. new URLSearchParams({ courseIds: this.selectedCourseIds })
  557. )
  558. .then(() => {
  559. this.$notify({
  560. type: "success",
  561. message: "删除成功!",
  562. });
  563. this.searchForm();
  564. });
  565. });
  566. }
  567. },
  568. //启用
  569. enableByIds() {
  570. if (this.selectedCourseIds.length === 0) {
  571. this.$notify({
  572. type: "warning",
  573. message: "请选择要启用的课程",
  574. });
  575. } else {
  576. this.$confirm("确定要启用所选课程吗?", "系统通知", {
  577. confirmButtonText: "确定",
  578. cancelButtonText: "取消",
  579. type: "warning",
  580. }).then(() => {
  581. var url = QUESTION_API + "/course/enable/" + this.courseIds;
  582. this.$httpWithMsg.put(url, {}).then(() => {
  583. this.$notify({
  584. type: "success",
  585. message: "启用成功!",
  586. });
  587. this.searchForm();
  588. });
  589. });
  590. }
  591. },
  592. enableById(row) {
  593. this.$confirm("是否启用该课程?", "系统通知", {
  594. confirmButtonText: "确定",
  595. cancelButtonText: "取消",
  596. type: "warning",
  597. }).then(() => {
  598. var url = QUESTION_API + "/course/enable/" + row.id;
  599. this.$httpWithMsg.put(url, {}).then(() => {
  600. this.$notify({
  601. type: "success",
  602. message: "启用成功!",
  603. });
  604. this.searchForm();
  605. });
  606. });
  607. },
  608. //禁用
  609. disableByIds() {
  610. if (this.selectedCourseIds.length === 0) {
  611. this.$notify({
  612. type: "warning",
  613. message: "请选择要禁用的课程",
  614. });
  615. } else {
  616. this.$confirm("确定要禁用所选课程吗?", "系统通知", {
  617. confirmButtonText: "确定",
  618. cancelButtonText: "取消",
  619. type: "error",
  620. }).then(() => {
  621. var url = QUESTION_API + "/course/disable/" + this.courseIds;
  622. this.$httpWithMsg.put(url, {}).then(() => {
  623. this.$notify({
  624. type: "success",
  625. message: "禁用成功!",
  626. });
  627. this.searchForm();
  628. });
  629. });
  630. }
  631. },
  632. //禁用
  633. disableById(row) {
  634. this.$confirm("是否禁用该课程?", "系统通知", {
  635. confirmButtonText: "确定",
  636. cancelButtonText: "取消",
  637. type: "error",
  638. }).then(() => {
  639. var url = QUESTION_API + "/course/disable/" + row.id;
  640. return this.$httpWithMsg.put(url, {}).then(() => {
  641. this.$notify({
  642. type: "success",
  643. message: "禁用成功!",
  644. });
  645. return this.searchForm();
  646. });
  647. });
  648. },
  649. //导入
  650. importCourse() {
  651. this.$refs.ImportCourseDialog.open();
  652. },
  653. uploadSuccess(response) {
  654. const { hasError, failRecords } = response.data;
  655. if (!hasError) {
  656. this.$notify({
  657. message: "上传成功",
  658. type: "success",
  659. });
  660. this.searchForm();
  661. } else {
  662. this.errMessages = failRecords;
  663. this.errDialog = true;
  664. }
  665. },
  666. },
  667. };
  668. </script>