cart-step.vue 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. <template>
  2. <z-paging ref="paging" v-model="list" :auto="false" :height="safeScrollHeight" auto-show-system-loading
  3. @query="handleQuery">
  4. <template #top>
  5. <slot name="top"/>
  6. <mx-condition-dropdown ref="dropdown" x layout="fx-row items-center gap-20 w-max"/>
  7. </template>
  8. <voluntary-search @search="handleSearch"/>
  9. <view class="fx-col p-20 gap-20">
  10. <voluntary-item v-for="item in list" :item="item" @major="openMajorPopup(item)" @notify="showNotify"/>
  11. <vip-guide-more v-if="isNotVip"/>
  12. </view>
  13. <template #bottom>
  14. <voluntary-bottom @modify="$refs.modifyPopup.open()" @cart="$refs.cartPopup.open()"/>
  15. </template>
  16. </z-paging>
  17. <!-- 这里渲染的弹窗不会被back-to-top遮挡 -->
  18. <score-batch-popup ref="modifyPopup"/>
  19. <voluntary-cart-popup ref="cartPopup"/>
  20. <major-popup ref="majorPopup" @notify="showNotify"/>
  21. <uv-notify ref="notifier"/>
  22. </template>
  23. <script setup>
  24. import {computed, ref, watch} from 'vue';
  25. import {toValue} from "@vueuse/core";
  26. import {createPropDefine} from "@/utils";
  27. import {sleep} from "@/uni_modules/uv-ui-tools/libs/function";
  28. import {getRecommendVoluntary, getVoluntaryMarjors} from "@/api/webApi/volunteer";
  29. import {useUserStore} from "@/hooks/useUserStore";
  30. import {useInjectVoluntaryForm} from "@/pages/voluntary/hooks/useVoluntaryFormInjection";
  31. import {useInjectVoluntaryAssistant} from "@/pages/voluntary/hooks/useVoluntaryAssistantInjection";
  32. import {useInjectVoluntaryStep} from "@/pages/voluntary/hooks/useVoluntaryStepInjection";
  33. import {useInjectVoluntaryHeader} from "@/pages/voluntary/hooks/useVoluntaryHeaderInjection";
  34. import {useVoluntaryMajorGroupIdentifier} from "@/pages/voluntary/hooks/useVoluntaryMajorGroupIdentifier";
  35. import {useInjectVoluntaryCart} from "@/pages/voluntary/hooks/useVoluntaryCartInjection";
  36. import VoluntaryItem from "@/pages/voluntary/index/components/voluntary-item.vue";
  37. import VoluntaryBottom from "@/pages/voluntary/index/components/voluntary-bottom.vue";
  38. import MajorPopup from "@/pages/voluntary/index/components/major-popup.vue";
  39. import ScoreBatchPopup from "@/pages/voluntary/index/components/score-batch-popup.vue";
  40. import VoluntaryCartPopup from "@/pages/voluntary/index/components/voluntary-cart-popup.vue";
  41. import VoluntarySearch from "@/pages/voluntary/index/components/voluntary-search.vue";
  42. import {useProvideVoluntarySearch} from "@/pages/voluntary/hooks/useVoluntarySearchInjection";
  43. const props = defineProps({
  44. editMode: createPropDefine(false, Boolean)
  45. })
  46. const paging = ref(null)
  47. const notifier = ref(null)
  48. const majorPopup = ref(null)
  49. const cartPopup = ref(null)
  50. const dropdown = ref(null)
  51. const {currentUser, GetInfo, isBind} = useUserStore()
  52. const {model, batch, mode} = useInjectVoluntaryForm()
  53. const {currentStep} = useInjectVoluntaryStep()
  54. const {
  55. resetCart, total, list, selectedList,
  56. syncMajorGroupToSelected, syncMajorsToSelectedGroup
  57. } = useInjectVoluntaryCart()
  58. const {scrollHeight, onBeforeBack, save} = useInjectVoluntaryAssistant() // 填报页下面有原生tabs,必须手动设置高度
  59. const {isMock, ensureHistoryYears} = useInjectVoluntaryHeader()
  60. const {formatQueryParams, onSearch, reset: resetCondition} = useProvideVoluntarySearch()
  61. const safeScrollHeight = computed(() => scrollHeight ? toValue(scrollHeight) + 'px' : undefined)
  62. const isNotVip = computed(() => {
  63. return !toValue(isBind) && toValue(total) > 1
  64. })
  65. const showNotify = (message) => {
  66. const msg = message || '未发布详细的征集信息'
  67. notifier.value.show({
  68. message: msg,
  69. type: 'warning',
  70. top: 1
  71. })
  72. }
  73. const openMajorPopup = (item) => {
  74. if (item.isExpand) {
  75. return majorPopup.value.open(item)
  76. } else {
  77. item.isExpand = true
  78. loadMajorDetails(item)
  79. }
  80. }
  81. const loadMajorDetails = (item) => {
  82. uni.showLoading()
  83. getVoluntaryMarjors({
  84. batchName: toValue(batch).name,
  85. collegeCode: item.recruitPlan.collegeCode,
  86. jCode: item.jCode,
  87. mode: toValue(mode),
  88. universityId: item.recruitPlan.universityId,
  89. year: item.recruitPlan.year,
  90. score: toValue(model).score
  91. }).then(res => {
  92. syncMajorsToSelectedGroup(res.data, item)
  93. item.majors = res.data
  94. majorPopup.value.open(item)
  95. }).finally(() => uni.hideLoading())
  96. }
  97. const syncUserScoreByNeed = (query) => {
  98. const {score, seatInput/*, mode*/} = toValue(currentUser)
  99. // if query score mode seatInput changed, re-call getInfo.
  100. if (query.score != score ||
  101. // query.mode != mode ||
  102. query.seatInput != seatInput) {
  103. GetInfo()
  104. }
  105. }
  106. const handleQuery = async (pageNum, pageSize) => {
  107. const batchVal = toValue(batch)
  108. const modelVal = toValue(model)
  109. const batchData = {
  110. batchName: batchVal.name,
  111. batch: batchVal.batch,
  112. batchMinScore: batchVal.score2 || batchVal.score1
  113. }
  114. const modelData = {
  115. mode: toValue(mode),
  116. score: modelVal.score,
  117. seatInput: modelVal.seatInput
  118. }
  119. const data = {
  120. ...batchData,
  121. ...modelData,
  122. ...formatQueryParams()
  123. }
  124. const res = await getRecommendVoluntary(data, {pageNum, pageSize})
  125. if (pageNum == 1) syncUserScoreByNeed(data)
  126. total.value = res.total
  127. // make reactive properties
  128. let rows = {}
  129. rows = res.rows.map(item => {
  130. item.isExpand = false
  131. item.majors = []
  132. return item
  133. })
  134. rows.forEach(useVoluntaryMajorGroupIdentifier)
  135. // 回显
  136. syncMajorGroupToSelected(rows)
  137. paging.value.completeByTotal(rows, total.value)
  138. }
  139. const checkPopupBlock = async () => {
  140. // major popup
  141. if (majorPopup.value.show) {
  142. majorPopup.value.close()
  143. return Promise.reject('popup close')
  144. }
  145. if (dropdown.value.getShow()) {
  146. dropdown.value.terminate()
  147. return Promise.reject('popup close')
  148. }
  149. }
  150. const confirmSave = async () => {
  151. return new Promise((resolve, reject) => {
  152. uni.showModal({
  153. content: '是否要保存当前志愿表',
  154. showCancel: true,
  155. cancelText: '放弃保存',
  156. confirmText: '保存志愿表',
  157. success: res => {
  158. if (res.confirm) {
  159. reject() // to prevent back operation.
  160. save(isMock.value)
  161. } else {
  162. resolve() // to continue back operation.
  163. }
  164. }
  165. })
  166. })
  167. }
  168. const handleSearch = () => paging.value.reload() // 输入框触发
  169. onSearch(() => paging.value.reload()) // 条件选择器触发
  170. onBeforeBack(async () => {
  171. if (currentStep.value == 2) {
  172. // 先控制弹层元素 专业详情/条件筛选
  173. await checkPopupBlock()
  174. // 再判定志愿表
  175. if (selectedList.value.length) {
  176. await confirmSave()
  177. }
  178. }
  179. })
  180. const reloadWatches = [
  181. currentStep,
  182. () => model.value.score * 1,
  183. () => model.value.seatInput * 1,
  184. () => batch.value.batch * 1
  185. ]
  186. watch(reloadWatches, async ([step, score, input, batch], arg2) => {
  187. if (step == 2) {
  188. if (!props.editMode) resetCart() // 编辑模式下保留cart数据
  189. cartPopup.value.close()
  190. majorPopup.value.close()
  191. dropdown.value.terminate()
  192. await sleep(400) // wait for animation complete
  193. resetCondition()
  194. }
  195. })
  196. watch(currentStep, async (step) => {
  197. if (step == 2) {
  198. const payload = {mode: toValue(mode), year: toValue(batch).year, isMock: toValue(isMock)}
  199. await ensureHistoryYears(payload)
  200. }
  201. })
  202. defineExpose({checkPopupBlock, confirmSave})
  203. </script>
  204. <style scoped lang="scss">
  205. ::v-deep .zp-page-bottom-container {
  206. z-index: 10;
  207. }
  208. </style>