reservation.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  1. "use strict";
  2. const common_vendor = require("../../common/vendor.js");
  3. const _sfc_main = {
  4. props: {
  5. isQuantum: {
  6. type: Boolean,
  7. default: false
  8. },
  9. isMultiple: {
  10. //是否多选
  11. type: Boolean,
  12. default: false
  13. },
  14. isSection: {
  15. //预约时间段
  16. type: Boolean,
  17. default: false
  18. },
  19. disableText: {
  20. //禁用显示的文本
  21. type: String,
  22. default: "已预约"
  23. },
  24. disableSumText: {
  25. type: String,
  26. default: "已约满"
  27. },
  28. undisableText: {
  29. //未禁用显示的文本
  30. type: String,
  31. default: "可预约"
  32. },
  33. timeInterval: {
  34. // 时间间隔,小时为单位
  35. type: Number,
  36. default: 1
  37. },
  38. selectedTabColor: {
  39. // 日期栏选中的颜色
  40. type: String,
  41. default: "#51bf81"
  42. },
  43. selectedItemColor: {
  44. // 时间选中的颜色
  45. type: String,
  46. default: "#51bf81"
  47. },
  48. beginTime: {
  49. type: String,
  50. default: "08:30"
  51. },
  52. endTime: {
  53. type: String,
  54. default: "19:30"
  55. },
  56. appointTime: {
  57. // 预约的时间
  58. type: Array,
  59. default() {
  60. return [];
  61. }
  62. },
  63. disableTimeSlot: {
  64. // 预约开始和结束时间,来禁用时间段
  65. type: Array,
  66. default() {
  67. return [];
  68. }
  69. }
  70. },
  71. watch: {
  72. appointTime: {
  73. handler(val) {
  74. if (val && val.length) {
  75. this.initOnload();
  76. }
  77. }
  78. },
  79. disableTimeSlot: {
  80. handler(val) {
  81. if (val && val.length) {
  82. this.initOnload();
  83. }
  84. }
  85. }
  86. },
  87. data() {
  88. return {
  89. data: [
  90. {
  91. "teacher_id": 6,
  92. "teacher_name": "张老师",
  93. "list": {
  94. "id": 6,
  95. "course_id": 1,
  96. "teacher_id": 6,
  97. "start_time": 1731823931,
  98. "end_time": 1731324931,
  99. "duration": 60,
  100. "course_number": 30,
  101. "reservation_number": 0,
  102. "teacher_name": "张老师",
  103. "teacher_desc": "擅长舞蹈",
  104. "course_name": "拳击初级课",
  105. "course_image": "../../static/logo2.jpg",
  106. "course_desc": "拳击讲解",
  107. "address": "一方天地"
  108. }
  109. },
  110. {
  111. "teacher_id": 7,
  112. "teacher_name": "王老师",
  113. "list": {
  114. "id": 7,
  115. "course_id": 1,
  116. "teacher_id": 7,
  117. "start_time": 1731324931,
  118. "end_time": 1731823931,
  119. "duration": 60,
  120. "course_number": 30,
  121. "reservation_number": 0,
  122. "teacher_name": "王老师",
  123. "teacher_desc": "从业20年,资深老教室",
  124. "course_name": "拳击初级课",
  125. "course_image": "../../static/logo2.jpg",
  126. "course_desc": "拳击讲解",
  127. "address": "一方天地"
  128. }
  129. }
  130. ],
  131. course_number: 30,
  132. reservation_number: 0,
  133. teacher_desc: "",
  134. course_name: "",
  135. course_image: "",
  136. start_time: 1731823931,
  137. //开始时间戳
  138. end_time: 1731324931,
  139. //结束时间戳
  140. orders_product_id: 0,
  141. //商品id
  142. course_id: 0,
  143. //课程id
  144. schedule_id: 0,
  145. //排课id
  146. teacherActive: -1,
  147. orderDateTime: "暂无选择",
  148. // 选中时间
  149. orderTimeArr: {},
  150. //多选的时间
  151. dateArr: [],
  152. //日期数据
  153. timeArr: [],
  154. //时间数据
  155. nowDate: "",
  156. // 当前日期
  157. dateActive: -1,
  158. //选中的日期索引
  159. timeActive: 0,
  160. //选中的时间索引
  161. timeQuanBeginIndex: 0,
  162. //时间段开始的下标
  163. selectDate: "",
  164. //选择的日期
  165. timeQuanBegin: "",
  166. //时间段开始时间
  167. timeQuanEnd: ""
  168. //时间段结束时间
  169. // isTime:[],
  170. // teacherList: ['王老师', '崔老师','王老师', '崔老师'],
  171. // days: ['周一', '周二', '周三', '周四', '周五'],
  172. };
  173. },
  174. onLoad(e) {
  175. let { orders_product_id, course_id } = e;
  176. this.orders_product_id = orders_product_id;
  177. this.course_id = course_id;
  178. },
  179. onShow() {
  180. this.defaultTeacherDesc();
  181. this.initOnload();
  182. if (this.orders_product_id > 0 && this.course_id > 0) {
  183. this.$http.request("api/course/get_schedule_list", { orders_product_id: this.orders_product_id, course_id: this.course_id }, "post").then((res) => {
  184. if (res.code === "success") {
  185. this.data = res.data;
  186. }
  187. });
  188. }
  189. },
  190. methods: {
  191. //老师选择事件
  192. selectTeacher(index, item) {
  193. if (this.teacherActive == index)
  194. return;
  195. this.teacherActive = index;
  196. if (!this.isMultiple) {
  197. this.orderDateTime = "暂无选择";
  198. }
  199. if (this.data.length > 0) {
  200. if (this.teacherActive == index) {
  201. this.course_number = this.data[index]["list"].course_number;
  202. this.reservation_number = this.data[index]["list"].reservation_number;
  203. this.teacher_desc = this.data[index]["list"].teacher_desc;
  204. this.course_name = this.data[index]["list"].course_name;
  205. this.course_image = this.data[index]["list"].course_image;
  206. this.start_time = this.data[index]["list"].start_time;
  207. this.selectDate = this.schedule_id = this.data[index]["list"].id;
  208. this.initOnload();
  209. }
  210. }
  211. },
  212. //默认选项
  213. defaultTeacherDesc() {
  214. if (this.data.length > 0) {
  215. this.course_number = this.data[0]["list"].course_number;
  216. this.reservation_number = this.data[0]["list"].reservation_number;
  217. this.teacher_desc = this.data[0]["list"].teacher_desc;
  218. this.course_name = this.data[0]["list"].course_name;
  219. this.course_image = this.data[0]["list"].course_image;
  220. this.teacherActive = 0;
  221. this.start_time = this.data[0]["list"].start_time;
  222. this.schedule_id = this.data[0]["list"].id;
  223. }
  224. },
  225. //预约课程事件
  226. reservationPopup() {
  227. if (this.schedule_id === 0) {
  228. common_vendor.index.showToast({
  229. title: "请选择老师",
  230. icon: "none"
  231. });
  232. return;
  233. }
  234. if (this.dateActive < 0) {
  235. common_vendor.index.showToast({
  236. title: "请选择预约日期",
  237. icon: "none"
  238. });
  239. return;
  240. }
  241. if (this.orderDateTime === "暂无选择") {
  242. common_vendor.index.showToast({
  243. title: "请选择预约时间",
  244. icon: "none"
  245. });
  246. return;
  247. }
  248. this.$http.request("api/course/reservation/", { orders_product_id: this.orders_product_id, schedule_id: this.schedule_id }, "post").then((res) => {
  249. if (res.code === "success") {
  250. if (this.reservation_number < this.course_number) {
  251. this.reservation_number++;
  252. }
  253. this.handleSubmit();
  254. this.initOnload();
  255. this.$refs.outcomePopup.open("center");
  256. } else {
  257. common_vendor.index.showToast({
  258. title: `${res.msg}`,
  259. icon: "error"
  260. });
  261. return;
  262. }
  263. });
  264. },
  265. outcomeButton() {
  266. this.orderDateTime = "暂无选择";
  267. this.$refs.outcomePopup.close();
  268. },
  269. initOnload() {
  270. this.dateArr = this.initData();
  271. this.timeArr = this.initTime(this.beginTime, this.endTime, this.timeInterval, this.isQuantum);
  272. this.timeQuanBegin = this.timeQuanEnd = "";
  273. console.log(this.orderTimeArr);
  274. this.timeArr.forEach((item, index) => {
  275. if (this.isQuantum) {
  276. const cur_be_time = `${this.selectDate} ${item.begin}:00`;
  277. const cur_end_time = `${this.selectDate} ${item.end}:00`;
  278. for (let time of this.disableTimeSlot) {
  279. const [begin_time = "", end_time = ""] = time;
  280. if (begin_time && end_time && (begin_time <= cur_be_time && cur_end_time <= end_time)) {
  281. item.disable = true;
  282. }
  283. }
  284. if (this.selectDate == this.nowDate && this.currentTime().time > `${item.begin}:00`) {
  285. item.disable = true;
  286. }
  287. if (this.orderTimeArr[this.selectDate]) {
  288. for (let items of this.orderTimeArr[this.selectDate]) {
  289. if (items[0].split(" ")[1] === `${item.begin}:00` && items[1].split(" ")[1] === `${item.end}:00`) {
  290. item.isActive = true;
  291. }
  292. }
  293. }
  294. } else {
  295. if (this.reservation_number === this.course_number) {
  296. item.disableSum = true;
  297. }
  298. this.appointTime.forEach((t) => {
  299. let [date, time] = t.split(" ");
  300. if (date == this.selectDate && item.time == time) {
  301. item.disable = true;
  302. }
  303. });
  304. const cur_time = `${this.selectDate} ${item.time}`;
  305. for (let time of this.disableTimeSlot) {
  306. const [begin_time = "", end_time = ""] = time;
  307. if (begin_time && end_time && (begin_time <= cur_time && cur_time <= end_time)) {
  308. item.disable = true;
  309. }
  310. }
  311. if (!item.disable)
  312. ;
  313. this.isSection && (item.isInclude = false);
  314. if (this.isMultiple && (this.orderTimeArr[this.selectDate] || []).includes(item.time)) {
  315. item.isActive = true;
  316. }
  317. }
  318. });
  319. this.timeActive = -1;
  320. },
  321. // 日期选择事件
  322. selectDateEvent(index, item) {
  323. if (this.dateActive == index)
  324. return;
  325. this.dateActive = index;
  326. this.selectDate = item.date;
  327. if (!this.isMultiple) {
  328. this.orderDateTime = "暂无选择";
  329. }
  330. this.initOnload();
  331. },
  332. // 时间选择事件
  333. selectTimeEvent(index, item) {
  334. if (this.isQuantum) {
  335. return this.handleSelectQuantum(index, item);
  336. }
  337. if (item.disable)
  338. return;
  339. if (item.disableSum)
  340. return;
  341. if (this.isMultiple) {
  342. item.isActive = !item.isActive;
  343. this.timeArr = this.timeArr.slice();
  344. this.orderTimeArr[this.selectDate] = this.timeArr.reduce((prev, cur) => {
  345. cur.isActive && prev.push(cur.time);
  346. return prev;
  347. }, []);
  348. } else {
  349. console.log("hhh");
  350. this.timeActive = index;
  351. this.orderDateTime = `${this.selectDate} ${item.time}`;
  352. }
  353. },
  354. // 选择时间段
  355. handleSection(index, item) {
  356. if (item.disable)
  357. return;
  358. function clearTime() {
  359. this.timeQuanBeginIndex = index;
  360. this.timeQuanBegin = item.time;
  361. this.timeQuanEnd = "";
  362. }
  363. if (!this.timeQuanBegin) {
  364. clearTime.call(this);
  365. return;
  366. }
  367. if (!this.timeQuanEnd && this.timeQuanBegin) {
  368. let isDisble = false;
  369. let start = this.timeQuanBeginIndex;
  370. let end = index;
  371. start > end && ([start, end] = [end, start]);
  372. for (let i = start + 1; i < end; i++) {
  373. if (this.timeArr[i].disable) {
  374. isDisble = true;
  375. clearTime.call(this);
  376. return;
  377. }
  378. }
  379. if (!isDisble) {
  380. for (let i = start + 1; i < end; i++) {
  381. this.timeArr[i].isInclude = true;
  382. }
  383. }
  384. this.timeQuanEnd = item.time;
  385. return;
  386. }
  387. if (this.timeQuanBegin && this.timeQuanEnd) {
  388. this.timeArr.forEach((t) => {
  389. t.isInclude = false;
  390. });
  391. clearTime.call(this);
  392. }
  393. },
  394. handleSelectQuantum(index, item) {
  395. if (item.disable)
  396. return;
  397. if (this.isMultiple) {
  398. item.isActive = !item.isActive;
  399. this.timeArr = this.timeArr.slice();
  400. this.orderTimeArr[this.selectDate] = this.timeArr.reduce((prev, cur) => {
  401. const cur_be_time = `${this.selectDate} ${cur.begin}:00`;
  402. const cur_end_time = `${this.selectDate} ${cur.end}:00`;
  403. cur.isActive && prev.push([cur_be_time, cur_end_time]);
  404. return prev;
  405. }, []);
  406. } else {
  407. this.timeActive = index;
  408. this.orderDateTime = {
  409. begin: `${this.selectDate} ${item.begin}:00`,
  410. end: `${this.selectDate} ${item.end}:00`
  411. };
  412. }
  413. console.log(this.orderTimeArr);
  414. },
  415. handleChange() {
  416. this.timeQuanBegin > this.timeQuanEnd && ([this.timeQuanBegin, this.timeQuanEnd] = [
  417. this.timeQuanEnd,
  418. this.timeQuanBegin
  419. ]);
  420. },
  421. handleSubmit() {
  422. if (this.isMultiple) {
  423. if (this.isQuantum) {
  424. this.$emit("change", this.orderTimeArr);
  425. return;
  426. }
  427. for (let date in this.orderTimeArr) {
  428. this.orderTimeArr[date].forEach((item) => {
  429. });
  430. }
  431. } else {
  432. this.appointTime.push(this.orderDateTime);
  433. }
  434. },
  435. //字符串拼接
  436. strFormat(str) {
  437. return str < 10 ? `0${str}` : str;
  438. },
  439. // 获取当前时间
  440. currentTime() {
  441. const myDate = /* @__PURE__ */ new Date();
  442. const y = myDate.getFullYear();
  443. const m = myDate.getMonth() + 1;
  444. const d = myDate.getDate();
  445. const date = y + "-" + this.strFormat(m) + "-" + this.strFormat(d);
  446. const hour = myDate.getHours();
  447. const min = myDate.getMinutes();
  448. const secon = myDate.getSeconds();
  449. const time = this.strFormat(hour) + ":" + this.strFormat(min) + ":" + this.strFormat(secon);
  450. return {
  451. date,
  452. time
  453. };
  454. },
  455. //时间戳转日期
  456. timeStamp(time, isQuantum) {
  457. const dates = new Date(time);
  458. const year = dates.getFullYear();
  459. const month = dates.getMonth() + 1;
  460. const date = dates.getDate();
  461. const day = dates.getDay();
  462. const hour = dates.getHours();
  463. const min = dates.getMinutes();
  464. const days = ["日", "一", "二", "三", "四", "五", "六"];
  465. return {
  466. allDate: `${year}/${this.strFormat(month)}/${this.strFormat(date)}`,
  467. date: `${this.strFormat(year)}-${this.strFormat(month)}-${this.strFormat(date)}`,
  468. //返回的日期 07-01
  469. day: `周${days[day]}`,
  470. //返回的礼拜天数 星期一
  471. hour: this.strFormat(hour) + ":" + this.strFormat(min) + (isQuantum ? "" : "")
  472. //返回的时钟 08:00
  473. };
  474. },
  475. //获取最近7天的日期和礼拜天数
  476. initData() {
  477. const time = [];
  478. const now = this.start_time * 1e3;
  479. let timeStr = 3600 * 24 * 1e3;
  480. let obj = {
  481. 0: "今天"
  482. // 1: "明天",
  483. // 2: "后天"
  484. };
  485. for (let i = 0; i < 7; i++) {
  486. time.push({
  487. date: this.timeStamp(now + timeStr * i).date,
  488. //保存日期
  489. timeStamp: now + timeStr * i,
  490. //保存时间戳
  491. week: obj[i] ?? this.timeStamp(now + timeStr * i).day
  492. });
  493. }
  494. return time;
  495. },
  496. //时间数组
  497. initTime(startTime = "10:00:00", endTime = "21:00:00", timeInterval = 1, isQuantum = false) {
  498. const time = [];
  499. const date = this.timeStamp(Date.now()).allDate;
  500. const startDate = `${date} ${startTime}`;
  501. const endDate = `${date} ${endTime}`;
  502. const startTimeStamp = new Date(startDate).getTime();
  503. const endTimeStamp = new Date(endDate).getTime();
  504. const timeStr = 3600 * 1e3 * timeInterval;
  505. const sum = (endTimeStamp - startTimeStamp) / timeStr;
  506. const count = sum % 2 == 0 ? sum : sum - 1;
  507. for (let i = startTimeStamp; i <= endTimeStamp; i = i + timeStr) {
  508. if (isQuantum) {
  509. num++;
  510. time.push({
  511. begin: this.timeStamp(i, isQuantum).hour,
  512. end: this.timeStamp(i + timeStr, isQuantum).hour,
  513. disable: false
  514. });
  515. } else {
  516. time.push({
  517. time: this.timeStamp(i).hour,
  518. sum: `${this.reservation_number}/${this.course_number}`,
  519. disableSum: false,
  520. disable: false
  521. });
  522. }
  523. if (isQuantum && num >= count)
  524. return time;
  525. }
  526. return time;
  527. }
  528. }
  529. };
  530. if (!Array) {
  531. const _easycom_uni_popup2 = common_vendor.resolveComponent("uni-popup");
  532. _easycom_uni_popup2();
  533. }
  534. const _easycom_uni_popup = () => "../../uni_modules/uni-popup/components/uni-popup/uni-popup.js";
  535. if (!Math) {
  536. _easycom_uni_popup();
  537. }
  538. function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
  539. return {
  540. a: common_vendor.t($data.course_name),
  541. b: common_vendor.t($data.teacher_desc),
  542. c: $data.course_image,
  543. d: common_vendor.f($data.data, (item, index, i0) => {
  544. return {
  545. a: common_vendor.t(item.teacher_name),
  546. b: index,
  547. c: common_vendor.o(($event) => $options.selectTeacher(index, item), index),
  548. d: common_vendor.n(index === $data.teacherActive ? "active" : "")
  549. };
  550. }),
  551. e: common_vendor.f($data.dateArr, (item, index, i0) => {
  552. return {
  553. a: common_vendor.t(item.week),
  554. b: common_vendor.t(item.date),
  555. c: index,
  556. d: common_vendor.o(($event) => $options.selectDateEvent(index, item), index),
  557. e: index == $data.dateActive ? 1 : "",
  558. f: index == $data.dateActive ? $props.selectedTabColor : "#333"
  559. };
  560. }),
  561. f: common_vendor.f($data.timeArr, (item, _index, i0) => {
  562. return {
  563. a: common_vendor.t(item.disable ? $props.disableText : $props.undisableText),
  564. b: common_vendor.t(item.time),
  565. c: common_vendor.t(item.sum),
  566. d: _index,
  567. e: item.disable ? 1 : "",
  568. f: ($props.isMultiple ? item.isActive : _index == $data.timeActive) ? 1 : "",
  569. g: $props.isMultiple ? item.isActive ? "#fff" : "#333" : _index == $data.timeActive ? "#fff" : "#333",
  570. h: $props.isMultiple ? item.isActive ? $props.selectedItemColor : "" : _index == $data.timeActive ? $props.selectedItemColor : "",
  571. i: common_vendor.o(($event) => $options.selectTimeEvent(_index, item), _index)
  572. };
  573. }),
  574. g: common_vendor.t($data.orderDateTime),
  575. h: common_vendor.o(($event) => $options.reservationPopup()),
  576. i: common_vendor.t($data.orderDateTime),
  577. j: common_vendor.o(($event) => $options.outcomeButton()),
  578. k: common_vendor.sr("outcomePopup", "46f39ab6-0"),
  579. l: common_vendor.p({
  580. ["is-mask-click"]: false
  581. })
  582. };
  583. }
  584. const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);
  585. wx.createPage(MiniProgramPage);