CourseProperty.vue 22 KB

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