vipList.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. <template>
  2. <div class="m-container">
  3. <h2>
  4. <div class="squrt"></div>VIP课列表
  5. </h2>
  6. <div class="newBand"
  7. v-permission="'/buildVip'"
  8. @click="gotoBuildVip">新建VIP课</div>
  9. <div class="newBand"
  10. v-permission="'export/vipGroupList'"
  11. @click="onVIPCourseExport">导出VIP课</div>
  12. <div class="newBand"
  13. v-permission="'export/vipGroup'"
  14. @click="onStudentExport"
  15. style="max-width: inherit;">VIP课程续费提醒</div>
  16. <div class="m-core">
  17. <!-- 搜索类型 -->
  18. <el-form :inline="true"
  19. class="searchForm"
  20. v-model.trim="searchForm">
  21. <!-- 状态 指导老师 活动方案-->
  22. <el-form-item>
  23. <el-input v-model.trim="searchForm.search"
  24. @keyup.enter.native="search"
  25. placeholder="课程名称"></el-input>
  26. </el-form-item>
  27. <el-form-item prop="orgin">
  28. <el-select class="multiple"
  29. v-model.trim="searchForm.orgin"
  30. filterable
  31. clearable
  32. placeholder="请选择分部">
  33. <el-option v-for="(item,index) in organList"
  34. :key="index"
  35. :label="item.name"
  36. :value="item.id"></el-option>
  37. </el-select>
  38. </el-form-item>
  39. <!-- statusList -->
  40. <el-form-item prop="status">
  41. <el-select class="multiple"
  42. v-model.trim="searchForm.status"
  43. filterable
  44. clearable
  45. placeholder="请选课程状态">
  46. <el-option v-for="(item,index) in statusList"
  47. :key="index"
  48. :label="item.lable"
  49. :value="item.value"></el-option>
  50. </el-select>
  51. </el-form-item>
  52. <el-form-item>
  53. <el-select v-model.trim="searchForm.teacherId"
  54. clearable
  55. filterable
  56. placeholder="指导老师">
  57. <el-option v-for="(item,index) in teacherList"
  58. :key="index"
  59. :value="item.id"
  60. :label="item.realName"></el-option>
  61. </el-select>
  62. </el-form-item>
  63. <el-form-item>
  64. <el-select v-model.trim="searchForm.activityId"
  65. clearable
  66. filterable
  67. placeholder="活动方案">
  68. <el-option v-for="(item,index) in activeList"
  69. :key="index"
  70. :value="item.id"
  71. :label="item.name"></el-option>
  72. </el-select>
  73. </el-form-item>
  74. <el-form-item prop="status">
  75. <el-select class="multiple"
  76. v-model.trim="searchForm.hasEducationalTeacherId"
  77. filterable
  78. clearable
  79. placeholder="是否有教务老师">
  80. <el-option label="是"
  81. value="true"></el-option>
  82. <el-option label="否"
  83. value="false"></el-option>
  84. </el-select>
  85. </el-form-item>
  86. <el-form-item>
  87. <el-button @click="search"
  88. type="danger">搜索</el-button>
  89. <el-button @click="onReSet"
  90. type="primary">重置</el-button>
  91. </el-form-item>
  92. </el-form>
  93. <!-- 查询列表 -->
  94. <!-- tab -->
  95. <div class="tableWrap">
  96. <el-table style="width: 100%"
  97. :header-cell-style="{background:'#EDEEF0',color:'#444'}"
  98. :data="tableData">
  99. <el-table-column align="center"
  100. width="120px"
  101. prop="id"
  102. label="课程组编号"></el-table-column>
  103. <el-table-column align="center"
  104. width="200px"
  105. prop="name"
  106. label="课程名称">
  107. <!-- <template slot-scope="scope">
  108. <el-tooltip placement="top-start">
  109. <div slot="content">{{ scope.row.name }}</div>
  110. <div style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
  111. <span>{{ scope.row.name }}</span>
  112. </div>
  113. </el-tooltip>
  114. </template> -->
  115. </el-table-column>
  116. <el-table-column align="center"
  117. prop="vipGroupCategoryName"
  118. label="课程形式"></el-table-column>
  119. <el-table-column align="center"
  120. prop="status"
  121. label="课程状态">
  122. <template slot-scope="scope">
  123. <div>{{ scope.row.status | formatterStatus}}</div>
  124. </template>
  125. </el-table-column>
  126. <el-table-column align="center"
  127. prop="userName"
  128. label="指导老师"
  129. width='100px'></el-table-column>
  130. <el-table-column align="center"
  131. prop="educationalTeacherName"
  132. label="教务老师"></el-table-column>
  133. <el-table-column align="center"
  134. prop="studentNum"
  135. label="班级人数"></el-table-column>
  136. <el-table-column align="center"
  137. label="课程单价">
  138. <template slot-scope="scope">
  139. <div>
  140. <p>{{scope.row.courseUnitPrice| moneyFormat }} 元</p>
  141. </div>
  142. </template>
  143. </el-table-column>
  144. <el-table-column align="center"
  145. prop="vipGroupActivityName"
  146. label="活动方案"></el-table-column>
  147. <el-table-column align="center"
  148. label="当前课次">
  149. <template slot-scope="scope">
  150. <div>
  151. <p>{{scope.row.currentClassTimes + '/' + scope.row.totalClassTimes}}</p>
  152. </div>
  153. </template>
  154. </el-table-column>
  155. <el-table-column align="center"
  156. label="月均消耗">
  157. <template slot-scope="scope">{{ scope.row.monthConsumeRate }}%</template>
  158. </el-table-column>
  159. <el-table-column align="center"
  160. prop="createTime"
  161. label="上次课时间"
  162. width='100px'>
  163. <template slot-scope="scope">
  164. <div>
  165. <p>{{scope.row.lastOverTime | formatterTime}}</p>
  166. </div>
  167. </template>
  168. </el-table-column>
  169. <el-table-column align="center"
  170. prop="paymentExpireDate"
  171. label="开课时间"
  172. width='100px'>
  173. <template slot-scope="scope">
  174. <div>
  175. <p>{{scope.row.courseStartDate | formatterTime}}</p>
  176. </div>
  177. </template>
  178. </el-table-column>
  179. <el-table-column align="center"
  180. prop="coursesExpireDate"
  181. label="结束时间"
  182. width='100px'>
  183. <template slot-scope="scope">
  184. <div>
  185. <p>{{scope.row.coursesExpireDate | formatterTime}}</p>
  186. </div>
  187. </template>
  188. </el-table-column>
  189. <el-table-column align="center"
  190. prop="createTime"
  191. label="申请时间"
  192. width='100px'>
  193. <template slot-scope="scope">
  194. <div>
  195. <p>{{scope.row.createTime | formatterTime}}</p>
  196. </div>
  197. </template>
  198. </el-table-column>
  199. <el-table-column align="center"
  200. prop="stopReason"
  201. label="备注">
  202. </el-table-column>
  203. <el-table-column align="center"
  204. width="150px"
  205. fixed="right"
  206. label="操作">
  207. <template slot-scope="scope">
  208. <div>
  209. <el-button type="text"
  210. v-if="permission('/vipDetail')"
  211. @click="gotoVipDetail(scope.row)">查看</el-button>
  212. <!--
  213. <el-button type="text">启动</el-button>-->
  214. <!-- <el-button type="text"
  215. v-if="scope.row.status <3"
  216. @click='closeVip(scope.row.id)'>关闭</el-button>-->
  217. <el-popover placement="top"
  218. width="160"
  219. v-if="scope.row.status < 3 && scope.row.enableDelete != 1 && permission('vipGroupManage/stopVipGroup')"
  220. :ref="scope.$index">
  221. <p style="margin-bottom:10px;">确定停止该vip课?</p>
  222. <el-input v-model.trim="stopReason"
  223. placeholder="请输入关闭原因"></el-input>
  224. <div style="text-align: right; margin-top: 20px">
  225. <el-button size="mini"
  226. type="text"
  227. @click="onCancelVip(scope)">取消</el-button>
  228. <el-button type="primary"
  229. size="mini"
  230. @click="closeVip(scope)">确定</el-button>
  231. </div>
  232. <el-button type="text"
  233. slot="reference">停止</el-button>
  234. </el-popover>
  235. <el-button type="text"
  236. @click="onVipDelete(scope.row)"
  237. v-if="scope.row.enableDelete == 1 && permission('vipGroupManage/deleteVipGroup')">删除</el-button>
  238. <el-button type="text"
  239. v-if="scope.row.status > 1&&scope.row.status != 3 && permission('/vipReset')"
  240. @click="resetVip(scope.row)">修改</el-button>
  241. </div>
  242. </template>
  243. </el-table-column>
  244. </el-table>
  245. <!-- 分页器 -->
  246. <pagination :total="rules.total"
  247. :page.sync="rules.page"
  248. :limit.sync="rules.limit"
  249. :page-sizes="rules.page_size"
  250. @pagination="getList" />
  251. </div>
  252. </div>
  253. </div>
  254. </template>
  255. <script>
  256. import pagination from "@/components/Pagination/index";
  257. import {
  258. getVipList,
  259. vipGroupActivity,
  260. closeVip,
  261. getVipGroupDetail,
  262. deleteVipGroup
  263. } from "@/api/vipSeting";
  264. import { getTeacher, getEmployeeOrgan } from "@/api/buildTeam";
  265. import store from "@/store";
  266. import axios from "axios";
  267. import { getToken } from "@/utils/auth";
  268. import load from "@/utils/loading";
  269. import { permission } from '@/utils/directivePage'
  270. export default {
  271. components: { pagination },
  272. name: "vipList",
  273. data () {
  274. return {
  275. organId: null,
  276. searchForm: {
  277. teacherId: null,
  278. activityId: null,
  279. search: null,
  280. orgin: null,
  281. status: null,
  282. hasEducationalTeacherId: null
  283. },
  284. teacherList: [],
  285. activeList: [],
  286. tableData: [],
  287. organList: [],
  288. rules: {
  289. // 分页规则
  290. limit: 10, // 限制显示条数
  291. page: 1, // 当前页
  292. total: 0, // 总条数
  293. page_size: [10, 20, 40, 50] // 选择限制显示条数
  294. },
  295. statusList: [
  296. { lable: "未开始", value: "0" },
  297. { lable: "报名中", value: "1" },
  298. { lable: "报名结束", value: "5" },
  299. { lable: "进行中", value: "2" },
  300. { lable: "已结束", value: "4" },
  301. { lable: "取消", value: "3" },
  302. { lable: "暂停", value: "6" }
  303. ],
  304. stopReason: null, // 停止原因
  305. };
  306. },
  307. created () {
  308. if (this.$route.query.searchForm) {
  309. this.$route.query.searchForm instanceof Object
  310. ? (this.searchForm = this.$route.query.searchForm)
  311. : (this.searchForm = JSON.parse(this.$route.query.searchForm));
  312. }
  313. if (this.$route.query.rules) {
  314. this.$route.query.rules instanceof Object
  315. ? (this.rules = this.$route.query.rules)
  316. : (this.rules = JSON.parse(this.$route.query.rules));
  317. }
  318. },
  319. mounted () {
  320. this.init();
  321. },
  322. activated () {
  323. this.init();
  324. },
  325. methods: {
  326. init () {
  327. getEmployeeOrgan().then(res => {
  328. if (res.code == 200) {
  329. this.organList = res.data;
  330. }
  331. });
  332. // <!-- 状态 指导老师 活动方案-->
  333. getTeacher({ organId: this.organId }).then(res => {
  334. if (res.code == 200) {
  335. this.teacherList = res.data;
  336. }
  337. });
  338. // 获取活动方案
  339. vipGroupActivity({ organId: this.organId, rows: 9999 }).then(res => {
  340. if (res.code == 200) {
  341. this.activeList = res.data.rows;
  342. }
  343. });
  344. this.getList();
  345. },
  346. search () {
  347. this.rules.page = 1;
  348. this.getList();
  349. },
  350. onReSet () {
  351. this.searchForm = {
  352. teacherId: null,
  353. activityId: null,
  354. search: null,
  355. orgin: null,
  356. status: null
  357. };
  358. this.getList();
  359. },
  360. getList () {
  361. let params = this.searchForm;
  362. params.page = this.rules.page;
  363. params.rows = this.rules.limit;
  364. params.hasEducationalTeacherId =
  365. this.searchForm.hasEducationalTeacherId || null;
  366. params.organId = this.searchForm.orgin || null;
  367. params.status = this.searchForm.status || null;
  368. getVipList(params).then(res => {
  369. if (res.code == 200) {
  370. // this.tableData = [];
  371. setTimeout(() => {
  372. this.tableData = res.data.rows;
  373. }, 50);
  374. this.rules.total = res.data.total;
  375. }
  376. });
  377. },
  378. // 跳转到vip详情
  379. gotoVipDetail (row) {
  380. let rules = JSON.stringify(this.rules);
  381. let searchForm = JSON.stringify(this.searchForm);
  382. let id = row.id;
  383. let name = row.name;
  384. this.$router.push({
  385. path: "/business/vipDetail",
  386. query: { id, name, rules, searchForm }
  387. });
  388. },
  389. closeVip (scope) {
  390. let id = scope.row.id;
  391. closeVip({ vipGroupId: id, stopReason: this.stopReason }).then(
  392. res => {
  393. if (res.code == 200) {
  394. this.$message.success("停止课程成功");
  395. scope._self.$refs[scope.$index].doClose();
  396. this.getList();
  397. }
  398. }
  399. );
  400. },
  401. onCancelVip (scope) {
  402. this.stopReason = null
  403. scope._self.$refs[scope.$index].doClose()
  404. },
  405. gotoBuildVip () {
  406. let rules = JSON.stringify(this.rules);
  407. let searchForm = JSON.stringify(this.searchForm);
  408. this.$router.push({
  409. path: "/business/buildVip",
  410. query: { rules, searchForm }
  411. });
  412. },
  413. onVIPCourseExport () {
  414. // 导出VIP课
  415. let searchForm = this.searchForm;
  416. let data = {
  417. teacherId: searchForm.teacherId || null,
  418. activityId: searchForm.activityId || null,
  419. organId: searchForm.orgin || null,
  420. status: searchForm.status || null,
  421. search: searchForm.search || null
  422. };
  423. let url = "/api-web/export/vipGroupList";
  424. const options = {
  425. method: "get",
  426. headers: {
  427. Authorization: getToken()
  428. },
  429. params: data,
  430. url,
  431. responseType: "blob"
  432. };
  433. this.$confirm("您确定导出VIP课吗?", "提示", {
  434. confirmButtonText: "确定",
  435. cancelButtonText: "取消",
  436. type: "warning"
  437. })
  438. .then(() => {
  439. load.startLoading();
  440. axios(options)
  441. .then(res => {
  442. let blob = new Blob([res.data], {
  443. // type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8'
  444. type: "application/vnd.ms-excel;charset=utf-8"
  445. //word文档为application/msword,pdf文档为application/pdf,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8
  446. });
  447. let text = new Response(blob).text();
  448. text.then(res => {
  449. // 判断是否报错
  450. if (res.indexOf("code") != -1) {
  451. let json = JSON.parse(res);
  452. this.$message.error(json.msg);
  453. } else {
  454. let objectUrl = URL.createObjectURL(blob);
  455. let link = document.createElement("a");
  456. let fname = "VIP列表" + new Date().getTime(); //下载文件的名字
  457. link.href = objectUrl;
  458. link.setAttribute("download", fname);
  459. document.body.appendChild(link);
  460. link.click();
  461. }
  462. });
  463. load.endLoading();
  464. })
  465. .catch(error => {
  466. this.$message.error("导出数据失败,请联系管理员");
  467. load.endLoading();
  468. });
  469. })
  470. .catch(() => { });
  471. },
  472. onStudentExport () {
  473. // 导出VIP课
  474. // let searchForm = this.searchForm;
  475. let data = {
  476. // teacherId: searchForm.teacherId || null,
  477. // activityId: searchForm.activityId || null,
  478. // organId: searchForm.orgin || null,
  479. // status: searchForm.status || null,
  480. // search: searchForm.search || null
  481. };
  482. let url = "/api-web/export/vipGroup";
  483. const options = {
  484. method: "get",
  485. headers: {
  486. Authorization: getToken()
  487. },
  488. params: data,
  489. url,
  490. responseType: "blob"
  491. };
  492. this.$confirm("VIP课程续费提醒导出?", "提示", {
  493. confirmButtonText: "确定",
  494. cancelButtonText: "取消",
  495. type: "warning"
  496. })
  497. .then(() => {
  498. load.startLoading();
  499. axios(options)
  500. .then(res => {
  501. let blob = new Blob([res.data], {
  502. // type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8'
  503. type: "application/vnd.ms-excel;charset=utf-8"
  504. //word文档为application/msword,pdf文档为application/pdf,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8
  505. });
  506. let text = new Response(blob).text();
  507. text.then(res => {
  508. // 判断是否报错
  509. if (res.indexOf("code") != -1) {
  510. let json = JSON.parse(res);
  511. this.$message.error(json.msg);
  512. } else {
  513. let objectUrl = URL.createObjectURL(blob);
  514. let link = document.createElement("a");
  515. let fname = "VIP课程续费提醒" + new Date().getTime() + '.xlsx'; //下载文件的名字
  516. link.href = objectUrl;
  517. link.setAttribute("download", fname);
  518. document.body.appendChild(link);
  519. link.click();
  520. }
  521. });
  522. load.endLoading();
  523. })
  524. .catch(error => {
  525. this.$message.error("导出数据失败,请联系管理员");
  526. load.endLoading();
  527. });
  528. })
  529. .catch(() => { });
  530. },
  531. // 修改vip
  532. resetVip (row) {
  533. let id = row.id;
  534. let organId = row.organId;
  535. let educationalTeacherId = row.educationalTeacherId;
  536. let userId = row.userId; // 课程组上指导老师
  537. let rules = JSON.stringify(this.rules);
  538. let searchForm = JSON.stringify(this.searchForm);
  539. let name = row.name;
  540. let endTimeStr = row.coursesExpireDate
  541. let startTimeStr = row.courseStartDate
  542. this.$router.push({
  543. path: "/business/vipReset",
  544. query: { id, educationalTeacherId, organId, userId, rules, searchForm, name, endTimeStr, startTimeStr }
  545. });
  546. },
  547. // 删除VIP
  548. onVipDelete (row) {
  549. this.$confirm("您确定删除该VIP课吗?", "提示", {
  550. confirmButtonText: "确定",
  551. cancelButtonText: "取消",
  552. type: "warning"
  553. }).then(() => {
  554. deleteVipGroup({ vipGroupId: row.id }).then(res => {
  555. if (res.code == 200) {
  556. this.$message.success("删除成功");
  557. this.getList();
  558. }
  559. })
  560. }).catch(() => { });
  561. },
  562. permission (str) {
  563. return permission(str)
  564. }
  565. },
  566. filters: {
  567. formatterTime (val) {
  568. let result;
  569. if (val) {
  570. result = val.split(" ")[0];
  571. } else {
  572. result = "";
  573. }
  574. return result;
  575. },
  576. formatterStatus (val) {
  577. let arr = [
  578. "未开始",
  579. "报名中",
  580. "进行中",
  581. "取消",
  582. "已结束",
  583. "报名结束",
  584. "暂停"
  585. ];
  586. return arr[val];
  587. }
  588. }
  589. };
  590. </script>
  591. <style lang="scss" scoped>
  592. .m-container {
  593. box-sizing: border-box;
  594. background-color: #fff;
  595. // padding: 18px 95px 55px 60px;
  596. }
  597. .newBand {
  598. display: inline-block;
  599. }
  600. </style>