PropertyInfo.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661
  1. <template>
  2. <section class="property-info">
  3. <!-- 正文信息 -->
  4. <div class="part-box">
  5. <h2 class="part-box-title">{{ courseProperty.name }}</h2>
  6. <!-- <el-form
  7. class="part-filter-form"
  8. :inline="true"
  9. :model="courseProperty"
  10. label-position="right"
  11. label-width="100px"
  12. >
  13. <el-form-item label="课程名称">
  14. <el-select
  15. v-model="courseProperty.courseId"
  16. filterable
  17. :remote-method="getCourses"
  18. remote
  19. clearable
  20. :disabled="true"
  21. >
  22. <el-option
  23. v-for="item in courseInfoSelect"
  24. :key="item.courseId"
  25. :label="item.courseInfo"
  26. :value="item.courseId"
  27. >
  28. </el-option>
  29. </el-select>
  30. </el-form-item>
  31. </el-form> -->
  32. <div class="part-box-action">
  33. <div class="icon-btn-group">
  34. <svg-btn name="xinzeng" @click="insertParent">新增一级</svg-btn>
  35. <svg-btn name="xinzeng" :disabled="showSonButtton" @click="insertSon"
  36. >新增二级</svg-btn
  37. >
  38. <svg-btn name="bianji" :disabled="showButton" @click="updateProperty"
  39. >编辑</svg-btn
  40. >
  41. <svg-btn name="daoru" @click="impCourseProperty">导入</svg-btn>
  42. <svg-btn name="daochu" @click="exportCourseProperty">导出</svg-btn>
  43. <svg-btn
  44. name="shanchu"
  45. :disabled="!multipleSelection.length"
  46. @click="deleteProperty"
  47. >删除</svg-btn
  48. >
  49. <svg-btn
  50. name="shangjiantou"
  51. :disabled="showMoveButtton"
  52. @click="moveUp"
  53. >上移</svg-btn
  54. >
  55. <svg-btn
  56. name="xiajiantou"
  57. :disabled="showMoveButtton"
  58. @click="moveDown"
  59. >下移</svg-btn
  60. >
  61. </div>
  62. <!-- <div>
  63. <el-button
  64. type="primary"
  65. icon="icon icon-plus-white"
  66. @click="insertParent"
  67. >新增一级</el-button
  68. >
  69. <el-button
  70. type="primary"
  71. icon="icon icon-plus-white"
  72. :disabled="showSonButtton"
  73. @click="insertSon"
  74. >新增二级</el-button
  75. >
  76. <el-button
  77. type="primary"
  78. plain
  79. icon="icon icon-edit"
  80. :disabled="showButton"
  81. @click="updateProperty"
  82. >编辑</el-button
  83. >
  84. <el-button
  85. type="danger"
  86. plain
  87. icon="icon icon-delete"
  88. :disabled="!multipleSelection.length"
  89. @click="deleteProperty"
  90. >删除</el-button
  91. >
  92. <el-button
  93. type="primary"
  94. plain
  95. icon="icon icon-import"
  96. :disabled="showMoveButtton"
  97. @click="moveUp"
  98. >上移</el-button
  99. >
  100. <el-button
  101. type="primary"
  102. plain
  103. icon="icon icon-export"
  104. :disabled="showMoveButtton"
  105. @click="moveDown"
  106. >下移</el-button
  107. >
  108. </div> -->
  109. <div>
  110. <el-button type="danger" plain icon="icon icon-back" @click="back"
  111. >返回</el-button
  112. >
  113. </div>
  114. </div>
  115. </div>
  116. <div class="part-box property-box">
  117. <el-tree
  118. ref="PropertyTree"
  119. class="property-tree"
  120. :data="treeData"
  121. node-key="id"
  122. :props="defaultProps"
  123. :default-expanded-keys="ids"
  124. highlight-current
  125. show-checkbox
  126. :check-strictly="true"
  127. @node-click="handleNodeClick"
  128. @check="checkChange"
  129. ><span
  130. slot-scope="{ data }"
  131. :class="{ 'node-level-one': !data.parentId }"
  132. >
  133. <span>{{ data.name }}({{ data.code }})</span>
  134. </span></el-tree
  135. >
  136. </div>
  137. <el-dialog
  138. :title="title"
  139. :visible.sync="propertyDialog"
  140. :modal="true"
  141. width="620px"
  142. :close-on-click-modal="false"
  143. :close-on-press-escape="false"
  144. append-to-body
  145. custom-class="side-dialog"
  146. @close="closeModel"
  147. >
  148. <el-form
  149. ref="propertyForm"
  150. :model="propertyForm"
  151. :rules="rules"
  152. inline-message
  153. class="form-tight"
  154. label-width="100px"
  155. >
  156. <el-row>
  157. <el-form-item label="编号" prop="code">
  158. <el-input
  159. v-model="propertyForm.code"
  160. auto-complete="off"
  161. class="dialog-input-width"
  162. disabled
  163. ></el-input>
  164. </el-form-item>
  165. </el-row>
  166. <el-row v-if="isFirstLev()">
  167. <el-form-item label="一级名称" prop="name">
  168. <el-input
  169. v-model="propertyForm.name"
  170. auto-complete="off"
  171. class="dialog-input-width"
  172. ></el-input>
  173. </el-form-item>
  174. </el-row>
  175. <el-row v-if="isSecondLev()">
  176. <el-form-item label="二级名称" prop="name">
  177. <el-input
  178. v-model="propertyForm.name"
  179. auto-complete="off"
  180. class="dialog-input-width"
  181. ></el-input>
  182. </el-form-item>
  183. </el-row>
  184. <el-row>
  185. <el-form-item label="名称备注">
  186. <el-input
  187. v-model="propertyForm.remark"
  188. auto-complete="off"
  189. :maxlength="100"
  190. ></el-input>
  191. </el-form-item>
  192. </el-row>
  193. </el-form>
  194. <div slot="footer" class="dialog-footer">
  195. <el-button type="primary" @click="submit">确定</el-button>
  196. <el-button type="danger" plain @click="closeModel">取消</el-button>
  197. </div>
  198. </el-dialog>
  199. <!-- 导入弹窗 -->
  200. <import-file-dialog
  201. ref="ImportCourseDialog"
  202. dialog-title="导入知识点"
  203. :template-url="courseTemplateUrl"
  204. :upload-url="uploadCourseUrl"
  205. @uploaded="uploadSuccess"
  206. :uploadData="uploadData"
  207. ></import-file-dialog>
  208. </section>
  209. </template>
  210. <script>
  211. import { QUESTION_API } from "@/constants/constants";
  212. import { mapState } from "vuex";
  213. import ImportFileDialog from "@/components/ImportFileDialog.vue";
  214. import { downloadByApi } from "@/plugins/download";
  215. export default {
  216. components: { ImportFileDialog },
  217. data() {
  218. return {
  219. uploadCourseUrl: `${QUESTION_API}/courseProperty/import`,
  220. // courseTemplateUrl: `${QUESTION_API}/courseProperty/importTemplate`,
  221. coursePropertyId: "",
  222. courseProperty: {
  223. name: "",
  224. courseId: "",
  225. },
  226. courseList: [],
  227. ids: [],
  228. loading: false,
  229. propertyDialog: false,
  230. propertyForm: {
  231. id: "",
  232. code: "",
  233. name: "",
  234. parentId: "",
  235. number: "",
  236. coursePropertyId: "",
  237. remark: "",
  238. },
  239. curProperty: {
  240. id: "",
  241. code: "",
  242. name: "",
  243. parentId: "",
  244. number: "",
  245. coursePropertyId: "",
  246. remark: "",
  247. },
  248. multipleSelection: [],
  249. showButton: true,
  250. showSonButtton: true,
  251. showMoveButtton: true,
  252. treeData: [],
  253. defaultProps: {
  254. children: "propertyList",
  255. },
  256. title: "新增知识点",
  257. rules: {
  258. code: [
  259. {
  260. required: true,
  261. message: "请输入编码",
  262. trigger: "blur",
  263. },
  264. {
  265. max: 100,
  266. message: "编码最多100个字符",
  267. trigger: "blur",
  268. },
  269. ],
  270. name: [
  271. {
  272. required: true,
  273. message: "请输入名称",
  274. trigger: "blur",
  275. },
  276. {
  277. max: 100,
  278. message: "名称最多100个字符",
  279. trigger: "blur",
  280. },
  281. ],
  282. },
  283. };
  284. },
  285. computed: {
  286. ...mapState({ user: (state) => state.user }),
  287. courseInfoSelect() {
  288. var courseList = [];
  289. for (var i = 0; i < this.courseList.length; i++) {
  290. var courseInfo = {
  291. courseInfo:
  292. this.courseList[i].name + "(" + this.courseList[i].code + ")",
  293. courseId: this.courseList[i].id,
  294. };
  295. courseList.push(courseInfo);
  296. }
  297. return courseList;
  298. },
  299. IS_ASSIGN_TEACHER() {
  300. // 命题老师
  301. return this.user.roleList.some(
  302. (item) => item.roleCode === "ASSIGN_TEACHER"
  303. );
  304. },
  305. courseTemplateUrl() {
  306. return `${QUESTION_API}/courseProperty/importTemplate?coursePropertyId=${this.coursePropertyId}`;
  307. },
  308. uploadData() {
  309. return {
  310. coursePropertyId: this.coursePropertyId,
  311. };
  312. },
  313. },
  314. created() {
  315. // this.coursePropertyId = this.$route.params.id;
  316. this.courseProperty.courseId = this.$route.params.id;
  317. this.searchProperty();
  318. },
  319. mounted() {
  320. setTimeout(() => {
  321. this.$store.commit("UPDATE_CURRENT_PATHS", ["课程管理", "知识点"]);
  322. }, 200);
  323. },
  324. methods: {
  325. // 导出
  326. async exportCourseProperty() {
  327. if (this.downloading) return;
  328. this.downloading = true;
  329. const res = await downloadByApi(() => {
  330. return this.$httpWithMsg.get(
  331. `${QUESTION_API}/courseProperty/detail/export`,
  332. {
  333. params: { coursePropertyId: this.coursePropertyId },
  334. responseType: "blob",
  335. }
  336. );
  337. }).catch((e) => {
  338. this.$message.error(e || "导出失败,请重新尝试!");
  339. });
  340. this.downloading = false;
  341. if (!res) return;
  342. this.$message.success("导出成功!");
  343. },
  344. impCourseProperty() {
  345. this.$refs.ImportCourseDialog.open();
  346. },
  347. uploadSuccess() {
  348. // if (res.success) {
  349. // this.$notify({
  350. // message: "导入成功",
  351. // type: "success",
  352. // });
  353. // this.searchCourProperty();
  354. this.$notify({
  355. message: "导入成功",
  356. type: "success",
  357. });
  358. this.$refs.ImportCourseDialog.cancel();
  359. this.searchProperty();
  360. // } else {
  361. // this.$notify({
  362. // message: res.message,
  363. // type: "error",
  364. // });
  365. // }
  366. },
  367. disAllBtn() {
  368. this.showButton = true;
  369. this.showSonButtton = true;
  370. this.showMoveButtton = true;
  371. },
  372. isFirstLev() {
  373. if (this.propertyForm.parentId == "0") {
  374. return true;
  375. } else {
  376. return false;
  377. }
  378. },
  379. isSecondLev() {
  380. if (this.propertyForm.parentId && this.propertyForm.parentId != "0") {
  381. return true;
  382. } else {
  383. return false;
  384. }
  385. },
  386. closeModel() {
  387. this.propertyDialog = false;
  388. this.$refs.propertyForm.resetFields();
  389. },
  390. //树形节点选中
  391. handleNodeClick(object) {
  392. this.showButton = false;
  393. //判断选中节点,如果是父节点,可以新增二级
  394. if (object.parentId == "0") {
  395. this.showSonButtton = false;
  396. } else {
  397. this.showSonButtton = true;
  398. }
  399. this.showMoveButtton = false;
  400. this.curProperty = Object.assign({}, object);
  401. },
  402. checkChange(data, { checkedKeys }) {
  403. const checked = checkedKeys.includes(data.id);
  404. if (!data.propertyList || !data.propertyList.length) {
  405. this.multipleSelection = this.$refs.PropertyTree.getCheckedKeys();
  406. if (checked) return;
  407. this.multipleSelection = this.multipleSelection.filter(
  408. (id) => id !== data.parentId
  409. );
  410. this.$refs.PropertyTree.setCheckedKeys(this.multipleSelection);
  411. return;
  412. }
  413. let propsIds = [];
  414. const getPropIds = (propertyList) => {
  415. if (!propertyList || !propertyList.length) return;
  416. propertyList.forEach((item) => {
  417. propsIds.push(item.id);
  418. if (item.propertyList) getPropIds(item.propertyList);
  419. });
  420. };
  421. if (data.propertyList && data.propertyList.length) {
  422. getPropIds(data.propertyList);
  423. if (checked) {
  424. let checkedKeys = this.$refs.PropertyTree.getCheckedKeys();
  425. checkedKeys.push(...propsIds);
  426. const idSet = new Set(checkedKeys);
  427. this.multipleSelection = Array.from(idSet);
  428. this.$refs.PropertyTree.setCheckedKeys(this.multipleSelection);
  429. } else {
  430. let checkedKeys = this.$refs.PropertyTree.getCheckedKeys();
  431. this.multipleSelection = checkedKeys.filter(
  432. (item) => !propsIds.includes(item)
  433. );
  434. this.$refs.PropertyTree.setCheckedKeys(this.multipleSelection);
  435. }
  436. } else {
  437. this.multipleSelection = this.$refs.PropertyTree.getCheckedKeys();
  438. }
  439. },
  440. //查询所有课程
  441. getCourses(query) {
  442. this.courseList = [];
  443. if (query) {
  444. this.courseLoading = true;
  445. this.$httpWithMsg
  446. .get(QUESTION_API + "/course/" + query)
  447. .then((response) => {
  448. var courseBean = response.data;
  449. this.courseList.push(courseBean);
  450. this.courseProperty.name = courseBean.name;
  451. });
  452. } else {
  453. this.courseList = [];
  454. }
  455. },
  456. //查询
  457. searchProperty() {
  458. this.loading = true;
  459. // var coursePropertyStorge = sessionStorage.getItem("courseProperty");
  460. // if (typeof coursePropertyStorge == "string") {
  461. // this.courseProperty = JSON.parse(coursePropertyStorge);
  462. this.getCourses(this.courseProperty.courseId);
  463. // }
  464. // this.$http
  465. // .get(QUESTION_API + "/property/all/" + this.coursePropertyId)
  466. // .then((response) => {
  467. // this.treeData = response.data;
  468. // for (var i = 0; i < this.treeData.length; i++) {
  469. // var property = this.treeData[i];
  470. // this.ids.push(property.id);
  471. // }
  472. // this.loading = false;
  473. // });
  474. this.$httpWithMsg
  475. .post(
  476. QUESTION_API +
  477. "/property/all/by/course?courseId=" +
  478. this.$route.params.id
  479. )
  480. .then((response) => {
  481. this.coursePropertyId = response.data.coursePropertyId;
  482. this.treeData = response.data.propertys;
  483. for (var i = 0; i < this.treeData.length; i++) {
  484. var property = this.treeData[i];
  485. this.ids.push(property.id);
  486. }
  487. this.loading = false;
  488. });
  489. },
  490. getPropertyCode(parentId) {
  491. this.$httpWithMsg
  492. .post(QUESTION_API + "/property/get_code", {
  493. rootOrgId: this.user.rootOrgId,
  494. coursePropertyId: this.coursePropertyId,
  495. parentId,
  496. })
  497. .then((response) => {
  498. this.propertyForm.code = response.data;
  499. });
  500. },
  501. //新增一级
  502. insertParent() {
  503. this.disAllBtn();
  504. this.title = "新增知识点";
  505. this.propertyForm = {
  506. id: "",
  507. code: "",
  508. name: "",
  509. parentId: "0",
  510. number: "",
  511. coursePropertyId: this.coursePropertyId,
  512. remark: "",
  513. };
  514. this.propertyDialog = true;
  515. this.getPropertyCode(0);
  516. },
  517. //新增二级
  518. insertSon() {
  519. this.disAllBtn();
  520. this.title = "新增知识点";
  521. //父对象id赋值
  522. this.propertyForm = {
  523. id: "",
  524. code: "",
  525. name: "",
  526. parentId: this.curProperty.id,
  527. number: "",
  528. coursePropertyId: this.coursePropertyId,
  529. remark: "",
  530. };
  531. this.propertyDialog = true;
  532. this.getPropertyCode(this.curProperty.id);
  533. },
  534. //修改
  535. updateProperty() {
  536. this.disAllBtn();
  537. this.title = "修改知识点";
  538. this.propertyForm = Object.assign({}, this.curProperty);
  539. this.propertyDialog = true;
  540. },
  541. //保存
  542. async submit() {
  543. const res = await this.$refs.propertyForm.validate();
  544. if (res === false) {
  545. return;
  546. }
  547. this.$httpWithMsg
  548. .post(QUESTION_API + "/property/save", this.propertyForm)
  549. .then(() => {
  550. this.$notify({
  551. message: this.propertyForm.id ? "修改成功" : "新增成功",
  552. type: "success",
  553. });
  554. this.propertyDialog = false;
  555. this.searchProperty();
  556. });
  557. // .catch((error) => {
  558. // this.$notify({
  559. // type: "error",
  560. // message: error.response.data.desc,
  561. // });
  562. // });
  563. this.showButton = true;
  564. this.showSonButtton = true;
  565. },
  566. //删除
  567. async deleteProperty() {
  568. this.disAllBtn();
  569. const confirm = await this.$confirm("确认删除知识点吗?", "系统通知", {
  570. type: "warning",
  571. }).catch(() => {});
  572. if (confirm !== "confirm") return;
  573. this.loading = true;
  574. const res = await this.$httpWithMsg
  575. .delete(
  576. QUESTION_API +
  577. "/property/delete/" +
  578. this.multipleSelection.join() +
  579. "/" +
  580. this.coursePropertyId
  581. )
  582. .catch(() => {});
  583. this.loading = false;
  584. if (!res) return;
  585. this.$notify({
  586. message: "删除成功",
  587. type: "success",
  588. });
  589. this.multipleSelection = [];
  590. this.searchProperty();
  591. this.showButton = true;
  592. this.showSonButtton = true;
  593. },
  594. //返回
  595. back() {
  596. // this.$router.push({
  597. // path: "/questions/course_property/1",
  598. // });
  599. this.$router.back();
  600. },
  601. //上移
  602. moveUp() {
  603. this.disAllBtn();
  604. this.$httpWithMsg
  605. .put(QUESTION_API + "/property/moveUp", this.curProperty)
  606. .then(() => {
  607. this.searchProperty();
  608. this.showMoveButtton = true;
  609. })
  610. .catch(() => {
  611. // this.$notify({
  612. // type: "error",
  613. // message: error.response.data.desc,
  614. // });
  615. this.showMoveButtton = true;
  616. });
  617. },
  618. //下移
  619. moveDown() {
  620. this.disAllBtn();
  621. this.$httpWithMsg
  622. .put(QUESTION_API + "/property/moveDown", this.curProperty)
  623. .then(() => {
  624. this.searchProperty();
  625. this.showMoveButtton = true;
  626. })
  627. .catch(() => {
  628. // this.$notify({
  629. // type: "error",
  630. // message: error.response.data.desc,
  631. // });
  632. this.showMoveButtton = true;
  633. });
  634. },
  635. },
  636. };
  637. </script>
  638. <style lang="scss" scoped>
  639. .property-info {
  640. :deep(.el-tree-node__children) {
  641. padding-left: 20px;
  642. }
  643. }
  644. </style>