index.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728
  1. <template>
  2. <div id="moduleManagementEdit">
  3. <div class="boxWidth">
  4. <el-form
  5. label-position="right"
  6. label-width="120px"
  7. :model="listData"
  8. :rules="rules"
  9. ref="listData"
  10. >
  11. <el-form-item label="适用业务层级">
  12. <el-select
  13. v-model="eduType"
  14. placeholder="请选择教育类型"
  15. @change="changeEduType"
  16. >
  17. <el-option
  18. v-for="(item, index) in eduTypeOptions"
  19. :key="index"
  20. :label="item.educationName"
  21. :value="item.id"
  22. >
  23. </el-option>
  24. </el-select>
  25. <el-select
  26. v-model="courType"
  27. placeholder="请选择业务层次"
  28. @change="changecourseType"
  29. >
  30. <el-option
  31. v-for="(item, index) in newCourTypeOptions"
  32. :key="index"
  33. :label="item.businessName"
  34. :value="item.id"
  35. >
  36. </el-option>
  37. </el-select>
  38. <el-popover
  39. ref="popovers"
  40. placement="bottom"
  41. trigger="click"
  42. @show="showHandle"
  43. @hide="hideHandle"
  44. :disabled="courType ? false : true"
  45. >
  46. <el-checkbox-group v-model="sujectArray" class="checkboxSty">
  47. <el-checkbox
  48. v-for="(item, index) in newSujectOption"
  49. :label="item.newId"
  50. :key="index"
  51. >{{ item.subjectName }}</el-checkbox
  52. >
  53. </el-checkbox-group>
  54. <div style="display: block; text-align: center; margin-top: 10px">
  55. <el-button size="mini" type="primary" @click="submitSujectArray"
  56. >确定</el-button
  57. >
  58. </div>
  59. <el-button slot="reference" style="margin-left: 12px"
  60. >请选择科目</el-button
  61. >
  62. </el-popover>
  63. </el-form-item>
  64. <el-form-item label="">
  65. <div :class="changeHeight ? 'ach' : 'clh'">
  66. <div
  67. v-for="(item, index) in newSujectApis"
  68. :key="index"
  69. class="listBoxStys"
  70. >
  71. {{
  72. item.educationName +
  73. " - " +
  74. item.projectName +
  75. " - " +
  76. item.businessName +
  77. " - " +
  78. item.subjectName
  79. }}
  80. <i class="el-icon-error closeIcons" @click="closeType(index)"></i>
  81. </div>
  82. </div>
  83. <el-button
  84. size="mini"
  85. v-if="newSujectApis.length > 1"
  86. @click="changeType"
  87. >{{ changeHeight ? "展开" : "关闭" }}</el-button
  88. >
  89. <!-- <span v-if="newSujectApis.length === 0">未选项目类型</span> -->
  90. </el-form-item>
  91. <el-form-item label="标题前缀" prop="prefixName">
  92. <el-input v-model="listData.prefixName"></el-input>
  93. </el-form-item>
  94. <el-form-item label="模块标题" prop="moduleName">
  95. <el-input v-model="listData.moduleName"></el-input>
  96. </el-form-item>
  97. <el-form-item label="模块封面">
  98. <div class="imgBoxins">
  99. <img :src="$methodsTools.splitImgHost(listData.coverUrl)" alt="" />
  100. <div
  101. class="posimg"
  102. v-if="
  103. listData.coverUrl === null ||
  104. listData.coverUrl === '' ||
  105. listData.coverUrl === undefined
  106. "
  107. >
  108. <label for="uplose">
  109. <i class="el-icon-circle-plus-outline iconStsz"></i
  110. ></label>
  111. <input
  112. ref="file"
  113. type="file"
  114. style="display: none"
  115. id="uplose"
  116. @change="getImgFile"
  117. />
  118. <p>
  119. 注:请上传小于300kb,尺寸为750*440的图片,支持gif、jpg、jpeg、png等类型
  120. </p>
  121. </div>
  122. </div>
  123. <el-button
  124. v-if="
  125. listData.coverUrl !== null &&
  126. listData.coverUrl !== '' &&
  127. listData.coverUrl !== undefined
  128. "
  129. type="danger"
  130. size="mini"
  131. class="margin-top: 20px;"
  132. @click="clearImgs"
  133. >删除</el-button
  134. >
  135. </el-form-item>
  136. <el-form-item label="是否发布" prop="publishStatus">
  137. <el-radio-group v-model="listData.publishStatus">
  138. <el-radio :label="1">是</el-radio>
  139. <el-radio :label="0">否</el-radio>
  140. </el-radio-group>
  141. </el-form-item>
  142. <el-form-item label="管理章">
  143. <div class="dis_plays">
  144. <div>
  145. <el-button size="small" @click="openBoxs">添加章</el-button>
  146. </div>
  147. <div style="color: #f56c6c">
  148. <!-- <span style="margin-right: 10px">节总数:{{ tableData.length }}</span> -->
  149. <!-- <span>总时长:{{ minTimeAll }}分钟</span> -->
  150. </div>
  151. </div>
  152. <el-table
  153. :data="tableData"
  154. border
  155. :header-cell-style="{
  156. 'background-color': '#eee',
  157. padding: '8px',
  158. color: '#333',
  159. }"
  160. :default-sort="{ prop: 'sort', order: 'ascending' }"
  161. >
  162. <template v-for="(item, index) in tableSet">
  163. <el-table-column
  164. :width="item.width"
  165. :key="index"
  166. :label="item.label"
  167. align="center"
  168. :show-overflow-tooltip="true"
  169. header-align="center"
  170. :sortable="item.prop === 'sort'"
  171. sort-by="sort"
  172. :prop="item.prop"
  173. >
  174. <template slot-scope="scope">
  175. <span v-if="item.scope === 'types'">{{
  176. scope.row[item.prop] === 1
  177. ? "录播"
  178. : scope.row[item.prop] === 2
  179. ? "直播"
  180. : scope.row[item.prop] === 3
  181. ? "回放"
  182. : "未知"
  183. }}</span>
  184. <span v-else-if="item.scope === 'Status'">
  185. {{
  186. scope.row[item.prop] === 1
  187. ? "发布"
  188. : scope.row[item.prop] === 0
  189. ? "未发布"
  190. : "未知"
  191. }}
  192. </span>
  193. <div v-else-if="item.scope === 'inputs'">
  194. <el-input-number style="width:50px" size="small" :controls="false" v-model="scope.row[item.prop]" controls-position="right" :min="0"></el-input-number>
  195. </div>
  196. <span v-else>{{ scope.row[item.prop] }}</span></template
  197. >
  198. </el-table-column></template
  199. >
  200. <el-table-column
  201. label="操作"
  202. align="center"
  203. fixed="right"
  204. width="100px"
  205. >
  206. <template slot-scope="scope">
  207. <el-button type="text" @click="delList(scope.row)"
  208. >删除</el-button
  209. >
  210. </template>
  211. </el-table-column>
  212. </el-table>
  213. </el-form-item>
  214. <el-form-item>
  215. <el-button @click="backPage">取消</el-button>
  216. <el-button type="primary" @click="submit('listData')">确定</el-button>
  217. </el-form-item>
  218. </el-form>
  219. </div>
  220. <el-dialog title="添加章" :visible.sync="dialogVisible" width="800px">
  221. <el-table
  222. ref="multipleTable"
  223. :data="boxtableData"
  224. border
  225. @select-all="selectAll"
  226. @select="select"
  227. :row-key="getRowKeys"
  228. :header-cell-style="{
  229. 'background-color': '#eee',
  230. padding: '8px',
  231. color: '#333',
  232. }"
  233. >
  234. <el-table-column
  235. align="center"
  236. type="selection"
  237. width="55"
  238. header-align="center"
  239. :selectable="checkboxT"
  240. :reserve-selection="true"
  241. >
  242. </el-table-column>
  243. <template v-for="(item, index) in tableSet">
  244. <el-table-column
  245. v-if="item.scope !== 'inputs'"
  246. :width="item.width"
  247. :key="index"
  248. :label="item.label"
  249. align="center"
  250. :show-overflow-tooltip="true"
  251. header-align="center"
  252. >
  253. <template slot-scope="scope">
  254. <span v-if="item.scope === 'types'">{{
  255. scope.row[item.prop] === 1
  256. ? "录播"
  257. : scope.row[item.prop] === 2
  258. ? "直播"
  259. : scope.row[item.prop] === 3
  260. ? "回放"
  261. : "未知"
  262. }}</span>
  263. <span v-else-if="item.scope === 'Status'">
  264. {{
  265. scope.row[item.prop] === 1
  266. ? "发布"
  267. : scope.row[item.prop] === 0
  268. ? "未发布"
  269. : "未知"
  270. }}
  271. </span>
  272. <span v-else>{{ scope.row[item.prop] }}</span></template
  273. >
  274. </el-table-column></template
  275. >
  276. </el-table>
  277. <pagination
  278. :total="total"
  279. :pageSize="pageSize"
  280. :currentPage="currentPage"
  281. @handleSizeChange="handleSizeChange"
  282. @handleCurrentChange="handleCurrentChange"
  283. />
  284. <span slot="footer" class="dialog-footer">
  285. <el-button @click="dialogVisible = false">取 消</el-button>
  286. <el-button type="primary" :disabled="activeLists.length === 0" @click="submitForm">确 定</el-button>
  287. </span>
  288. </el-dialog>
  289. </div>
  290. </template>
  291. <script>
  292. import pagination from "@/components/pagination";
  293. export default {
  294. components: { pagination },
  295. data() {
  296. return {
  297. // 弹窗数据
  298. changeHeight: true,
  299. bfImg: "oss/images/avatar/20211013/1634097664410_1397766697",
  300. listData: {
  301. recordingUrl: "",
  302. liveUrl: "",
  303. coverUrl: "oss/images/avatar/20211013/1634097664410_1397766697",
  304. },
  305. eduTypeOptions: [], //教育类型数据
  306. projectTypeOptions: [], //项目类型数据
  307. courTypeOptions: [], //业务层次数据
  308. newCourTypeOptions: [], //当前业务层次数据
  309. sujectOption: [], //科目数据
  310. newSujectOption: [], //当前科目数据数据
  311. eduType: "", //当前选中教育类型
  312. courType: "", //当前选中业务层次
  313. sujectApis: [], //当前存在的科目
  314. newSujectApis: [],
  315. sujectArray: [], //选中的科目
  316. //表单验证
  317. rules: {
  318. prefixName: [
  319. { required: true, message: "请输入标题前缀", trigger: "blur" },
  320. ],
  321. moduleName: [{ required: true, message: "请输入节标题", trigger: "blur" }],
  322. // liveDuration: [
  323. // { required: true, message: "节时长不能为空" },
  324. // { type: "number", message: "节时长必须为数字值" },
  325. // ],
  326. publishStatus: [
  327. { required: true, message: "请选择是否发布", trigger: "change" },
  328. ],
  329. },
  330. numberAll: 0, //节总数
  331. minTimeAll: 0, //总时长
  332. tableSet: [
  333. { label: "排序", prop: "sort", scope: "inputs", width: "100" },
  334. { label: "章编码", prop: "code" },
  335. { label: "标题前缀", prop: "prefixName", width: "120" },
  336. { label: "章标题", prop: "name" },
  337. {
  338. label: "发布状态",
  339. prop: "publishStatus",
  340. scope: "Status",
  341. width: "120",
  342. },
  343. ],
  344. tableData: [],
  345. dialogVisible: false,
  346. boxtableData: [],
  347. total: 0, //一共多少条
  348. pageSize: 10, //每页多少条数据
  349. currentPage: 1, //当前页码
  350. disCheckList: [], //已选转禁用复选列表
  351. activeLists:[],
  352. };
  353. },
  354. watch: {
  355. sujectApis: {
  356. immediate: true,
  357. handler(newName, oldName) {
  358. this.changeTypes();
  359. },
  360. },
  361. },
  362. mounted() {
  363. this.getDict();
  364. this.search();
  365. },
  366. methods: {
  367. getMessage() {
  368. if (!this.courType) {
  369. this.$message.warning("请先选择业务层级");
  370. }
  371. },
  372. openBoxs() {
  373. var self = this;
  374. this.$api
  375. .inquireCourseListchapter({
  376. status: 1,
  377. pageNum: this.currentPage,
  378. pageSize: this.pageSize,
  379. })
  380. .then((res) => {
  381. var aList = [];
  382. this.tableData.map((item) => {
  383. aList.push(item.chapterId);
  384. });
  385. this.disCheckList = aList;
  386. this.boxtableData = res.rows;
  387. this.total = res.total;
  388. this.dialogVisible = true;
  389. this.$nextTick(function () {
  390. self.$refs.multipleTable.clearSelection();
  391. });
  392. });
  393. },
  394. getInfosList() {
  395. this.$api
  396. .inquireCourseListmodulechapter(this.$route.query.id)
  397. .then((result) => {
  398. // this.numberAll = result.total;
  399. // this.minTimeAll = result.timeTotal;
  400. this.tableData = result.data;
  401. });
  402. },
  403. getInfos() {
  404. this.$api
  405. .inquireCourseListchapter({
  406. status: 1,
  407. pageNum: this.currentPage,
  408. pageSize: this.pageSize,
  409. })
  410. .then((res) => {
  411. this.boxtableData = res.rows;
  412. this.total = res.total;
  413. });
  414. },
  415. search() {
  416. this.$api.obtainCoursemodule(this.$route.query.id).then((res) => {
  417. this.bfImg = res.data.coverUrl;
  418. this.listData = res.data;
  419. this.$api
  420. .obtainCoursechapterbusiness(this.$route.query.id)
  421. .then((result) => {
  422. var arrays = [];
  423. result.data.map((item) => {
  424. arrays.push(item.businessId + "-" + item.subjectId);
  425. });
  426. this.sujectApis = arrays;
  427. this.getInfosList();
  428. });
  429. });
  430. },
  431. clearImgs() {
  432. this.listData.coverUrl = "";
  433. },
  434. changeTypes() {
  435. var self = this;
  436. var arrays = [];
  437. this.sujectApis.map((item, index) => {
  438. this.courTypeOptions.map((items) => {
  439. if (items.id === item.split("-").map(Number)[0]) {
  440. var obj = {
  441. educationTypeId: items.educationId,
  442. educationName: items.educationName,
  443. projectId: items.projectId,
  444. projectName: items.projectName,
  445. businessId: items.id,
  446. businessName: items.businessName,
  447. };
  448. self.sujectOption.map((i) => {
  449. if (
  450. i.id === item.split("-").map(Number)[1] &&
  451. i.courseArrays.indexOf(items.projectId) !== -1
  452. ) {
  453. obj.subjectName = i.subjectName;
  454. obj.subjectId = i.id;
  455. }
  456. });
  457. arrays.push(obj);
  458. }
  459. });
  460. });
  461. this.newSujectApis = arrays;
  462. },
  463. changeType() {
  464. this.changeHeight = !this.changeHeight;
  465. },
  466. submitSujectArray() {
  467. var self = this;
  468. this.sujectApis = this.sujectApis.filter((item, index) => {
  469. return item.split("-").map(Number)[0] !== Number(self.courType);
  470. });
  471. for (let i = 0; i < this.sujectArray.length; i++) {
  472. this.sujectApis.push(this.sujectArray[i]);
  473. }
  474. this.$refs.popovers.doClose();
  475. },
  476. showHandle() {
  477. var array = [];
  478. for (let i = 0; i < this.sujectApis.length; i++) {
  479. if (
  480. this.sujectApis[i].split("-").map(Number)[0] === Number(this.courType)
  481. ) {
  482. array.push(this.sujectApis[i]);
  483. }
  484. }
  485. this.sujectArray = array;
  486. this.newSujectOption.map((item) => {
  487. item.newId = this.courType + "-" + item.id;
  488. });
  489. },
  490. hideHandle() {},
  491. getDict() {
  492. this.$api.inquireCourseEducationType({ status: 1 }).then((res) => {
  493. this.eduTypeOptions = res.rows;
  494. });
  495. this.$api.inquireCourseProjectType({ status: 1 }).then((res) => {
  496. this.projectTypeOptions = res.rows;
  497. });
  498. this.$api.inquirebusinessList({ status: 1 }).then((res) => {
  499. this.courTypeOptions = res.rows;
  500. this.newCourTypeOptions = res.rows;
  501. });
  502. this.$api.inquireCourseSubject({ status: 1 }).then((res) => {
  503. res.rows.map((item, index) => {
  504. var array = [];
  505. item.courseProjectTypes.map((items, indexs) => {
  506. array.push(items.id);
  507. });
  508. item.courseArrays = array;
  509. });
  510. this.sujectOption = res.rows;
  511. });
  512. },
  513. changeEduType() {
  514. if (!(this.courType === undefined || this.courType === "")) {
  515. this.courType = "";
  516. }
  517. var arrays = [];
  518. this.courTypeOptions.map((item) => {
  519. if (item.educationId === this.eduType) {
  520. arrays.push(item);
  521. }
  522. });
  523. this.newCourTypeOptions = arrays;
  524. },
  525. changecourseType() {
  526. this.newCourTypeOptions.map((item, index) => {
  527. if (item.id === this.courType) {
  528. this.eduType = item.educationId;
  529. var array = [];
  530. this.sujectOption.map((items, indexs) => {
  531. if (items.courseArrays.indexOf(item.projectId) !== -1) {
  532. array.push(items);
  533. }
  534. });
  535. this.newSujectOption = array;
  536. }
  537. });
  538. var arrays = [];
  539. this.courTypeOptions.map((item) => {
  540. if (item.educationId === this.eduType) {
  541. arrays.push(item);
  542. }
  543. });
  544. this.newCourTypeOptions = arrays;
  545. this.$refs.popovers.doClose();
  546. },
  547. submit(formName) {
  548. this.$refs[formName].validate((valid) => {
  549. if (valid) {
  550. if (
  551. this.listData.coverUrl === "" ||
  552. this.listData.coverUrl === null ||
  553. this.listData.coverUrl === undefined
  554. ) {
  555. this.$message.error("请上传节封面");
  556. return false;
  557. }
  558. this.rulesTableSumbit();
  559. } else {
  560. return false;
  561. }
  562. });
  563. },
  564. async rulesTableSumbit() {
  565. var chapterIdList = []
  566. this.tableData.map(item => {
  567. chapterIdList.push({chapterId:item.chapterId,sort:Number(item.sort)})
  568. })
  569. var dataInfos = {
  570. status: 1,
  571. moduleId: this.$route.query.id,
  572. businessList: this.newSujectApis,
  573. chapterIdList:chapterIdList,
  574. coverUrl: this.listData.coverUrl,
  575. moduleName: this.listData.moduleName,
  576. prefixName: this.listData.prefixName,
  577. publishStatus: this.listData.publishStatus,
  578. };
  579. this.$api.editCoursemodule(dataInfos).then((res) => {
  580. this.$message.success("修改成功");
  581. setTimeout(() => {
  582. this.$router.go(-1);
  583. }, 500);
  584. });
  585. },
  586. backPage() {
  587. this.$router.go(-1);
  588. },
  589. closeType(index) {
  590. this.sujectApis.splice(index, 1);
  591. },
  592. getImgFile() {
  593. var self = this;
  594. var file = self.$refs.file.files[0];
  595. if (file === undefined) {
  596. self.$set(self.listData, "coverUrl", "");
  597. return;
  598. }
  599. if (file.size > 0.3 * 1024 * 1024) {
  600. self.$message.error("图片不得大于300kb");
  601. return;
  602. }
  603. var type = self.$refs.file.value.toLowerCase().split(".").splice(-1);
  604. if (
  605. type[0] != "jpg" &&
  606. type[0] != "png" &&
  607. type[0] != "jpeg" &&
  608. type[0] != "gif"
  609. ) {
  610. self.$message.error("上传格式需为:.jpg/.png/.jpeg/gif");
  611. self.$refs.file.value = "";
  612. return;
  613. }
  614. this.$upload.upload(file, 0).then((res) => {
  615. self.listData.coverUrl = res;
  616. });
  617. },
  618. handleSizeChange(v) {
  619. this.pageSize = v;
  620. this.currentPage = 1;
  621. this.getInfos();
  622. },
  623. handleCurrentChange(v) {
  624. this.currentPage = v;
  625. this.getInfos();
  626. },
  627. selectAll(value) {
  628. this.activeLists = value;
  629. },
  630. select(value) {
  631. this.activeLists = value;
  632. },
  633. checkboxT(row, index) {
  634. if (this.disCheckList.indexOf(row.chapterId) !== -1) {
  635. return false;
  636. } else {
  637. return true;
  638. }
  639. },
  640. getRowKeys(row) {
  641. return row.chapterId;
  642. },
  643. submitForm() {
  644. if (this.activeLists.length === 0) {
  645. this.dialogVisible = false;
  646. return;
  647. }
  648. this.tableData = this.tableData.concat(this.activeLists);
  649. this.dialogVisible = false;
  650. this.$message.success("添加成功");
  651. this.activeLists = [];
  652. },
  653. delList(item) {
  654. this.tableData.map((items,indexs) => {
  655. if(items.chapterId === item.chapterId){
  656. this.tableData.splice(indexs,1)
  657. this.$message.success("删除成功");
  658. }
  659. })
  660. },
  661. },
  662. };
  663. </script>
  664. <style lang="less" scoped>
  665. .boxWidth {
  666. width: 800px;
  667. }
  668. .numInputs {
  669. width: 150px;
  670. }
  671. .checkboxSty {
  672. max-height: 210px;
  673. overflow: auto;
  674. display: flex;
  675. flex-direction: column;
  676. }
  677. .listBoxStys {
  678. flex-shrink: 0;
  679. padding: 0px 10px;
  680. border-radius: 8px;
  681. border: 1px solid #eee;
  682. margin-right: 10px;
  683. margin-bottom: 6px;
  684. }
  685. .closeIcons {
  686. color: red;
  687. cursor: pointer;
  688. margin-left: 6px;
  689. }
  690. .ach {
  691. display: flex;
  692. align-items: center;
  693. overflow: hidden;
  694. }
  695. .clh {
  696. display: flex;
  697. align-items: center;
  698. flex-wrap: wrap;
  699. }
  700. .imgBoxins {
  701. width: 375px;
  702. height: 220px;
  703. text-align: center;
  704. img {
  705. height: 100%;
  706. }
  707. }
  708. .iconStsz {
  709. font-size: 40px;
  710. color: #67c23a;
  711. cursor: pointer;
  712. }
  713. .dis_plays {
  714. display: flex;
  715. align-items: center;
  716. justify-content: space-between;
  717. margin-bottom: 10px;
  718. }
  719. .comInputsty {
  720. width: 50px;
  721. height: 24px;
  722. text-align: center;
  723. border: none;
  724. }
  725. </style>