diff --git a/common/js/diy.js b/common/js/diy.js index 87149b5..cab3742 100644 --- a/common/js/diy.js +++ b/common/js/diy.js @@ -51,6 +51,11 @@ export default { lastDiyInfoTime: 0, // 上次成功加载的时间戳 lastDiyInfoLang: '', // 上次加载时的语言,语言切换时强制刷新 diyInfoTtl: 3 * 60 * 1000, // 3分钟内不重复请求 + + // diy 数据网络加载失败时的页面内错误提示(比 showModal 在各端更可靠) + diyLoadError: false, + diyLoadErrorMsg: '', + diyLoadErrorUrl: '', // 出错的网络请求地址 //启动广告 adv:{}, @@ -310,6 +315,52 @@ export default { } }, + // 无法从网络获取 diy 数据时:在页面内渲染错误横幅(各端可靠、一定可见) + // @param {Object|string} [err] 网络异常对象 {errMsg, statusCode} / 服务端消息字符串 + // @param {string} [url] 出错的请求地址(完整 URL),用于横幅展示 + _showDiyLoadError(err, url) { + this.diyLoadErrorMsg = this._buildDiyErrorMsg(err); + this.diyLoadErrorUrl = url || ''; + this.diyLoadError = true; + }, + // 根据错误信息组织更详细的提示文案 + // 说明:remote-only 模式下 $lang 可能返回空串,故统一用 `|| 中文兜底` 保证非空 + _buildDiyErrorMsg(err) { + // 无错误信息 -> 通用网络异常 + if (!err) return this.$lang('diy.networkError'); + // 服务端明确返回的业务消息(字符串) + if (typeof err === 'string') return err; + + const statusCode = err.statusCode; + const errMsg = err.errMsg || err.message || ''; + let reason; + + if (statusCode) { + // HTTP 状态码类错误 + if (statusCode === 404) reason = this.$lang('diy.errNotFound'); + else if (statusCode >= 500) reason = this.$lang('diy.errServer'); + else if (statusCode === 401 || statusCode === 403) reason = this.$lang('diy.errAuth'); + else reason = this.$lang('diy.errRequest'); + reason += '(' + statusCode + ')'; + } else if (/timeout/i.test(errMsg)) { + reason = this.$lang('diy.errTimeout'); + } else if (/(connect|network|fail)/i.test(errMsg)) { + reason = this.$lang('diy.errNetwork'); + } else { + // 未知错误 -> 通用网络异常 + return this.$lang('diy.networkError'); + } + + const tpl = this.$lang('diy.loadFailTpl'); + return tpl.replace('{reason}', reason); + }, + // 错误横幅「重试」入口 + retryDiyInfo() { + this.diyLoadError = false; + this.diyLoadErrorMsg = ''; + this.diyLoadErrorUrl = ''; + this.getDiyInfo(true); + }, async getDiyInfo(force = false) { // 节流:正在请求 / N 秒内已加载过 / 语言未变 -> 跳过 const now = Date.now(); @@ -324,9 +375,12 @@ export default { this.diyInfoLoading = true; let res; + // 出错时用于展示的完整请求地址(Request URL),与 http.js 拼接/归一化方式保持一致 + const diyInfoUrl = '/api/diyview/info'; + const diyInfoFullUrl = ((Config.baseUrl || '') + diyInfoUrl).replace(/(? + + + + {{ diyLoadErrorMsg || '网络异常,请稍后重试' }} + {{ diyLoadErrorUrl }} + + {{ $lang('diy.retry') || '重试' }} + + @@ -179,6 +188,52 @@ export default { z-index: 122; } +.diy-load-error { + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 100000; + display: flex; + align-items: center; + justify-content: space-between; + padding: 24rpx 28rpx; + padding-top: calc(24rpx + var(--status-bar-height, 0px)); + background-color: #fff5f5; + border-bottom: 1rpx solid #ffccc7; +} + +.diy-load-error__body { + flex: 1; + display: flex; + flex-direction: column; + min-width: 0; +} + +.diy-load-error__msg { + font-size: 26rpx; + color: #cf1322; + line-height: 1.5; +} + +.diy-load-error__url { + margin-top: 6rpx; + font-size: 22rpx; + color: #999; + line-height: 1.4; + word-break: break-all; +} + +.diy-load-error__btn { + margin-left: 20rpx; + padding: 10rpx 28rpx; + font-size: 26rpx; + color: #fff; + background-color: #cf1322; + border-radius: 32rpx; + white-space: nowrap; +} + .small-bot swiper { width: 560rpx; height: 784rpx;