addVisit.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670
  1. <template>
  2. <div class="addVisit">
  3. <m-header v-if="statusList.headerStatus" :name="name" />
  4. <van-cell-group>
  5. <van-field
  6. label="回访老师"
  7. v-model="teacherName"
  8. readonly
  9. input-align="right"
  10. placeholder="请选择"
  11. />
  12. </van-cell-group>
  13. <van-cell-group>
  14. <van-field
  15. label="学员姓名"
  16. @click="onCheckStudent"
  17. v-model="studentName"
  18. readonly
  19. input-align="right"
  20. :is-link="id || userId || studentId ? false : true"
  21. placeholder="请选择"
  22. >
  23. <template #right-icon>
  24. <a v-if="studentPhone" @click.stop="() => {}" class="phone_section" :href="'tel:' + studentPhone"><img src="../../assets/images/icon_phone.png" class="iconPhone" alt=""></a>
  25. </template>
  26. </van-field>
  27. <van-field
  28. label="回访类型"
  29. @click="onChange('type')"
  30. v-model="form.type"
  31. readonly
  32. input-align="right"
  33. :is-link="id || userId ? false : true"
  34. placeholder="请选择"
  35. />
  36. <van-field
  37. label="回访目的"
  38. @click="onChange('purpose')"
  39. v-model="form.purpose"
  40. readonly
  41. input-align="right"
  42. :is-link="id || userId ? false : true"
  43. placeholder="请选择"
  44. />
  45. </van-cell-group>
  46. <van-cell-group>
  47. <div class="dot"></div>
  48. <van-field
  49. label="当前学生情况"
  50. class="textarea"
  51. :readonly="id ? true : false"
  52. v-model="form.overview"
  53. rows="2"
  54. autosize
  55. type="textarea"
  56. maxlength="50"
  57. placeholder="请输入留言"
  58. :show-word-limit="id ? false : true"
  59. />
  60. </van-cell-group>
  61. <van-cell-group>
  62. <div class="dot"></div>
  63. <van-field
  64. label="沟通后家长反馈"
  65. class="textarea"
  66. :readonly="id ? true : false"
  67. v-model="form.feedback"
  68. rows="2"
  69. autosize
  70. type="textarea"
  71. maxlength="50"
  72. placeholder="请输入留言"
  73. :show-word-limit="id ? false : true"
  74. />
  75. </van-cell-group>
  76. <van-cell-group>
  77. <van-field
  78. label="回访时间"
  79. class="visiTimer"
  80. v-model="form.visitTime"
  81. readonly
  82. @click="onEnListShow"
  83. input-align="right"
  84. :is-link="id ? false : true"
  85. placeholder="请选择"
  86. />
  87. </van-cell-group>
  88. <div class="button-group" v-if="!id">
  89. <van-button type="primary" @click="onSubmit" round size="large"
  90. >确认</van-button
  91. >
  92. </div>
  93. <van-action-sheet
  94. v-model="visit.status"
  95. :actions="visit.data"
  96. cancel-text="取消"
  97. @cancel="visit.status = false"
  98. @select="onModeSelect"
  99. />
  100. <van-popup v-model="dataForm.status" position="bottom">
  101. <van-datetime-picker
  102. v-model="dataForm.currentDate"
  103. type="date"
  104. :min-date="dataForm.minDate"
  105. :max-date="dataForm.maxDate"
  106. :formatter="formatter"
  107. @cancel="dataForm.status = false"
  108. @confirm="onCurrentConfirm"
  109. />
  110. </van-popup>
  111. <!-- 选择上课学生 -->
  112. <van-popup
  113. v-model="statusList.studentStatus"
  114. :lock-scroll="true"
  115. position="bottom"
  116. :style="{ height: '180%' }"
  117. >
  118. <van-sticky>
  119. <van-search
  120. show-action
  121. shape="round"
  122. :left-icon="searchIcon"
  123. @search="onSearch"
  124. v-model="params.search"
  125. placeholder="请输入学生名或手机号"
  126. >
  127. <template #action>
  128. <div @click="onSearch">搜索</div>
  129. </template>
  130. </van-search>
  131. </van-sticky>
  132. <div class="paddingB80">
  133. <van-list
  134. v-model="loading"
  135. class="studentContainer"
  136. v-if="dataShow"
  137. key="data"
  138. :finished="finished"
  139. finished-text=""
  140. @load="getStudent"
  141. >
  142. <van-radio-group v-model="radioSelect">
  143. <van-cell-group>
  144. <van-cell
  145. v-for="(item, index) in dataList"
  146. :key="index"
  147. @click="onCheckboxSelect(item)"
  148. class="input-cell"
  149. :center="true"
  150. >
  151. <template slot="icon">
  152. <img
  153. class="logo"
  154. v-if="item.avatar"
  155. :src="item.avatar"
  156. alt=""
  157. />
  158. <img
  159. class="logo"
  160. v-else
  161. src="@/assets/images/icon_student.png"
  162. alt=""
  163. />
  164. </template>
  165. <template slot="title">
  166. <div class="studentName">
  167. {{ item.userName }}
  168. </div>
  169. </template>
  170. <template slot="label">
  171. <span>{{ desensitPhone(item.phone) }}</span>
  172. </template>
  173. <template slot="default">
  174. <van-radio :name="item.userId"></van-radio>
  175. </template>
  176. </van-cell>
  177. </van-cell-group>
  178. </van-radio-group>
  179. </van-list>
  180. <m-empty class="empty" v-else key="data" />
  181. </div>
  182. <div class="button-group-popup">
  183. <span class="btn" @click="onPopupCancel">取消</span>
  184. <span class="btn primary" @click="onPopupSubmit">确认选择</span>
  185. </div>
  186. </van-popup>
  187. </div>
  188. </template>
  189. <script>
  190. import MHeader from "@/components/MHeader";
  191. import { browser } from "@/common/common";
  192. import MEmpty from "@/components/MEmpty";
  193. import dayjs from "dayjs";
  194. import {
  195. queryStudentsWithTeacher,
  196. visitAdd,
  197. visitGetInfo,
  198. queryUserById
  199. } from "@/api/teacher";
  200. import { queryUserInfo } from "@/api/app";
  201. import setLoading from "@/utils/loading";
  202. export default {
  203. name: "addVisit",
  204. components: {
  205. MHeader,
  206. MEmpty,
  207. },
  208. data() {
  209. const query = this.$route.query;
  210. return {
  211. id: query.id,
  212. name: query.name,
  213. userId: query.userId, // 如果有userId的时候说明是从评测详情进来的
  214. studentId: query.studentId, // 这个参数是从原生传过来的,单独做了处理
  215. inside: query.inside || 0,
  216. visitFlag: Number(query.visitFlag) || 0,
  217. dataForm: {
  218. // 时间下拉框
  219. status: false,
  220. minDate: new Date(2000, 0, 1),
  221. maxDate: new Date(),
  222. currentDate: new Date(),
  223. },
  224. statusList: {
  225. // 散状态集合
  226. headerStatus: true, // 头部是否展示
  227. studentStatus: false, // 上课学生状态
  228. },
  229. typeList: [{ name: "课程推荐" }, { name: "常规回访" }, { name: "云教练" }, { name: "其它" }],
  230. visit: {
  231. status: false,
  232. type: null,
  233. data: [],
  234. },
  235. studentName: query.username || null,
  236. studentPhone: query.phone || null,
  237. teacherName: null,
  238. form: {
  239. teacherId: null,
  240. studentId: query.userId || query.studentId || null,
  241. type: query.userId ? '云教练' : null,
  242. purpose: query.userId ? '体验回访' : null,
  243. overview: "",
  244. feedback: "",
  245. visitTime: query.userId || query.id ? dayjs().format("YYYY年MM月DD日") : null,
  246. visiterType: "TEACHER",
  247. },
  248. loading: false,
  249. finished: false,
  250. params: {
  251. search: null,
  252. page: 1,
  253. rows: 20,
  254. },
  255. dataShow: true, // 是否有数据
  256. radioSelect: null,
  257. radioSelectName: null,
  258. radioSelectPhone: null,
  259. clickStatus: false,
  260. dataList: [],
  261. searchIcon: require("@/assets/images/search.png"),
  262. };
  263. },
  264. mounted() {
  265. let params = this.$route.query;
  266. if (params.Authorization) {
  267. localStorage.setItem("Authorization", decodeURI(params.Authorization));
  268. localStorage.setItem("userInfo", decodeURI(params.Authorization));
  269. }
  270. if (browser().android || browser().iPhone) {
  271. this.statusList.headerStatus = false;
  272. }
  273. document.title = this.name || '新增回访记录';
  274. this.__init();
  275. },
  276. methods: {
  277. async __init() {
  278. let res = await queryUserInfo();
  279. let result = res.data;
  280. if (res.status == 200) {
  281. this.teacherName = result.realName;
  282. this.form.teacherId = result.id;
  283. } else {
  284. this.$toast(res.msg);
  285. }
  286. if (this.id) {
  287. setLoading(true);
  288. let queryInfo = await visitGetInfo({ id: this.id });
  289. const queryResult = queryInfo.data;
  290. let form = this.form;
  291. setLoading(false);
  292. if (queryResult.code == 200) {
  293. let tempData = queryResult.data;
  294. this.studentName = tempData.studentName;
  295. form.studentId = tempData.studentId;
  296. form.type = tempData.type;
  297. form.purpose = tempData.purpose;
  298. form.overview = tempData.overview;
  299. form.feedback = tempData.feedback;
  300. form.visitTime = dayjs(tempData.visitTime).format("YYYY年MM月DD日");
  301. form.visiterType = tempData.visiterType;
  302. } else {
  303. this.$toast(res.msg);
  304. }
  305. }
  306. let userId = this.userId || this.studentId
  307. if(userId) {
  308. await queryUserById({ userId }).then(res => {
  309. let result = res.data
  310. this.studentPhone = result.phone
  311. this.studentName = result.username
  312. })
  313. }
  314. },
  315. async onSubmit() {
  316. let form = this.form;
  317. if (!form.studentId) {
  318. this.$toast("请选择学员");
  319. return;
  320. } else if (!form.type) {
  321. this.$toast("请选择回访类型");
  322. return;
  323. } else if (!form.purpose) {
  324. this.$toast("请选择回访目的");
  325. return;
  326. } else if (!form.overview) {
  327. this.$toast("请输入当前学生情况");
  328. return;
  329. } else if (!form.feedback) {
  330. this.$toast("请输入沟通后家长反馈");
  331. return;
  332. } else if (!form.visitTime) {
  333. this.$toast("请选择回访时间");
  334. return;
  335. }
  336. if (this.clickStatus) {
  337. return;
  338. }
  339. this.clickStatus = true;
  340. setLoading(true);
  341. // let visitTime = this.form.visitTime.replace(/[^\d]/g,'/');
  342. // let someDate = new Date(visitTime)
  343. let visitTime = dayjs(this.dataForm.currentDate).format("YYYY-MM-DD")
  344. let params = {
  345. ...form,
  346. visitTime
  347. }
  348. let res = await visitAdd({ ...params });
  349. let result = res.data;
  350. setLoading(false);
  351. if (result.code == 200) {
  352. this.$toast("添加成功");
  353. setTimeout(() => {
  354. if(this.inside) {
  355. this.onAppBack()
  356. } else if(this.userId) {
  357. let { visitFlag ,...query } = this.$route.query
  358. visitFlag = 0
  359. this.$router.replace({
  360. path: '/trainDetail',
  361. query: {
  362. ...query,
  363. visitFlag
  364. }
  365. });
  366. } else {
  367. this.$router.replace("visitList");
  368. }
  369. }, 800);
  370. } else {
  371. this.$toast(result.msg);
  372. this.clickStatus = false;
  373. return;
  374. }
  375. },
  376. onAppBack() {
  377. if (browser().android) {
  378. DAYA.postMessage(JSON.stringify({ api: "back" }));
  379. } else if (browser().iPhone) {
  380. window.webkit.messageHandlers.DAYA.postMessage(
  381. JSON.stringify({ api: "back" })
  382. );
  383. }
  384. },
  385. onCheckStudent() {
  386. if (this.id || this.userId || this.studentId) {
  387. return;
  388. }
  389. this.statusList.studentStatus = true;
  390. },
  391. onChange(type) {
  392. if (this.id || this.userId) {
  393. return;
  394. }
  395. let visit = this.visit;
  396. let form = this.form;
  397. if (type == "type") {
  398. visit.data = this.typeList;
  399. } else if (type == "purpose") {
  400. if (form.type == "其它") {
  401. visit.data = [{ name: "其它" }];
  402. } else if (form.type == "课程推荐") {
  403. visit.data = [{ name: "新课推荐" }, { name: "续费提醒" }];
  404. } else if (form.type == "常规回访") {
  405. visit.data = [{ name: "课后及作业回访" }, { name: "练习及乐团表现" }];
  406. } else if(form.type == '云教练') {
  407. visit.data = [{ name: "体验回访" }]
  408. } else {
  409. this.$toast("请选择回访类型");
  410. return;
  411. }
  412. }
  413. visit.status = true;
  414. visit.type = type;
  415. },
  416. onSearch() {
  417. this.params.page = 1;
  418. this.dataList = [];
  419. this.dataShow = true;
  420. this.loading = true;
  421. this.finished = false;
  422. this.getStudent();
  423. },
  424. onCheckboxSelect(item) {
  425. this.radioSelect = item.userId;
  426. this.radioSelectName = item.userName;
  427. this.radioSelectPhone = item.phone
  428. },
  429. onPopupCancel() {
  430. this.statusList.studentStatus = false;
  431. },
  432. onPopupSubmit() {
  433. this.form.studentId = this.radioSelect;
  434. this.studentName = this.radioSelectName;
  435. this.studentPhone = this.radioSelectPhone;
  436. this.statusList.studentStatus = false;
  437. },
  438. onCurrentConfirm(value) {
  439. if (value) {
  440. this.form.visitTime = dayjs(value).format("YYYY年MM月DD日");
  441. }
  442. this.dataForm.status = false;
  443. },
  444. onEnListShow() {
  445. // 从云教练统计来的,不许改时间,默认当前时间
  446. if (this.id || this.visitFlag) {
  447. return;
  448. }
  449. this.dataForm.status = true;
  450. },
  451. getStudent() {
  452. let params = this.params;
  453. queryStudentsWithTeacher(params).then((res) => {
  454. let result = res.data;
  455. this.loading = false;
  456. if (result.code == 200 && result.data) {
  457. params.page = result.data.pageNo;
  458. this.dataList = this.dataList.concat(result.data.rows);
  459. if (params.page >= result.data.totalPage) {
  460. this.finished = true;
  461. }
  462. this.params.page++;
  463. } else {
  464. this.finished = true;
  465. }
  466. // 判断是否有数据
  467. if (this.dataList.length <= 0) {
  468. this.dataShow = false;
  469. }
  470. });
  471. },
  472. onModeSelect(value) {
  473. let visit = this.visit;
  474. let form = this.form;
  475. if (visit.type == "type") {
  476. form.type = value.name;
  477. form.purpose = null;
  478. } else if (visit.type == "purpose") {
  479. form.purpose = value.name;
  480. }
  481. visit.status = false;
  482. },
  483. formatter(type, value) {
  484. if (type === "year") {
  485. return `${value}年`;
  486. } else if (type === "month") {
  487. return `${value}月`;
  488. } else if (type === "day") {
  489. return `${value}日`;
  490. }
  491. return value;
  492. },
  493. desensitPhone(phone) {
  494. // 手机号脱敏
  495. let first = phone.substr(0, 3);
  496. let last = phone.substr(-4);
  497. return first + "****" + last;
  498. },
  499. },
  500. };
  501. </script>
  502. <style lang='less' scoped>
  503. @import url("../../assets/commonLess/variable.less");
  504. /deep/.van-popup--bottom {
  505. border-radius: 0px 0px 0px 0px!important;
  506. overflow: auto!important;
  507. }
  508. .addVisit {
  509. min-height: 100vh;
  510. }
  511. .vip-title {
  512. padding: .06rem .14rem .04rem;
  513. font-size: .14rem;
  514. color: #808080;
  515. }
  516. /deep/.van-cell-group {
  517. margin-bottom: 0.1rem;
  518. }
  519. /deep/.van-cell {
  520. display: flex;
  521. align-items: center;
  522. font-size: 0.16rem;
  523. line-height: 0.28rem;
  524. }
  525. /deep/.van-field__label,
  526. /deep/.van-cell__value {
  527. flex: 1 auto;
  528. }
  529. /deep/.van-field__word-limit {
  530. margin-top: 0px;
  531. position: absolute;
  532. top: -0.2rem;
  533. right: 5px;
  534. font-size: 0.14rem;
  535. }
  536. /deep/.van-field__control:disabled {
  537. color: #6a6969;
  538. }
  539. .textarea {
  540. display: flex;
  541. flex-direction: column;
  542. align-items: inherit;
  543. padding: 0.1rem 0.21rem;
  544. /deep/.van-field__label {
  545. width: 100%;
  546. }
  547. // /deep/.van-field__value {
  548. // border: 1px solid #ccc;
  549. // }
  550. }
  551. .button-group {
  552. margin: 0.3rem 0.26rem 0.2rem;
  553. .van-button--primary {
  554. background: @mColor;
  555. border: 1px solid @mColor;
  556. font-size: 0.18rem;
  557. height: 0.5rem;
  558. }
  559. }
  560. .studentContainer {
  561. /deep/.van-cell__title {
  562. font-size: 0.14rem;
  563. color: @mFontColor;
  564. // flex: 1 auto;
  565. }
  566. .logo {
  567. width: 0.42rem;
  568. height: 0.42rem;
  569. margin-right: 0.12rem;
  570. border-radius: 100%;
  571. }
  572. .input-cell {
  573. padding: 0.2rem 0.16rem;
  574. .van-radio {
  575. justify-content: flex-end;
  576. }
  577. }
  578. /deep/.van-cell__value {
  579. height: 0.2rem;
  580. }
  581. /deep/.van-radio__icon .van-icon {
  582. border-color: #d3d3d3;
  583. }
  584. /deep/.van-radio__icon--checked {
  585. .van-icon {
  586. border-color: @mColor;
  587. background: @mColor;
  588. }
  589. }
  590. .van-tag {
  591. margin-left: 0.08rem;
  592. }
  593. }
  594. /deep/.van-field__right-icon, .phone_section {
  595. display: flex;
  596. }
  597. .iconPhone {
  598. width: .17rem;
  599. height: .21rem;
  600. }
  601. .paddingB80 {
  602. padding-bottom: 0.8rem;
  603. }
  604. .button-group-popup {
  605. position: fixed;
  606. bottom: 0;
  607. padding: 0.2rem 0;
  608. width: 100%;
  609. text-align: center;
  610. background-color: #ffffff;
  611. .btn {
  612. line-height: 0.5rem;
  613. display: inline-block;
  614. border: 1px solid @mColor;
  615. width: 1.65rem;
  616. border-radius: 0.4rem;
  617. color: @mColor;
  618. background: #fff;
  619. font-size: 0.18rem;
  620. &.primary {
  621. color: #fff;
  622. background: @mColor;
  623. }
  624. }
  625. .btn + .btn {
  626. margin-left: 0.1rem;
  627. }
  628. }
  629. .studentColor {
  630. color: @mColor;
  631. }
  632. .visiTimer {
  633. /deep/.van-field__control {
  634. color: #333333 !important;
  635. font-size: 0.16rem;
  636. }
  637. }
  638. .studentName {
  639. font-size: 0.16rem;
  640. color: #1a1a1a;
  641. line-height: 0.22rem;
  642. }
  643. .dot {
  644. width: 4px;
  645. height: 0.17rem;
  646. background: #01c1b5;
  647. border-radius: 3px;
  648. position: absolute;
  649. z-index: 200;
  650. top: 0.14rem;
  651. left: 0.12rem;
  652. }
  653. .van-icon-search {
  654. color: @mColor;
  655. }
  656. </style>