index.vue 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. <template>
  2. <Container
  3. :title="title"
  4. :scrollY="maskStyle.height < 0"
  5. @onSafeAreaChange="onSafeAreaChange"
  6. >
  7. <uni-collapse
  8. ref="collapse"
  9. v-model="value"
  10. class="class-content"
  11. @change="onChnage"
  12. v-show="!showContainer"
  13. >
  14. <view class="free-content">
  15. <uni-collapse-item
  16. :title="item.name"
  17. v-for="item in freeChaptersList"
  18. :key="item.id"
  19. class="text"
  20. >
  21. <view class="-mt-20">
  22. <Tree
  23. :chaptersList="item.children"
  24. @onChnage="onChnage"
  25. @onClickButton="onClickButton"
  26. />
  27. </view>
  28. </uni-collapse-item>
  29. </view>
  30. <!-- 付费功能 -->
  31. <view class="pay-content" v-if="chaptersList.length">
  32. <view
  33. class="modal-mask"
  34. :style="{
  35. height: `${maskStyle.height}px`,
  36. width: `100vw`,
  37. }"
  38. v-if="maskStyle.height > 0"
  39. >
  40. <view class="locked">
  41. <uni-icons type="locked" color="#fff" size="35"></uni-icons>
  42. </view>
  43. <view class="modal-wrapper" @click="onClickMask">邀请好友可解锁</view>
  44. </view>
  45. <uni-collapse-item
  46. :title="item.name"
  47. v-for="item in chaptersList"
  48. :key="item.id"
  49. class="text"
  50. >
  51. <view class="-mt-20">
  52. <Tree
  53. :chaptersList="item.children"
  54. @onChnage="onChnage"
  55. @onClickButton="onClickButton"
  56. />
  57. </view>
  58. </uni-collapse-item>
  59. </view>
  60. </uni-collapse>
  61. <Modal
  62. ref="popup"
  63. background-color="#fff"
  64. v-model:open="showContainer"
  65. title="邀请新客户解锁课程"
  66. >
  67. <text class="unlock"
  68. >邀请一名新用户注册并完成第一章全部考点学习,可解锁新两章内容</text
  69. >
  70. <template #footer>
  71. <button>立即邀请</button>
  72. </template>
  73. </Modal>
  74. </Container>
  75. </template>
  76. <script setup name="regulations">
  77. import Tree from "../../components/Tree/Tree.vue";
  78. import Container from "../../components/Container/Container.vue";
  79. import Modal from "@/components/Modal/Modal.vue";
  80. import { ref, getCurrentInstance } from "vue";
  81. import { getRect, arrayToTree } from "../../utils";
  82. import { getRoute, router } from "../../utils/router";
  83. import { request } from "../../utils/request";
  84. import { onShow } from "@dcloudio/uni-app";
  85. const title = ref("");
  86. const collapse = ref(null);
  87. const popup = ref(null);
  88. const showContainer = ref(false);
  89. const value = ref("");
  90. const instance = getCurrentInstance();
  91. const safeArea = ref({});
  92. const maskStyle = ref({
  93. height: 0,
  94. width: 0,
  95. });
  96. const chaptersList = ref([]);
  97. const freeChaptersList = ref([]);
  98. // 点击学习按钮
  99. const onClickButton = (item) => {
  100. console.log(item);
  101. router.push({
  102. url: "/pages/regulations/learing",
  103. params: {
  104. id: item.id,
  105. parent_id: item.parent_id,
  106. name: item.name,
  107. },
  108. });
  109. };
  110. const resolveHeight = () =>
  111. setTimeout(() => {
  112. getRect({
  113. name: ".free-content",
  114. instance,
  115. onSuccess(res) {
  116. maskStyle.value.height = safeArea.value.height - res.height;
  117. },
  118. });
  119. // 动画300需要等待
  120. }, 800);
  121. const onSafeAreaChange = (s) => {
  122. safeArea.value = s;
  123. resolveHeight();
  124. };
  125. const onChnage = () => {
  126. resolveHeight();
  127. };
  128. const onClickMask = () => {
  129. router.push({
  130. url: "/pages/user/share",
  131. });
  132. };
  133. onShow(async () => {
  134. const id = getRoute().params.id;
  135. const res = await request(
  136. "api/question_bank/question_reception/chapter/get_all_chapter",
  137. {
  138. id,
  139. }
  140. );
  141. const list = arrayToTree({
  142. list: res.data,
  143. firstId: +id,
  144. });
  145. const freeList = list.filter((item) => !item.is_lock);
  146. const payList = list.filter((item) => item.is_lock);
  147. // 免费
  148. freeChaptersList.value = freeList;
  149. // 付费章节
  150. chaptersList.value = payList;
  151. title.value = getRoute().params.title;
  152. });
  153. </script>
  154. <style scoped lang="scss">
  155. @import "@/uni.scss";
  156. .text {
  157. font-family: PingFang SC, PingFang SC;
  158. font-weight: 500;
  159. font-size: 28rpx;
  160. color: #000000;
  161. }
  162. .content {
  163. display: flex;
  164. justify-content: space-between;
  165. align-items: center;
  166. padding: 8rpx 20rpx 10rpx 40rpx;
  167. .buttons {
  168. display: flex;
  169. gap: 10rpx;
  170. }
  171. .comment {
  172. width: 132rpx;
  173. height: 48rpx;
  174. display: flex;
  175. align-items: center;
  176. justify-content: center;
  177. background-color: #fff;
  178. color: $primary;
  179. border: 1px solid $primary;
  180. font-family: "PingFang SC, PingFang SC";
  181. font-weight: 500;
  182. font-size: 28rpx;
  183. color: $primary;
  184. border-radius: 4rpx;
  185. }
  186. .comment.success {
  187. color: $success;
  188. border: 1px solid $success;
  189. }
  190. .comment.warning {
  191. color: $warning;
  192. border: 1px solid $warning;
  193. }
  194. }
  195. .unlock {
  196. font-family: PingFang SC, PingFang SC;
  197. font-weight: 500;
  198. font-size: 28rpx;
  199. color: #000000;
  200. margin: 100rpx 0;
  201. display: block;
  202. }
  203. .class-content {
  204. height: 100%;
  205. }
  206. .pay-content {
  207. flex: 1;
  208. position: relative;
  209. .modal-mask {
  210. background-color: rgba($color: #333333, $alpha: 0.8);
  211. position: absolute;
  212. height: 100%;
  213. z-index: 9999;
  214. left: -24rpx;
  215. display: flex;
  216. align-items: center;
  217. flex-direction: column;
  218. justify-content: center;
  219. gap: 34rpx;
  220. }
  221. }
  222. .modal-wrapper {
  223. width: 685rpx;
  224. height: 64rpx;
  225. background: $primary;
  226. font-family: PingFang SC, PingFang SC;
  227. font-weight: 500;
  228. font-size: 28rpx;
  229. color: #fff;
  230. display: flex;
  231. align-items: center;
  232. justify-content: center;
  233. }
  234. .locked {
  235. width: 96rpx;
  236. height: 96rpx;
  237. background: linear-gradient(159deg, #00d0ff 0%, #008cff 100%);
  238. border-radius: 50%;
  239. display: flex;
  240. align-items: center;
  241. justify-content: center;
  242. }
  243. </style>