@kc-one/smart-fill-sdk 0.0.1-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +204 -0
- package/dist/examples/vanilla/main.d.ts +2 -0
- package/dist/examples/vanilla/main.d.ts.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.esm.js +1492 -0
- package/dist/index.umd.cjs +92 -0
- package/dist/src/adapters/native.d.ts +3 -0
- package/dist/src/adapters/native.d.ts.map +1 -0
- package/dist/src/client/gateway-client.d.ts +52 -0
- package/dist/src/client/gateway-client.d.ts.map +1 -0
- package/dist/src/config/defaults.d.ts +7 -0
- package/dist/src/config/defaults.d.ts.map +1 -0
- package/dist/src/core/errors.d.ts +13 -0
- package/dist/src/core/errors.d.ts.map +1 -0
- package/dist/src/core/instance-manager.d.ts +24 -0
- package/dist/src/core/instance-manager.d.ts.map +1 -0
- package/dist/src/core/smart-fill-instance.d.ts +105 -0
- package/dist/src/core/smart-fill-instance.d.ts.map +1 -0
- package/dist/src/core/smart-fill.d.ts +39 -0
- package/dist/src/core/smart-fill.d.ts.map +1 -0
- package/dist/src/events/event-bus.d.ts +12 -0
- package/dist/src/events/event-bus.d.ts.map +1 -0
- package/dist/src/filler/dom-filler.d.ts +32 -0
- package/dist/src/filler/dom-filler.d.ts.map +1 -0
- package/dist/src/index.d.ts +10 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/rules/local-rules.d.ts +9 -0
- package/dist/src/rules/local-rules.d.ts.map +1 -0
- package/dist/src/scanner/dom-scanner.d.ts +34 -0
- package/dist/src/scanner/dom-scanner.d.ts.map +1 -0
- package/dist/src/scanner/fingerprint.d.ts +22 -0
- package/dist/src/scanner/fingerprint.d.ts.map +1 -0
- package/dist/src/types/index.d.ts +255 -0
- package/dist/src/types/index.d.ts.map +1 -0
- package/dist/src/ui/panel.d.ts +78 -0
- package/dist/src/ui/panel.d.ts.map +1 -0
- package/dist/style.css +1 -0
- package/package.json +45 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
(function(p,y){typeof exports=="object"&&typeof module<"u"?y(exports):typeof define=="function"&&define.amd?define(["exports"],y):(p=typeof globalThis<"u"?globalThis:p||self,y(p.SmartFillSDK={}))})(this,function(p){"use strict";var nt=Object.defineProperty;var st=(p,y,v)=>y in p?nt(p,y,{enumerable:!0,configurable:!0,writable:!0,value:v}):p[y]=v;var c=(p,y,v)=>st(p,typeof y!="symbol"?y+"":y,v);const y="https://loan.kdbank.cn";class v extends Error{constructor(t){super(t.message);c(this,"smartFillError");this.name="SmartFillException",this.smartFillError=t}}function E(n,e,t,s={}){return new v({code:n,message:e,stage:t,...s})}function oe(n,e,t="RECOGNIZE_FAILED"){return n instanceof v?n.smartFillError:{code:t,message:n instanceof Error?n.message:String(n||"智能录入异常"),stage:e,retryable:e==="recognize"}}function C(n="sf"){return`${n}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2,10)}`}class le{constructor(e){c(this,"seToken","");c(this,"baseURL",y);this.config=e}setAccessToken(e){this.seToken=e}async createSession(){if(!/^seKey-[A-Za-z0-9_-]{6,}$/.test(this.config.apiKey))throw E("API_KEY_INVALID","apiKey 格式不正确,应以 seKey- 开头。","setup");return{apiKey:this.config.apiKey,rulesVersion:"0.0.1"}}async getFormConfig(e){return e?this.request(`/sdk/forms/${encodeURIComponent(e)}`,{method:"GET"}):null}async resolveInputText(e){var r,a,o,d;const t=(r=e.images)!=null&&r.length?e.images:[],s=((a=e.text)==null?void 0:a.trim())||"";if(!t.length)return{text:s,usedOcr:!1};(o=e.onStatusChange)==null||o.call(e,"image_uploading");const i=await this.recognizeImages(t);return(d=e.onStatusChange)==null||d.call(e,"image_recognizing"),{text:i,usedOcr:!0}}async recognize(e){var a,o;const t=performance.now(),s=(a=e.text)==null?void 0:a.trim();(o=e.onStatusChange)==null||o.call(e,"recognizing");const i=await this.request("/fcloud/flow-product/agentChat/smartEntry",{method:"POST",body:JSON.stringify({formCode:e.formCode||"",configVersion:e.configVersion||"",formMsg:e.fields.map(({element:d,...l})=>l),userInputMsg:s||""})}),r=de(i,e.fields,e.scanToken);return{scanToken:e.scanToken,suggestions:r,trace:i.trace||{traceId:C("trace"),usedOcr:!!e.usedOcr,usedAi:!0,durationMs:Math.round(performance.now()-t)}}}async recognizeImages(e){const t=new FormData;e.forEach(r=>{t.append("image",r,r.name)});const s=await this.request("/fcloud/flow-product/agentChat/smartEntry/ocr",{method:"POST",body:t}),i=fe(s);if(!i)throw E("RECOGNIZE_FAILED","图片识别未提取到文本内容。","recognize");return i}async request(e,t){const s=new AbortController,i=window.setTimeout(()=>s.abort(),this.config.requestTimeoutMs??3e4),r=new Headers(t.headers);t.body&&!(t.body instanceof FormData)&&!r.has("Content-Type")&&r.set("Content-Type","application/json"),r.set("x-trace-id",C("trace")),this.seToken&&r.set("seToken",`${this.seToken}`);try{const a=await fetch(`${this.baseURL}${e}`,{...t,headers:r,signal:s.signal});if(!a.ok)throw E(pe(a.status),await a.text(),e.includes("session")?"setup":"recognize",{retryable:a.status>=500||a.status===429});return a.json()}catch(a){throw a instanceof DOMException&&a.name==="AbortError"?E("RECOGNIZE_TIMEOUT","识别请求超时,请稍后重试。","recognize",{retryable:!0}):a}finally{window.clearTimeout(i)}}}const ce=.95;function de(n,e,t){var r;const s=new Map(e.map(a=>[a.fieldId,a]));return(((r=n.data)==null?void 0:r.fieldValues)||[]).filter(a=>!!(a!=null&&a.fieldId)).map(a=>{const o=s.get(a.fieldId);return{fieldId:a.fieldId,scanToken:t,label:a.label||(o==null?void 0:o.label)||a.fieldId,value:a.value,displayValue:a.value==null?"":String(a.value),confidence:ue(a.confidence),source:a.source||"ai",warnings:a.warnings}})}function ue(n){return typeof n!="number"||Number.isNaN(n)?ce:n<0?0:n>1?1:n}function fe(n){var t;const e=typeof n.data=="string"?n.data:((t=n.data)==null?void 0:t.text)||n.text||"";return String(e||"").trim()}function pe(n){return n===401?"TOKEN_EXPIRED":n===403?"API_KEY_FORBIDDEN":n===404?"FORM_CONFIG_NOT_FOUND":"RECOGNIZE_FAILED"}class _{constructor(){c(this,"handlers",new Map)}on(e,t){const s=this.handlers.get(e)??new Set;return s.add(t),this.handlers.set(e,s),()=>this.off(e,t)}off(e,t){var s;(s=this.handlers.get(e))==null||s.delete(t)}emit(e,t){var s;(s=this.handlers.get(e))==null||s.forEach(i=>i(t))}clear(){this.handlers.clear()}}class he{constructor(){c(this,"instances",new Set);c(this,"active",null)}add(e){this.instances.add(e)}activate(e){this.active&&this.active!==e&&this.active.close(),this.active=e}remove(e){this.instances.delete(e),this.active===e&&(this.active=null)}destroyAll(){this.instances.forEach(e=>e.destroy()),this.instances.clear(),this.active=null}}const ge=[/^(el|rc|ant|radix|headlessui|mui|chakra)-/i,/[0-9a-f]{8,}/i,/\d{6,}/];function w(n){const e=String(n||"").trim();return!e||ge.some(t=>t.test(e))?"":e}function O(n){const e=(n.options||[]).slice(0,20).map(t=>`${t.label}:${String(t.value)}`).join("|");return A([n.fieldId,n.tagName,n.type,w(n.name),w(n.id),n.label,n.placeholder,n.section,e].join("::"))}function A(n){return String(n??"").replace(/\s+/g," ").trim().toLowerCase()}const $=new WeakMap;class D{constructor(e,t,s=[]){this.fields=e,this.schemas=t,this.adapters=s}async apply(e){const t=[],s=[];for(const i of e.values){const r=this.fields.find(l=>l.fieldId===i.fieldId);if(!r){s.push(L(i.fieldId,"",i.value,"字段不在当前扫描结果中","FIELD_NOT_FOUND"));continue}if(r.scanToken!==e.scanToken){s.push(L(r.fieldId,r.label,i.value,"页面扫描已过期,请重新扫描","SCAN_TOKEN_EXPIRED"));continue}const a=this.schemas.find(l=>l.fieldId===i.fieldId),o=a!=null&&a.transform?a.transform(i.value):i.value,d=await this.getValue(r,a);try{const l=a!=null&&a.validate?await a.validate(o):!0;if(l!==!0){s.push(L(r.fieldId,r.label,o,typeof l=="string"?l:"字段校验未通过","VALIDATE_FAILED"));continue}await this.setValue(r,o,a),t.push({fieldId:r.fieldId,label:r.label,value:o,previousValue:d})}catch(l){s.push(L(r.fieldId,r.label,o,l instanceof Error?l.message:"字段回填失败","SET_VALUE_FAILED"))}}return{applied:t,skipped:s,warnings:s.length?["部分字段未回填,请查看跳过原因。"]:void 0}}async getValue(e,t){if(t!=null&&t.getValue)return t.getValue();const s=this.matchAdapter(e);if(s!=null&&s.getValue)return s.getValue(e);const i=R(e);if(i)return i instanceof HTMLInputElement&&i.type==="checkbox"?i.checked:i instanceof HTMLInputElement&&i.type==="radio"?i.checked?i.value:void 0:i instanceof HTMLInputElement||i instanceof HTMLTextAreaElement||i instanceof HTMLSelectElement?i.value:i.textContent}async setValue(e,t,s){if(s!=null&&s.setValue){await s.setValue(t);return}const i=R(e);if(!i)throw new Error("页面中未找到对应字段");if(e.fingerprint&&e.fingerprint!==O({...e,tagName:i.tagName.toLowerCase()}))throw new Error("字段结构已变化,请重新扫描");if(e.disabled||e.readonly||i.hasAttribute("disabled")||i.hasAttribute("readonly"))throw new Error("字段不可编辑");const r=this.matchAdapter(e);if(r){await r.setValue(e,t);return}me(i,t),ye(i)}matchAdapter(e){const t=R(e);return t?this.adapters.find(s=>s.match(t,e)):void 0}}function R(n){var e;return(e=n.element)!=null&&e.isConnected?n.element:document.querySelector(`[data-smart-fill-id="${P(n.fieldId)}"]`)}function me(n,e){if(n instanceof HTMLInputElement&&n.type==="checkbox")n.checked=!!e;else if(n instanceof HTMLInputElement&&n.type==="radio"){const t=document.querySelector(`input[type="radio"][name="${P(n.name)}"][value="${P(String(e))}"]`);(t||n).checked=!0}else n instanceof HTMLInputElement||n instanceof HTMLTextAreaElement||n instanceof HTMLSelectElement?n.value=String(e??""):n.isContentEditable&&(n.textContent=String(e??""));n.dispatchEvent(new Event("input",{bubbles:!0})),n.dispatchEvent(new Event("change",{bubbles:!0}))}function ye(n){var s;n.setAttribute("data-smart-fill-highlighted","true"),(s=$.get(n))==null||s.abort();const e=new AbortController,t=i=>{i&&"isTrusted"in i&&!i.isTrusted||(n.removeAttribute("data-smart-fill-highlighted"),e.abort(),$.delete(n))};$.set(n,e),n.addEventListener("focus",t,{signal:e.signal}),n.addEventListener("pointerdown",t,{signal:e.signal}),n.addEventListener("keydown",t,{signal:e.signal}),n.addEventListener("input",t,{signal:e.signal}),n.addEventListener("change",t,{signal:e.signal})}function L(n,e,t,s,i){return{fieldId:n,label:e,attemptedValue:t,reason:s,reasonCode:i}}function P(n){return typeof CSS<"u"&&CSS.escape?CSS.escape(n):n.replace(/["\\]/g,"\\$&")}const be=[{key:"mobile",pattern:new RegExp("(?<!\\d)1[3-9]\\d{9}(?!\\d)","g"),confidence:.98,reason:"手机号正则命中"},{key:"idCard",pattern:new RegExp("(?<!\\d)\\d{17}[\\dXx](?!\\d)","g"),confidence:.96,reason:"身份证号正则命中"},{key:"email",pattern:/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g,confidence:.95,reason:"邮箱正则命中"},{key:"bankCard",pattern:new RegExp("(?<!\\d)\\d{16,19}(?!\\d)","g"),confidence:.9,reason:"银行卡号正则命中"},{key:"amount",pattern:/(?:金额|价格|费用|合计|总计)[::\s]*([0-9]+(?:\.[0-9]{1,2})?)/g,confidence:.88,reason:"金额关键词命中"},{key:"date",pattern:/\d{4}[-/.年]\d{1,2}[-/.月]\d{1,2}日?/g,confidence:.86,reason:"日期格式命中"}],V={legalPerson:["法人","法定代表人","法定代表","企业法人","legal person","legal representative"],emergencyContact:["紧急联系人","紧急联络人","emergency contact"],contact:["联系人","联络人","联系人员","contact"],spouse:["配偶","爱人","夫妻","spouse"]},g={mobile:["手机","手机号","电话","联系电话","mobile","phone"],legalPersonMobile:["法人手机号","法人电话","法定代表人手机号","法人手机","legal person mobile"],emergencyContactMobile:["紧急联系人手机号","紧急联系人电话","紧急联系电话","emergency contact mobile"],contactMobile:["联系人手机号","联系人电话","联系手机","contact mobile"],spouseMobile:["配偶手机号","配偶电话","爱人手机号","spouse mobile"],idCard:["身份证","证件号","身份证号","idcard","id card"],legalPersonIdCard:["法人身份证","法人身份证号","法定代表人身份证号"],spouseIdCard:["配偶身份证","配偶身份证号","爱人身份证号"],email:["邮箱","邮件","email","mail"],contactEmail:["联系人邮箱","联系邮箱","contact email"],name:["姓名","名字","称呼","name"],customerName:["客户姓名","申请人姓名","用户姓名","借款人姓名","客户名称"],legalPersonName:["法人姓名","法定代表人姓名","企业法人姓名"],emergencyContactName:["紧急联系人姓名","紧急联系人名称"],contactName:["联系人姓名","联系人名称"],spouseName:["配偶姓名","爱人姓名"],companyName:["公司名称","企业名称","单位名称","商户名称","公司","企业"],address:["地址","住址","通讯地址","联系地址","现住址","办公地址"],detailAddress:["详细地址","街道地址","门牌地址","详细住址"],amount:["金额","费用","价格","合计","总计","amount","price"],applyAmount:["申请金额","贷款金额","借款金额","授信金额","申请额度"],date:["日期","时间","有效期","date"],applyDate:["申请日期","申请时间","受理日期","进件日期"],bankCard:["银行卡","卡号","bank","bank card"]},q={mobile:"mobile",legalPersonMobile:"mobile",emergencyContactMobile:"mobile",contactMobile:"mobile",spouseMobile:"mobile",idCard:"idCard",legalPersonIdCard:"idCard",spouseIdCard:"idCard",email:"email",contactEmail:"email",name:"name",customerName:"name",legalPersonName:"name",emergencyContactName:"name",contactName:"name",spouseName:"name",companyName:"companyName",address:"address",detailAddress:"address",amount:"amount",applyAmount:"amount",date:"date",applyDate:"date",bankCard:"bankCard"};class U{recognize(e,t,s){const i=Le([...Ee(e),...xe(e)]),r=new Set,a=[];for(const o of i.sort((d,l)=>l.confidence-d.confidence)){const d=we(o,t,r);d&&(a.push({fieldId:d.fieldId,scanToken:s,label:d.label,value:Ie(o.value,d),displayValue:o.value,confidence:o.confidence,source:"local_rule",reason:o.reason}),r.add(d.fieldId))}return a}}function Ee(n){const e=[];for(const t of be)for(const s of n.matchAll(t.pattern)){const i=B(s[1]||s[0]);e.push({key:t.key,value:i,confidence:t.confidence,reason:t.reason,baseKey:q[t.key]})}return e}function xe(n){const e=[],t=n.split(/\r?\n|[;,;]/).map(s=>s.trim()).filter(Boolean);for(const s of t){const i=s.match(/^[“"'`]?([^::=]{2,30})[”"'`]?[::=]\s*(.+)$/);if(!i)continue;const r=Ce(i[1]),a=B(i[2]);if(!(!r||!a))for(const o of ve(r,a))e.push(o)}return e}function ve(n,e){const t=A(n),s=Te(e),i=[],r=Ae(t);return h(t,g.applyDate)&&i.push("applyDate"),h(t,g.applyAmount)&&i.push("applyAmount"),h(t,g.companyName)&&i.push("companyName"),h(t,g.detailAddress)&&i.push("detailAddress"),h(t,g.address)&&i.push("address"),(h(t,g.mobile)||s==="mobile")&&r&&z(i,r,"mobile"),(h(t,g.idCard)||s==="idCard")&&r&&z(i,r,"idCard"),(h(t,g.email)||s==="email")&&r&&z(i,r,"email"),(h(t,g.mobile)||s==="mobile")&&i.push("mobile"),(h(t,g.idCard)||s==="idCard")&&i.push("idCard"),(h(t,g.email)||s==="email")&&i.push("email"),(h(t,g.bankCard)||s==="bankCard")&&i.push("bankCard"),(h(t,g.amount)||s==="amount")&&i.push("amount"),(h(t,g.date)||s==="date")&&i.push("date"),Fe(i).map((a,o)=>({key:a,value:e,confidence:Math.max(.84,.96-o*.04),reason:r?`键值对文本命中(${n},角色增强)`:`键值对文本命中(${n})`,baseKey:q[a]}))}function we(n,e,t){let s=null;for(const i of e){if(t.has(i.fieldId))continue;const r=Se(n,i);r>((s==null?void 0:s.score)??0)&&(s={field:i,score:r})}return s&&s.score>=.45?s.field:null}function Se(n,e){const t=A([e.fieldId,e.label,e.placeholder,e.name,e.id,e.section].join(" ")),s=g[n.key]||[n.key],i=g[n.baseKey]||[n.baseKey];let r=0;return h(t,s)?r+=.95:n.key!==n.baseKey&&h(t,i)?r+=.68:h(t,i)&&(r+=.82),t.includes(A(n.key))&&(r+=.22),e.required&&(r+=.05),n.baseKey==="amount"&&(e.type==="amount"||e.type==="number")&&(r+=.18),n.baseKey==="date"&&e.type==="date"&&(r+=.18),n.baseKey==="address"&&(e.type==="textarea"||e.type==="text")&&(r+=.12),["name","companyName","email","mobile","idCard","bankCard"].includes(n.baseKey)&&e.type==="text"&&(r+=.08),Math.min(r,1)}function Ie(n,e){var t;return e.type==="date"?n.replace(/[年月/.]/g,"-").replace(/日/g,"").replace(/--/g,"-"):e.type==="number"||e.type==="amount"?((t=n.match(/[0-9]+(?:\.[0-9]+)?/))==null?void 0:t[0])??n:e.name&&/mobile|phone|idcard|bankcard/i.test(e.name)||e.id&&/mobile|phone|idcard|bankcard/i.test(e.id)||/mobile|phone|idcard|bankcard/i.test(e.fieldId)?n.replace(/\s+/g,""):n}function Ae(n){const e=Object.keys(V).filter(t=>h(n,V[t]));return e.length?e.includes("emergencyContact")?"emergencyContact":e.includes("legalPerson")?"legalPerson":e.includes("spouse")?"spouse":"contact":null}function Te(n){const e=n.replace(/\s+/g,"");return/^1[3-9]\d{9}$/.test(e)?"mobile":/^\d{17}[\dXx]$/.test(e)?"idCard":/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/.test(n)?"email":/^\d{16,19}$/.test(e)?"bankCard":/^\d{4}[-/.年]\d{1,2}[-/.月]\d{1,2}日?$/.test(n)?"date":/^[0-9]+(?:\.[0-9]{1,2})?$/.test(e)?"amount":/[省市区县路街道号栋室乡镇]/.test(n)?"address":/^[\u4e00-\u9fa5a-zA-Z·]{2,20}$/.test(n)?"name":"unknown"}function z(n,e,t){var i;const s=(i=ke[e])==null?void 0:i[t];s&&n.push(s)}const ke={legalPerson:{mobile:"legalPersonMobile",idCard:"legalPersonIdCard",name:"legalPersonName"},emergencyContact:{mobile:"emergencyContactMobile",name:"emergencyContactName"},contact:{mobile:"contactMobile",email:"contactEmail",name:"contactName"},spouse:{mobile:"spouseMobile",idCard:"spouseIdCard",name:"spouseName"}};function Ce(n){return n.replace(/[“”"'`]/g,"").replace(/\s+/g," ").trim()}function B(n){return n.replace(/[,。;;]+$/g,"").replace(/^[“”"'`\s]+|[“”"'`\s]+$/g,"").trim()}function h(n,e){const t=A(n);return e.some(s=>t.includes(A(s)))}function Le(n){const e=new Map;for(const t of n){const s=`${t.key}::${t.value}`,i=e.get(s);(!i||i.confidence<t.confidence)&&e.set(s,t)}return[...e.values()]}function Fe(n){return[...new Set(n)]}const Me=["input","textarea","select","[contenteditable]:not([contenteditable='false'])"].join(", "),j=["dialog[open]","[role='dialog']","[aria-modal='true']",".modal",".modal-dialog",".ant-modal",".ant-drawer",".el-dialog",".el-drawer",".n-dialog",".n-modal",".popup",".drawer"].join(", "),Ne=new Set(["hidden","submit","button","image","reset","file","password"]);class Y{constructor(e=document){this.root=e}scan(e={}){var d;const t=C("scan");if((d=e.registered)!=null&&d.length)return{scanToken:t,fields:e.registered.map(l=>this.fromSchema(l,t))};const s=this.resolveRoot(e.scanContainer),i=this.collectVisibleFields(s),r=this.detectTopLayerContainer(i),a=i.filter(l=>r.contains(l)),o=(a.length?a:i).slice(0,e.maxFields??200);return{scanToken:t,fields:o.map((l,u)=>this.fromElement(l,u,t))}}fromSchema(e,t){const s=Pe(e.element,this.root),i={fieldId:e.rowKey==null?e.fieldId:`${e.fieldId}:${e.rowKey}`,label:e.label,type:e.type,localRuleMode:e.localRuleMode??"inherit",required:e.required,section:e.section,options:e.options,source:"registered",scanToken:t,element:s||void 0,fingerprint:""};return i.fingerprint=O({...i,tagName:s==null?void 0:s.tagName.toLowerCase()}),i}fromElement(e,t,s){const i=_e(e,t),r=De(e),a={fieldId:i,fingerprint:"",scanToken:s,type:Oe(e),localRuleMode:"inherit",label:Z(e),placeholder:G(e),name:w(e.getAttribute("name"))||void 0,id:w(e.id)||void 0,section:$e(e),options:r,required:e.hasAttribute("required")||e.getAttribute("aria-required")==="true",readonly:e.hasAttribute("readonly"),disabled:e.hasAttribute("disabled"),source:"form_scan",element:e};return a.fingerprint=O({...a,tagName:e.tagName.toLowerCase()}),a}resolveRoot(e){if(e){const t=X(this.root,e);if(t)return t}return this.root}collectVisibleFields(e){return Array.from(e.querySelectorAll(Me)).filter(t=>!(t instanceof HTMLElement)||!Re(t)||t instanceof HTMLInputElement&&Ne.has((t.type||"").toLowerCase())?!1:!t.hasAttribute("disabled")&&!t.hasAttribute("readonly"))}detectTopLayerContainer(e){const t=document.activeElement instanceof HTMLElement?document.activeElement:null,s=t==null?void 0:t.closest(j);if(s instanceof HTMLElement&&e.some(r=>s.contains(r)))return s;const i=e.map(r=>r.closest(j)).filter(r=>r instanceof HTMLElement);return i.length?i.sort((r,a)=>e.filter(o=>a.contains(o)).length-e.filter(o=>r.contains(o)).length)[0]:document.body}}function _e(n,e){const t=n.getAttribute("data-smart-fill-id");if(t)return t;const i=w(n.getAttribute("data-smart-fill-key"))||w(n.getAttribute("name"))||w(n.id)||`smart-fill-${Date.now()}-${e}`;return n.setAttribute("data-smart-fill-id",i),i}function Oe(n){if(n instanceof HTMLTextAreaElement)return"textarea";if(n instanceof HTMLSelectElement)return"select";if(n instanceof HTMLInputElement){const e=(n.type||"text").toLowerCase();if(e==="radio")return"radio";if(e==="checkbox")return"checkbox";if(e==="date"||e==="month")return"date";if(e==="number")return"number"}return"text"}function Z(n){const e=n.getAttribute("aria-label");if(e)return e.trim();if(n.id){const r=document.querySelector(`label[for="${W(n.id)}"]`);if(r!=null&&r.textContent)return T(r.textContent)}const t=n.closest("label");if(t!=null&&t.textContent)return T(t.textContent);const s=n.closest(".form-item, .ant-form-item, .el-form-item, .field, .form-row"),i=s==null?void 0:s.querySelector("label, .ant-form-item-label, .el-form-item__label, .label");return i!=null&&i.textContent?T(i.textContent):G(n)||n.getAttribute("name")||n.id||"未命名字段"}function G(n){return n.getAttribute("placeholder")||n.getAttribute("aria-placeholder")||void 0}function $e(n){const e=n.closest("fieldset, section, .panel, .card, .form-section"),t=e==null?void 0:e.querySelector("legend, h1, h2, h3, .title, .section-title");return t!=null&&t.textContent?T(t.textContent):void 0}function De(n){if(n instanceof HTMLSelectElement)return Array.from(n.options).map(e=>({label:T(e.textContent||e.label),value:e.value}));if(n instanceof HTMLInputElement&&(n.type==="radio"||n.type==="checkbox")&&n.name)return Array.from(document.querySelectorAll(`input[name="${W(n.name)}"]`)).map(e=>({label:Z(e),value:e.value||!0}))}function Re(n){const e=window.getComputedStyle(n);return e.display==="none"||e.visibility==="hidden"||Number(e.opacity)===0?!1:!!(n.offsetWidth||n.offsetHeight||n.getClientRects().length)}function Pe(n,e){return n instanceof HTMLElement?n:typeof n=="string"?X(e,n):null}function X(n,e){try{const t=n.querySelector(e);return t instanceof HTMLElement?t:null}catch{return null}}function T(n){return n.replace(/[*::]/g,"").replace(/\s+/g," ").trim()}function W(n){return typeof CSS<"u"&&CSS.escape?CSS.escape(n):n.replace(/["\\]/g,"\\$&")}const K=5,ze=10*1024*1024,Ke=50*1024*1024;class He{constructor(e){c(this,"host",null);c(this,"root",null);c(this,"autoApplyState",null);c(this,"selectedFiles",[]);c(this,"inputText","");c(this,"localPriorityEnabled");c(this,"isOpen",!1);c(this,"dragState",null);c(this,"suppressOpenClick",!1);c(this,"isUploadHovering",!1);c(this,"handleDragMove",e=>{if(!this.dragState||!this.host||e.pointerId!==this.dragState.pointerId)return;const t=e.clientX-this.dragState.startX,s=e.clientY-this.dragState.startY;(Math.abs(t)>3||Math.abs(s)>3)&&(this.dragState.moved=!0);const i=this.host.getBoundingClientRect(),r=Math.max(8,window.innerWidth-i.width-8),a=Math.max(8,window.innerHeight-i.height-8),o=F(this.dragState.startLeft+t,8,r),d=F(this.dragState.startTop+s,8,a);this.host.style.left=`${o}px`,this.host.style.top=`${d}px`});c(this,"handleDragEnd",e=>{!this.dragState||e.pointerId!==this.dragState.pointerId||(this.suppressOpenClick=this.dragState.moved,this.dragState=null,document.removeEventListener("pointermove",this.handleDragMove),document.removeEventListener("pointerup",this.handleDragEnd),document.removeEventListener("pointercancel",this.handleDragEnd),this.suppressOpenClick&&window.setTimeout(()=>{this.suppressOpenClick=!1},0))});c(this,"handleDocumentPaste",e=>{const t=qe(e);if(!t.length||!this.isOpen||!this.host)return;const s=document.activeElement,i=this.root instanceof ShadowRoot?this.root.activeElement:null;!(s===this.host||this.host.contains(s)||i)&&!this.isUploadHovering||(e.preventDefault(),this.handleImages(t))});this.options=e,this.localPriorityEnabled=e.localPriorityEnabled??!1}mount(e){this.host=document.createElement("div"),this.host.className=`sf-sdk-host sf-sdk-host-${this.options.mode}`,e.appendChild(this.host),this.root=this.host.attachShadow?this.host.attachShadow({mode:"open"}):this.host,this.isOpen=this.options.initialOpen??this.options.mode==="inline",document.addEventListener("paste",this.handleDocumentPaste),this.render(this.isOpen)}setOpen(e){this.isOpen=e,this.render(this.isOpen),this.keepHostInViewport()}setLocalPriorityEnabled(e){this.localPriorityEnabled=e;const t=this.query('[data-role="local-priority-toggle"]');t&&(t.checked=e)}setBusy(e,t=""){const s=this.query('[data-role="recognize"]');s&&(s.disabled=e,s.textContent=e?t:this.t("recognize","智能识别"))}setStatus(e){const t=this.query('[data-role="status"]');t&&(t.textContent=e,t.removeAttribute("data-status"))}setError(e){const t=this.query('[data-role="status"]');t&&(t.textContent=e,t.setAttribute("data-status","error"))}setAutoApplyState(e){this.autoApplyState=e,this.render(!0),this.keepHostInViewport(),this.setStatus(this.t("recognized","识别完成,正在自动回填..."))}setApplyResult(e){const t=this.query('[data-role="status"]');t&&(t.textContent=`已回填 ${e.applied.length} 项,跳过 ${e.skipped.length} 项。`,t.setAttribute("data-status",e.skipped.length?"warning":"success"))}destroy(){var e;document.removeEventListener("pointermove",this.handleDragMove),document.removeEventListener("pointerup",this.handleDragEnd),document.removeEventListener("pointercancel",this.handleDragEnd),document.removeEventListener("paste",this.handleDocumentPaste),(e=this.host)==null||e.remove(),this.host=null,this.root=null,this.dragState=null,this.isUploadHovering=!1}render(e){this.root&&(this.root.innerHTML=`
|
|
2
|
+
<style>${Ue}</style>
|
|
3
|
+
${this.options.mode==="floating"?`<button class="sf-float" type="button" data-role="open">${this.t("entry","智能录入")}</button>`:""}
|
|
4
|
+
<section class="sf-panel ${e?"is-open":""} ${this.options.mode==="inline"?"is-inline":"is-floating"}" aria-label="智能录入面板">
|
|
5
|
+
<header class="sf-header">
|
|
6
|
+
<strong>${this.t("title","智能录入")}</strong>
|
|
7
|
+
<button class="sf-icon-btn" type="button" data-role="close" aria-label="${this.options.mode==="inline"?e?this.t("collapse","收起"):this.t("expand","展开"):this.t("close","关闭")}">${this.options.mode==="inline"?e?"∧":"∨":"x"}</button>
|
|
8
|
+
</header>
|
|
9
|
+
<div class="sf-body ${e?"is-open":""}">
|
|
10
|
+
<label class="sf-toggle">
|
|
11
|
+
<span class="sf-toggle-main">
|
|
12
|
+
<input type="checkbox" data-role="local-priority-toggle" ${this.localPriorityEnabled?"checked":""} />
|
|
13
|
+
<span class="sf-toggle-title">${this.t("localPriorityTitle","启用本地优先识别")}</span>
|
|
14
|
+
</span>
|
|
15
|
+
<span class="sf-toggle-desc">${this.t("localPriorityDesc","开启后优先使用前端本地规则提取手机号、证件号等;关闭后直接走后端识别流程。")}</span>
|
|
16
|
+
</label>
|
|
17
|
+
<div class="sf-entry-grid">
|
|
18
|
+
<div class="sf-textarea-wrap">
|
|
19
|
+
<textarea class="sf-textarea" data-role="text" placeholder="${this.t("placeholder","粘贴文本,如:姓名:张三 手机号:13800000000")}">${Ve(this.inputText)}</textarea>
|
|
20
|
+
<div class="sf-textarea-actions">
|
|
21
|
+
<button class="sf-btn sf-btn-secondary" type="button" data-role="clear">${this.t("clear","清空")}</button>
|
|
22
|
+
<button class="sf-btn sf-btn-primary" type="button" data-role="recognize">${this.t("recognize","智能识别")}</button>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
<label class="sf-upload" data-role="upload" tabindex="0">
|
|
26
|
+
<input data-role="file" type="file" name="files" accept="image/*" multiple hidden />
|
|
27
|
+
<span class="sf-upload-illustration" aria-hidden="true">
|
|
28
|
+
<span class="sf-upload-icon">
|
|
29
|
+
<svg viewBox="0 0 24 24" class="sf-upload-svg" focusable="false" aria-hidden="true">
|
|
30
|
+
<path d="M6 5.5h8.2L18.5 9v9.5a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1v-12a1 1 0 0 1 1-1Z" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linejoin="round"/>
|
|
31
|
+
<path d="M14 5.5V9h4.5" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linejoin="round"/>
|
|
32
|
+
<path d="m8.5 16 2.2-2.2a.9.9 0 0 1 1.3 0l1.2 1.2 1.6-1.6a.9.9 0 0 1 1.3 0L18.5 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
|
|
33
|
+
<circle cx="10" cy="10.5" r="1" fill="currentColor"/>
|
|
34
|
+
</svg>
|
|
35
|
+
</span>
|
|
36
|
+
<span class="sf-upload-hint">${this.t("uploadHint",`点击、拖拽、Ctrl + V 粘贴图片至此(最多 ${K} 张)`)}</span>
|
|
37
|
+
</span>
|
|
38
|
+
<span class="sf-upload-btn" data-role="file-label">图片识别</span>
|
|
39
|
+
</label>
|
|
40
|
+
</div>
|
|
41
|
+
<div class="sf-actions">
|
|
42
|
+
<span class="sf-status" data-role="status">${this.t("empty","暂无识别结果")}</span>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
</section>
|
|
46
|
+
`,this.bindEvents())}bindEvents(){var s,i,r,a,o,d,l;const e=this.query('[data-role="open"]');e==null||e.addEventListener("pointerdown",u=>this.startDrag(u)),e==null||e.addEventListener("click",()=>{this.suppressOpenClick||this.options.onOpen()}),(s=this.query(".sf-header"))==null||s.addEventListener("pointerdown",u=>this.startDrag(u)),(i=this.query('[data-role="close"]'))==null||i.addEventListener("click",()=>{if(this.options.mode==="inline"){this.isOpen?this.options.onClose():this.options.onOpen();return}this.options.onClose()}),(r=this.query('[data-role="file"]'))==null||r.addEventListener("change",u=>{const m=u.target;this.handleImages(Array.from(m.files||[]))});const t=this.query('[data-role="upload"]');t==null||t.addEventListener("pointerenter",()=>{this.isUploadHovering=!0}),t==null||t.addEventListener("pointerleave",()=>{this.isUploadHovering=!1,t.removeAttribute("data-dragover")}),t==null||t.addEventListener("dragenter",u=>{u.preventDefault(),this.isUploadHovering=!0,t.setAttribute("data-dragover","true")}),t==null||t.addEventListener("dragover",u=>{u.preventDefault(),t.setAttribute("data-dragover","true")}),t==null||t.addEventListener("dragleave",u=>{u.currentTarget.contains(u.relatedTarget)||(this.isUploadHovering=!1,t.removeAttribute("data-dragover"))}),t==null||t.addEventListener("drop",u=>{var m;u.preventDefault(),this.isUploadHovering=!1,t.removeAttribute("data-dragover"),this.handleImages(Array.from(((m=u.dataTransfer)==null?void 0:m.files)||[]))}),(a=this.query('[data-role="text"]'))==null||a.addEventListener("input",u=>{this.inputText=u.target.value}),(o=this.query('[data-role="local-priority-toggle"]'))==null||o.addEventListener("change",u=>{var m,S;this.localPriorityEnabled=u.target.checked,(S=(m=this.options).onLocalPriorityChange)==null||S.call(m,this.localPriorityEnabled)}),(d=this.query('[data-role="clear"]'))==null||d.addEventListener("click",()=>{this.clearFormState()}),(l=this.query('[data-role="recognize"]'))==null||l.addEventListener("click",()=>{const u=this.query('[data-role="text"]'),m=u==null?void 0:u.value.trim();if(this.inputText=(u==null?void 0:u.value)||this.inputText,!m){this.setError(this.t("emptyInput","请输入文本内容。"));return}this.options.onRecognize({text:m})})}clearFormState(){this.inputText="",this.resetSelectedFiles(),this.autoApplyState=null,this.render(!0),this.setStatus(this.t("empty","暂无识别结果"))}resetSelectedFiles(){var t;this.selectedFiles=[];const e=this.query('[data-role="file"]');e&&(e.value=""),this.isUploadHovering=!1,(t=this.query('[data-role="upload"]'))==null||t.removeAttribute("data-dragover")}async handleImages(e){const t=e.filter(r=>r.type.startsWith("image/"));if(!t.length){this.resetSelectedFiles(),this.setError(this.t("invalidImageError","请选择图片文件。"));return}if(t.length>K){this.resetSelectedFiles(),this.setError(this.t("maxFilesError",`最多上传 ${K} 张图片。`));return}if(t.find(r=>r.size>ze)){this.resetSelectedFiles(),this.setError(this.t("maxSingleFileSizeError","单张图片不能超过 10MB。"));return}if(t.reduce((r,a)=>r+a.size,0)>Ke){this.resetSelectedFiles(),this.setError(this.t("maxTotalFileSizeError","上传图片总大小不能超过 50MB。"));return}this.selectedFiles=t,this.setStatus(this.t("imageReady",`已选择 ${this.selectedFiles.length} 张图片,开始识别...`));try{await this.options.onRecognize({images:[...this.selectedFiles]}),this.resetSelectedFiles()}catch{}}startDrag(e){var s;if(this.options.mode!=="floating"||!this.host||e.button!==0||(s=e.target)!=null&&s.closest('[data-role="close"]'))return;const t=this.host.getBoundingClientRect();this.host.style.left=`${t.left}px`,this.host.style.top=`${t.top}px`,this.host.style.right="auto",this.host.style.bottom="auto",this.dragState={pointerId:e.pointerId,startX:e.clientX,startY:e.clientY,startLeft:t.left,startTop:t.top,moved:!1},e.preventDefault(),document.addEventListener("pointermove",this.handleDragMove),document.addEventListener("pointerup",this.handleDragEnd),document.addEventListener("pointercancel",this.handleDragEnd)}keepHostInViewport(){this.options.mode!=="floating"||!this.host||!this.host.style.left||!this.host.style.top||window.requestAnimationFrame(()=>{if(!this.host)return;const e=this.host.getBoundingClientRect(),t=F(e.left,8,Math.max(8,window.innerWidth-e.width-8)),s=F(e.top,8,Math.max(8,window.innerHeight-e.height-8));this.host.style.left=`${t}px`,this.host.style.top=`${s}px`})}query(e){var t;return((t=this.root)==null?void 0:t.querySelector(e))||null}t(e,t){var s;return((s=this.options.messages)==null?void 0:s[e])||t}}function Ve(n){return n.replace(/[&<>"']/g,e=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[e]||e)}function F(n,e,t){return Math.min(Math.max(n,e),t)}function qe(n){var t;return Array.from(((t=n.clipboardData)==null?void 0:t.items)||[]).filter(s=>s.kind==="file"&&s.type.startsWith("image/")).map(s=>s.getAsFile()).filter(s=>!!s)}const Ue=`
|
|
47
|
+
:host, .sf-panel { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
|
|
48
|
+
:host(.sf-sdk-host-floating), .sf-sdk-host-floating { position: fixed; top: 24px; right: 24px; z-index: 2147483647; display: flex; flex-direction: column; align-items: flex-end; gap: 12px; width: min(420px, calc(100vw - 32px)); pointer-events: none; }
|
|
49
|
+
.sf-float { align-self: flex-end; border: 0; border-radius: 999px; padding: 12px 18px; color: #fff; background: #2563eb; box-shadow: 0 10px 24px rgba(37,99,235,.3); cursor: move; user-select: none; touch-action: none; pointer-events: auto; }
|
|
50
|
+
.sf-panel { display: none; width: 100%; box-sizing: border-box; border: 1px solid #dbe3ef; border-radius: 16px; background: #fff; color: #172033; box-shadow: 0 18px 48px rgba(15,23,42,.18); padding: 16px; pointer-events: auto; }
|
|
51
|
+
.sf-panel.is-open { display: block; }
|
|
52
|
+
.sf-panel.is-inline { display: block; }
|
|
53
|
+
.sf-body { display: none; }
|
|
54
|
+
.sf-body.is-open { display: block; }
|
|
55
|
+
.sf-header, .sf-actions { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
|
|
56
|
+
.sf-header { cursor: move; user-select: none; touch-action: none; }
|
|
57
|
+
.sf-icon-btn {font-size: 16px; border: 0; background: transparent; cursor: pointer; color: #64748b; font-weight: 700; }
|
|
58
|
+
.sf-tip, .sf-status, .sf-empty, small { color: #64748b; font-size: 12px; }
|
|
59
|
+
.sf-toggle { display: grid; gap: 4px; margin: 10px 0 12px; padding: 10px 12px; border: 1px solid #dbe3ef; border-radius: 10px; background: #f8fbff; }
|
|
60
|
+
.sf-toggle-main { display: flex; align-items: center; gap: 8px; color: #172033; font-size: 13px; font-weight: 600; }
|
|
61
|
+
.sf-toggle-main input { margin: 0; }
|
|
62
|
+
.sf-toggle-desc { color: #64748b; font-size: 12px; line-height: 1.4; }
|
|
63
|
+
.sf-entry-grid { display: grid; grid-template-columns: minmax(0, 1fr) 200px; gap: 12px; align-items: stretch; margin: 10px 0 14px; }
|
|
64
|
+
.sf-textarea-wrap { position: relative; }
|
|
65
|
+
.sf-textarea { width: 100%; min-height: 140px; resize: vertical; border: 1px solid #cbd5e1; border-radius: 10px; padding: 10px 10px 56px; box-sizing: border-box; }
|
|
66
|
+
.sf-textarea-actions { position: absolute; right: 12px; bottom: 12px; display: flex; gap: 10px; }
|
|
67
|
+
.sf-upload { display: flex; flex-direction: column; justify-content: space-between; align-items: center; border: 1px solid #e4e7ee; border-radius: 10px; padding: 14px 10px 12px; text-align: center; color: #98a2b3; cursor: pointer; height: 140px; background: #f7f8fb; box-sizing: border-box; transition: border-color .18s ease, background-color .18s ease, box-shadow .18s ease; outline: none; }
|
|
68
|
+
.sf-upload[data-dragover="true"] { border-color: #7aa7ff; background: #eef4ff; box-shadow: inset 0 0 0 1px rgba(78, 134, 255, .18); }
|
|
69
|
+
.sf-upload:focus-visible { border-color: #7aa7ff; box-shadow: 0 0 0 3px rgba(78, 134, 255, .18); }
|
|
70
|
+
.sf-upload-illustration { display: grid; justify-items: center; gap: 8px; width: 100%; }
|
|
71
|
+
.sf-upload-icon { display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px; color: #b6bdc9; }
|
|
72
|
+
.sf-upload-svg { width: 24px; height: 24px; }
|
|
73
|
+
.sf-upload-hint { color: #a0a7b4; font-size: 12px; line-height: 1.45; word-break: break-word; }
|
|
74
|
+
.sf-upload-btn { display: inline-flex; align-items: center; justify-content: center; min-width: 92px; padding: 8px 16px; border: 1px solid #d2d6df; border-radius: 999px; background: #fff; color: #667085; font-size: 13px; line-height: 1; }
|
|
75
|
+
.sf-actions { margin: 0 0 12px; }
|
|
76
|
+
.sf-status { flex: 1; min-width: 0; line-height: 1.4; }
|
|
77
|
+
.sf-btn { border: 1px solid #d7e3f5; border-radius: 999px; background: #fff; color: #4b5563; padding: 8px 20px; cursor: pointer; font-size: 13px; font-weight: 600; transition: all .18s ease; }
|
|
78
|
+
.sf-btn:hover { transform: translateY(-1px); box-shadow: 0 8px 20px rgba(15, 23, 42, .08); }
|
|
79
|
+
.sf-btn-secondary { background: #fff; color: #6b7280; border-color: #e5e7eb; }
|
|
80
|
+
.sf-btn-primary { min-width: 100px; border-color: transparent; background: linear-gradient(135deg, #6aa6ff 0%, #4e86ff 45%, #3b72f6 100%); color: #fff; box-shadow: 0 12px 26px rgba(59, 114, 246, .32); }
|
|
81
|
+
.sf-btn:disabled { opacity: .55; cursor: not-allowed; }
|
|
82
|
+
.sf-panel.is-floating .sf-entry-grid { grid-template-columns: 1fr; gap: 10px; }
|
|
83
|
+
.sf-panel.is-floating .sf-textarea { min-height: 140px; }
|
|
84
|
+
.sf-panel.is-floating .sf-upload { height: 96px; padding-top: 10px; padding-bottom: 10px; }
|
|
85
|
+
.sf-panel.is-floating .sf-upload-illustration { gap: 6px; }
|
|
86
|
+
.sf-panel.is-floating .sf-upload-icon { width: 22px; height: 22px; }
|
|
87
|
+
.sf-panel.is-floating .sf-upload-svg { width: 20px; height: 20px; }
|
|
88
|
+
.sf-panel.is-floating .sf-upload-hint { font-size: 11px; line-height: 1.35; }
|
|
89
|
+
[data-status="error"] { color: #dc2626; }
|
|
90
|
+
[data-status="warning"] { color: #d97706; }
|
|
91
|
+
[data-status="success"] { color: #16a34a; }
|
|
92
|
+
`,Be=.75;class J{constructor(e,t){c(this,"events",new _);c(this,"scanner");c(this,"ruleEngine",new U);c(this,"panel",null);c(this,"panels",[]);c(this,"panelStorageKeys",new Map);c(this,"registeredFields",[]);c(this,"adapters",[]);c(this,"scanResult",null);c(this,"autoApplyState",null);c(this,"formConfigVersion");c(this,"localPriorityEnabled",!1);c(this,"destroyed",!1);this.config=e,this.context=t,this.scanner=new Y(e.root||document),this.localPriorityEnabled=Je(),this.context.manager.add(this)}on(e,t){return this.events.on(e,t)}useAdapter(e){return this.assertAlive(),this.adapters.push(e),this}registerFields(e){this.assertAlive();const t=new Set;for(const s of e){const i=s.rowKey==null?s.fieldId:`${s.fieldId}:${s.rowKey}`;if(t.has(i))throw E("UNSUPPORTED_PAGE",`字段 ${i} 重复注册。`,"scan");t.add(i)}return this.registeredFields=e,this}unregisterFields(e){this.assertAlive(),this.registeredFields=e!=null&&e.length?this.registeredFields.filter(t=>!e.includes(t.fieldId)):[]}mount(e){this.assertAlive();const t=typeof e=="string"?document.querySelector(e):e;if(!t)throw E("UNSUPPORTED_PAGE","未找到智能录入挂载点。","ui");const s=te("inline",We(e,t)),i=ne(s,!0);return this.createPanel("inline",s,i).mount(t),this}mountFloatingButton(){this.assertAlive();const e=te("floating"),t=ne(e,!1);return this.createPanel("floating",e,t).mount(document.body),this}createPanel(e,t,s){let i;return i=new He({mode:e,initialOpen:s,messages:this.config.messages,localPriorityEnabled:this.localPriorityEnabled,onOpen:()=>this.open(i),onClose:()=>this.close(i),onRecognize:r=>(this.panel=i,this.recognize(r)),onLocalPriorityChange:r=>this.handleLocalPriorityChange(r,i)}),this.panels.push(i),this.panelStorageKeys.set(i,t),this.panel=i,i}handleLocalPriorityChange(e,t){this.localPriorityEnabled=e,Qe(e);for(const s of this.panels)s!==t&&s.setLocalPriorityEnabled(e)}async open(e=this.panel){this.assertAlive(),e&&(this.context.manager.activate(this),this.panel=e,e.setOpen(!0),se(this.panelStorageKeys.get(e),!0),await this.rescan())}close(e=this.panel){e&&(this.panel=e,e.setOpen(!1),se(this.panelStorageKeys.get(e),!1))}async rescan(){var e;this.assertAlive();try{this.formConfigVersion=void 0;const t=this.registeredFields.length?this.registeredFields:void 0;if(this.scanResult=this.scanner.scan({registered:t,maxFields:this.config.maxFields}),!this.scanResult.fields.length)throw E("NO_FIELDS_FOUND","当前页面未找到可回填字段。","scan");return this.events.emit("scanCompleted",{scanToken:this.scanResult.scanToken,fieldCount:this.scanResult.fields.length}),(e=this.panel)==null||e.setStatus(`已扫描 ${this.scanResult.fields.length} 个字段。`),this.scanResult}catch(t){throw this.emitError(t,"scan"),t}}async recognize(e){var r,a,o;this.assertAlive();const t=this.scanResult||await this.rescan(),s=C("trace"),i=performance.now();this.events.emit("recognizing",{scanToken:t.scanToken,traceId:s}),(r=this.panel)==null||r.setBusy(!0,"识别中...");try{const d=t.fields.filter(b=>Ge(b.localRuleMode,this.localPriorityEnabled)),l=t.fields.filter(b=>b.localRuleMode!=="only"),{text:u,usedOcr:m}=await this.context.client.resolveInputText({text:e.text,images:e.images,onStatusChange:b=>{var M,I,N;if(b==="image_uploading"){(M=this.panel)==null||M.setStatus("图片上传中...");return}if(b==="image_recognizing"){(I=this.panel)==null||I.setStatus("图片识别中...");return}(N=this.panel)==null||N.setStatus("识别中...")}}),S=u?this.ruleEngine.recognize(u,d,t.scanToken):[];let x;if(!l.length)x=ee(t.scanToken,s,S,i,void 0,m);else try{const b=await this.context.client.recognize({scanToken:t.scanToken,formCode:this.config.formCode,configVersion:this.formConfigVersion,text:u,usedOcr:m,fields:l,onStatusChange:()=>{var I;(I=this.panel)==null||I.setStatus("识别中...")}});b.trace.durationMs=b.trace.durationMs||Math.round(performance.now()-i);const M=Ze(S,b.suggestions.filter(I=>l.some(N=>N.fieldId===I.fieldId)));x={...b,suggestions:M}}catch(b){if(!S.length)throw b;x=ee(t.scanToken,s,S,i,[m?"后端识别失败,已使用 OCR 文本触发本地识别继续回填。":"后端识别失败,已启用本地识别继续回填。"],m)}return this.autoApplyState=je(x.scanToken,x.trace.traceId,x.suggestions,t,this.registeredFields),this.events.emit("recognized",x),(a=this.panel)==null||a.setAutoApplyState(this.autoApplyState),await this.applyAutoItems(this.autoApplyState),x}catch(d){throw this.emitError(d,"recognize"),d}finally{(o=this.panel)==null||o.setBusy(!1)}}async apply(e){var i;if(this.assertAlive(),!this.scanResult)throw E("SCAN_TOKEN_EXPIRED","请先扫描字段后再回填。","apply");this.events.emit("applying",{scanToken:e.scanToken,count:e.values.length});const s=await new D(this.scanResult.fields,this.registeredFields,this.adapters).apply(e);return this.events.emit("applied",s),(i=this.panel)==null||i.setApplyResult(s),s}async applyAutoItems(e){var o,d;if(!this.scanResult)throw E("SCAN_TOKEN_EXPIRED","请先扫描字段后再回填。","apply");const t=Ye(e),s=e.items.filter(l=>Q(l)).map(l=>({fieldId:l.fieldId,value:l.value,source:l.source}));this.events.emit("applying",{scanToken:e.scanToken,count:s.length}),(o=this.panel)==null||o.setStatus("识别完成,正在自动回填...");const r=await new D(this.scanResult.fields,this.registeredFields,this.adapters).apply({scanToken:e.scanToken,values:s}),a={...r,skipped:[...t,...r.skipped],warnings:[...r.warnings||[],...t.length?["部分字段因置信度或风险策略被跳过。"]:[]]};return this.events.emit("applied",a),(d=this.panel)==null||d.setApplyResult(a),a}destroy(){if(!this.destroyed){this.destroyed=!0;for(const e of this.panels)e.destroy();this.panels.length=0,this.panelStorageKeys.clear(),this.panel=null,this.events.clear(),this.context.manager.remove(this)}}assertAlive(){if(this.destroyed)throw E("INSTANCE_DESTROYED","实例已销毁。","ui")}emitError(e,t){var i;const s=oe(e,t);this.events.emit("error",s),(i=this.panel)==null||i.setError(s.message)}}function je(n,e,t,s,i){return{scanToken:n,traceId:e,items:t.map(r=>{const a=s.fields.find(l=>l.fieldId===r.fieldId),o=i.find(l=>l.fieldId===r.fieldId),d=o!=null&&o.getValue?o.getValue():Xe(a==null?void 0:a.element);return{applyItemId:`${r.fieldId}_${Math.random().toString(36).slice(2,8)}`,fieldId:r.fieldId,scanToken:n,groupId:r.groupId,label:r.label,value:r.value,currentValue:d,displayValue:r.displayValue||String(r.value??""),confidence:r.confidence,source:r.source,warnings:r.warnings,previousValue:d}})}}function Q(n){var e;return n.confidence>=Be&&!((e=n.warnings)!=null&&e.length)}function Ye(n){return n.items.filter(e=>!Q(e)).map(e=>{var t,s;return{fieldId:e.fieldId,label:e.label,attemptedValue:e.value,reason:((t=e.warnings)==null?void 0:t.join(";"))||`置信度 ${Math.round(e.confidence*100)}% 低于自动回填阈值`,reasonCode:(s=e.warnings)!=null&&s.length?"AUTO_APPLY_WARNING":"LOW_CONFIDENCE"}})}function Ze(n,e){const t=new Map;for(const s of e)t.set(s.fieldId,s);for(const s of n)t.has(s.fieldId)||t.set(s.fieldId,s);return[...t.values()]}function Ge(n,e){return n==="only"?!0:n==="off"?!1:e}function ee(n,e,t,s,i,r=!1){return{scanToken:n,suggestions:t,warnings:i,trace:{traceId:e,usedOcr:r,usedAi:!1,durationMs:Math.round(performance.now()-s)}}}function Xe(n){if(n)return n instanceof HTMLInputElement&&n.type==="checkbox"?n.checked:n instanceof HTMLInputElement||n instanceof HTMLTextAreaElement||n instanceof HTMLSelectElement?n.value:n.textContent}function te(n,e="default"){const t=typeof location<"u"?location.pathname:"unknown-page",s=e.replace(/[^\w-]/g,"_")||"default";return`smart-fill:${n}:${t}:${s}:open`}function We(n,e){if(typeof n=="string")return n;if(e.id)return`#${e.id}`;const t=typeof e.className=="string"?e.className.trim().split(/\s+/).filter(Boolean)[0]:"";return t?`.${t}`:e.tagName.toLowerCase()}function ne(n,e){try{const t=window.localStorage.getItem(n);return t==null?e:t==="1"}catch{return e}}function se(n,e){if(n)try{window.localStorage.setItem(n,e?"1":"0")}catch{}}function ie(){return`smart-fill:${typeof location<"u"?location.pathname:"unknown-page"}:local-priority`}function Je(){try{return window.localStorage.getItem(ie())==="1"}catch{return!1}}function Qe(n){try{window.localStorage.setItem(ie(),n?"1":"0")}catch{}}const f={status:"idle"},H=new _,re=new he;class ae{static async setup(e){if(typeof window>"u")return f.status="ready",et();if(f.status==="ready"&&f.apiKey===e.apiKey&&f.session)return f.session;if(f.status==="loading"&&f.apiKey===e.apiKey&&f.promise)return f.promise;f.apiKey&&f.apiKey!==e.apiKey&&re.destroyAll();const t=new le(e);return f.status="loading",f.apiKey=e.apiKey,f.client=t,f.promise=t.createSession().then(s=>(console.log("SmartFill session created:",s),t.setAccessToken(s.apiKey),f.status="ready",f.session=s,H.emit("ready",{apiKey:e.apiKey}),s)).catch(s=>{throw f.status="error",s}),f.promise}static create(e={}){if(typeof window>"u")return k();if(f.status!=="ready"||!f.client)throw E("SDK_NOT_READY","请先 await SmartFill.setup({ apiKey })。","setup");return new J(e,{client:f.client,manager:re})}}c(ae,"on",H.on.bind(H));function et(){return{apiKey:"server-mock",accessToken:"server-mock",expiresIn:0,refreshBefore:0,features:{text:!1,image:!1,ai:!1,localRuleOnly:!0},rulesVersion:"server"}}function k(n){const e=()=>{};return{on:e,useAdapter:()=>k(),registerFields:()=>k(),unregisterFields:e,mount:()=>k(),mountFloatingButton:()=>k(),open:async()=>{},close:e,rescan:async()=>({scanToken:"server",fields:[]}),recognize:async()=>({scanToken:"server",suggestions:[],trace:{traceId:"server",usedOcr:!1,usedAi:!1,durationMs:0}}),apply:async()=>({applied:[],skipped:[]}),destroy:e}}const tt={name:"native",match:n=>n instanceof HTMLInputElement||n instanceof HTMLTextAreaElement||n instanceof HTMLSelectElement,getValue:n=>{const e=n.element;if(e instanceof HTMLInputElement&&e.type==="checkbox")return e.checked;if(e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement||e instanceof HTMLSelectElement)return e.value},setValue:(n,e)=>{const t=n.element;t instanceof HTMLInputElement&&t.type==="checkbox"?t.checked=!!e:(t instanceof HTMLInputElement||t instanceof HTMLTextAreaElement||t instanceof HTMLSelectElement)&&(t.value=String(e??"")),t==null||t.dispatchEvent(new Event("input",{bubbles:!0})),t==null||t.dispatchEvent(new Event("change",{bubbles:!0}))}};p.DEFAULT_BASE_URL=y,p.DomFiller=D,p.DomScanner=Y,p.EventBus=_,p.LocalRuleEngine=U,p.NativeAdapter=tt,p.SmartFill=ae,p.SmartFillInstance=J,Object.defineProperty(p,Symbol.toStringTag,{value:"Module"})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"native.d.ts","sourceRoot":"","sources":["../../../src/adapters/native.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAEhD,eAAO,MAAM,aAAa,EAAE,gBAoB3B,CAAA"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { FieldDescriptor, FormConfigResponse, RecognizePayload, RecognizeResult, SessionResponse, SmartFillSetupConfig } from '../types';
|
|
2
|
+
type RecognizeStatus = 'image_uploading' | 'image_recognizing' | 'recognizing';
|
|
3
|
+
export declare class GatewayClient {
|
|
4
|
+
private readonly config;
|
|
5
|
+
/** 会话 accessToken,写入请求头 seToken */
|
|
6
|
+
private seToken;
|
|
7
|
+
/** 网关根地址,见 config/defaults.ts */
|
|
8
|
+
private readonly baseURL;
|
|
9
|
+
constructor(config: SmartFillSetupConfig);
|
|
10
|
+
/** 设置会话 token,后续 request 自动携带 seToken 请求头 */
|
|
11
|
+
setAccessToken(token: string): void;
|
|
12
|
+
/**
|
|
13
|
+
* 创建 SDK 会话。
|
|
14
|
+
* 校验 apiKey 格式(seKey- 前缀),当前阶段返回 mock session。
|
|
15
|
+
*/
|
|
16
|
+
createSession(): Promise<SessionResponse>;
|
|
17
|
+
/** 按 formCode 拉取远端表单配置(当前扫描流程已不再依赖) */
|
|
18
|
+
getFormConfig(formCode?: string): Promise<FormConfigResponse | null>;
|
|
19
|
+
/**
|
|
20
|
+
* 将识别输入统一为文本。
|
|
21
|
+
* - 图片:先走 OCR 提取文本,供本地规则和后端识别共用
|
|
22
|
+
* - 纯文本:直接返回 trim 后的输入
|
|
23
|
+
*/
|
|
24
|
+
resolveInputText(payload: Pick<RecognizePayload, 'text' | 'images'> & {
|
|
25
|
+
onStatusChange?: (status: RecognizeStatus) => void;
|
|
26
|
+
}): Promise<{
|
|
27
|
+
text: string;
|
|
28
|
+
usedOcr: boolean;
|
|
29
|
+
}>;
|
|
30
|
+
/**
|
|
31
|
+
* 调用后端智能识别接口。
|
|
32
|
+
* 将 data.fieldValues 归一化为 FieldSuggestion[],缺失字段补默认值:
|
|
33
|
+
* - label:扫描字段 label → fieldId
|
|
34
|
+
* - confidence:DEFAULT_REMOTE_CONFIDENCE
|
|
35
|
+
* - source:'ai'
|
|
36
|
+
*/
|
|
37
|
+
recognize(payload: {
|
|
38
|
+
scanToken: string;
|
|
39
|
+
text?: string;
|
|
40
|
+
usedOcr?: boolean;
|
|
41
|
+
formCode?: string;
|
|
42
|
+
configVersion?: string;
|
|
43
|
+
fields: FieldDescriptor[];
|
|
44
|
+
onStatusChange?: (status: RecognizeStatus) => void;
|
|
45
|
+
}): Promise<RecognizeResult>;
|
|
46
|
+
/** 图片 OCR:以 multipart/form-data 上传 files,返回提取出的 text 文本 */
|
|
47
|
+
private recognizeImages;
|
|
48
|
+
/** 通用 fetch 封装:超时控制、trace 头、HTTP 错误映射为 SmartFillException */
|
|
49
|
+
private request;
|
|
50
|
+
}
|
|
51
|
+
export {};
|
|
52
|
+
//# sourceMappingURL=gateway-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gateway-client.d.ts","sourceRoot":"","sources":["../../../src/client/gateway-client.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EACV,eAAe,EAEf,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,oBAAoB,EACrB,MAAM,UAAU,CAAC;AAmClB,KAAK,eAAe,GAAG,iBAAiB,GAAG,mBAAmB,GAAG,aAAa,CAAA;AAE9E,qBAAa,aAAa;IAMZ,OAAO,CAAC,QAAQ,CAAC,MAAM;IALnC,mCAAmC;IACnC,OAAO,CAAC,OAAO,CAAK;IACpB,iCAAiC;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmB;gBAEd,MAAM,EAAE,oBAAoB;IAEzD,6CAA6C;IAC7C,cAAc,CAAC,KAAK,EAAE,MAAM;IAI5B;;;OAGG;IACG,aAAa,IAAI,OAAO,CAAC,eAAe,CAAC;IAiB/C,uCAAuC;IACjC,aAAa,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;IAU1E;;;;OAIG;IACG,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,gBAAgB,EAAE,MAAM,GAAG,QAAQ,CAAC,GAAG;QAC1E,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,IAAI,CAAA;KACnD;;;;IAcD;;;;;;OAMG;IACG,SAAS,CAAC,OAAO,EAAE;QACvB,SAAS,EAAE,MAAM,CAAA;QACjB,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,OAAO,CAAC,EAAE,OAAO,CAAA;QACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,aAAa,CAAC,EAAE,MAAM,CAAA;QACtB,MAAM,EAAE,eAAe,EAAE,CAAA;QACzB,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,IAAI,CAAA;KACnD,GAAG,OAAO,CAAC,eAAe,CAAC;IAkC5B,2DAA2D;YAC7C,eAAe;IAqB7B,6DAA6D;YAC/C,OAAO;CA+BtB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../../src/config/defaults.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,2BAA2B,CAAA"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { SmartFillError } from '../types';
|
|
2
|
+
export declare class SmartFillException extends Error {
|
|
3
|
+
/** 结构化错误信息,含 code / stage / retryable */
|
|
4
|
+
readonly smartFillError: SmartFillError;
|
|
5
|
+
constructor(error: SmartFillError);
|
|
6
|
+
}
|
|
7
|
+
/** 创建 SDK 标准异常,供 throw 和 emit error 使用 */
|
|
8
|
+
export declare function createError(code: string, message: string, stage: SmartFillError['stage'], extra?: Partial<SmartFillError>): SmartFillException;
|
|
9
|
+
/** 将未知 error 归一化为 SmartFillError,非 SmartFillException 则包装默认信息 */
|
|
10
|
+
export declare function toSmartFillError(error: unknown, stage: SmartFillError['stage'], code?: string): SmartFillError;
|
|
11
|
+
/** 生成唯一追踪 ID,用于 scanToken / traceId */
|
|
12
|
+
export declare function createTraceId(prefix?: string): string;
|
|
13
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/core/errors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAE9C,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,yCAAyC;IACzC,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAA;gBAE3B,KAAK,EAAE,cAAc;CAKlC;AAED,0CAA0C;AAC1C,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,cAAc,CAAC,OAAO,CAAC,EAC9B,KAAK,GAAE,OAAO,CAAC,cAAc,CAAM,GAClC,kBAAkB,CAEpB;AAED,iEAAiE;AACjE,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,cAAc,CAAC,OAAO,CAAC,EAC9B,IAAI,SAAqB,GACxB,cAAc,CAWhB;AAED,uCAAuC;AACvC,wBAAgB,aAAa,CAAC,MAAM,SAAO,UAE1C"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 多实例 UI 互斥管理器。
|
|
3
|
+
*
|
|
4
|
+
* 同一页面可能存在多个 SmartFillInstance(如多 Tab),
|
|
5
|
+
* activate 时自动关闭上一个实例的面板,避免 UI 重叠。
|
|
6
|
+
*/
|
|
7
|
+
export declare class InstanceManager<T extends {
|
|
8
|
+
close: () => void;
|
|
9
|
+
destroy: () => void;
|
|
10
|
+
}> {
|
|
11
|
+
/** 当前页面所有存活实例 */
|
|
12
|
+
private instances;
|
|
13
|
+
/** 当前激活(面板打开)的实例 */
|
|
14
|
+
private active;
|
|
15
|
+
/** 注册新实例 */
|
|
16
|
+
add(instance: T): void;
|
|
17
|
+
/** 激活实例,自动关闭上一个实例的面板 */
|
|
18
|
+
activate(instance: T): void;
|
|
19
|
+
/** 实例销毁时从管理器移除 */
|
|
20
|
+
remove(instance: T): void;
|
|
21
|
+
/** 销毁所有实例(apiKey 变更时调用) */
|
|
22
|
+
destroyAll(): void;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=instance-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instance-manager.d.ts","sourceRoot":"","sources":["../../../src/core/instance-manager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,qBAAa,eAAe,CAAC,CAAC,SAAS;IAAE,KAAK,EAAE,MAAM,IAAI,CAAC;IAAC,OAAO,EAAE,MAAM,IAAI,CAAA;CAAE;IAC/E,iBAAiB;IACjB,OAAO,CAAC,SAAS,CAAe;IAChC,oBAAoB;IACpB,OAAO,CAAC,MAAM,CAAiB;IAE/B,YAAY;IACZ,GAAG,CAAC,QAAQ,EAAE,CAAC;IAIf,wBAAwB;IACxB,QAAQ,CAAC,QAAQ,EAAE,CAAC;IAOpB,kBAAkB;IAClB,MAAM,CAAC,QAAQ,EAAE,CAAC;IAOlB,2BAA2B;IAC3B,UAAU;CAKX"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { GatewayClient } from '../client/gateway-client';
|
|
2
|
+
import { ScanResult } from '../scanner/dom-scanner';
|
|
3
|
+
import { ApplyInput, ApplyResult, FieldSchema, RecognizeResult, SmartFillAdapter, SmartFillCreateConfig, SmartFillEventMap } from '../types';
|
|
4
|
+
import { SmartFillPanel } from '../ui/panel';
|
|
5
|
+
import { InstanceManager } from './instance-manager';
|
|
6
|
+
/** 实例运行时依赖:网关客户端 + 多实例互斥管理器 */
|
|
7
|
+
type InternalContext = {
|
|
8
|
+
client: GatewayClient;
|
|
9
|
+
manager: InstanceManager<SmartFillInstance>;
|
|
10
|
+
};
|
|
11
|
+
export declare class SmartFillInstance {
|
|
12
|
+
private readonly config;
|
|
13
|
+
private readonly context;
|
|
14
|
+
/** 实例级事件总线,对应 instance.on(...) */
|
|
15
|
+
private readonly events;
|
|
16
|
+
/** 页面字段扫描器,root 来自 SmartFill.create({ root }) */
|
|
17
|
+
private readonly scanner;
|
|
18
|
+
/** 浏览器端本地规则引擎,用于文本正则/键值对提取 */
|
|
19
|
+
private readonly ruleEngine;
|
|
20
|
+
/** Shadow DOM 面板,mount / mountFloatingButton 后可用(指向最后挂载的面板,用于状态展示) */
|
|
21
|
+
private panel;
|
|
22
|
+
/** 已挂载的全部面板(inline / floating 可同时存在),用于本地优先开关广播与销毁 */
|
|
23
|
+
private readonly panels;
|
|
24
|
+
/** 面板展开状态持久化 key */
|
|
25
|
+
private readonly panelStorageKeys;
|
|
26
|
+
/** 业务方 registerFields 注册的字段;非空时 rescan 仅扫描这些字段 */
|
|
27
|
+
private registeredFields;
|
|
28
|
+
/** 组件库回填适配器链,如 AntD / Element 自定义控件 */
|
|
29
|
+
private adapters;
|
|
30
|
+
/** 最近一次 rescan 结果;scanToken 用于识别/回填防过期校验 */
|
|
31
|
+
private scanResult;
|
|
32
|
+
/** recognize 完成后生成的自动回填候选,供面板展示与 applyAutoItems 使用 */
|
|
33
|
+
private autoApplyState;
|
|
34
|
+
/** 预留:表单配置版本号,识别请求可携带给后端 */
|
|
35
|
+
private formConfigVersion?;
|
|
36
|
+
/** 面板「启用本地优先识别」开关状态,默认关闭(走后端识别) */
|
|
37
|
+
private localPriorityEnabled;
|
|
38
|
+
/** 实例是否已 destroy,销毁后所有公开方法抛 INSTANCE_DESTROYED */
|
|
39
|
+
private destroyed;
|
|
40
|
+
constructor(config: SmartFillCreateConfig, context: InternalContext);
|
|
41
|
+
/** 订阅实例事件,返回取消订阅函数 */
|
|
42
|
+
on<K extends keyof SmartFillEventMap>(event: K, handler: (payload: SmartFillEventMap[K]) => void): () => void;
|
|
43
|
+
/** 注册组件库回填适配器,支持链式调用 */
|
|
44
|
+
useAdapter(adapter: SmartFillAdapter): this;
|
|
45
|
+
/**
|
|
46
|
+
* 显式注册字段映射(L3 模式)。
|
|
47
|
+
* 注册后 rescan 不再自动扫 DOM,仅解析 element 选择器定位控件。
|
|
48
|
+
* rowKey 用于明细行等同 fieldId 多行场景,不可重复。
|
|
49
|
+
*/
|
|
50
|
+
registerFields(fields: FieldSchema[]): this;
|
|
51
|
+
/** 取消注册字段;不传 fieldIds 时清空全部注册 */
|
|
52
|
+
unregisterFields(fieldIds?: string[]): void;
|
|
53
|
+
/** 将面板嵌入指定容器(inline 模式) */
|
|
54
|
+
mount(target: string | HTMLElement): this;
|
|
55
|
+
/** 挂载右下角悬浮按钮 + 弹框(floating 模式) */
|
|
56
|
+
mountFloatingButton(): this;
|
|
57
|
+
/**
|
|
58
|
+
* 创建面板并登记到 panels。
|
|
59
|
+
* inline / floating 共用同一份 localPriorityEnabled,开关变更经 handleLocalPriorityChange 持久化并广播。
|
|
60
|
+
*/
|
|
61
|
+
private createPanel;
|
|
62
|
+
/** 同步本地优先开关:更新内存态、写入 localStorage,并广播到其他已挂载面板 */
|
|
63
|
+
private handleLocalPriorityChange;
|
|
64
|
+
/** 打开面板并触发 rescan,同时激活当前实例(关闭其他实例面板) */
|
|
65
|
+
open(targetPanel?: SmartFillPanel | null): Promise<void>;
|
|
66
|
+
/** 关闭面板(不销毁实例) */
|
|
67
|
+
close(targetPanel?: SmartFillPanel | null): void;
|
|
68
|
+
/**
|
|
69
|
+
* 扫描页面可回填字段。
|
|
70
|
+
* 优先级:registerFields > 页面 DOM 自动扫描。
|
|
71
|
+
* 扫描成功 emit scanCompleted,失败 emit error。
|
|
72
|
+
*/
|
|
73
|
+
rescan(): Promise<ScanResult>;
|
|
74
|
+
/**
|
|
75
|
+
* 识别入口:文本/图片 → 本地规则 + 后端网关 → 合并 → 自动回填。
|
|
76
|
+
*
|
|
77
|
+
* localRuleMode 分流:
|
|
78
|
+
* - off:跳过本地规则
|
|
79
|
+
* - only:跳过后端,仅本地识别
|
|
80
|
+
* - inherit:跟随 localPriorityEnabled 总开关
|
|
81
|
+
*
|
|
82
|
+
* 后端失败时,仅在当前已启用本地规则时,降级使用本地结果继续回填。
|
|
83
|
+
*/
|
|
84
|
+
recognize(input: {
|
|
85
|
+
text?: string;
|
|
86
|
+
images?: File[];
|
|
87
|
+
}): Promise<RecognizeResult>;
|
|
88
|
+
/**
|
|
89
|
+
* 手动回填指定字段值。
|
|
90
|
+
* 通常由业务方调用;recognize 流程内的自动回填走 applyAutoItems。
|
|
91
|
+
* 需传入与当前 scanResult 一致的 scanToken。
|
|
92
|
+
*/
|
|
93
|
+
apply(input: ApplyInput): Promise<ApplyResult>;
|
|
94
|
+
/**
|
|
95
|
+
* 自动回填:过滤 confidence ≥ 阈值且无 warnings 的候选项,写入 DOM。
|
|
96
|
+
* 被策略跳过的字段记录在 skipped 中,reasonCode 为 LOW_CONFIDENCE / AUTO_APPLY_WARNING。
|
|
97
|
+
*/
|
|
98
|
+
private applyAutoItems;
|
|
99
|
+
/** 销毁实例:移除面板、清空事件、从 InstanceManager 注销 */
|
|
100
|
+
destroy(): void;
|
|
101
|
+
private assertAlive;
|
|
102
|
+
private emitError;
|
|
103
|
+
}
|
|
104
|
+
export {};
|
|
105
|
+
//# sourceMappingURL=smart-fill-instance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smart-fill-instance.d.ts","sourceRoot":"","sources":["../../../src/core/smart-fill-instance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAIzD,OAAO,EAAc,KAAK,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACrE,OAAO,KAAK,EACV,UAAU,EACV,WAAW,EAEX,WAAW,EACX,eAAe,EACf,gBAAgB,EAChB,qBAAqB,EACrB,iBAAiB,EAClB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1D,+BAA+B;AAC/B,KAAK,eAAe,GAAG;IACrB,MAAM,EAAE,aAAa,CAAA;IACrB,OAAO,EAAE,eAAe,CAAC,iBAAiB,CAAC,CAAA;CAC5C,CAAA;AAKD,qBAAa,iBAAiB;IA6B1B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IA7B1B,kCAAkC;IAClC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;IACxC,iDAAiD;IACjD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAY;IACpC,8BAA8B;IAC9B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAwB;IACnD,sEAAsE;IACtE,OAAO,CAAC,KAAK,CAA8B;IAC3C,sDAAsD;IACtD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuB;IAC9C,oBAAoB;IACpB,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAoC;IACrE,kDAAkD;IAClD,OAAO,CAAC,gBAAgB,CAAoB;IAC5C,uCAAuC;IACvC,OAAO,CAAC,QAAQ,CAAyB;IACzC,4CAA4C;IAC5C,OAAO,CAAC,UAAU,CAA0B;IAC5C,sDAAsD;IACtD,OAAO,CAAC,cAAc,CAA8B;IACpD,4BAA4B;IAC5B,OAAO,CAAC,iBAAiB,CAAC,CAAQ;IAClC,mCAAmC;IACnC,OAAO,CAAC,oBAAoB,CAAQ;IACpC,kDAAkD;IAClD,OAAO,CAAC,SAAS,CAAQ;gBAGN,MAAM,EAAE,qBAAqB,EAC7B,OAAO,EAAE,eAAe;IAO3C,sBAAsB;IACtB,EAAE,CAAC,CAAC,SAAS,MAAM,iBAAiB,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC,CAAC,KAAK,IAAI;IAIhG,wBAAwB;IACxB,UAAU,CAAC,OAAO,EAAE,gBAAgB;IAMpC;;;;OAIG;IACH,cAAc,CAAC,MAAM,EAAE,WAAW,EAAE;IAcpC,iCAAiC;IACjC,gBAAgB,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE;IAOpC,2BAA2B;IAC3B,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW;IAYlC,kCAAkC;IAClC,mBAAmB;IAQnB;;;OAGG;IACH,OAAO,CAAC,WAAW;IAqBnB,iDAAiD;IACjD,OAAO,CAAC,yBAAyB;IAQjC,wCAAwC;IAClC,IAAI,CAAC,WAAW,wBAAa;IAUnC,kBAAkB;IAClB,KAAK,CAAC,WAAW,wBAAa;IAO9B;;;;OAIG;IACG,MAAM;IAwBZ;;;;;;;;;OASG;IACG,SAAS,CAAC,KAAK,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAA;KAAE;IAoFzD;;;;OAIG;IACG,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC;IAapD;;;OAGG;YACW,cAAc;IA6B5B,0CAA0C;IAC1C,OAAO;IAWP,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,SAAS;CAKlB"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { SessionResponse, SmartFillCreateConfig, SmartFillSetupConfig } from '../types';
|
|
2
|
+
import { SmartFillInstance } from './smart-fill-instance';
|
|
3
|
+
export declare class SmartFill {
|
|
4
|
+
/** 初始化 SDK:校验 apiKey、创建会话、获取 accessToken */
|
|
5
|
+
static setup(config: SmartFillSetupConfig): Promise<SessionResponse>;
|
|
6
|
+
/** 创建页面实例,必须在 setup ready 后调用 */
|
|
7
|
+
static create(config?: SmartFillCreateConfig): SmartFillInstance | {
|
|
8
|
+
on: () => undefined;
|
|
9
|
+
useAdapter: () => /*elided*/ any;
|
|
10
|
+
registerFields: () => /*elided*/ any;
|
|
11
|
+
unregisterFields: () => undefined;
|
|
12
|
+
mount: () => /*elided*/ any;
|
|
13
|
+
mountFloatingButton: () => /*elided*/ any;
|
|
14
|
+
open: () => Promise<undefined>;
|
|
15
|
+
close: () => undefined;
|
|
16
|
+
rescan: () => Promise<{
|
|
17
|
+
scanToken: string;
|
|
18
|
+
fields: never[];
|
|
19
|
+
}>;
|
|
20
|
+
recognize: () => Promise<{
|
|
21
|
+
scanToken: string;
|
|
22
|
+
suggestions: never[];
|
|
23
|
+
trace: {
|
|
24
|
+
traceId: string;
|
|
25
|
+
usedOcr: boolean;
|
|
26
|
+
usedAi: boolean;
|
|
27
|
+
durationMs: number;
|
|
28
|
+
};
|
|
29
|
+
}>;
|
|
30
|
+
apply: () => Promise<{
|
|
31
|
+
applied: never[];
|
|
32
|
+
skipped: never[];
|
|
33
|
+
}>;
|
|
34
|
+
destroy: () => undefined;
|
|
35
|
+
};
|
|
36
|
+
/** 订阅全局事件(目前仅 ready) */
|
|
37
|
+
static on: <K extends keyof import('..').SmartFillEventMap>(event: K, handler: (payload: import('..').SmartFillEventMap[K]) => void) => () => void;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=smart-fill.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smart-fill.d.ts","sourceRoot":"","sources":["../../../src/core/smart-fill.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,eAAe,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAG7F,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAmB1D,qBAAa,SAAS;IACpB,4CAA4C;WAC/B,KAAK,CAAC,MAAM,EAAE,oBAAoB;IAuC/C,iCAAiC;IACjC,MAAM,CAAC,MAAM,CAAC,MAAM,GAAE,qBAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAehD,wBAAwB;IACxB,MAAM,CAAC,EAAE,0IAAqC;CAC/C"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { SmartFillEventMap } from '../types';
|
|
2
|
+
type Handler<T> = (payload: T) => void;
|
|
3
|
+
export declare class EventBus {
|
|
4
|
+
private handlers;
|
|
5
|
+
/** 订阅事件,返回 unsubscribe 函数 */
|
|
6
|
+
on<K extends keyof SmartFillEventMap>(event: K, handler: Handler<SmartFillEventMap[K]>): () => void;
|
|
7
|
+
off<K extends keyof SmartFillEventMap>(event: K, handler: Handler<SmartFillEventMap[K]>): void;
|
|
8
|
+
emit<K extends keyof SmartFillEventMap>(event: K, payload: SmartFillEventMap[K]): void;
|
|
9
|
+
clear(): void;
|
|
10
|
+
}
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=event-bus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-bus.d.ts","sourceRoot":"","sources":["../../../src/events/event-bus.ts"],"names":[],"mappings":"AAAA,oDAAoD;AACpD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AAEjD,KAAK,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,IAAI,CAAA;AAEtC,qBAAa,QAAQ;IACnB,OAAO,CAAC,QAAQ,CAAwD;IAExE,6BAA6B;IAC7B,EAAE,CAAC,CAAC,SAAS,MAAM,iBAAiB,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;IAOtF,GAAG,CAAC,CAAC,SAAS,MAAM,iBAAiB,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;IAIvF,IAAI,CAAC,CAAC,SAAS,MAAM,iBAAiB,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAI/E,KAAK;CAGN"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { ApplyInput, ApplyResult, FieldDescriptor, FieldSchema, SmartFillAdapter } from '../types';
|
|
2
|
+
export declare class DomFiller {
|
|
3
|
+
/** 当前扫描字段列表,含 element 引用和 fingerprint */
|
|
4
|
+
private readonly fields;
|
|
5
|
+
/** 业务注册 Schema,提供 transform/validate/setValue 扩展 */
|
|
6
|
+
private readonly schemas;
|
|
7
|
+
/** 组件库适配器链 */
|
|
8
|
+
private readonly adapters;
|
|
9
|
+
constructor(
|
|
10
|
+
/** 当前扫描字段列表,含 element 引用和 fingerprint */
|
|
11
|
+
fields: FieldDescriptor[],
|
|
12
|
+
/** 业务注册 Schema,提供 transform/validate/setValue 扩展 */
|
|
13
|
+
schemas: FieldSchema[],
|
|
14
|
+
/** 组件库适配器链 */
|
|
15
|
+
adapters?: SmartFillAdapter[]);
|
|
16
|
+
/**
|
|
17
|
+
* 批量回填字段值。
|
|
18
|
+
* 每条 value 依次校验:字段存在 → scanToken 有效 → validate → setValue。
|
|
19
|
+
* 失败项记入 skipped,不中断后续字段。
|
|
20
|
+
*/
|
|
21
|
+
apply(input: ApplyInput): Promise<ApplyResult>;
|
|
22
|
+
/** 读取字段当前值,优先级:schema.getValue > adapter > DOM */
|
|
23
|
+
private getValue;
|
|
24
|
+
/**
|
|
25
|
+
* 写入字段值,优先级:schema.setValue > adapter > 原生 DOM。
|
|
26
|
+
* 写入前校验 fingerprint 防 DOM 变化误填,写入后触发高亮。
|
|
27
|
+
*/
|
|
28
|
+
private setValue;
|
|
29
|
+
/** 匹配第一个适用的组件库适配器 */
|
|
30
|
+
private matchAdapter;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=dom-filler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dom-filler.d.ts","sourceRoot":"","sources":["../../../src/filler/dom-filler.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,eAAe,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAKvG,qBAAa,SAAS;IAElB,yCAAyC;IACzC,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,oDAAoD;IACpD,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,cAAc;IACd,OAAO,CAAC,QAAQ,CAAC,QAAQ;;IALzB,yCAAyC;IACxB,MAAM,EAAE,eAAe,EAAE;IAC1C,oDAAoD;IACnC,OAAO,EAAE,WAAW,EAAE;IACvC,cAAc;IACG,QAAQ,GAAE,gBAAgB,EAAO;IAGpD;;;;OAIG;IACG,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC;IAyCpD,kDAAkD;YACpC,QAAQ;IAYtB;;;OAGG;YACW,QAAQ;IAyBtB,qBAAqB;IACrB,OAAO,CAAC,YAAY;CAIrB"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { SmartFill } from './core/smart-fill';
|
|
2
|
+
export { SmartFillInstance } from './core/smart-fill-instance';
|
|
3
|
+
export { EventBus } from './events/event-bus';
|
|
4
|
+
export { DomScanner } from './scanner/dom-scanner';
|
|
5
|
+
export { LocalRuleEngine } from './rules/local-rules';
|
|
6
|
+
export { DomFiller } from './filler/dom-filler';
|
|
7
|
+
export { NativeAdapter } from './adapters/native';
|
|
8
|
+
export { DEFAULT_BASE_URL } from './config/defaults';
|
|
9
|
+
export type { AutoApplyItem, AutoApplyState, ApplyInput, ApplyResult, FieldDescriptor, FieldOption, FieldSchema, FieldSuggestion, FieldType, RecognizePayload, RecognizeResult, SessionResponse, SmartFillAdapter, SmartFillCreateConfig, SmartFillError, SmartFillEventMap, SmartFillSetupConfig } from './types';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,aAAa,CAAA;AAEpB,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AAC9D,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACpD,YAAY,EACV,aAAa,EACb,cAAc,EACd,UAAU,EACV,WAAW,EACX,eAAe,EACf,WAAW,EACX,WAAW,EACX,eAAe,EACf,SAAS,EACT,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,qBAAqB,EACrB,cAAc,EACd,iBAAiB,EACjB,oBAAoB,EACrB,MAAM,SAAS,CAAA"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { FieldDescriptor, FieldSuggestion } from '../types';
|
|
2
|
+
export declare class LocalRuleEngine {
|
|
3
|
+
/**
|
|
4
|
+
* 从文本中提取事实并匹配到 scan 字段。
|
|
5
|
+
* 按 confidence 降序分配,每个 fieldId 仅匹配一次(usedFieldIds 去重)。
|
|
6
|
+
*/
|
|
7
|
+
recognize(text: string, fields: FieldDescriptor[], scanToken: string): FieldSuggestion[];
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=local-rules.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-rules.d.ts","sourceRoot":"","sources":["../../../src/rules/local-rules.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AA0HhE,qBAAa,eAAe;IAC1B;;;OAGG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,eAAe,EAAE;CAwBzF"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { FieldDescriptor, FieldSchema } from '../types';
|
|
2
|
+
/** 单次扫描结果,scanToken 贯穿识别与回填 */
|
|
3
|
+
export type ScanResult = {
|
|
4
|
+
scanToken: string;
|
|
5
|
+
fields: FieldDescriptor[];
|
|
6
|
+
};
|
|
7
|
+
export declare class DomScanner {
|
|
8
|
+
private readonly root;
|
|
9
|
+
constructor(root?: HTMLElement | ShadowRoot | Document);
|
|
10
|
+
/**
|
|
11
|
+
* 扫描可回填字段。
|
|
12
|
+
* - registered 非空:仅解析注册 Schema,不扫 DOM
|
|
13
|
+
* - 否则:自动扫描可见 input/textarea/select,优先弹窗内控件
|
|
14
|
+
*/
|
|
15
|
+
scan(options?: {
|
|
16
|
+
registered?: FieldSchema[];
|
|
17
|
+
scanContainer?: string;
|
|
18
|
+
maxFields?: number;
|
|
19
|
+
}): ScanResult;
|
|
20
|
+
/** FieldSchema → FieldDescriptor,解析 element 并生成 fingerprint */
|
|
21
|
+
private fromSchema;
|
|
22
|
+
/** DOM 元素 → FieldDescriptor,自动推断 label/type 并写入 data-smart-fill-id */
|
|
23
|
+
private fromElement;
|
|
24
|
+
/** 解析扫描根节点,scanContainer 为 CSS 选择器 */
|
|
25
|
+
private resolveRoot;
|
|
26
|
+
/** 收集 root 下可见且可编辑的表单控件 */
|
|
27
|
+
private collectVisibleFields;
|
|
28
|
+
/**
|
|
29
|
+
* 检测最应优先扫描的容器。
|
|
30
|
+
* 优先 activeElement 所在弹窗,否则取包含最多字段的弹窗容器。
|
|
31
|
+
*/
|
|
32
|
+
private detectTopLayerContainer;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=dom-scanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dom-scanner.d.ts","sourceRoot":"","sources":["../../../src/scanner/dom-scanner.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAgC5D,+BAA+B;AAC/B,MAAM,MAAM,UAAU,GAAG;IACvB,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,eAAe,EAAE,CAAA;CAC1B,CAAA;AAED,qBAAa,UAAU;IACT,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,GAAE,WAAW,GAAG,UAAU,GAAG,QAAmB;IAEjF;;;;OAIG;IACH,IAAI,CAAC,OAAO,GAAE;QAAE,UAAU,CAAC,EAAE,WAAW,EAAE,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,UAAU;IAsB1G,+DAA+D;IAC/D,OAAO,CAAC,UAAU;IAsBlB,sEAAsE;IACtE,OAAO,CAAC,WAAW;IA4BnB,sCAAsC;IACtC,OAAO,CAAC,WAAW;IAUnB,2BAA2B;IAC3B,OAAO,CAAC,oBAAoB;IAY5B;;;OAGG;IACH,OAAO,CAAC,uBAAuB;CAiBhC"}
|