accompanyList.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694
  1. <template>
  2. <div class>
  3. <!-- <h2>
  4. <div class="squrt"></div>网管课列表
  5. </h2>-->
  6. <div class="topWrap">
  7. <div
  8. class="newBand"
  9. v-permission="'export/practiceGroup'"
  10. @click="onStudentExport"
  11. style="width: 150px; max-width: 150px"
  12. >
  13. 续费提醒导出
  14. </div>
  15. <div
  16. class="newBand"
  17. v-permission="'export/practiceGroupList'"
  18. @click="onPracticeExport"
  19. style="width: 120px"
  20. >
  21. 网管课导出
  22. </div>
  23. <div
  24. class="newBand"
  25. v-permission="'/newPractice'"
  26. @click="newPractice"
  27. style="width: 120px"
  28. >
  29. 新建网管课
  30. </div>
  31. </div>
  32. <div class="m-core">
  33. <save-form
  34. :inline="true"
  35. class="searchForm"
  36. save-key="accompanyList"
  37. @submit="search"
  38. @reset="onReSet"
  39. :model.sync="searchForm"
  40. >
  41. <!-- 状态 指导老师 活动方案-->
  42. <el-form-item>
  43. <el-input
  44. v-model.trim="searchForm.search"
  45. clearable
  46. placeholder="课程组名称"
  47. ></el-input>
  48. </el-form-item>
  49. <el-form-item>
  50. <el-select
  51. class="multiple"
  52. v-model.trim="searchForm.organIdList"
  53. filterable
  54. clearable
  55. placeholder="请选择分部"
  56. >
  57. <el-option
  58. v-for="(item, index) in selects.branchs"
  59. :key="index"
  60. :label="item.name"
  61. :value="item.id"
  62. ></el-option>
  63. </el-select>
  64. </el-form-item>
  65. <el-form-item>
  66. <el-select
  67. v-model.trim="searchForm.practiceGroupType"
  68. clearable
  69. filterable
  70. placeholder="课程组类型"
  71. >
  72. <el-option
  73. v-for="(item, index) in practiceGroupType"
  74. :key="index"
  75. :value="item.value"
  76. :label="item.label"
  77. ></el-option>
  78. </el-select>
  79. </el-form-item>
  80. <el-form-item prop="status">
  81. <el-select
  82. class="multiple"
  83. v-model.trim="searchForm.hasEducationalTeacherId"
  84. filterable
  85. clearable
  86. placeholder="是否有乐团主管"
  87. >
  88. <el-option label="是" value="true"></el-option>
  89. <el-option label="否" value="false"></el-option>
  90. </el-select>
  91. </el-form-item>
  92. <el-form-item>
  93. <remote-search
  94. :commit="'setTeachers'"
  95. v-model="searchForm.teacherId"
  96. />
  97. </el-form-item>
  98. <el-form-item>
  99. <el-select
  100. v-model.trim="searchForm.groupStatus"
  101. clearable
  102. filterable
  103. placeholder="课程组状态"
  104. >
  105. <el-option
  106. v-for="(item, index) in commGroupStatus"
  107. :key="index"
  108. :value="item.value"
  109. :label="item.label"
  110. ></el-option>
  111. </el-select>
  112. </el-form-item>
  113. <el-form-item>
  114. <el-select
  115. v-model.trim="searchForm.firstOrRenew"
  116. clearable
  117. filterable
  118. placeholder="是否续费"
  119. >
  120. <el-option label="首充" value="1"></el-option>
  121. <el-option label="续费" value="0"></el-option>
  122. <el-option label="免费" value="2"></el-option>
  123. </el-select>
  124. </el-form-item>
  125. <el-form-item>
  126. <el-button native-type="submit" type="danger">搜索</el-button>
  127. <el-button native-type="reset" type="primary">重置</el-button>
  128. </el-form-item>
  129. </save-form>
  130. <!-- tab -->
  131. <div class="tableWrap">
  132. <el-table
  133. style="width: 100%"
  134. :header-cell-style="{ background: '#EDEEF0', color: '#444' }"
  135. :data="tableData"
  136. >
  137. <el-table-column
  138. align="center"
  139. prop="id"
  140. label="课程组编号"
  141. width="100"
  142. >
  143. <template slot-scope="scope">
  144. <copy-text>{{ scope.row.id }}</copy-text>
  145. </template>
  146. </el-table-column>
  147. <el-table-column
  148. align="center"
  149. prop="name"
  150. label="课程组名称"
  151. width="100"
  152. >
  153. <template slot-scope="scope">
  154. <copy-text>{{ scope.row.name }}</copy-text>
  155. </template>
  156. </el-table-column>
  157. <el-table-column
  158. align="center"
  159. prop="type"
  160. label="课程组类型"
  161. width="100"
  162. >
  163. <template slot-scope="scope">
  164. <div>
  165. <p>{{ scope.row.type | comType }}</p>
  166. </div>
  167. </template>
  168. </el-table-column>
  169. <el-table-column align="center" prop="organName" label="所属分部">
  170. <template slot-scope="scope">
  171. <copy-text>{{ scope.row.organName }}</copy-text>
  172. </template>
  173. </el-table-column>
  174. <!-- educationalTeacherId -->
  175. <el-table-column
  176. align="center"
  177. prop="educationalTeacherName"
  178. label="乐团主管"
  179. ></el-table-column>
  180. <el-table-column align="center" prop="teacherName" label="指导老师">
  181. <template slot-scope="scope">
  182. <copy-text>{{ scope.row.teacherName }}</copy-text>
  183. </template>
  184. </el-table-column>
  185. <el-table-column
  186. align="center"
  187. prop="studentNum"
  188. label="班级人数"
  189. ></el-table-column>
  190. <!-- <el-table-column align="center" label="课程单价">
  191. <template slot-scope="scope">
  192. <div>
  193. <p>线上:{{scope.row.onlineClassesUnitPrice}}</p>
  194. <p>线下:{{scope.row.offlineClassesUnitPrice}}</p>
  195. </div>
  196. </template>
  197. </el-table-column>-->
  198. <el-table-column align="center" label="当前课次">
  199. <template slot-scope="scope">
  200. <div>
  201. <p>
  202. {{
  203. scope.row.currentClassTimes +
  204. "/" +
  205. scope.row.totalClassTimes
  206. }}
  207. </p>
  208. </div>
  209. </template>
  210. </el-table-column>
  211. <el-table-column
  212. align="center"
  213. prop="coursesStartDate"
  214. label="开课时间"
  215. width="120"
  216. >
  217. <template slot-scope="scope">
  218. <div>
  219. <p>{{ scope.row.coursesStartDate | formatTimer }}</p>
  220. </div>
  221. </template>
  222. </el-table-column>
  223. <el-table-column
  224. align="center"
  225. prop="coursesExpireDate"
  226. label="结束时间"
  227. width="120"
  228. >
  229. <template slot-scope="scope">
  230. <div>
  231. <p>{{ scope.row.coursesExpireDate | formatTimer }}</p>
  232. </div>
  233. </template>
  234. </el-table-column>
  235. <el-table-column
  236. align="center"
  237. prop="groupStatus"
  238. label="课程组状态"
  239. width="100"
  240. >
  241. <template slot-scope="scope">
  242. <div>
  243. <p>{{ scope.row.groupStatus | comCourseGroup }}</p>
  244. </div>
  245. </template>
  246. </el-table-column>
  247. <el-table-column align="center" label="是否续费" fixed="right">
  248. <template slot-scope="scope">
  249. <div>
  250. <p v-if="scope.row.type=='FREE'|| scope.row.type=='CARE_PACKAGE' || scope.row.type=='TRIAL' " >免费</p>
  251. <p v-if="scope.row.type=='CHARGE'||scope.row.type=='COME_ON_PACKAGE'">
  252. {{ scope.row.beRenewGroupId > 0 ? "续费" : "首充" }}
  253. </p>
  254. </div>
  255. </template>
  256. </el-table-column>
  257. <el-table-column width="150" prop="memo" label="备注" fixed="right">
  258. <template slot-scope="scope">
  259. <overflow-text
  260. :text="scope.row.memo"
  261. width="150px"
  262. ></overflow-text>
  263. </template>
  264. </el-table-column>
  265. <el-table-column
  266. align="center"
  267. width="200"
  268. fixed="right"
  269. label="操作"
  270. >
  271. <template slot-scope="scope">
  272. <div>
  273. <!-- v-permission="'courseSchedule/classStartDateAdjust'" v-if="!scope.row.isSettlement" -->
  274. <el-button
  275. type="text"
  276. @click="lookCrouse(scope.row)"
  277. v-if="permission('/accompanys')"
  278. >查看</el-button
  279. >
  280. <el-button
  281. type="text"
  282. v-if="
  283. scope.row.groupStatus == 'NORMAL' &&
  284. permission('practiceGroupManage/cancelGroup')
  285. "
  286. @click="closeCrouse(scope.row)"
  287. >关闭</el-button
  288. >
  289. <el-button
  290. type="text"
  291. v-if="permission('practiceGroupManage/updateMemo')"
  292. @click="resetMemo(scope.row)"
  293. >修改备注</el-button
  294. >
  295. </div>
  296. </template>
  297. </el-table-column>
  298. </el-table>
  299. <pagination
  300. save-key="accompanyList"
  301. sync
  302. :total.sync="rules.total"
  303. :page.sync="rules.page"
  304. :limit.sync="rules.limit"
  305. :page-sizes="rules.page_size"
  306. @pagination="getList"
  307. />
  308. </div>
  309. </div>
  310. <!-- <el-dialog title="关闭课程组" width="400px" :visible.sync="closeVisible">
  311. <el-form
  312. :model="closeForm"
  313. ref="closeForm"
  314. label-position="right"
  315. label-width="80px;"
  316. :inline="true"
  317. >
  318. <el-form-item label="是否退费" prop="isBasck">
  319. <el-radio v-model="closeForm.isBack" :label="true">是</el-radio>
  320. <el-radio v-model="closeForm.isBack" :label="false">否</el-radio>
  321. </el-form-item>
  322. <el-form-item label="退费金额" v-if="closeForm.isBack" prop="money">
  323. <el-input
  324. type="number"
  325. @mousewheel.native.prevent
  326. v-model.trim="closeForm.money"
  327. ></el-input>
  328. </el-form-item>
  329. </el-form>
  330. <div slot="footer" class="dialog-footer">
  331. <el-button @click="closeVisible = false">取 消</el-button>
  332. <el-button type="primary" @click="submieCloseCrouse">确 定</el-button>
  333. </div>
  334. </el-dialog> -->
  335. <el-dialog title="备注" width="400px" :visible.sync="memoVisible">
  336. <el-input
  337. type="textarea"
  338. v-model.trim="memoForm.memo"
  339. :rows="7"
  340. :maxlength="255"
  341. show-word-limit
  342. ></el-input>
  343. <div slot="footer" class="dialog-footer">
  344. <el-button @click="memoVisible = false">取 消</el-button>
  345. <el-button type="primary" @click="subMemo">确 定</el-button>
  346. </div>
  347. </el-dialog>
  348. </div>
  349. </template>
  350. <script>
  351. import pagination from "@/components/Pagination/index";
  352. import { Searchs } from "@/helpers";
  353. import { permission } from "@/utils/directivePage";
  354. import cleanDeep from "clean-deep";
  355. import { commGroupStatus, practiceGroupType } from "@/utils/searchArray";
  356. import {
  357. getEmployeeOrgan,
  358. practiceGroupManage,
  359. cancelGroup,
  360. practiceUpdateMemo,
  361. } from "@/api/buildTeam";
  362. import axios from "axios";
  363. import { getToken } from "@/utils/auth";
  364. import load from "@/utils/loading";
  365. export default {
  366. components: { pagination },
  367. data() {
  368. return {
  369. searchForm: {
  370. search: null,
  371. status: null,
  372. teacherId: null,
  373. organIdList: null,
  374. firstOrRenew: null,
  375. practiceGroupType: null,
  376. groupStatus: null,
  377. },
  378. closeForm: {
  379. isBack: false,
  380. money: null,
  381. },
  382. memoForm: {
  383. memo: "",
  384. groupId: "",
  385. },
  386. memoVisible: false,
  387. closeVisible: false,
  388. activeRow: null,
  389. organList: [],
  390. statusList: [],
  391. teacherList: [],
  392. tableData: [],
  393. practiceGroupType: practiceGroupType,
  394. commGroupStatus: commGroupStatus,
  395. rules: {
  396. // 分页规则
  397. limit: 10, // 限制显示条数
  398. page: 1, // 当前页
  399. total: 0, // 总条数
  400. page_size: [10, 20, 40, 50], // 选择限制显示条数
  401. },
  402. };
  403. },
  404. mounted() {
  405. const { query } = this.$route;
  406. if (query.search) {
  407. this.searchForm.search = query.search;
  408. }
  409. this.init();
  410. },
  411. activated() {
  412. this.init();
  413. },
  414. methods: {
  415. init() {
  416. this.$store.dispatch("setBranchs");
  417. this.getList();
  418. },
  419. permission(str, parent) {
  420. return permission(str, parent);
  421. },
  422. search() {
  423. this.rules.page = 1;
  424. this.getList();
  425. },
  426. onReSet() {
  427. this.searchForm = {
  428. search: null,
  429. status: null,
  430. teacherId: null,
  431. organIdList: null,
  432. firstOrRenew: null,
  433. practiceGroupType: null,
  434. groupStatus: null,
  435. };
  436. new Searchs().removeByKey('accompanyList');
  437. this.search();
  438. },
  439. onStudentExport() {
  440. // 导出VIP课
  441. // let searchForm = this.searchForm;
  442. let data = {
  443. // teacherId: searchForm.teacherId || null,
  444. // activityId: searchForm.activityId || null,
  445. // organId: searchForm.orgin || null,
  446. // status: searchForm.status || null,
  447. // search: searchForm.search || null
  448. };
  449. let url = "/api-web/export/practiceGroup";
  450. const options = {
  451. method: "get",
  452. headers: {
  453. Authorization: getToken(),
  454. },
  455. params: data,
  456. url,
  457. responseType: "blob",
  458. };
  459. this.$confirm("网管课续费提醒导出?", "提示", {
  460. confirmButtonText: "确定",
  461. cancelButtonText: "取消",
  462. type: "warning",
  463. })
  464. .then(() => {
  465. load.startLoading();
  466. axios(options)
  467. .then((res) => {
  468. let blob = new Blob([res.data], {
  469. // type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8'
  470. type: "application/vnd.ms-excel;charset=utf-8",
  471. //word文档为application/msword,pdf文档为application/pdf,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8
  472. });
  473. let text = new Response(blob).text();
  474. text.then((res) => {
  475. // 判断是否报错
  476. if (res.indexOf("code") != -1) {
  477. let json = JSON.parse(res);
  478. this.$message.error(json.msg);
  479. } else {
  480. let objectUrl = URL.createObjectURL(blob);
  481. let link = document.createElement("a");
  482. let fname = "网管课续费提醒" + new Date().getTime() + ".xls"; //下载文件的名字
  483. link.href = objectUrl;
  484. link.setAttribute("download", fname);
  485. document.body.appendChild(link);
  486. link.click();
  487. }
  488. });
  489. load.endLoading();
  490. })
  491. .catch((error) => {
  492. this.$message.error("导出数据失败,请联系管理员");
  493. load.endLoading();
  494. });
  495. })
  496. .catch(() => {});
  497. },
  498. onPracticeExport() {
  499. // 导出VIP课
  500. let searchForm = this.searchForm;
  501. let obj = {
  502. search: searchForm.search || null,
  503. teacherId: searchForm.teacherId || null,
  504. organId: searchForm.organIdList || null,
  505. hasEducationalTeacherId: searchForm.hasEducationalTeacherId || null,
  506. type: searchForm.firstOrRenew || null,
  507. practiceGroupType: searchForm.practiceGroupType || null,
  508. groupStatus: searchForm.groupStatus || null,
  509. };
  510. let url = "/api-web/export/practiceGroupList";
  511. const options = {
  512. method: "get",
  513. headers: {
  514. Authorization: getToken(),
  515. },
  516. params: cleanDeep(obj),
  517. url,
  518. responseType: "blob",
  519. };
  520. this.$confirm("网管课导出?", "提示", {
  521. confirmButtonText: "确定",
  522. cancelButtonText: "取消",
  523. type: "warning",
  524. })
  525. .then(() => {
  526. load.startLoading();
  527. axios(options)
  528. .then((res) => {
  529. let blob = new Blob([res.data], {
  530. // type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8'
  531. type: "application/vnd.ms-excel;charset=utf-8",
  532. //word文档为application/msword,pdf文档为application/pdf,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8
  533. });
  534. let text = new Response(blob).text();
  535. text.then((res) => {
  536. // 判断是否报错
  537. if (res.indexOf("code") != -1) {
  538. let json = JSON.parse(res);
  539. this.$message.error(json.msg);
  540. } else {
  541. let objectUrl = URL.createObjectURL(blob);
  542. let link = document.createElement("a");
  543. let fname = "网管课" + new Date().getTime() + ".xls"; //下载文件的名字
  544. link.href = objectUrl;
  545. link.setAttribute("download", fname);
  546. document.body.appendChild(link);
  547. link.click();
  548. }
  549. });
  550. load.endLoading();
  551. })
  552. .catch((error) => {
  553. this.$message.error("导出数据失败,请联系管理员");
  554. load.endLoading();
  555. });
  556. })
  557. .catch(() => {});
  558. },
  559. getList() {
  560. let obj = {
  561. search: this.searchForm.search || null,
  562. teacherId: this.searchForm.teacherId || null,
  563. organId: this.searchForm.organIdList || null,
  564. page: this.rules.page,
  565. rows: this.rules.limit,
  566. hasEducationalTeacherId:
  567. this.searchForm.hasEducationalTeacherId || null,
  568. type: this.searchForm.firstOrRenew || null,
  569. practiceGroupType: this.searchForm.practiceGroupType || null,
  570. groupStatus: this.searchForm.groupStatus || null,
  571. };
  572. practiceGroupManage(obj).then((res) => {
  573. if (res.code == 200) {
  574. this.tableData = res.data.rows;
  575. this.rules.total = res.data.total;
  576. }
  577. });
  578. },
  579. lookCrouse(row) {
  580. let coursesStartDate = this.$helpers
  581. .dayjs(row.coursesStartDate)
  582. .format("YYYY-MM-DD");
  583. let coursesExpireDate = this.$helpers
  584. .dayjs(row.coursesExpireDate)
  585. .format("YYYY-MM-DD");
  586. this.$router.push({
  587. path: "/business/accompanys",
  588. query: {
  589. id: row.id,
  590. type: row.type,
  591. coursesStartDate,
  592. coursesExpireDate,
  593. },
  594. });
  595. },
  596. closeCrouse(row) {
  597. this.activeRow = row;
  598. this.$confirm("请确认是否关闭课程组,关闭后不予退费", "提示", {
  599. confirmButtonText: "确定",
  600. cancelButtonText: "取消",
  601. type: "warning",
  602. }).then(res=>{
  603. cancelGroup({
  604. groupId: row.id,
  605. groupType: "PRACTICE",
  606. refundAmount: null,
  607. }).then((res) => {
  608. if (res.code == 200) {
  609. this.$message.success("关闭成功");
  610. this.getList();
  611. // this.closeVisible = false;
  612. }
  613. });
  614. }).catch(()=>{})
  615. // this.closeVisible = true;
  616. },
  617. courseVisibleClose() {
  618. // 关闭弹窗前
  619. },
  620. submieCloseCrouse() {
  621. // 提交关闭课程组
  622. if (this.closeForm.isBack) {
  623. if (!this.closeForm.money) {
  624. this.$message.error("请输入退费金额");
  625. return;
  626. }
  627. } else {
  628. this.closeForm.money = null;
  629. }
  630. // 请求数据
  631. cancelGroup({
  632. groupId: this.activeRow.id,
  633. groupType: "PRACTICE",
  634. refundAmount: this.closeForm.money,
  635. }).then((res) => {
  636. if (res.code == 200) {
  637. this.$message.success("关闭成功");
  638. this.getList();
  639. this.closeVisible = false;
  640. }
  641. });
  642. },
  643. resetMemo(row) {
  644. this.$set(this.memoForm, "memo", row.memo);
  645. this.$set(this.memoForm, "groupId", row.id);
  646. this.memoVisible = true;
  647. },
  648. subMemo() {
  649. practiceUpdateMemo(this.memoForm).then((res) => {
  650. if (res.code == 200) {
  651. this.$message.success("修改成功");
  652. this.memoVisible = false;
  653. this.getList();
  654. }
  655. });
  656. },
  657. newPractice() {
  658. this.$router.push({
  659. path: "/business/newPractice",
  660. query:{courseType:'PRACTICE'}
  661. });
  662. },
  663. },
  664. watch: {
  665. closeVisible(val) {
  666. if (!val) {
  667. this.activeRow = null;
  668. (this.closeForm = {
  669. isBack: false,
  670. money: null,
  671. }),
  672. this.$refs.closeForm.resetFields();
  673. this.closeVisible = false;
  674. }
  675. },
  676. },
  677. };
  678. </script>
  679. <style lang='scss' scoped>
  680. .topWrap {
  681. display: flex;
  682. flex-direction: row;
  683. justify-content: flex-start;
  684. div {
  685. margin-right: 10px;
  686. }
  687. }
  688. </style>