From 68a838221b01ed8570db01d4d8878d5dd533ea5a Mon Sep 17 00:00:00 2001 From: hongqiwei <1143662660@qq.com> Date: Tue, 8 Sep 2026 20:30:55 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9C=BA=E5=9C=B0=E9=A2=84=E7=BA=A6=E6=95=B4?= =?UTF-8?q?=E6=94=B9=EF=BC=9A=E5=88=86=E5=B7=A5=E4=BC=9A/=E5=8D=8F?= =?UTF-8?q?=E4=BC=9A=E5=AE=A1=E6=A0=B8-=E6=A0=A1=E5=B7=A5=E4=BC=9A?= =?UTF-8?q?=E5=AE=A1=E6=A0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../static/assets/mobile/css/main.css | 3 +- .../views/mobile/activity/site/info.html | 70 ++++++++++++++++--- .../views/mobile/activity/site/reserve.html | 4 +- 3 files changed, 66 insertions(+), 11 deletions(-) diff --git a/src/main/resources/static/assets/mobile/css/main.css b/src/main/resources/static/assets/mobile/css/main.css index ab67e8a..d3b8e21 100644 --- a/src/main/resources/static/assets/mobile/css/main.css +++ b/src/main/resources/static/assets/mobile/css/main.css @@ -22,7 +22,8 @@ body { } [v-cloak] { - display: none; + /* Vue 挂载前隐藏原始模板及弹框内容,避免被 #app 的 display 规则覆盖;挂载后 Vue 自动移除此属性。 */ + display: none !important; } a, img { diff --git a/src/main/resources/views/mobile/activity/site/info.html b/src/main/resources/views/mobile/activity/site/info.html index 0f7359f..f94d057 100644 --- a/src/main/resources/views/mobile/activity/site/info.html +++ b/src/main/resources/views/mobile/activity/site/info.html @@ -198,10 +198,11 @@ layout("/mobile/platform.html"){ -
+
@@ -269,8 +270,10 @@ layout("/mobile/platform.html"){ (() => { // PJAX 先执行内联脚本,等待历史组件加载;离开后的旧加载回调不能挂载到新页面。 const pageRoot = document.getElementById('app') + let pageStarted = false const startPage = () => { - if (document.getElementById('app') !== pageRoot || !pageRoot.isConnected) return + if (pageStarted || document.getElementById('app') !== pageRoot || !pageRoot.isConnected) return + pageStarted = true const siteTypeUtil = new typeUtil() new Vue({ @@ -282,8 +285,11 @@ layout("/mobile/platform.html"){ typeFilterShow:false, formLoading:false, tarBarActive: 0, list: ['a', 'b'], - typeList: [], + typeList: [{text:'全部场地类型',value:''}], siteId: '', + // 初始化完成前禁止列表触发请求;requesting 独立于 Vant 的 loading 双向绑定。 + listReady: false, requesting: false, requestVersion: 0, listError: false, + loading: true, mLoading: true, } }, watch: { @@ -297,6 +303,9 @@ layout("/mobile/platform.html"){ beforeDestroy() { // PJAX 替换 DOM 不会自动销毁实例,显式清理本页监听并触发历史 mixin 注销。 $(document).off('pjax:beforeReplace.siteList', this._siteListDispose) + // 离开页面后,类型请求和列表请求的旧回调均不能再发请求或追加数据。 + this.$set(this, 'listReady', false) + this.$set(this, 'requestVersion', this.requestVersion + 1) }, methods: { setPopupState(key, value) { this.$set(this, key, value) }, @@ -332,17 +341,62 @@ layout("/mobile/platform.html"){ this.clearPopupHistory(()=>{location.href = '/mobile/activity/site/info/reserve?id=' + this.siteId}) }, doSearch() { - this.pageForm.pageNumber = 1 - this.tableData = [] - this.finished = false + if (!this.listReady || this._isDestroyed || this._isBeingDestroyed) return + // 新筛选拥有独立请求版本,旧响应及其 always 不能污染新列表或关闭新请求的 loading。 + this.$set(this, 'requestVersion', this.requestVersion + 1) + this.$set(this, 'requesting', false) + this.$set(this.pageForm, 'pageNumber', 1) + this.$set(this.pageForm, 'totalCount', 0) + this.$set(this, 'tableData', []) + this.$set(this, 'finished', false) + this.$set(this, 'listError', false) this.onLoad() }, onLoad() { - this.loading=true;return $.post('/mobile/activity/site/info/pageData',this.pageForm).then((res)=>{if(res.code===0){this.tableData=this.tableData.concat(res.data.list);this.finished=this.tableData.length>=res.data.totalCount;if(!this.finished)this.pageForm.pageNumber++}else{vant.Toast(res.msg)}}).always(()=>{this.loading=false}); + if (!this.listReady || this.requesting || this.finished || this._isDestroyed || this._isBeingDestroyed) return + const version = this.requestVersion + // 请求携带筛选和页码快照;成功后才推进页码,失败重试仍请求原页。 + const params = Object.assign({}, this.pageForm) + this.$set(this, 'requesting', true) + this.$set(this, 'loading', true) + this.$set(this, 'listError', false) + return $.post('/mobile/activity/site/info/pageData', params).then((res) => { + if (version !== this.requestVersion) return + if (!res || res.code !== 0 || !res.data || !Array.isArray(res.data.list)) { + this.$set(this, 'listError', true) + vant.Toast(res && res.msg || '场地列表加载失败,请重试') + return + } + const rows = this.tableData.concat(res.data.list) + this.$set(this, 'tableData', rows) + this.$set(this.pageForm, 'totalCount', res.data.totalCount) + this.$set(this, 'finished', res.data.list.length === 0 || rows.length >= res.data.totalCount) + this.$set(this.pageForm, 'pageNumber', params.pageNumber + 1) + }, () => { + if (version !== this.requestVersion) return + this.$set(this, 'listError', true) + vant.Toast('场地列表加载失败,请重试') + }).always(() => { + if (version !== this.requestVersion) return + this.$set(this, 'requesting', false) + this.$set(this, 'loading', false) + this.$set(this, 'mLoading', false) + }) }, }, created() { - siteTypeUtil.getAllType().then((rows)=>{this.typeList=[{text:'全部场地类型'}].concat(rows);this.$set(this.pageForm,'typeId',this.typeList[0].value);this.onLoad()}); + // 类型加载结束后统一启动首屏;类型请求失败时仍允许查看全部场地。 + siteTypeUtil.getAllType().then((rows) => { + if (this._isDestroyed || this._isBeingDestroyed) return + this.$set(this, 'typeList', [{text:'全部场地类型',value:''}].concat(rows)) + }, () => { + if (!this._isDestroyed && !this._isBeingDestroyed) vant.Toast('场地类型加载失败,先显示全部场地') + }).always(() => { + if (this._isDestroyed || this._isBeingDestroyed) return + this.$set(this.pageForm, 'typeId', '') + this.$set(this, 'listReady', true) + this.doSearch() + }) } }) } diff --git a/src/main/resources/views/mobile/activity/site/reserve.html b/src/main/resources/views/mobile/activity/site/reserve.html index f9db9a8..63f70ad 100644 --- a/src/main/resources/views/mobile/activity/site/reserve.html +++ b/src/main/resources/views/mobile/activity/site/reserve.html @@ -265,8 +265,8 @@ layout("/mobile/platform.html"){ 确认
- - + +