vipStudentList.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646
  1. <template>
  2. <div>
  3. <div
  4. class="newBand"
  5. v-permission="'vipGroupManage/addVipGroupStudents'"
  6. @click="addStudentList"
  7. >
  8. 新增学员
  9. </div>
  10. <div class="tableWrap">
  11. <el-table
  12. :data="tableList"
  13. :header-cell-style="{ background: '#EDEEF0', color: '#444' }"
  14. >
  15. <el-table-column
  16. label="学员姓名"
  17. prop="userName"
  18. align="center"
  19. width="180"
  20. >
  21. </el-table-column>
  22. <el-table-column label="手机号" align="center" prop="phone" width="180">
  23. </el-table-column>
  24. <el-table-column prop="studentStatus" align="center" label="学员状态">
  25. <template slot-scope="scope">
  26. <div>
  27. {{ scope.row.studentStatus | studentStatus }}
  28. </div>
  29. </template>
  30. </el-table-column>
  31. <el-table-column prop="courseSalary" align="center" label="课程余额">
  32. <template slot-scope="scope">
  33. <div>
  34. {{ scope.row.courseSalary | moneyFormat }}
  35. </div>
  36. </template>
  37. </el-table-column>
  38. <el-table-column prop="applyDate" align="center" label="报名时间">
  39. <template slot-scope="scope">
  40. <div>
  41. {{ scope.row.applyDate | formatTimer }}
  42. </div>
  43. </template>
  44. </el-table-column>
  45. <el-table-column prop="refundDate" align="center" label="退课时间">
  46. <template slot-scope="scope">
  47. <div>
  48. {{ scope.row.refundDate | formatTimer }}
  49. </div>
  50. </template>
  51. </el-table-column>
  52. <el-table-column label="操作" align="center">
  53. <template slot-scope="scope">
  54. <div>
  55. <el-button
  56. type="text"
  57. v-if="
  58. scope.row.studentStatus == 0 || scope.row.studentStatus == 3
  59. "
  60. v-permission="'vipGroupManage/applyRefundForStudent'"
  61. @click="lookFee(scope)"
  62. >退学</el-button
  63. >
  64. <el-button
  65. type="text"
  66. v-if="scope.row.studentStatus == 0"
  67. @click="stopCourse(scope)"
  68. >休学</el-button
  69. >
  70. <el-button
  71. type="text"
  72. v-if="scope.row.studentStatus == 3"
  73. @click="recoveryCourse(scope)"
  74. >恢复</el-button
  75. >
  76. </div>
  77. </template>
  78. </el-table-column>
  79. </el-table>
  80. </div>
  81. <el-dialog title="学员列表" width="70%" :visible.sync="maskVisible">
  82. <el-form :model="maskForm" :inline="true">
  83. <el-form-item>
  84. <el-input
  85. placeholder="请输入学生姓名或手机号"
  86. @keyup.enter.native="search"
  87. v-model.trim="maskForm.search"
  88. ></el-input>
  89. </el-form-item>
  90. <el-form-item>
  91. <el-button type="danger" @click="search">搜索</el-button>
  92. </el-form-item>
  93. <el-form-item>
  94. <el-button type="primary" @click="reset">重置</el-button>
  95. </el-form-item>
  96. </el-form>
  97. <el-table
  98. :data="maskStudentList"
  99. :header-cell-style="{ background: '#EDEEF0', color: '#444' }"
  100. >
  101. <el-table-column label="" width="55">
  102. <template slot-scope="scope">
  103. <el-radio
  104. v-model.trim="activeStudent"
  105. :label="scope.row.id"
  106. @change.native="getTemplateRow(scope.$index, scope.row)"
  107. >&nbsp</el-radio
  108. >
  109. </template>
  110. </el-table-column>
  111. <el-table-column
  112. prop="userName"
  113. align="center"
  114. label="学生姓名"
  115. width="150"
  116. ></el-table-column>
  117. <el-table-column
  118. prop="phone"
  119. align="center"
  120. label="手机号"
  121. width="200"
  122. ></el-table-column>
  123. <el-table-column prop="courseSalary" label="课程余额"></el-table-column>
  124. </el-table>
  125. <pagination
  126. save-key='vipDetail-vipStudentList'
  127. sync
  128. :total.sync="rules.total"
  129. :page.sync="rules.page"
  130. :limit.sync="rules.limit"
  131. :page-sizes="rules.page_size"
  132. @pagination="getList"
  133. />
  134. <div slot="footer" class="dialog-footer">
  135. <el-button @click="maskVisible = false">取 消</el-button>
  136. <el-button type="primary" @click="addStudent">确 定</el-button>
  137. </div>
  138. </el-dialog>
  139. <el-dialog title="学员复学" width="800px" :visible.sync="adjustmentVisible">
  140. <el-form
  141. :model="adjustmentForm"
  142. label-position="right"
  143. label-width="120px"
  144. ref="adjustmentForm"
  145. :rules="adjustmentRules"
  146. :inline="true"
  147. >
  148. <el-form-item label="剩余课时">
  149. <el-input
  150. disabled
  151. v-model.trim="adjustmentForm.count"
  152. style="width: 200px !important"
  153. ></el-input>
  154. </el-form-item>
  155. <el-form-item label="任课老师" prop="teacher">
  156. <el-select
  157. v-model.trim="adjustmentForm.teacher"
  158. clearable
  159. filterable
  160. style="width: 200px !important"
  161. >
  162. <el-option
  163. v-for="(item, index) in teacherList"
  164. :key="index"
  165. :label="item.realName"
  166. :value="item.id"
  167. ></el-option>
  168. </el-select>
  169. </el-form-item>
  170. <!-- <br /> -->
  171. <el-form-item label="排课起始时间" prop="courseTime">
  172. <el-date-picker
  173. v-model.trim="adjustmentForm.courseTime"
  174. @change="changeCourseTime"
  175. :picker-options="pickerOptions"
  176. style="width: 200px !important"
  177. type="date"
  178. value-format="yyyy-MM-dd"
  179. placeholder="选择日期"
  180. >
  181. </el-date-picker>
  182. </el-form-item>
  183. <!-- vipGroupManage/recoverForStudent1 -->
  184. <el-form-item label="剩余有效期" prop="days">
  185. <el-input-number :controls='false'
  186. class="inputNumber"
  187. style="width: 200px !important;"
  188. :disabled="!permission('vipGroupManage/recoverForStudent1')"
  189. v-model.trim="adjustmentForm.days"
  190. ></el-input-number>
  191. </el-form-item>
  192. <el-form-item label="有效期截止" prop="expireDate">
  193. <el-date-picker
  194. :disabled="true"
  195. v-model.trim="adjustmentForm.expireDate"
  196. :picker-options="pickerOptions"
  197. style="width: 200px !important"
  198. type="date"
  199. value-format="yyyy-MM-dd"
  200. placeholder="选择日期"
  201. >
  202. </el-date-picker>
  203. </el-form-item>
  204. <el-form-item>
  205. <el-checkbox
  206. style="margin-left: 10px"
  207. v-model.trim="adjustmentForm.checked"
  208. >是否跳过节假日</el-checkbox
  209. >
  210. </el-form-item>
  211. </el-form>
  212. <div class="WeekWrap">
  213. <h3 style="margin-bottom: 20px">
  214. 循环次数
  215. <el-button type="text" style="margin-left: 10px" @click="addWeek"
  216. >添加</el-button
  217. >
  218. </h3>
  219. <div class="countWrap" style="margin-bottom: 10px">
  220. <div
  221. class="countItem"
  222. style="margin-bottom: 20px"
  223. v-for="(item, index) in weekList"
  224. :key="index"
  225. >
  226. <span class="title">循环周期: </span>
  227. <el-select
  228. v-model.trim="item.dayOfWeek"
  229. filterable
  230. clearable
  231. style="width: 200px !important"
  232. >
  233. <el-option
  234. v-for="(item, index) in weekDateList"
  235. :key="index"
  236. :label="item.label"
  237. :value="item.value"
  238. ></el-option>
  239. </el-select>
  240. <span style="margin-left: 10px">开始时间</span>
  241. <el-time-select
  242. style="margin-left: 10px; width: 100px"
  243. placeholder=""
  244. v-model.trim="item.startClassTime"
  245. :picker-options="{
  246. start: '04:30',
  247. step: '00:05',
  248. end: '23:55',
  249. }"
  250. >
  251. </el-time-select>
  252. <el-button
  253. style="margin-left: 10px"
  254. type="danger"
  255. @click="removeWeek(item)"
  256. icon="el-icon-delete"
  257. circle
  258. ></el-button>
  259. </div>
  260. </div>
  261. </div>
  262. <div slot="footer" class="dialog-footer">
  263. <el-button @click="adjustmentVisible = false">取 消</el-button>
  264. <el-button type="primary" @click="submieRecover">确 定</el-button>
  265. </div>
  266. </el-dialog>
  267. </div>
  268. </template>
  269. <script>
  270. import pagination from "@/components/Pagination/index";
  271. import dayjs from 'dayjs'
  272. import {
  273. findVipGroupStudents,
  274. leaveSchool,
  275. getStudentSurplusCourseFee,
  276. getHaveCourseBalanceStudents,
  277. addVipGroupStudents,
  278. vipPauseForStudent,
  279. getStudentPauseInfo,
  280. recoverForStudent,
  281. findTeacherWithVipGroupOrganAndSubject,
  282. } from "@/api/vipSeting";
  283. import { permission } from "@/utils/directivePage";
  284. export default {
  285. components: { pagination },
  286. data() {
  287. return {
  288. adjustmentVisible: false,
  289. tableList: [],
  290. id: "",
  291. maskStudentList: [],
  292. maskVisible: false,
  293. rules: {
  294. // 分页规则
  295. limit: 10, // 限制显示条数
  296. page: 1, // 当前页
  297. total: 0, // 总条数
  298. page_size: [10, 20, 40, 50], // 选择限制显示条数
  299. },
  300. activeStudent: "",
  301. maskForm: {
  302. search: "",
  303. },
  304. adjustmentForm: {
  305. count: "",
  306. courseTime: "",
  307. checked: false,
  308. addCount: "",
  309. courseType: "",
  310. fee: "",
  311. teacher: "",
  312. days: "",
  313. expireDate: "",
  314. },
  315. adjustmentRules: {
  316. courseTime: [{ required: true, message: "请选择开始时间" }],
  317. addCount: [{ required: true, message: "请输入加课次数" }],
  318. courseType: [{ required: true, message: "请选择课程类型" }],
  319. fee: [{ required: true, message: "请输入费用" }],
  320. teacher: [{ required: true, message: "请选择老师" }],
  321. days: [{ required: true, message: "请输入剩余有效期" }],
  322. expireDate: [{ required: true, message: "请输入有效期截止" }],
  323. },
  324. weekDateList: [
  325. { value: "1", label: "星期一" },
  326. { value: "2", label: "星期二" },
  327. { value: "3", label: "星期三" },
  328. { value: "4", label: "星期四" },
  329. { value: "5", label: "星期五" },
  330. { value: "6", label: "星期六" },
  331. { value: "7", label: "星期日" },
  332. ],
  333. weekList: [
  334. {
  335. dayOfWeek: "",
  336. startTime: "",
  337. endTime: "",
  338. moid: new Date().getTime(),
  339. },
  340. ],
  341. pickerOptions: {
  342. firstDayOfWeek: 1,
  343. disabledDate(time) {
  344. return time.getTime() + 86400000 <= new Date().getTime();
  345. },
  346. },
  347. teacherList: [],
  348. };
  349. },
  350. mounted() {
  351. this.__init();
  352. },
  353. activated() {
  354. this.__init();
  355. },
  356. methods: {
  357. permission (str) {
  358. console.log(permission(str))
  359. return permission(str);
  360. },
  361. __init() {
  362. let id = this.$route.query.id;
  363. this.id = id;
  364. this.rules.page = 1;
  365. this.getStudents();
  366. findTeacherWithVipGroupOrganAndSubject({ vipGroupId: this.id }).then(
  367. (res) => {
  368. if (res.code == 200) {
  369. this.teacherList = res.data;
  370. }
  371. }
  372. );
  373. },
  374. search() {
  375. this.rules.page = 1;
  376. this.getList();
  377. },
  378. reset() {
  379. this.rules.page = 1;
  380. this.maskForm.search = null;
  381. this.activeStudent = "";
  382. this.getList();
  383. },
  384. getStudents() {
  385. findVipGroupStudents({ vipGroupId: this.id }).then((res) => {
  386. if (res.code == 200) {
  387. this.tableList = res.data.rows;
  388. for (let i in this.tableList) {
  389. this.tableList[i].fee = 0;
  390. this.tableList[i].visible = false;
  391. }
  392. }
  393. });
  394. },
  395. // 删除循环周
  396. removeWeek(item) {
  397. for (let i in this.weekList) {
  398. if (this.weekList[i].id == item.id) {
  399. this.weekList.splice(i, 1);
  400. }
  401. }
  402. },
  403. leaveSchool(scope) {
  404. let studentId = scope.row.id;
  405. let vipGroupId = this.id;
  406. let amount = scope.row.fee;
  407. leaveSchool({ studentId, vipGroupId, amount }).then((res) => {
  408. if (res.code == 200) {
  409. this.$message.success("退学成功");
  410. this.getStudents();
  411. }
  412. });
  413. },
  414. lookFee(scope) {
  415. this.$confirm(`确定是否退学?`, "提示", {
  416. confirmButtonText: "确定",
  417. cancelButtonText: "取消",
  418. type: "warning",
  419. })
  420. .then(() => {
  421. let id = scope.row.id;
  422. if (scope.row.studentStatus == 3) {
  423. this.leaveSchool(scope);
  424. } else {
  425. getStudentSurplusCourseFee({
  426. studentId: id,
  427. vipGroupId: this.id,
  428. }).then((res) => {
  429. if (res.code == 200) {
  430. // scope.row.fee =
  431. this.$prompt("请输入退课金额", "提示", {
  432. confirmButtonText: "确定",
  433. cancelButtonText: "取消",
  434. inputValue: res.data.suplusCourseFee,
  435. })
  436. .then(({ value }) => {
  437. scope.row.fee = value;
  438. this.leaveSchool(scope);
  439. })
  440. .catch((res) => {});
  441. }
  442. });
  443. }
  444. })
  445. .catch(() => {});
  446. },
  447. addStudentList() {
  448. // 发请求 搜索学生
  449. if (this.tableList.length <= 0) {
  450. this.$confirm(
  451. "添加学员后,该课程组将无法通过购买途径加入,是否确认该操作?",
  452. "提示",
  453. {
  454. confirmButtonText: "确定",
  455. cancelButtonText: "取消",
  456. type: "warning",
  457. }
  458. )
  459. .then(() => {
  460. this.getList();
  461. })
  462. .catch(() => {});
  463. } else {
  464. this.getList();
  465. }
  466. },
  467. getList() {
  468. let search = this.maskForm.search || null;
  469. getHaveCourseBalanceStudents({
  470. organId: null,
  471. page: this.rules.page,
  472. rows: this.rules.limit,
  473. search,
  474. }).then((res) => {
  475. if (res.code == 200) {
  476. this.rules.total = res.data.total;
  477. this.maskStudentList = res.data.rows;
  478. this.maskVisible = true;
  479. }
  480. });
  481. },
  482. getTemplateRow(index, row) {
  483. this.activeStudent = row.id;
  484. },
  485. addStudent() {
  486. if (!this.activeStudent) {
  487. this.$message.error("请选择一名学生");
  488. return;
  489. }
  490. addVipGroupStudents({
  491. vipGroupId: this.id,
  492. studentIds: this.activeStudent,
  493. }).then((res) => {
  494. if (res.code == 200) {
  495. this.$message.success("添加成功");
  496. this.getStudents();
  497. }
  498. });
  499. },
  500. stopCourse(scope) {
  501. this.$confirm("是否休学?", "提示", {
  502. confirmButtonText: "确定",
  503. cancelButtonText: "取消",
  504. type: "warning",
  505. })
  506. .then(() => {
  507. // 发请求 申请休学
  508. vipPauseForStudent({
  509. vipGroupId: this.id,
  510. studentId: scope.row.id,
  511. }).then((res) => {
  512. if (res.code == 200) {
  513. this.$message.success("休学成功");
  514. this.getStudents();
  515. }
  516. });
  517. })
  518. .catch(() => {});
  519. },
  520. recoveryCourse(scope) {
  521. getStudentPauseInfo({
  522. studentId: scope.row.id,
  523. vipGroupId: this.id,
  524. }).then((res) => {
  525. if (res.code == 200) {
  526. if (res.data.isPause == 0) {
  527. // vip状态没暂停 不需要排课
  528. // 课程编号 学生编号
  529. const h = this.$createElement;
  530. this.$msgbox({
  531. title: "提示",
  532. message: h("p", null, [
  533. h("p", null, "将按照当前剩余课时安排上课"),
  534. // h("span", null, `排课截至时间:`),
  535. // h("span", { style: "color: red" }, `${res.data.expireDate}`), 辜经理同意注释
  536. ]),
  537. confirmButtonText: "确定",
  538. cancelButtonText: "取消",
  539. showCancelButton: true,
  540. })
  541. .then(() => {
  542. // 发请求 恢复上课
  543. recoverForStudent({
  544. vipGroupId: this.id,
  545. userId: scope.row.id,
  546. }).then((res) => {
  547. if (res.code == 200) {
  548. this.adjustmentVisible = false;
  549. this.getStudents();
  550. }
  551. });
  552. })
  553. .catch(() => {});
  554. } else {
  555. this.activeStudent = res.data.studentId;
  556. this.adjustmentVisible = true;
  557. this.adjustmentForm.teacher = res.data.teacherId;
  558. this.adjustmentForm.count = `${res.data.totalCourseTimes}+${res.data.giveCourseTimes}`;
  559. this.adjustmentForm.days = res.data.days;
  560. }
  561. }
  562. });
  563. // this.$confirm('是否休学?', '提示', {
  564. // confirmButtonText: '确定',
  565. // cancelButtonText: '取消',
  566. // type: 'warning'
  567. // }).then(() => {
  568. // // 发请求 申请休学
  569. // vipPauseForStudent({ vipGroupId: this.id, studentId: scope.row.id }).then(res => {
  570. // if (res.code == 200) {
  571. // this.$message.success('休学成功')
  572. // this.getList()
  573. // }
  574. // })
  575. // }).catch(() => {
  576. // });
  577. },
  578. addWeek() {
  579. // 添加循环周期
  580. this.weekList.push({
  581. dayOfWeek: "",
  582. startClassTime: "",
  583. endClassTime: "",
  584. id: new Date(),
  585. });
  586. },
  587. submieRecover() {
  588. if (this.weekList.length <= 0) {
  589. this.$message.error("排课循环次数不能为空");
  590. return;
  591. }
  592. this.$refs["adjustmentForm"].validate((res) => {
  593. if (res) {
  594. // 发请求
  595. let obj = {};
  596. obj.courseCreateStartTime = this.adjustmentForm.courseTime;
  597. obj.skipHoliday = this.adjustmentForm.checked;
  598. obj.teacherId = this.adjustmentForm.teacher;
  599. obj.userId = this.activeStudent;
  600. obj.courseTimes = [];
  601. obj.courseTimes = this.weekList;
  602. obj.vipGroupId = this.id;
  603. obj.days = this.adjustmentForm.days;
  604. obj.expireDate = this.adjustmentForm.expireDate;
  605. recoverForStudent(obj).then((res) => {
  606. if (res.code == 200) {
  607. this.adjustmentVisible = false;
  608. this.getStudents();
  609. }
  610. });
  611. } else {
  612. this.$message.error("请填写必要参数");
  613. }
  614. });
  615. this.activeStudent;
  616. },
  617. changeCourseTime(val) {
  618. if(!this.adjustmentForm.days){
  619. this.$message.error('请填写剩余有效期');
  620. return
  621. }
  622. if(val){
  623. this.adjustmentForm.expireDate = dayjs(val).add(this.adjustmentForm.days,'day').format('YYYY-MM-DD')
  624. }else{
  625. this.adjustmentForm.expireDate = ''
  626. }
  627. },
  628. },
  629. };
  630. </script>
  631. <style lang="scss" scoped>
  632. .title {
  633. display: inline-block;
  634. width: 108px;
  635. text-align: right;
  636. margin-right: 10px;
  637. }
  638. /deep/.el-input-number .el-input__inner{
  639. text-align: left!important;
  640. }
  641. </style>