/** * 方案 A:页面加载时注入,保留双地址 React 状态,阻止 pickup 在切换 delivery 时被清空。 * 纯字符串,供 context.addInitScript 使用。 */ export const DUAL_ADDRESS_PATCH_INIT = `(() => { if (window.__rpaDualAddressPatchInstalled) return; window.__rpaDualAddressPatchInstalled = true; window.__rpaDualAddressVault = { pickup: null, delivery: null }; function findQuoterStateNode() { var selectors = [ "#react-quoter-landing-plugin", "[data-testid='quoter-widget']", "[class*='Quoter']", ]; var widget = null; for (var s = 0; s < selectors.length; s += 1) { widget = document.querySelector(selectors[s]); if (widget) break; } if (!widget) return null; var fiberKey = Object.keys(widget).find(function(k) { return k.indexOf("__reactFiber$") === 0 || k.indexOf("__reactInternalInstance$") === 0; }); if (!fiberKey) return null; var queue = [widget[fiberKey]]; var seen = new Set(); while (queue.length > 0) { var fiber = queue.shift(); if (!fiber || seen.has(fiber)) continue; seen.add(fiber); var sn = fiber.stateNode; if (sn && typeof sn.setState === "function" && sn.state) { var st = sn.state; if ( "pickupAddress" in st || "pickup" in st || "deliveryAddress" in st || (st.addresses && typeof st.addresses === "object") ) { return sn; } } if (fiber.child) queue.push(fiber.child); if (fiber.sibling) queue.push(fiber.sibling); } return null; } function buildAddressData(entry) { if (!entry) return null; return { placeId: entry.placeId, location: entry.location || {}, formattedAddress: entry.description || entry.formattedAddress || "", isCommitted: true, }; } function isPickupCleared(partial, prevState) { if (!partial || typeof partial !== "object") return false; var keys = ["pickupAddress", "pickup"]; for (var i = 0; i < keys.length; i += 1) { var k = keys[i]; if (!(k in partial)) continue; var v = partial[k]; if (v === null || v === undefined || v === "") return true; if (typeof v === "object" && !v.placeId && !v.formattedAddress) return true; } if (partial.addresses && partial.addresses.pickup === null) return true; if ( partial.activeAddressSide === "delivery" && prevState && prevState.pickupAddress && !partial.pickupAddress ) { return true; } return false; } function wrapStateNode(node) { if (!node || node.__rpaDualPatchWrapped) return; node.__rpaDualPatchWrapped = true; var orig = node.setState.bind(node); node.setState = function(partial, callback) { var vault = window.__rpaDualAddressVault; if (vault && vault.pickup && isPickupCleared(partial, node.state)) { var pdata = buildAddressData(vault.pickup); if (pdata) { partial = Object.assign({}, partial, { pickupAddress: pdata }); } } if (vault && vault.delivery && partial && partial.deliveryAddress === null) { var ddata = buildAddressData(vault.delivery); if (ddata) { partial = Object.assign({}, partial, { deliveryAddress: ddata }); } } return orig(partial, callback); }; } function injectSide(side) { var entry = window.__rpaDualAddressVault[side]; if (!entry) return false; var node = findQuoterStateNode(); if (!node) return false; wrapStateNode(node); var data = buildAddressData(entry); if (!data) return false; var patch = {}; if (side === "pickup") { patch.pickupAddress = data; patch.activeAddressSide = "delivery"; } else { patch.deliveryAddress = data; } try { node.setState(patch); return true; } catch (e) { return false; } } window.__rpaDualAddressApi = { register: function(side, payload) { window.__rpaDualAddressVault[side] = payload; var node = findQuoterStateNode(); if (node) wrapStateNode(node); return injectSide(side); }, preservePickup: function() { var node = findQuoterStateNode(); if (node) wrapStateNode(node); return injectSide("pickup"); }, preserveBoth: function() { var pickupOk = injectSide("pickup"); var deliveryOk = injectSide("delivery"); return pickupOk && deliveryOk; }, hasPickup: function() { var v = window.__rpaDualAddressVault.pickup; return !!(v && v.placeId); }, stats: function() { return { pickupRegistered: !!window.__rpaDualAddressVault.pickup, deliveryRegistered: !!window.__rpaDualAddressVault.delivery, wrapped: !!findQuoterStateNode(), apiInstalled: true, }; }, releasePickupInput: function() { var widget = document.querySelector("#react-quoter-landing-plugin"); if (!widget) return false; var clicked = false; var nodes = widget.querySelectorAll("*"); for (var i = 0; i < nodes.length; i += 1) { var t = (nodes[i].textContent || "").trim(); if (/^Deliver to$/i.test(t)) { nodes[i].click(); clicked = true; break; } } var inputs = widget.querySelectorAll("input"); for (var j = 0; j < inputs.length; j += 1) { var ph = (inputs[j].placeholder || "").toLowerCase(); if (!/search/.test(ph)) continue; if ((inputs[j].value || "").trim().length >= 8) { inputs[j].blur(); } } return clicked; }, }; var tick = 0; setInterval(function() { if (!window.__rpaDualAddressVault.pickup) return; tick += 1; if (tick % 4 !== 0) return; var node = findQuoterStateNode(); if (node) { wrapStateNode(node); injectSide("pickup"); } }, 400); })();`;