index.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  1. <template>
  2. <div class="m-container">
  3. <h2>
  4. <div class="squrt"></div>
  5. 退团申请
  6. <filter-search
  7. @reload="reloadSearch"
  8. :keys="['visitFlag']"
  9. :moreKeys="['organId']"
  10. />
  11. </h2>
  12. <div class="m-core">
  13. <save-form
  14. :inline="true"
  15. @submit="submit"
  16. @reset="onReSet"
  17. ref="searchForm"
  18. :model.sync="searchForm"
  19. >
  20. <el-form-item>
  21. <el-input
  22. v-model.trim="searchForm.search"
  23. clearable
  24. placeholder="学员(乐团)编号、名称"
  25. ></el-input>
  26. </el-form-item>
  27. <el-form-item prop="organId">
  28. <el-select
  29. class="multiple"
  30. style="width: 180px !important"
  31. v-model.trim="searchForm.organId"
  32. filterable
  33. clearable
  34. placeholder="请选择分部"
  35. >
  36. <el-option
  37. v-for="(item, index) in selects.branchs"
  38. :key="index"
  39. :label="item.name"
  40. :value="item.id"
  41. ></el-option>
  42. </el-select>
  43. </el-form-item>
  44. <el-form-item>
  45. <el-select
  46. v-model="searchForm.status"
  47. clearable
  48. placeholder="请选择状态"
  49. >
  50. <el-option
  51. v-for="(item, key) in withdrawalStatus"
  52. :key="key"
  53. :label="item"
  54. :value="key"
  55. ></el-option>
  56. </el-select>
  57. </el-form-item>
  58. <el-form-item>
  59. <el-select
  60. v-model="searchForm.currentApproveRole"
  61. clearable
  62. placeholder="请选择角色"
  63. >
  64. <el-option label="分部经理" value="3"></el-option>
  65. <el-option label="乐团主管" value="4"></el-option>
  66. </el-select>
  67. </el-form-item>
  68. <el-form-item>
  69. <el-button native-type="submit" type="danger">搜索</el-button>
  70. <el-button native-type="reset" type="primary">重置</el-button>
  71. <el-button
  72. @click="onExport"
  73. type="primary"
  74. v-permission="'export/musicGroupQuit'"
  75. >导出</el-button
  76. >
  77. </el-form-item>
  78. </save-form>
  79. <div class="btnList">
  80. <auth :auths="['musicGroupQuit/batchQuitMusicGroup']">
  81. <el-button type="primary" @click="quiteTeamAll">批量处理</el-button>
  82. </auth>
  83. </div>
  84. <el-table
  85. :data="list"
  86. style="width: 100%"
  87. :header-cell-style="{ background: '#EDEEF0', color: '#444' }"
  88. @selection-change="handleSelectionChange"
  89. >
  90. <el-table-column
  91. type="selection"
  92. width="55"
  93. :selectable="checkSeleabled"
  94. >
  95. </el-table-column>
  96. <el-table-column prop="userId" label="学员编号">
  97. <copy-text slot-scope="scope">{{ scope.row.userId }}</copy-text>
  98. </el-table-column>
  99. <el-table-column prop="userId" label="学员姓名">
  100. <copy-text slot-scope="scope">{{
  101. scope.row.user.username
  102. }}</copy-text>
  103. </el-table-column>
  104. <el-table-column prop="organName" label="所属分部">
  105. <div slot-scope="scope">{{ scope.row.musicGroup.organName }}</div>
  106. </el-table-column>
  107. <el-table-column prop="musicGroupId" label="所属乐团">
  108. <copy-text slot-scope="scope">{{
  109. scope.row.musicGroup.name
  110. }}</copy-text>
  111. </el-table-column>
  112. <el-table-column prop="createTime" label="申请时间">
  113. <template slot-scope="scope">
  114. <div>
  115. {{ scope.row.createTime | dateForMinFormat }}
  116. </div>
  117. </template>
  118. </el-table-column>
  119. <el-table-column prop="applyUserName" label="申请人"></el-table-column>
  120. <el-table-column prop="createTime" label="退费金额">
  121. <template slot-scope="scope">
  122. <div>
  123. <p v-if="!scope.row.returnTotalFee">--</p>
  124. <p v-else>
  125. {{ scope.row.returnTotalFee | moneyFormat }}
  126. </p>
  127. </div>
  128. </template>
  129. </el-table-column>
  130. <el-table-column prop="userComment" label="退团原因">
  131. <overflow-text
  132. width="100%"
  133. slot-scope="scope"
  134. :text="scope.row.userComment"
  135. ></overflow-text>
  136. </el-table-column>
  137. <el-table-column label="状态">
  138. <template slot-scope="scope">
  139. <div>
  140. {{ scope.row.status | withdrawalStatus }}
  141. <span v-if="scope.row.status == 'PROCESSING'"
  142. >({{
  143. scope.row.currentApproveRole == 3 ? "分部经理" : "乐团主管"
  144. }})</span
  145. >
  146. </div>
  147. </template>
  148. </el-table-column>
  149. <el-table-column
  150. align="center"
  151. fixed="right"
  152. width="200px;"
  153. label="操作"
  154. v-if="
  155. permission('musicGroupQuit/quitMusicGroup/quit') ||
  156. permission('musicGroupQuit/quitMusicGroup/quit-only') ||
  157. permission('visit/add/tuituanliebiao')
  158. "
  159. >
  160. <template slot-scope="scope">
  161. <div>
  162. <el-button
  163. type="text"
  164. v-if="permission('musicGroupQuit/quitMusicGroup/quit')"
  165. :disabled="
  166. scope.row.status != 'PROCESSING' ||
  167. scope.row.status == 'DENIED' ||
  168. scope.row.status == 'CANCELED' ||
  169. (scope.row.status == 'PROCESSING' &&
  170. isManage == 'manage' &&
  171. scope.row.currentApproveRole == '4') ||
  172. (scope.row.status == 'PROCESSING' &&
  173. !isManage &&
  174. scope.row.currentApproveRole == '3')
  175. "
  176. @click="quieTeamMask(scope.row)"
  177. >立即处理</el-button
  178. >
  179. <el-button
  180. type="text"
  181. v-if="permission('musicGroupQuit/quitMusicGroup/quit')"
  182. :disabled="
  183. !(
  184. scope.row.status != 'PROCESSING' ||
  185. scope.row.status == 'DENIED' ||
  186. scope.row.status == 'CANCELED' ||
  187. (scope.row.status == 'PROCESSING' &&
  188. isManage == 'manage' &&
  189. scope.row.currentApproveRole == '4') ||
  190. (scope.row.status == 'PROCESSING' &&
  191. !isManage &&
  192. scope.row.currentApproveRole == '3')
  193. )
  194. "
  195. @click="quieTeamMask(scope.row, 'look')"
  196. >查看</el-button
  197. >
  198. <!-- <el-button
  199. type="text"
  200. v-if="permission('musicGroupQuit/quitMusicGroup/quit-only')"
  201. :disabled="scope.row.status != 'PROCESSING'"
  202. @click="quieTeam(scope.row)"
  203. >退团</el-button> -->
  204. <el-button
  205. type="text"
  206. v-if="permission('visit/add/tuituanliebiao')"
  207. @click="addVisit(scope.row)"
  208. >新增回访</el-button
  209. >
  210. </div>
  211. </template>
  212. </el-table-column>
  213. </el-table>
  214. <pagination
  215. sync
  216. :total.sync="rules.total"
  217. :page.sync="rules.page"
  218. :limit.sync="rules.limit"
  219. :page-sizes="rules.page_size"
  220. @pagination="FetchList"
  221. />
  222. </div>
  223. <el-dialog
  224. :title="isDisabled ? '查看' : '立即处理'"
  225. width="700px"
  226. :visible.sync="quitVisible"
  227. >
  228. <quitModal
  229. v-if="quitVisible"
  230. :quitForm="quitForm"
  231. @close="quitVisible = false"
  232. @submited="FetchList"
  233. :isDisabled="isDisabled"
  234. ref="musicForm"
  235. />
  236. <p style="color: red; paddingleft: 150px">退费金额暂不进入账户余额</p>
  237. <span slot="footer" class="dialog-footer question">
  238. <div>
  239. <el-popover placement="right" width="500" trigger="click">
  240. <div class="popoverWrap">
  241. <p>乐团退团退费规则:</p>
  242. <p>退还乐器练习云教练费用:报名缴费时缴费的乐器练习云教练费用</p>
  243. <p>退还课程费用:缴费总额-已结束课时单价之和</p>
  244. <p>退还乐器费用:报名缴费时缴纳的乐器费用(团购、租金)</p>
  245. <p>退还教辅费用:报名缴费时缴费的教辅费用</p>
  246. <p>退还乐保费用:报名缴费时缴费的乐保费用</p>
  247. </div>
  248. <el-button
  249. type="text"
  250. icon="el-icon-question"
  251. slot="reference"
  252. style="color: red"
  253. >退团退费说明</el-button
  254. >
  255. </el-popover>
  256. </div>
  257. <div v-if="!isDisabled">
  258. <el-button
  259. type="primary"
  260. v-permission="'musicGroupQuit/quitMusicGroup'"
  261. v-if="!isManage"
  262. @click="submitInfo('PROCESSING')"
  263. >提交审核</el-button
  264. >
  265. <el-button
  266. v-else
  267. type="primary"
  268. v-permission="'musicGroupQuit/quitMusicGroup'"
  269. @click="submitInfo('APPROVED')"
  270. >同意</el-button
  271. >
  272. <el-button
  273. type="danger"
  274. v-permission="'musicGroupQuit/quitMusicGroup'"
  275. @click="submitInfo('DENIED')"
  276. >拒绝</el-button
  277. >
  278. </div>
  279. </span>
  280. </el-dialog>
  281. <!-- <el-dialog title="退团" width="500px" :visible.sync="quitOnlyVisible">
  282. <quitOnlyModal
  283. v-if="quitOnlyVisible && detail"
  284. :detail="detail"
  285. @close="quitOnlyVisible = false"
  286. @submited="FetchList"
  287. />
  288. </el-dialog> -->
  289. <el-dialog title="新增回访" width="500px" :visible.sync="visitVisible">
  290. <visit
  291. v-if="visitVisible && detail"
  292. :detail="detail"
  293. @close="visitVisible = false"
  294. @submited="FetchList"
  295. />
  296. </el-dialog>
  297. </div>
  298. </template>
  299. <script>
  300. import pagination from "@/components/Pagination/index";
  301. import { permission } from "@/utils/directivePage";
  302. import quitModal from "@/views/teamDetail/components/modals/quite-team";
  303. import quitOnlyModal from "./modals/quitOnly";
  304. import visit from "./modals/visit";
  305. import { Export } from "@/utils/downLoadFile";
  306. import { quitMusicGroup } from "@/api/journal";
  307. import qs from "qs";
  308. import { musicGroupQuitQeryPage, batchQuitMusicGroup } from "./api";
  309. import cleanDeep from "clean-deep";
  310. import { musicGroupQuit } from "@/api/journal";
  311. import { withdrawalStatus } from "@/constant";
  312. let that;
  313. const initSearch = {
  314. search: "",
  315. status: null,
  316. organId: "",
  317. };
  318. export default {
  319. components: { pagination, quitModal, quitOnlyModal, visit },
  320. data() {
  321. return {
  322. withdrawalStatus,
  323. quitVisible: false,
  324. quitOnlyVisible: false,
  325. visitVisible: false,
  326. detail: null,
  327. list: [],
  328. searchForm: {
  329. ...initSearch,
  330. },
  331. rules: {
  332. // 分页规则
  333. limit: 10, // 限制显示条数
  334. page: 1, // 当前页
  335. total: 0, // 总条数
  336. page_size: [10, 20, 40, 50], // 选择限制显示条数
  337. },
  338. quitForm: {
  339. // 退团信息确认
  340. isRefundCourseFee: null,
  341. isRefundInstrumentFee: null,
  342. isRefundTeachingAssistantsFee: null,
  343. reason: "",
  344. courseViewType: null,
  345. hasMaintenance: null,
  346. studentName: null,
  347. musicGroupName: null,
  348. isVisit: false,
  349. userComment: null,
  350. },
  351. isManage: false,
  352. isDisabled: false,
  353. multipleSelection: [],
  354. };
  355. },
  356. async mounted() {
  357. that = this;
  358. let isSuperAdmin = this.$store.getters.isSuperAdmin;
  359. let roles = this.$store.getters.roles;
  360. await this.$store.dispatch("setBranchs");
  361. if (isSuperAdmin) {
  362. this.isManage = "super";
  363. } else {
  364. if (roles.indexOf(3) != -1) {
  365. this.isManage = "manage";
  366. } else {
  367. this.isManage = false;
  368. }
  369. }
  370. if (roles.indexOf(3) != -1 && roles.indexOf(4) != -1) {
  371. this.isManage = "super";
  372. }
  373. this.FetchList();
  374. },
  375. methods: {
  376. permission,
  377. reloadSearch() {
  378. this.rules.page = 1;
  379. this.FetchList();
  380. },
  381. submit() {
  382. this.rules.page = 1;
  383. this.FetchList();
  384. },
  385. onReSet() {
  386. this.searchForm = { ...initSearch };
  387. this.submit();
  388. },
  389. async quieTeamMask(row, look) {
  390. await musicGroupQuit({ id: row.id }).then((res) => {
  391. if (res.code == 200) {
  392. if (look == "look") {
  393. this.isDisabled = true;
  394. } else {
  395. this.isDisabled = false;
  396. }
  397. this.musicForm = res.data;
  398. this.activeRow = { ...row, ...res.data.returnFeeDto };
  399. this.quitForm.courseViewType = res.data.musicGroup.courseViewType;
  400. this.quitForm.userComment = res.data.userComment;
  401. this.quitForm.isVisit = res.data.isVisit;
  402. this.quitForm.visitTime = res.data.visitTime;
  403. this.quitForm.studentName = res.data.user?.username;
  404. this.quitForm.musicGroupName = res.data.musicGroup?.name;
  405. this.quitForm.hasMaintenance = res.data.hasMaintenance;
  406. this.quitForm.reason = res.data.reason;
  407. this.quitForm.id = res.data.id;
  408. this.quitForm = { ...this.quitForm, ...res.data.returnFeeDto };
  409. this.quitVisible = true;
  410. } else {
  411. this.$message.error(res.msg);
  412. }
  413. });
  414. // this.detail = row;
  415. },
  416. quieTeam(row) {
  417. this.quitOnlyVisible = true;
  418. this.detail = row;
  419. },
  420. addVisit(row) {
  421. this.visitVisible = true;
  422. this.detail = row;
  423. },
  424. async FetchList() {
  425. try {
  426. const res = await musicGroupQuitQeryPage({
  427. page: this.rules.page,
  428. rows: this.rules.limit,
  429. visitFlag: this.$route.query.visitFlag,
  430. ...this.searchForm,
  431. });
  432. this.rules.total = res.data.total;
  433. this.list = res.data.rows;
  434. } catch (error) {}
  435. },
  436. onExport() {
  437. const { ...rest } = this.searchForm;
  438. Export(
  439. this,
  440. {
  441. url: "/api-web/export/musicGroupQuit",
  442. fileName: "退团申请.xls",
  443. method: "post",
  444. params: qs.stringify({
  445. visitFlag: this.$route.query.visitFlag,
  446. ...rest,
  447. }),
  448. },
  449. "您确定导出退团申请列表?"
  450. );
  451. },
  452. submitInfo(status) {
  453. this.$confirm("确定此操作吗?", "提示", {
  454. confirmButtonText: "确定",
  455. cancelButtonText: "取消",
  456. type: "warning",
  457. })
  458. .then(async () => {
  459. let query = this.quitForm;
  460. query.status = status;
  461. query.returnFeeDto = {
  462. accessoriesFee: query.accessoriesFee,
  463. courseFee: query.courseFee,
  464. isReturnAccessoriesFee: query.isReturnAccessoriesFee,
  465. isReturnCourseFee: query.isReturnCourseFee,
  466. isReturnMaintenanceFee: query.isReturnMaintenanceFee,
  467. isReturnMemberFee: query.isReturnMemberFee,
  468. isReturnMusicalFee: query.isReturnMusicalFee,
  469. maintenanceFee: query.maintenanceFee,
  470. memberFee: query.memberFee,
  471. musicalFee: query.musicalFee,
  472. };
  473. await quitMusicGroup(cleanDeep(query)).then((res) => {
  474. this.$message.success("处理成功");
  475. this.activeRow = null;
  476. if (this.$refs["musicForm"].$refs.quitForm) {
  477. this.$refs["musicForm"].$refs.quitForm.resetFields();
  478. }
  479. this.quitVisible = false;
  480. this.FetchList();
  481. });
  482. })
  483. .catch((e) => {
  484. console.log(e);
  485. });
  486. // 乐团主管这里
  487. },
  488. handleSelectionChange(val) {
  489. this.multipleSelection = val;
  490. },
  491. quiteTeamAll() {
  492. if (this.multipleSelection.length < 1) {
  493. this.$message.error("请至少选择一名学员");
  494. return;
  495. }
  496. let str = "";
  497. this.multipleSelection.forEach((stu) => {
  498. console.log(stu);
  499. str += stu.user.username + ",";
  500. });
  501. str += "的退团申请将批量处理";
  502. this.$prompt(str, "提示", {
  503. distinguishCancelAndClose: true,
  504. confirmButtonText: "同意",
  505. cancelButtonText: "拒绝",
  506. confirmButtonClass: "el-button--primary",
  507. cancelButtonClass: "el-button--danger",
  508. closeOnClickModal: false,
  509. inputPattern: /\S/,
  510. inputType: "textarea",
  511. inputErrorMessage: "请输入审批理由",
  512. inputPlaceholder: "请输入审批理由",
  513. beforeClose: async (val, instance, done) => {
  514. if (val == "confirm") {
  515. // reason
  516. let objList = this.multipleSelection.map((stu) => {
  517. return {
  518. id: stu.id,
  519. status: "APPROVED",
  520. reason: instance.inputValue,
  521. };
  522. });
  523. try {
  524. const res = await batchQuitMusicGroup(objList);
  525. this.$message.success("审批成功");
  526. done();
  527. this.FetchList();
  528. } catch (e) {
  529. console.log(e);
  530. }
  531. } else if (val == "cancel") {
  532. instance.validate();
  533. let objList = this.multipleSelection.map((stu) => {
  534. return {
  535. id: stu.id,
  536. status: "DENIED",
  537. reason: instance.inputValue,
  538. };
  539. });
  540. try {
  541. const res = await batchQuitMusicGroup(objList);
  542. this.$message.success("审批成功");
  543. done();
  544. this.FetchList();
  545. } catch (e) {
  546. console.log(e);
  547. }
  548. } else {
  549. done();
  550. }
  551. },
  552. })
  553. .then(() => {
  554. // 同意
  555. })
  556. .catch((msg) => {
  557. // close,cancel
  558. console.log(msg);
  559. });
  560. },
  561. checkSeleabled(row) {
  562. if (row.status == "PROCESSING" && row.currentApproveRole == "3") {
  563. return 1;
  564. } else {
  565. return 0;
  566. }
  567. },
  568. },
  569. };
  570. </script>
  571. <style lang="scss" scoped>
  572. .dialog-footer.question {
  573. display: flex;
  574. flex-direction: row;
  575. justify-content: space-between;
  576. }
  577. .btnList {
  578. margin-bottom: 20px;
  579. }
  580. .confirmButton {
  581. color: #fff;
  582. background-color: #f56c6c;
  583. border-color: #f56c6c;
  584. }
  585. .cancelButton {
  586. color: #fff;
  587. background-color: #14928a;
  588. border-color: #14928a;
  589. }
  590. </style>