// ==UserScript== // @name 腾讯文档 - 快递工具合集(优化版) // @namespace http://tampermonkey.net/ // @version 3.7 // @description 快递CSV单号匹配 + 智能文本解析 + 格式化填入 + 数量拆分 // @author Codex // @match https://docs.qq.com/sheet/* // @icon https://docs.qq.com/favicon.ico // @grant GM_notification // @license MIT // ==/UserScript== (function(){"use strict"; var D=document; // CSS注入 (function(){var s=D.createElement("style");s.textContent=".co{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,.35);z-index:999999;display:flex;align-items:center;justify-content:center;font-family:Microsoft YaHei,sans-serif}.cd{background:#fff;border-radius:12px;padding:0;width:760px;max-width:92vw;max-height:88vh;box-shadow:0 8px 32px rgba(0,0,0,.2);display:flex;flex-direction:column;font-size:14px;color:#1d2129;overflow:hidden}.ct{display:flex;background:#f7f8fa;border-bottom:1px solid #e5e6e8}.ct button{padding:12px 24px;border:none;background:transparent;font-size:14px;cursor:pointer;color:#4e5969;border-bottom:2px solid transparent}.ct button:hover{background:#eef0f4}.ct button.on{color:#2468f2;border-bottom-color:#2468f2;background:#fff;font-weight:600}.cb{padding:20px 24px 16px;overflow-y:auto;flex:1}.cb .hint{color:#86909c;font-size:13px;margin-bottom:8px}.cb textarea{width:100%;height:130px;padding:10px 12px;border:1px solid #e5e6e8;border-radius:6px;font-size:13px;font-family:Consolas,monospace;resize:vertical;box-sizing:border-box;outline:none;margin-bottom:8px}.cb textarea:focus{border-color:#2468f2}.cb label{font-size:13px;color:#4e5969;display:inline-flex;align-items:center;gap:4px;margin-right:10px}.cb label input[type=text]{width:50px;padding:4px 6px;border:1px solid #e5e6e8;border-radius:4px;font-size:13px;text-align:center;outline:none}.cb label input[type=text]:focus{border-color:#2468f2}.cb .br{display:flex;gap:10px;justify-content:flex-end;margin-top:8px;flex-wrap:wrap}.cb .br button{padding:8px 20px;border-radius:6px;border:none;font-size:14px;cursor:pointer}.cb .br button:hover{opacity:.85}.bp{background:#2468f2;color:#fff}.bs{background:#f2f3f5;color:#4e5969}.bp:disabled{opacity:.5;cursor:not-allowed}.cl{background:#f7f8fa;border-radius:6px;padding:10px 12px;margin-top:8px;max-height:200px;overflow:auto;font-size:12px;font-family:Consolas,monospace;line-height:1.6;white-space:pre-wrap}.cl .ok{color:#00b42a}.cl .skip{color:#86909c}.cl .err{color:#f53f3f}.cr{border:1px solid #e5e6e8;border-radius:6px;margin-top:8px;max-height:200px;overflow:auto;font-size:12px}.cr table{width:100%;border-collapse:collapse}.cr th{background:#f7f8fa;padding:5px 7px;text-align:left;font-weight:600;border-bottom:1px solid #e5e6e8;font-size:11px}.cr td{padding:4px 7px;border-bottom:1px solid #f2f3f5;max-width:140px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:11px}.cf,.cm{position:fixed;right:32px;z-index:999999;width:48px;height:48px;border-radius:50%;color:#fff;border:none;box-shadow:0 4px 12px rgba(36,104,242,.4);font-size:22px;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:.2s}.cf:hover,.cm:hover{transform:scale(1.08)}.cf{bottom:32px;background:#2468f2}.cm{bottom:92px;background:#00b42a}";D.head.appendChild(s)})(); // 按钮 D.body.appendChild(function(b){b.className="cf";b.textContent="CSV";b.title="CSV单号匹配";b.onclick=function(){showDialog("csv")};return b}(D.createElement("button"))); D.body.appendChild(function(b){b.className="cm";b.textContent="AI";b.title="智能解析文本";b.onclick=function(){showDialog("parse")};return b}(D.createElement("button"))); function sl(t){return new Promise(function(r){setTimeout(r,t)})} function L(el,t,c){var d=D.createElement("div");d.textContent=t;if(c)d.className=c;el.appendChild(d);el.scrollTop=el.scrollHeight} async function wc(cell,val){ var lb=D.querySelector(".bar-label"),ed=D.querySelector("#alloy-simple-text-editor"); if(!lb||!ed)return false; var v=String(val||"");lb.focus();lb.value=cell; lb.dispatchEvent(new Event("input",{bubbles:true})); ["keydown","keypress","keyup"].forEach(function(t){lb.dispatchEvent(new KeyboardEvent(t,{key:"Enter",keyCode:13,bubbles:true}))}); lb.dispatchEvent(new Event("change",{bubbles:true}));await sl(200); ed.focus();window.getSelection().selectAllChildren(ed);document.execCommand("delete",false); await sl(30);document.execCommand("insertText",false,v);await sl(30); ed.dispatchEvent(new Event("input",{bubbles:true}));ed.dispatchEvent(new Event("change",{bubbles:true})); await sl(50);ed.blur();await sl(100);return true } async function rc(cell){var lb=D.querySelector(".bar-label"),ed=D.querySelector("#alloy-simple-text-editor");if(!lb||!ed)return"";lb.focus();lb.value=cell;lb.dispatchEvent(new Event("input",{bubbles:true}));["keydown","keypress","keyup"].forEach(function(t){lb.dispatchEvent(new KeyboardEvent(t,{key:"Enter",keyCode:13,bubbles:true}))});lb.dispatchEvent(new Event("change",{bubbles:true}));await sl(250);return(ed.textContent||"").trim()} async function fr(f){for(var r=f||2;r<=Math.min((f||2)+20,500);r++){var v=await rc("A"+r);if(!v)return r}return f||2} async function fill(r,s,cl){var o=0,f=0;for(var i=0;i=2){ var S=function(s){return s.split(L[0].includes("\t")||L[1]&&L[1].includes("\t")?"\t":",").map(function(v){return v.replace(/^"|"$/g,"").trim()})}; var H=S(L[0]),ni=-1,ti=-1; for(var i=0;i=0&&ti>=0){for(var i=1;i=10){var n=m[2].trim(),tn=m[1];(M[n]=M[n]||[]).push(tn)} } return M }var _qtyRe=/^([\u4e00-\u4e8c\u4e24\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341\d]+)(?:\u7bb1|\u76d2|\u5305|\u888b|\u6761|\u7f50|\u74f6|\u6876|\u4e2a|\u4efd|\u5757|\u5377|\u5bf9|\u53cc|\u5957|\u6253|\u4ef6|\u6346|\u63d0)\s*/; var _num={一:1,二:2,两:2,三:3,四:4,五:5,六:6,七:7,八:8,九:9,十:10,俩:2}; var _mod=new Set(["送","赠送","附送","加送","免费","赠品","配件","备件","电话","手机","tel","联系电话","固话","座机"]); function parseQty(s){var m=s.match(_qtyRe);if(!m)return[1,s];var n=/^\d+$/.test(m[1])?parseInt(m[1]):(_num[m[1]]||1);return[n,s.slice(m[0].length).trim()]} function isBad(w){if(/^[\u4e00-\u4e8c\u4e24\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341\d]+[\u7bb1\u76d2\u5305\u888b\u6761\u7f50\u74f6\u6876\u4e2a\u4efd\u5757\u5377\u5bf9\u53cc\u5957\u6253\u4ef6\u6346\u63d0]$/.test(w))return true;if(_mod.has(w))return true;if(/^\d+$/.test(w))return true;return false} function splItems(t){return t.split(/[、,,;;\s]+/).map(function(s){return s.trim()}).filter(Boolean)} var _notName=/^(?:电话|手机|手机号码|手机号|联系电话|固话|座机|地址|收货地址|收件人|收件人姓名|姓名|名字|联系人|物品|商品|货品|产品|内容|省市区|所在地区|区县|省份|城市|邮编)$/; function isName(s){return /^[\u4e00-\u9fa5]{1,4}$/.test(s)&&!/[市区县镇乡街道路弄号巷村组楼]/.test(s)&&!_notName.test(s)} function parseOrder(text){ var t=text.trim();if(!t)return null;var r={name:"",phone:"",landline:"",address:"",items:[],_qty:1}; // 识别末尾数量标记,如(5箱)(2箱)或(5箱)(2箱),设置数量并移除 var qtyMatch=t.match(/[((]\s*(\d+)\s*(?:箱|盒|包|袋|条|罐|瓶|桶|个|份|块|卷|对|双|套|打|件|捆|提)\s*[))]$/); if(qtyMatch){r._qty=parseInt(qtyMatch[1]);t=t.replace(qtyMatch[0],"").trim()} // 去掉序号前缀 t=t.replace(/^\d+[、...]\s*/,""); // *标签最高优先级 var sn=t.match(/[**]\s*收件人姓名[::]?(.+?)(?:\n|$)/); if(sn){r.name=sn[1].trim().replace(/(?:先生|女士|小姐|师傅|小哥|同学|老师|收)\s*$/,"");t=t.replace(sn[0],"")} var sa=t.match(/[**]\s*省市区(县)详细地址[::]?(.+?)(?:\n|$)/); if(sa){r.address=sa[1].trim();t=t.replace(sa[0],"")} var sp=t.match(/[**]\s*收件人手机[::]?(1[3-9]\d{9})/); if(sp&&!r.phone){r.phone=sp[1];t=t.replace(sp[0],"")} var pm=t.match(/1\s*[3-9]\s*\d\s*\d\s*\d\s*\d\s*\d\s*\d\s*\d\s*\d\s*\d/); if(pm){r.phone=pm[0].replace(/\s+/g,"");t=t.replace(pm[0],"").replace(/收件人手机[::]?/,"").replace(/电话[::]?\s*/,"").replace(/手机号码[::]?\s*/,"").replace(/手机[::]?\s*/,"")} var lm=t.match(/0\d{2,3}[- ]?\d{7,8}/);if(lm){r.landline=lm[0];t=t.replace(lm[0],"").replace(/固话[::]?\s*/,"")} while(true){ var addrMatch=t.match(/(?:地址|收货地址|省市区|所在地|所在地区|详细地址)[::]\s*(.+?)(?=\n|$|(?:地址|收货地址|省市区|所在地|所在地区|详细地址)[::])/); if(!addrMatch)break; var addrPart=addrMatch[1].trim(); if(r.address&&addrPart.indexOf(r.address.slice(-4))>=0&&r.address.indexOf(addrPart.slice(0,4))>=0){t=t.replace(addrMatch[0],"");continue} r.address=(r.address||"")+addrPart; t=t.replace(addrMatch[0],"") } var nameMatch=t.match(/(?:姓名|收件人|收货人|联系人|名字)[::]\s*(.+?)(?:\n|$)/); if(nameMatch&&!r.name){r.name=nameMatch[1].trim().replace(/(?:先生|女士|小姐|师傅|小哥|同学|老师|收)\s*$/,"");t=t.replace(nameMatch[0],"")} var itemMatch=t.match(/(?:物品|商品|货品|产品|内容)[::]\s*(.+?)(?:\n|$)/); if(itemMatch){r.items=splItems(itemMatch[1]);t=t.replace(itemMatch[0],"")} t=t.replace(/(?:收件人|收货人|联系人|姓名|手机号码|手机|电话|固话|地址|详细地址|所在地区|省市区|物品|商品|产品|内容)[::]/gi,""); t=t.replace(/,+\s*,+/g,",").replace(/^[,\s]+/,"").replace(/[,\s]+$/,""); t=t.replace(/[。,]/g," "); var segs=t.split(/[\s,;;\n\r]+/).map(function(s){return s.trim()}).filter(Boolean); if(!r.name&&r.phone){ var searchText=text.replace(/^\d+[、...]\s*/,""); var pi=searchText.indexOf(r.phone); if(pi<0){var cp=t.indexOf(r.phone);pi=cp>=0?cp:0} var bp=searchText.substring(0,pi).split(/[\s,,、;;:\n\r]+/).filter(Boolean); var afterPart=searchText.substring(pi+r.phone.length).trim(); var afterWords=afterPart.split(/[\s,,、;;:\n\r]+/).filter(Boolean); // 判断手机号前面的词是否像地址(以省市开头) var isAddrBefore=bp.some(function(w){return /^(?:北京|天津|上海|重庆|河北|山西|辽宁|吉林|黑龙江|江苏|浙江|安徽|福建|江西|山东|河南|湖北|湖南|广东|海南|四川|贵州|云南|陕西|甘肃|青海|台湾|内蒙古|广西|西藏|宁夏|新疆)/.test(w)}); if(isAddrBefore&&afterWords.length){ // 地址在前 → 取手机号后面的词作为姓名 for(var i=0;i=1&&!/^\d+$/.test(w)&&!/^1[3-9]/.test(w)&&!/电话|手机|固话/.test(w)){r.name=w;break} } } if(!r.name){ // 姓名在前 → 取手机号前面最近的词 for(var i=bp.length-1;i>=0;i--){ var w=bp[i].trim(); if(w.length>=1&&!/^\d+$/.test(w)&&!/^1[3-9]/.test(w)&&!/电话|手机|固话/.test(w)){r.name=w;break} } } }var pRe=/^(?:北京|天津|上海|重庆|河北|山西|辽宁|吉林|黑龙江|江苏|浙江|安徽|福建|江西|山东|河南|湖北|湖南|广东|海南|四川|贵州|云南|陕西|甘肃|青海|台湾|内蒙古|广西|西藏|宁夏|新疆)/; if(r.name){var ni=-1;for(var i=0;i=0){r.address=(r.address||"")+segs.slice(0,ni).join("");segs=segs.slice(ni+1)}} if(!r.address){var aS=[],oS=[];for(var i=0;i=1){var ss=splItems(segs[i]);for(var j=0;j1?[""]:[]); // 用末尾数量标记覆盖物品数量 if(r._qty>1&&r.items.length===0){r.items=[""]} return r; function filterUnique(a){var seen={};return a.filter(function(x){if(seen[x])return false;seen[x]=true;return true})} } function parseMultipleOrders(text,startLine){ if(startLine>1){var _ls=text.split("\n");text=_ls.slice(startLine-1).join("\n")} // 自动分行:遇到"手机号(数量)→ 下条地址开头"插入空行 var _ln=text.split("\n");var _nf=[]; for(var _i=0;_i<_ln.length;_i++){ _nf.push(_ln[_i]); if(_i<_ln.length-1){ var _cu=_ln[_i].trim(),_nx=_ln[_i+1].trim(); // 手机号后跟商品名 if(_cu&&_nx&&/1[3-9]\d{9}$/.test(_cu.replace(/\s+/g,""))&&/^[一二两三四五六七八九十\d]+(?:箱|盒|包|袋|条|罐|瓶|桶|个|份|块|卷|对|双|套|打|件|捆|提)/.test(_nx)){ _nf.push(""); } // 序号开头 if(_cu&&_nx&&/^\d+[、..]/.test(_nx)){ _nf.push(""); } // 手机号+(数量)结尾 → 下一行非空且不以序号/空白开头 if(_cu&&_nx&&/1[3-9]\d{9}(\d+[箱盒包袋条罐瓶桶个份块卷对双套打件捆提])$/.test(_cu)&&!/^\d+[、..]/.test(_nx)){ _nf.push(""); } } } text=_nf.join("\n"); // 预处理手机号空格 text=text.replace(/1\s*[3-9]\s*\d\s*\d\s*\d\s*\d\s*\d\s*\d\s*\d\s*\d\s*\d/g,function(m){return m.replace(/\s+/g,"")}); var _pc=(text.match(/1[3-9]\d{9}/g)||[]); if(_pc.length<=1){ var _single=parseOrder(text); if(_single&&_single.name&&_single.phone){ var _si=_single.items.length?_single.items:[""];var _sr=[]; for(var _j=0;_j<_si.length;_j++){for(var _k=0;_k<_single._qty;_k++){_sr.push({name:_single.name,phone:_single.phone,landline:_single.landline,address:_single.address,item:_si[_j]})}} return{rows:_sr,errors:[]} } } var blocks=text.split(/\n\s*\n/).map(function(b){return b.trim()}).filter(Boolean); var allRows=[],errs=[]; for(var i=0;i=0||nc.indexOf(k)>=0){fk=k;break}}} if(!fk||!used[fk]||!used[fk].length){L(log,"第"+rw.row+"行"+c+"→CSV未匹配","err");fail++;continue} var tn=used[fk].shift(); if(!tn){L(log,"第"+rw.row+"行"+c+"→无单号","err");fail++;continue} (await wc("G"+rw.row,tn))?L(log,"第"+rw.row+"行"+c+" → "+tn,"ok"):L(log,"第"+rw.row+"行写入失败","err"); await sl(30) } L(log,"\n完成:填充"+fill+"行,跳过"+skip+"行,失败"+fail+"行"); }catch(e){L(log,"错误:"+e.message,"err")} btn.textContent="完成";btn.disabled=false; GM_notification({text:"单号匹配完成:"+fill+"行",timeout:3000}) } } function buildParse(ov){ var t=ov.querySelector("#tab-parse"); t.innerHTML='
粘贴快递文本,自动解析。支持多行/多单/数量标记如(5箱)
'; var ta=t.querySelector("textarea"),pv=t.querySelector("#ppv"),pl=t.querySelector("#ppl"),pb=t.querySelector("#ppb"),cur=[]; t.querySelector("#ppc").onclick=function(){ov.remove()}; t.querySelector("#ppp").onclick=function(){ var text=ta.value.trim();if(!text){alert("请先粘贴快递文本");return} var r=parseMultipleOrders(text,1);cur=r.rows; if(!cur.length){alert("未解析到有效信息");return} pv.style.display="block"; var h='
'; for(var i=0;i"} pv.innerHTML=h+"
姓名手机固话地址格式化合并
"+x.name+""+x.phone+""+(x.landline||"")+""+x.address+""+formatOrderLine(x)+"
"; pl.style.display="block";pl.innerHTML="";L(pl,"解析"+cur.length+"条,失败"+r.errors.length+"条");r.errors.forEach(function(e){L(pl,"!"+e,"err")}); pb.style.display="flex" }; t.querySelector("#ppfill").onclick=async function(){ if(!cur.length)return; var sr=parseInt(t.querySelector(".prn").value)||1; if(t.querySelector(".auto-row").checked)sr=await fr(sr); var fm=t.querySelector("#fmtMerge").checked,btn=t.querySelector("#ppfill"); btn.disabled=true;btn.textContent="写入中…"; var ok=0,fail=0; if(fm){ for(var i=0;i