CourseProperty.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751
  1. <template>
  2. <section class="content">
  3. <div v-show="isClear == 1">
  4. <LinkTitlesCustom :current-paths="['基础信息', '课程属性预设']" />
  5. </div>
  6. <!-- 正文信息 -->
  7. <div class="box-body">
  8. <el-form
  9. :inline="true"
  10. :model="formSearch"
  11. label-position="right"
  12. label-width="70px"
  13. >
  14. <el-row>
  15. <el-col :span="6">
  16. <el-form-item label="属性名称">
  17. <el-input
  18. v-model="formSearch.name"
  19. class="search_width"
  20. placeholder="请输入属性名称"
  21. size="small"
  22. ></el-input>
  23. </el-form-item>
  24. </el-col>
  25. <el-col :span="6">
  26. <el-form-item label="课程名称">
  27. <el-select
  28. v-model="formSearch.courseId"
  29. class="search_width"
  30. filterable
  31. :remote-method="getCourses"
  32. remote
  33. clearable
  34. placeholder="请选择"
  35. size="small"
  36. @focus="(e) => getCourses(e.target.value)"
  37. >
  38. <el-option
  39. v-for="item in courseInfoSelect"
  40. :key="item.courseId"
  41. :label="item.courseInfo"
  42. :value="item.courseId"
  43. >
  44. </el-option>
  45. </el-select>
  46. </el-form-item>
  47. </el-col>
  48. <el-col :span="6">
  49. <div class="search_down">
  50. <el-button size="small" type="primary" @click="searchFrom"
  51. ><i class="el-icon-search"></i> 查询</el-button
  52. >
  53. <el-button size="small" type="primary" @click="addCourseProperty"
  54. ><i class="el-icon-plus"></i> 新增</el-button
  55. >
  56. </div>
  57. </el-col>
  58. </el-row>
  59. <div
  60. style="width: 100%; border-bottom: 1px solid #ddd; margin: 10px 0"
  61. ></div>
  62. <el-row>
  63. <el-form-item class="pull-left">
  64. <span>批量操作:</span>
  65. <el-button
  66. size="small"
  67. type="success"
  68. :disabled="noBatchSelected"
  69. @click="openCoursePropertys"
  70. ><i class="el-icon-check"></i> 启用</el-button
  71. >
  72. <el-button
  73. size="small"
  74. type="danger"
  75. :disabled="noBatchSelected"
  76. @click="closeCoursePropertys"
  77. ><i class="el-icon-close"></i> 禁用</el-button
  78. >
  79. <el-button
  80. size="small"
  81. type="primary"
  82. icon="el-icon-upload2"
  83. @click="impCourseProperty"
  84. >
  85. 导入
  86. </el-button>
  87. </el-form-item>
  88. </el-row>
  89. </el-form>
  90. <div style="width: 100%; margin-bottom: 10px"></div>
  91. <!-- 页面列表 -->
  92. <el-table
  93. v-loading="loading"
  94. :data="tableData"
  95. element-loading-text="拼命加载中"
  96. border
  97. style="width: 100%"
  98. @selection-change="selectionChange"
  99. >
  100. <el-table-column type="selection" width="40"></el-table-column>
  101. <el-table-column label="课程名称">
  102. <template slot-scope="scope">
  103. <span>{{ scope.row.courseName }}</span>
  104. </template>
  105. </el-table-column>
  106. <el-table-column label="属性名称">
  107. <template slot-scope="scope">
  108. <span>{{ scope.row.name }}</span>
  109. </template>
  110. </el-table-column>
  111. <el-table-column label="状态">
  112. <template slot-scope="scope">
  113. <span v-if="scope.row.enable">
  114. <el-tooltip
  115. class="item"
  116. effect="dark"
  117. content="启用"
  118. placement="left"
  119. >
  120. <i class="el-icon-success" style="color: green"></i>
  121. </el-tooltip>
  122. </span>
  123. <span v-else>
  124. <el-tooltip
  125. class="item"
  126. effect="dark"
  127. content="禁用"
  128. placement="left"
  129. >
  130. <i class="el-icon-error" style="color: red"></i>
  131. </el-tooltip>
  132. </span>
  133. </template>
  134. </el-table-column>
  135. <el-table-column label="操作" width="260">
  136. <template slot-scope="scope">
  137. <div class="operate_left">
  138. <el-button
  139. size="mini"
  140. type="primary"
  141. plain
  142. @click="editCourseProperty(scope.row)"
  143. ><i class="el-icon-zoom-in"></i> 详情
  144. </el-button>
  145. <el-button
  146. v-if="!scope.row.enable"
  147. size="mini"
  148. type="primary"
  149. plain
  150. @click="openCourseProperty(scope.row)"
  151. >
  152. <i class="el-icon-check" aria-hidden="true"></i>启用
  153. </el-button>
  154. <el-button
  155. v-if="scope.row.enable"
  156. size="mini"
  157. type="danger"
  158. @click="closeCourseProperty(scope.row)"
  159. >
  160. <i class="el-icon-close" aria-hidden="true"></i>禁用
  161. </el-button>
  162. </div>
  163. </template>
  164. </el-table-column>
  165. </el-table>
  166. <div class="page pull-right">
  167. <el-pagination
  168. :current-page.sync="currentPage"
  169. :page-size="pageSize"
  170. :page-sizes="[10, 20, 50, 100, 200, 300]"
  171. layout="total, sizes, prev, pager, next, jumper"
  172. :total="total"
  173. @current-change="handleCurrentChange"
  174. @size-change="handleSizeChange"
  175. >
  176. </el-pagination>
  177. </div>
  178. </div>
  179. <el-dialog
  180. title="新增课程属性名称"
  181. :visible.sync="coursePropertyDialog"
  182. width="500px"
  183. >
  184. <el-form
  185. ref="coursePropertyForm"
  186. :model="coursePropertyForm"
  187. :rules="rules"
  188. label-position="right"
  189. label-width="90px"
  190. inline-message
  191. >
  192. <el-row>
  193. <el-form-item label="属性名称" label-width="120px" prop="name">
  194. <el-input
  195. v-model="coursePropertyForm.name"
  196. class="dialog_input_width"
  197. ></el-input>
  198. </el-form-item>
  199. </el-row>
  200. <el-row>
  201. <el-form-item label="课程名称" label-width="120px" prop="courseId">
  202. <el-select
  203. v-model="coursePropertyForm.courseId"
  204. class="dialog_input_width"
  205. filterable
  206. :remote-method="getCourses"
  207. remote
  208. clearable
  209. placeholder="请选择课程"
  210. @focus="(e) => getCourses(e.target.value)"
  211. >
  212. <el-option
  213. v-for="item in courseInfoSelect"
  214. :key="item.courseId"
  215. :label="item.courseInfo"
  216. :value="item.courseId"
  217. >
  218. </el-option>
  219. </el-select>
  220. </el-form-item>
  221. </el-row>
  222. <el-row class="margin_top_10 margin_left_120">
  223. <el-button type="primary" @click="submit('coursePropertyForm')"
  224. >保 存</el-button
  225. >
  226. <el-button @click="resetForm('coursePropertyForm')"
  227. ><i class="el-icon-refresh"></i> 重 置</el-button
  228. >
  229. <el-button type="primary" @click="back('coursePropertyForm')"
  230. ><i class="el-icon-arrow-left"></i> 返 回</el-button
  231. >
  232. </el-row>
  233. </el-form>
  234. </el-dialog>
  235. <!-- 导入弹窗 -->
  236. <el-dialog title="导入窗口" width="520px" :visible.sync="impDialog">
  237. <el-form>
  238. <el-row>
  239. <el-form-item style="margin-left: 20px">
  240. <el-upload
  241. ref="upload"
  242. class="form_left"
  243. accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
  244. :action="uploadAction"
  245. :headers="uploadHeaders"
  246. :data="uploadData"
  247. :before-upload="beforeUpload"
  248. :on-progress="uploadProgress"
  249. :on-success="uploadSuccess"
  250. :on-error="uploadError"
  251. :file-list="fileList"
  252. :auto-upload="false"
  253. :multiple="false"
  254. >
  255. <el-button
  256. slot="trigger"
  257. size="small"
  258. type="primary"
  259. icon="el-icon-search"
  260. >
  261. 选择文件
  262. </el-button>
  263. &nbsp;
  264. <el-button
  265. size="small"
  266. type="primary"
  267. icon="el-icon-check"
  268. @click="submitUpload"
  269. >
  270. 确认上传
  271. </el-button>
  272. <el-button
  273. size="small"
  274. type="primary"
  275. icon="el-icon-refresh"
  276. @click="removeFile"
  277. >
  278. 清空文件
  279. </el-button>
  280. <el-button
  281. size="small"
  282. type="primary"
  283. icon="el-icon-download"
  284. @click="exportFile"
  285. >
  286. 下载模板
  287. </el-button>
  288. <div slot="tip" class="el-upload__tip">只能上传xlsx文件</div>
  289. </el-upload>
  290. </el-form-item>
  291. </el-row>
  292. </el-form>
  293. </el-dialog>
  294. <!-- 导入错误信息列表 -->
  295. <el-dialog title="错误提示" :visible.sync="errDialog">
  296. <div
  297. v-for="errMessage in errMessages"
  298. :key="errMessage.lineNum"
  299. class="text-danger"
  300. >
  301. 第{{ errMessage.lineNum }}行:{{ errMessage.msg }}
  302. </div>
  303. <span slot="footer" class="dialog-footer">
  304. <el-button @click="errDialog = false">确定</el-button>
  305. </span>
  306. </el-dialog>
  307. </section>
  308. </template>
  309. <script>
  310. import { QUESTION_API } from "@/constants/constants";
  311. import LinkTitlesCustom from "@/components/LinkTitlesCustom.vue";
  312. import { mapState } from "vuex";
  313. export default {
  314. components: { LinkTitlesCustom },
  315. data() {
  316. return {
  317. formSearch: {
  318. name: "",
  319. courseId: "",
  320. },
  321. impDialog: false,
  322. uploadAction: QUESTION_API + "/courseProperty/import",
  323. uploadHeaders: {},
  324. uploadData: {},
  325. errMessages: [],
  326. errDialog: false,
  327. fileLoading: false,
  328. fileList: [],
  329. courseList: [],
  330. loading: false,
  331. tableData: [],
  332. currentPage: 1,
  333. pageSize: 10,
  334. total: 10,
  335. coursePropertyForm: {
  336. name: "",
  337. courseId: "",
  338. courseCode: "",
  339. },
  340. coursePropertyDialog: false,
  341. selectedList: [],
  342. rules: {
  343. name: [{ required: true, message: "请输入属性名称", trigger: "blur" }],
  344. courseId: [
  345. { required: true, message: "请选择课程名称", trigger: "change" },
  346. ],
  347. },
  348. };
  349. },
  350. computed: {
  351. ...mapState({
  352. user: (state) => state.user,
  353. }),
  354. selectedIds() {
  355. var selectedIdsStr = "";
  356. for (let id of this.selectedList) {
  357. if (!selectedIdsStr) {
  358. selectedIdsStr += id;
  359. } else {
  360. selectedIdsStr += "," + id;
  361. }
  362. }
  363. return selectedIdsStr;
  364. },
  365. courseInfoSelect() {
  366. var courseList = [];
  367. for (var i = 0; i < this.courseList.length; i++) {
  368. var courseInfo = {
  369. courseInfo:
  370. this.courseList[i].name + "(" + this.courseList[i].code + ")",
  371. courseId: this.courseList[i].id,
  372. };
  373. courseList.push(courseInfo);
  374. }
  375. return courseList;
  376. },
  377. noBatchSelected() {
  378. return this.selectedList.length === 0;
  379. },
  380. },
  381. watch: {
  382. $route: "initValue",
  383. },
  384. created() {
  385. this.initValue();
  386. this.uploadHeaders = {
  387. key: this.user.key,
  388. token: this.user.token,
  389. };
  390. },
  391. methods: {
  392. //导入
  393. impCourseProperty() {
  394. this.impDialog = true;
  395. this.initUpload();
  396. },
  397. initUpload() {
  398. this.fileList = [];
  399. },
  400. beforeUpload(file) {
  401. console.log(file);
  402. },
  403. uploadProgress() {
  404. console.log("uploadProgress");
  405. },
  406. uploadSuccess(response) {
  407. if (!response.hasError) {
  408. this.$notify({
  409. message: "上传成功",
  410. type: "success",
  411. });
  412. this.fileLoading = false;
  413. this.impDialog = false;
  414. this.searchCourProperty();
  415. } else {
  416. this.fileLoading = false;
  417. this.impDialog = false;
  418. this.errMessages = response.failRecords;
  419. this.errDialog = true;
  420. }
  421. },
  422. uploadError(response) {
  423. var json = JSON.parse(response.message);
  424. if (response.status == 500) {
  425. this.$notify({
  426. message: json.desc,
  427. type: "error",
  428. });
  429. }
  430. this.fileLoading = false;
  431. },
  432. //确定上传
  433. submitUpload() {
  434. if (!this.checkUpload()) {
  435. return false;
  436. }
  437. this.$refs.upload.submit();
  438. this.fileLoading = true;
  439. },
  440. checkUpload() {
  441. var fileList = this.$refs.upload.uploadFiles;
  442. if (fileList.length == 0) {
  443. this.$notify({
  444. message: "上传文件不能为空",
  445. type: "error",
  446. });
  447. return false;
  448. }
  449. if (fileList.length > 1) {
  450. this.$notify({
  451. message: "每次只能上传一个文件",
  452. type: "error",
  453. });
  454. return false;
  455. }
  456. for (let file of fileList) {
  457. if (!file.name.endsWith(".xlsx")) {
  458. this.$notify({
  459. message: "上传文件必须为xlsx格式",
  460. type: "error",
  461. });
  462. this.initUpload();
  463. return false;
  464. }
  465. }
  466. return true;
  467. },
  468. //清空文件
  469. removeFile() {
  470. // this.fileList = [];
  471. this.$refs.upload.clearFiles();
  472. },
  473. //下载模板
  474. exportFile() {
  475. window.location.href =
  476. QUESTION_API +
  477. "/courseProperty/importTemplate?$key=" +
  478. this.user.key +
  479. "&$token=" +
  480. this.user.token;
  481. },
  482. //查询所有课程属性
  483. searchFrom() {
  484. this.currentPage = 1;
  485. this.searchCourProperty();
  486. },
  487. searchCourProperty() {
  488. var pageNo = Number(this.currentPage);
  489. this.loading = true;
  490. var url =
  491. QUESTION_API +
  492. "/courseProperty/all/" +
  493. this.currentPage +
  494. "/" +
  495. this.pageSize;
  496. this.$http.get(url, { params: this.formSearch }).then((response) => {
  497. this.tableData = response.data.content;
  498. this.total = response.data.totalElements;
  499. this.currentPage = pageNo;
  500. this.loading = false;
  501. });
  502. },
  503. //新增
  504. addCourseProperty() {
  505. this.coursePropertyDialog = true;
  506. this.coursePropertyForm.name = "";
  507. this.coursePropertyForm.courseId = "";
  508. },
  509. //重置
  510. resetForm(formData) {
  511. this.coursePropertyForm.name = "";
  512. this.coursePropertyForm.courseId = "";
  513. this.$refs[formData].clearValidate();
  514. },
  515. //返回
  516. back(formData) {
  517. this.resetForm(formData);
  518. this.coursePropertyDialog = false;
  519. },
  520. //修改
  521. editCourseProperty(row) {
  522. sessionStorage.setItem("course_property_name", this.formSearch.name);
  523. sessionStorage.setItem(
  524. "course_property_courseId",
  525. this.formSearch.courseId
  526. );
  527. sessionStorage.setItem("course_property_currentPage", this.currentPage);
  528. sessionStorage.setItem("courseProperty", JSON.stringify(row));
  529. this.$router.push({
  530. path: "/questions/property_info/" + row.id,
  531. });
  532. },
  533. //开启
  534. openCourseProperty(row) {
  535. this.$confirm("确认开启?", "提示", {
  536. type: "success",
  537. }).then(() => {
  538. this.loading = true;
  539. this.$http
  540. .put(QUESTION_API + "/courseProperty/open/" + row.id)
  541. .then(() => {
  542. this.$notify({
  543. message: "开启成功",
  544. type: "success",
  545. });
  546. this.searchCourProperty();
  547. })
  548. .catch(() => {
  549. this.$notify({
  550. type: "error",
  551. message: "开启失败",
  552. });
  553. });
  554. });
  555. },
  556. //批量启用
  557. openCoursePropertys() {
  558. this.$confirm("是否确认开启?", "提示", {
  559. confirmButtonText: "确定",
  560. cancelButtonText: "取消",
  561. type: "error",
  562. }).then(() => {
  563. this.loading = true;
  564. var url = QUESTION_API + "/courseProperty/opens/" + this.selectedIds;
  565. this.$http
  566. .put(url)
  567. .then(() => {
  568. this.$notify({
  569. type: "success",
  570. message: "开启成功!",
  571. });
  572. this.searchCourProperty();
  573. this.selectedList = [];
  574. })
  575. .catch(() => {
  576. this.$notify({
  577. type: "error",
  578. message: "开启失败!",
  579. });
  580. this.selectedList = [];
  581. });
  582. });
  583. this.loading = false;
  584. },
  585. //关闭
  586. closeCourseProperty(row) {
  587. this.$confirm("确认禁用?", "提示", {
  588. type: "warning",
  589. }).then(() => {
  590. this.loading = true;
  591. this.$http
  592. .put(QUESTION_API + "/courseProperty/close/" + row.id)
  593. .then(() => {
  594. this.$notify({
  595. message: "禁用成功",
  596. type: "success",
  597. });
  598. this.searchCourProperty();
  599. })
  600. .catch(() => {
  601. this.$notify({
  602. type: "error",
  603. message: "禁用失败",
  604. });
  605. });
  606. });
  607. },
  608. //批量关闭
  609. closeCoursePropertys() {
  610. this.$confirm("是否确认禁用?", "提示", {
  611. confirmButtonText: "确定",
  612. cancelButtonText: "取消",
  613. type: "error",
  614. }).then(() => {
  615. this.loading = true;
  616. var url = QUESTION_API + "/courseProperty/closes/" + this.selectedIds;
  617. this.$http
  618. .put(url)
  619. .then(() => {
  620. this.$notify({
  621. type: "success",
  622. message: "禁用成功!",
  623. });
  624. this.searchCourProperty();
  625. this.selectedList = [];
  626. })
  627. .catch(() => {
  628. this.$notify({
  629. type: "error",
  630. message: "禁用失败!",
  631. });
  632. this.selectedList = [];
  633. });
  634. });
  635. this.loading = false;
  636. },
  637. //分页
  638. handleCurrentChange(val) {
  639. this.currentPage = val;
  640. this.searchCourProperty();
  641. },
  642. handleSizeChange(val) {
  643. this.pageSize = val;
  644. this.currentPage = 1;
  645. this.searchCourProperty();
  646. },
  647. //确定
  648. submit(formData) {
  649. this.$refs[formData].validate((valid) => {
  650. if (valid) {
  651. for (let course of this.courseList) {
  652. if (course.id == this.coursePropertyForm.courseId) {
  653. this.coursePropertyForm.courseCode = course.code;
  654. }
  655. }
  656. this.$http
  657. .post(
  658. QUESTION_API + "/courseProperty/save",
  659. this.coursePropertyForm
  660. )
  661. .then(() => {
  662. this.$notify({
  663. message: "新增成功",
  664. type: "success",
  665. });
  666. this.coursePropertyDialog = false;
  667. this.searchCourProperty();
  668. })
  669. .catch((error) => {
  670. this.$notify({
  671. type: "error",
  672. message: error.response.data.desc,
  673. });
  674. });
  675. } else {
  676. return false;
  677. }
  678. });
  679. },
  680. //查询所有课程
  681. getCourses(query) {
  682. query = query.trim();
  683. this.courseLoading = true;
  684. this.$http
  685. .get(QUESTION_API + "/course/query?name=" + query + "&enable=true")
  686. .then((response) => {
  687. this.courseList = response.data;
  688. this.courseLoading = false;
  689. });
  690. },
  691. removeItem() {
  692. sessionStorage.removeItem("course_property_name");
  693. sessionStorage.removeItem("course_property_courseId");
  694. sessionStorage.removeItem("course_property_currentPage");
  695. },
  696. //页面回填值
  697. initValue() {
  698. this.isClear = this.$route.params.isClear;
  699. if (this.isClear == 0 || !this.isClear) {
  700. this.removeItem();
  701. this.formSearch = {
  702. name: "",
  703. courseId: "",
  704. };
  705. } else {
  706. this.formSearch.name =
  707. sessionStorage.getItem("course_property_name") == "null"
  708. ? ""
  709. : sessionStorage.getItem("course_property_name");
  710. this.formSearch.courseId =
  711. sessionStorage.getItem("course_property_courseId") == ""
  712. ? ""
  713. : parseInt(sessionStorage.getItem("course_property_courseId"));
  714. this.currentPage =
  715. sessionStorage.getItem("course_property_currentPage") == null
  716. ? 1
  717. : parseInt(sessionStorage.getItem("course_property_currentPage"));
  718. }
  719. this.getOneCourse(this.formSearch.courseId);
  720. this.handleCurrentChange(this.currentPage);
  721. },
  722. //查询单个课程
  723. getOneCourse(courseId) {
  724. if (courseId) {
  725. this.$http
  726. .get(QUESTION_API + "/course/" + courseId)
  727. .then((response) => {
  728. this.courseList.push(response.data);
  729. });
  730. } else {
  731. this.courseList = [];
  732. }
  733. },
  734. //全选
  735. selectionChange(val) {
  736. this.selectedList = [];
  737. var selectedList = this.selectedList;
  738. val.forEach((element) => {
  739. selectedList.push(element.id);
  740. });
  741. this.selectedList = selectedList;
  742. },
  743. },
  744. };
  745. </script>
  746. <style scoped src="../styles/Common.css"></style>