cart-step.vue 8.0 KB

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