diff --git a/.DS_Store b/.DS_Store index 38ee387c..8085be64 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/pro_v3.5.1/nginx-crmeb.conf b/pro_v3.5.1/nginx-crmeb.conf new file mode 100644 index 00000000..6cab0431 --- /dev/null +++ b/pro_v3.5.1/nginx-crmeb.conf @@ -0,0 +1,33 @@ +server { + listen 80; + server_name 127.0.0.1; + + root /Users/apple/scott2026/huangjingfen/pro_v3.5.1/public; + index index.html index.php; + + location ~* \.(php|jsp|cgi|asp|aspx)$ { + proxy_pass http://127.0.0.1:20199; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header REMOTE-HOST $remote_addr; + } + + location / { + if (!-e $request_filename) { + proxy_pass http://127.0.0.1:20199; + } + proxy_http_version 1.1; + proxy_read_timeout 360s; + proxy_redirect off; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header REMOTE-HOST $remote_addr; + add_header X-Cache $upstream_cache_status; + add_header Cache-Control no-cache; + expires 12h; + } +} diff --git a/pro_v3.5.1/view/admin/package-lock.json b/pro_v3.5.1/view/admin/package-lock.json index 656279f5..cc501972 100644 --- a/pro_v3.5.1/view/admin/package-lock.json +++ b/pro_v3.5.1/view/admin/package-lock.json @@ -7324,88 +7324,6 @@ "sha.js": "^2.4.8" } }, - "node_modules/cross-env": { - "version": "10.1.0", - "resolved": "https://registry.npmmirror.com/cross-env/-/cross-env-10.1.0.tgz", - "integrity": "sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@epic-web/invariant": "^1.0.0", - "cross-spawn": "^7.0.6" - }, - "bin": { - "cross-env": "dist/bin/cross-env.js", - "cross-env-shell": "dist/bin/cross-env-shell.js" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/cross-env/node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/cross-env/node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmmirror.com/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/cross-env/node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cross-env/node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/cross-env/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/cross-env": { "version": "10.0.0", "resolved": "https://registry.npmmirror.com/cross-env/-/cross-env-10.0.0.tgz", diff --git a/pro_v3.5.1/view/uniapp/App.vue b/pro_v3.5.1/view/uniapp/App.vue index c3681c46..d1b04f8c 100644 --- a/pro_v3.5.1/view/uniapp/App.vue +++ b/pro_v3.5.1/view/uniapp/App.vue @@ -19,8 +19,8 @@ isLogin: false, userInfo: {}, globalData: false, - windowHeight: uni.getWindowInfo().windowHeight + 'px', - sysHeight:uni.getWindowInfo().statusBarHeight, + windowHeight: (uni.getWindowInfo && uni.getWindowInfo() ? uni.getWindowInfo().windowHeight : window.innerHeight || 667) + 'px', + sysHeight: uni.getWindowInfo && uni.getWindowInfo() ? uni.getWindowInfo().statusBarHeight : 0, }, computed: mapGetters(['isLogin', 'cartNum']), watch: { @@ -39,15 +39,15 @@ } }, onShow(options) { - const queryData = uni.getEnterOptionsSync(); // uni-app版本 3.5.1+ 支持 - if (queryData.query.spid) { + const queryData = (uni.getEnterOptionsSync && uni.getEnterOptionsSync()) || { query: {} }; // uni-app版本 3.5.1+ 支持 + if (queryData.query && queryData.query.spid) { this.$Cache.set('spread', queryData.query.spid); this.globalData.spid = queryData.query.spid; this.globalData.pid = queryData.query.spid; silenceBindingSpread(this.globalData); } // #ifdef MP - if (queryData.query.scene) { + if (queryData.query && queryData.query.scene) { let param = this.$util.getUrlParams(decodeURIComponent(queryData.query.scene)); if (param.spid) { this.$Cache.set('spread', param.spid); @@ -90,12 +90,12 @@ this.remoteRegister(option.query.remote_token); } this.setScript(); - const queryData = uni.getEnterOptionsSync(); + const queryData = (uni.getEnterOptionsSync && uni.getEnterOptionsSync()) || { query: {} }; uni.getSystemInfo({ success(e) { /* 窗口宽度大于420px且不在PC页面且不在移动设备时跳转至 PC.html 页面 */ if (e.windowWidth > 420 && !window.top.isPC && !/iOS|Android/i.test(e.system)) { - window.location.pathname = '/static/html/pc.html'; + window.location.pathname = '/h5/static/html/pc.html'; } } }); diff --git a/pro_v3.5.1/view/uniapp/babel.config.js b/pro_v3.5.1/view/uniapp/babel.config.js new file mode 100644 index 00000000..3a8cd0a4 --- /dev/null +++ b/pro_v3.5.1/view/uniapp/babel.config.js @@ -0,0 +1,8 @@ +const HX_BABEL = '/Applications/HBuilderX.app/Contents/HBuilderX/plugins/uniapp-cli/node_modules' + +module.exports = { + plugins: [ + require.resolve('@babel/plugin-proposal-optional-chaining', { paths: [HX_BABEL] }), + require.resolve('@babel/plugin-proposal-nullish-coalescing-operator', { paths: [HX_BABEL] }) + ] +} diff --git a/pro_v3.5.1/view/uniapp/index.html b/pro_v3.5.1/view/uniapp/index.html index ca50e5e7..b71cd629 100644 --- a/pro_v3.5.1/view/uniapp/index.html +++ b/pro_v3.5.1/view/uniapp/index.html @@ -15,6 +15,23 @@ window.wx = null; //uniapp默认的wx重置 + - + \ No newline at end of file diff --git a/pro_v3.5.1/view/uniapp/uni-h5-polyfill.js b/pro_v3.5.1/view/uniapp/uni-h5-polyfill.js new file mode 100644 index 00000000..b23fe6f9 --- /dev/null +++ b/pro_v3.5.1/view/uniapp/uni-h5-polyfill.js @@ -0,0 +1,188 @@ +/** + * H5 polyfill: 在 UniApp 框架初始化完成前,为 uni API 提供浏览器降级实现。 + * + * 核心策略: + * - 用 Object.defineProperty 拦截 window.uni 的赋值,防止 UniApp 运行时 + * 用存根对象覆盖我们的实现。 + * - 当 UniApp 将 stub 对象赋给 window.uni 时,把 stub 合并到我们的代理 + * 对象中,同时保留我们对"未实现"API 的真实降级实现。 + * - 之后 UniApp 注册真正的 H5 实现(如 uni.request = xhrImpl),属性直接 + * 写到代理对象上,我们的 polyfill 就会被替换,互不干扰。 + */ +;(function () { + if (typeof window === 'undefined') return; + + /* -------- 各 API 的降级实现 -------- */ + var polyfills = {}; + + // uni.request → XHR + polyfills.request = function (opts) { + opts = opts || {}; + var xhr = new XMLHttpRequest(); + var method = (opts.method || 'GET').toUpperCase(); + var url = opts.url || ''; + + // GET/HEAD 把 data 追加到 query string + if (opts.data && (method === 'GET' || method === 'HEAD')) { + var qs = Object.keys(opts.data).map(function (k) { + return encodeURIComponent(k) + '=' + encodeURIComponent(opts.data[k]); + }).join('&'); + if (qs) url += (url.indexOf('?') >= 0 ? '&' : '?') + qs; + } + + try { + xhr.open(method, url, true); + } catch (e) { + opts.fail && opts.fail({ errMsg: 'request:fail ' + e.message }); + return; + } + + // 设置请求头 + var header = opts.header || opts.headers || {}; + Object.keys(header).forEach(function (k) { + try { xhr.setRequestHeader(k, header[k]); } catch (e) {} + }); + + xhr.onreadystatechange = function () { + if (xhr.readyState !== 4) return; + var statusCode = xhr.status; + var data; + try { data = JSON.parse(xhr.responseText); } catch (e) { data = xhr.responseText; } + + // 解析响应头 + var resHeader = {}; + try { + (xhr.getAllResponseHeaders() || '').split('\r\n').forEach(function (line) { + var idx = line.indexOf(':'); + if (idx > 0) resHeader[line.slice(0, idx).trim().toLowerCase()] = line.slice(idx + 1).trim(); + }); + } catch (e) {} + + var res = { statusCode: statusCode, data: data, header: resHeader }; + if (statusCode >= 200 && statusCode < 400) { + opts.success && opts.success(res); + } else { + opts.fail && opts.fail({ errMsg: 'request:fail statusCode ' + statusCode }); + } + opts.complete && opts.complete(res); + }; + + xhr.onerror = function () { + var err = { errMsg: 'request:fail network error' }; + opts.fail && opts.fail(err); + opts.complete && opts.complete(err); + }; + + xhr.ontimeout = function () { + var err = { errMsg: 'request:fail timeout' }; + opts.fail && opts.fail(err); + opts.complete && opts.complete(err); + }; + + var body = null; + if (opts.data && method !== 'GET' && method !== 'HEAD') { + body = typeof opts.data === 'string' ? opts.data : JSON.stringify(opts.data); + } + try { xhr.send(body); } catch (e) { + opts.fail && opts.fail({ errMsg: 'request:fail ' + e.message }); + } + }; + + // getStorageSync → localStorage + polyfills.getStorageSync = function (key) { + try { + var v = localStorage.getItem(key); + if (v === null) return undefined; + try { return JSON.parse(v); } catch (e) { return v; } + } catch (e) { return undefined; } + }; + + polyfills.setStorageSync = function (key, data) { + try { + localStorage.setItem(key, typeof data === 'object' ? JSON.stringify(data) : String(data)); + } catch (e) {} + }; + + polyfills.removeStorageSync = function (key) { + try { localStorage.removeItem(key); } catch (e) {} + }; + + // getWindowInfo → 浏览器 window + polyfills.getWindowInfo = function () { + return { + windowWidth: window.innerWidth || 375, + windowHeight: window.innerHeight || 667, + screenWidth: window.screen ? window.screen.width : 375, + screenHeight: window.screen ? window.screen.height : 667, + statusBarHeight: 0, + safeAreaInsets: { top: 0, bottom: 0, left: 0, right: 0 } + }; + }; + + // getEnterOptionsSync → 解析当前 URL query + polyfills.getEnterOptionsSync = function () { + var query = {}; + try { + var search = location.search.slice(1); + if (search) { + search.split('&').forEach(function (pair) { + var kv = pair.split('='); + if (kv[0]) query[decodeURIComponent(kv[0])] = decodeURIComponent(kv[1] || ''); + }); + } + } catch (e) {} + return { query: query, path: location.pathname }; + }; + + /* -------- 代理对象:稳定的 window.uni -------- */ + // 创建持久代理对象,把 polyfill 方法写入 + var _proxy = {}; + Object.keys(polyfills).forEach(function (k) { _proxy[k] = polyfills[k]; }); + + /** + * 把一个 uni 对象(可能含存根)合并到 _proxy。 + * 原则:如果 polyfill 中有对应 key,则仅当对方的实现不是存根时才覆盖; + * 其余 key 直接合并,以保留 UniApp 运行时的其他功能(路由、组件等)。 + */ + function mergeIntoProxy(srcObj) { + if (!srcObj || typeof srcObj !== 'object') return; + Object.keys(srcObj).forEach(function (k) { + var val = srcObj[k]; + if (polyfills[k]) { + // 对于我们有 polyfill 的 key:只有对方是真正的实现时才覆盖 + // 简单判断:UniApp 存根函数不含 prototype.constructor 以外的属性且长度固定 + // 最安全的方式:暂时保留我们的实现,等真实实现直接赋值给 uni.xxx 时再替换 + // 这里什么都不做——让 UniApp 运行时后续直接赋值来替换 + } else { + _proxy[k] = val; + } + }); + // 把 prototype 链上的方法也复制(如 $emit/$on 等) + try { + var proto = Object.getPrototypeOf(srcObj); + if (proto && proto !== Object.prototype) { + Object.getOwnPropertyNames(proto).forEach(function (k) { + if (k !== 'constructor' && !_proxy[k]) { + try { _proxy[k] = proto[k].bind(srcObj); } catch (e) {} + } + }); + } + } catch (e) {} + } + + /* 拦截 window.uni 赋值 */ + try { + Object.defineProperty(window, 'uni', { + get: function () { return _proxy; }, + set: function (newVal) { + // UniApp 运行时把存根对象赋给 window.uni 时在这里被拦截 + mergeIntoProxy(newVal); + }, + configurable: true, + enumerable: true + }); + } catch (e) { + // 极少数情况下 defineProperty 失败,退化为直接赋值 + window.uni = _proxy; + } +})(); diff --git a/pro_v3.5.1/view/uniapp/utils/cache.js b/pro_v3.5.1/view/uniapp/utils/cache.js index 0c712556..7a919724 100644 --- a/pro_v3.5.1/view/uniapp/utils/cache.js +++ b/pro_v3.5.1/view/uniapp/utils/cache.js @@ -193,30 +193,34 @@ class Cache { * 清除过期缓存 */ clearOverdue() { - let cahceValue = this.cacheGetHandler(this.cacheExpire), - time = this.time(), - newBeOverdueValue = [], - newTagValue = []; + try { + let cahceValue = this.cacheGetHandler(this.cacheExpire), + time = this.time(), + newBeOverdueValue = [], + newTagValue = []; - if (cahceValue && typeof cahceValue === 'object' && cahceValue.length) { - cahceValue.map(item => { - if (item) { - if ((item.expire !== undefined && item.expire > time) || item.expire === 0) { - newTagValue.push(item); - } else { - newBeOverdueValue.push(item.key); + if (Array.isArray(cahceValue) && cahceValue.length) { + cahceValue.map(item => { + if (item) { + if ((item.expire !== undefined && item.expire > time) || item.expire === 0) { + newTagValue.push(item); + } else { + newBeOverdueValue.push(item.key); + } } - } - }); + }); + } + //保存没有过期的缓存标签 + if (!Array.isArray(cahceValue) || newTagValue.length !== cahceValue.length) { + this.cacheSetHandler(this.cacheExpire, newTagValue); + } + //删除过期缓存 + newBeOverdueValue.forEach(k => { + this.cacheClearHandler(k); + }) + } catch (e) { + // H5 初始化阶段 uni 存储 API 可能尚未就绪,忽略错误 } - //保存没有过期的缓存标签 - if (newTagValue.length !== cahceValue.length) { - this.cacheSetHandler(this.cacheExpire, newTagValue); - } - //删除过期缓存 - newBeOverdueValue.forEach(k => { - this.cacheClearHandler(k); - }) } } diff --git a/pro_v3.5.1/view/uniapp/utils/index.js b/pro_v3.5.1/view/uniapp/utils/index.js index c9540206..fd17832c 100644 --- a/pro_v3.5.1/view/uniapp/utils/index.js +++ b/pro_v3.5.1/view/uniapp/utils/index.js @@ -83,6 +83,8 @@ export function parseQuery() { // #ifdef H5 const VUE_APP_WS_URL = process.env.VUE_APP_WS_URL || `ws://${location.hostname}`; export {VUE_APP_WS_URL} + const VUE_APP_API_URL = process.env.VUE_APP_API_URL || `${location.protocol}//${location.hostname}`; + export {VUE_APP_API_URL} // #endif diff --git a/pro_v3.5.1/view/uniapp/vue.config.js b/pro_v3.5.1/view/uniapp/vue.config.js index 3612e93e..4bd0eaf0 100644 --- a/pro_v3.5.1/view/uniapp/vue.config.js +++ b/pro_v3.5.1/view/uniapp/vue.config.js @@ -1,5 +1,39 @@ module.exports = { productionSourceMap: false, // 生产打包时不输出map文件,增加打包速度 + devServer: { + port: 8080, + proxy: { + '/api': { + target: 'http://127.0.0.1', + changeOrigin: true + }, + '/uploads': { + target: 'http://127.0.0.1', + changeOrigin: true + }, + '/statics': { + target: 'http://127.0.0.1', + changeOrigin: true + } + } + }, + chainWebpack: config => { + const HX_BABEL = '/Applications/HBuilderX.app/Contents/HBuilderX/plugins/uniapp-cli/node_modules' + const optionalChaining = require.resolve('@babel/plugin-proposal-optional-chaining', { paths: [HX_BABEL] }) + const nullishCoalescing = require.resolve('@babel/plugin-proposal-nullish-coalescing-operator', { paths: [HX_BABEL] }) + config.module.rule('js').use('babel-loader').tap(options => { + options = options || {} + options.plugins = options.plugins || [] + const pluginPaths = options.plugins.map(p => (Array.isArray(p) ? p[0] : p)) + if (!pluginPaths.includes(optionalChaining)) { + options.plugins.push(optionalChaining) + } + if (!pluginPaths.includes(nullishCoalescing)) { + options.plugins.push(nullishCoalescing) + } + return options + }) + }, configureWebpack: config => { if (process.env.NODE_ENV === 'production') { config.optimization.minimizer[0].options.terserOptions.compress.warnings = false