dsh-form-fill-agent 0.2.3 → 0.2.5
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 +2 -2
- package/lib/brand.css +1 -0
- package/lib/ui.html +23 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -43,7 +43,7 @@ dsh plugin --profile web add dsh-form-fill-agent@latest
|
|
|
43
43
|
|
|
44
44
|
## 使用边界与数据保存
|
|
45
45
|
|
|
46
|
-
补充要求为模型可读文本;字段或工作表范围请通过向导/工作台修改,不能仅改文字后假定执行范围已同步。任务 schema 5 可读取 schema 1–5;回退旧版本请使用升级前目录副本或独立任务目录。主包为 0.2.
|
|
46
|
+
补充要求为模型可读文本;字段或工作表范围请通过向导/工作台修改,不能仅改文字后假定执行范围已同步。任务 schema 5 可读取 schema 1–5;回退旧版本请使用升级前目录副本或独立任务目录。主包为 0.2.5,共享内核和 Provider 保持 0.2.0。
|
|
47
47
|
|
|
48
48
|
支持企业完整登记名称或 18 位信用代码;简称、主体不一致或多候选不会自动猜选。仅有信用代码的表格也可作为查询锚点。连接候选检索工具时可检索简称,仍需人工确认;缺少工具时降级人工输入。字段映射采用确定性规则及人工确认,不让模型编造事实。支持普通内部公式、固定区域下拉、基础条件格式和普通表格对象;复杂 Excel 结构和 Word 暂不支持,保真边界见下方安全说明。
|
|
49
49
|
|
|
@@ -51,7 +51,7 @@ dsh plugin --profile web add dsh-form-fill-agent@latest
|
|
|
51
51
|
|
|
52
52
|
显式设置 DSH_HOME 时,任务保存至其 form-fill-tasks 目录,默认 24 小时过期;未设置时使用内存。任务保存输入表格和归一化预览,不持久化原始 MCP 响应,可主动删除任务。模型及 MCP 凭据由宿主管理。
|
|
53
53
|
|
|
54
|
-
0.2.
|
|
54
|
+
0.2.5 保存任务 schema 5,兼容读取旧 schema 1–4;回退旧版本须使用升级前任务目录副本或新目录,防止丢失已确认的字段/主体设置。
|
|
55
55
|
|
|
56
56
|
## 文档与反馈
|
|
57
57
|
|
package/lib/brand.css
CHANGED
|
@@ -44,3 +44,4 @@
|
|
|
44
44
|
.ff-ui .card{margin:16px 20px;padding:20px;border:1px solid var(--line);border-radius:8px;background:var(--surface);min-width:0}.ff-ui .card h2{margin:0 0 12px;font-size:18px}.ff-ui .card p{margin:8px 0 16px}.ff-ui #grid{margin:16px 20px;padding:16px;background:var(--surface);border:1px solid var(--line);border-radius:8px;min-width:0}.ff-ui #grid summary{cursor:pointer;font-weight:600}
|
|
45
45
|
.ff-ui #history{padding:20px}.ff-ui #preview>.controls{padding:0 20px 20px}.ff-ui input[type=file]{width:100%;max-width:100%;min-width:0;font-size:12px}.ff-ui input[type=file]::file-selector-button{font:inherit;border:1px solid var(--line);border-radius:6px;padding:8px 12px;margin-right:10px;background:var(--surface);color:var(--text);cursor:pointer}.ff-ui #samples{margin-top:12px}.ff-ui .history-item{background:var(--surface);padding:16px;border:1px solid var(--line);border-radius:8px;margin-top:12px}
|
|
46
46
|
@media(max-width:640px){.ff-ui .ff-shortcuts{justify-content:flex-start;padding-inline:12px;gap:8px}.ff-ui .ff-shortcuts button{flex:0 0 auto;min-width:92px;padding:7px 10px;font-size:12px}.ff-ui .card{margin:14px;padding:16px}.ff-ui #grid{margin:14px}.ff-ui .task-tabs{padding-inline:14px}.ff-ui #status{padding-inline:14px}.ff-ui #task-meta{margin-inline:14px;max-width:calc(100% - 28px)}.ff-ui .ff-execution-toolbar{margin-inline:14px}.ff-ui .ff-panel-head{padding:12px}.ff-ui .ff-panel-head .ff-brand{gap:8px}.ff-ui .ff-panel-head h2{font-size:14px}.ff-ui .ff-panel-actions{gap:4px}.ff-ui .ff-panel-actions button{font-size:11px;padding:6px}.ff-ui .ff-workbench-head{padding:16px}}
|
|
47
|
+
.ff-ui .ff-field-picker{position:relative;width:100%;min-width:0}.ff-ui .ff-field-picker>summary{padding:10px 12px;border:1px solid var(--line);border-radius:8px;background:var(--surface);cursor:pointer;overflow-wrap:anywhere}.ff-ui .ff-field-picker[open]>summary{border-color:var(--blue)}.ff-ui .ff-field-panel{padding:12px;border:1px solid var(--line);border-radius:8px;background:var(--surface);margin-top:4px;min-width:0}.ff-ui .ff-field-panel select[data-column]{width:100%;height:auto;max-width:100%}.ff-ui .ff-field-panel optgroup{font-weight:600}.ff-ui .ff-field-panel option{padding:7px;font-weight:400}
|
package/lib/ui.html
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
<div class="controls"><input type="file" id="file" accept=".xlsx" aria-label="选择 XLSX 文件"><button id="upload">分析表格</button></div>
|
|
16
16
|
<details><summary>体验合成模板</summary><p>下面模板只使用合成数据,不查询真实企业。</p><div class="controls" id="samples"><button class="secondary" data-name="客户台账">客户台账</button><button class="secondary" data-name="供应商准入表">供应商准入表</button><button class="secondary" data-name="合同主体信息表">合同主体信息表</button></div></details></div>
|
|
17
17
|
<section id="preview" hidden>
|
|
18
|
-
<div class="card" data-pane="rules"><h2>字段与规则</h2><p id="structure"></p><p id="anchor-alert" role="status"></p><p>默认只填空白。可选择工作表、修正表头行及字段;应用设置会清除旧预览和主体确认,请重新核验。</p><label>搜索字段 <input id="mapping-search" type="search" placeholder="按原表字段名称筛选"></label><p class="muted">未识别字段可手动选择;没有数据来源的字段选择“不填写”。规则只保存表头与映射,不含记录。</p><button id="mapping-save">保存字段规则</button><button id="mapping-load">复用字段规则</button><div id="mapping"></div><button id="configure" class="primary">应用字段设置</button></div>
|
|
18
|
+
<div class="card" data-pane="rules"><h2>字段与规则</h2><p id="structure"></p><p id="anchor-alert" role="status"></p><p>默认只填空白。可选择工作表、修正表头行及字段;应用设置会清除旧预览和主体确认,请重新核验。</p><label>搜索字段 <input id="mapping-search" type="search" placeholder="按原表字段名称筛选"></label><p class="muted">未识别字段可手动选择;没有数据来源的字段选择“不填写”。规则只保存表头与映射,不含记录。</p><button id="mapping-save">保存字段规则</button><button id="mapping-load">复用字段规则</button><div id="mapping"></div><button id="configure" class="primary">应用字段设置</button><div id="mapping-next" hidden role="status"><p>设置已保存。下一步核验企业主体,确认填写范围后生成指令并发送,查询结果会进入填写预览。</p><button id="mapping-continue" class="primary">下一步:主体核验</button></div></div>
|
|
19
19
|
<div class="card" data-pane="identity"><h2>主体核验与查询</h2><p id="connection"></p><p>候选不自动选择。查询返回歧义后,可选择返回候选或填写已核验的完整登记名称/信用代码;原表主体文字不覆盖,选择仅用于后续查询。</p><div id="entities"></div><button id="wizard-open">生成填写指令</button><p class="muted">查询不会自动发送;回填后可在原生对话框修改并发送。</p></div>
|
|
20
20
|
<div class="card" data-pane="preview"><h2>填写预览</h2><p id="summary"></p><details><summary>逐列填写结果</summary><p class="muted">按单元格统计;整行缺少主体标识的情况另见下方原因分类。</p><div class="scroll"><table><thead><tr><th>原表字段</th><th>映射字段</th><th>预览可填写格数</th><th>未完成项</th></tr></thead><tbody id="field-results"></tbody></table></div></details><p class="muted">每格显示原值、准备填写值和来源。取消勾选后点击“应用选择”,再确认新的预览。</p>
|
|
21
21
|
<div class="toolbar"><label>筛选单元格 <input id="result-search" type="search" placeholder="位置、字段或值"></label><span id="result-count" class="muted"></span></div>
|
|
@@ -151,6 +151,10 @@ function renderSettings(data){
|
|
|
151
151
|
const dimension=document.createElement('select');dimension.setAttribute('aria-label',sheet.name+' 字段维度 '+cell.label);
|
|
152
152
|
const groups=[{id:'',label:'全部维度'},...(data.catalogGroups||[]),{id:'other',label:'其他字段'}];
|
|
153
153
|
for(const g of groups){const option=document.createElement('option');option.value=g.id;option.textContent=g.label;dimension.append(option)}
|
|
154
|
+
const picker=document.createElement('details');picker.className='ff-field-picker';
|
|
155
|
+
const trigger=document.createElement('summary');picker.append(trigger);
|
|
156
|
+
const panel=document.createElement('div');panel.className='ff-field-panel';picker.append(panel);
|
|
157
|
+
picker.addEventListener('keydown',event=>{if(event.key==='Escape'){picker.open=false;trigger.focus();event.stopPropagation()}});
|
|
154
158
|
const status=document.createElement('p');status.className='ff-mapping-status';status.setAttribute('aria-live','polite');
|
|
155
159
|
const count=document.createElement('small');count.className='muted';
|
|
156
160
|
const suggestions=document.createElement('div');suggestions.className='ff-mapping-suggestions';
|
|
@@ -161,19 +165,28 @@ function renderSettings(data){
|
|
|
161
165
|
select.replaceChildren();
|
|
162
166
|
const list=[{key:'',label:'不填写'},...found];
|
|
163
167
|
if(chosen&&!found.some(f=>f.key===chosen)){const field=data.catalog.find(f=>f.key===chosen);if(field)list.splice(1,0,{...field,label:field.label+'(当前选择,筛选外)'})}
|
|
164
|
-
|
|
168
|
+
const buckets=new Map();
|
|
169
|
+
for(const field of list){const option=document.createElement('option');option.value=field.key;option.textContent=field.label;const group=field.key?data.catalogGroups?.find(g=>g.fields.includes(field.key)):null;if(group){if(!buckets.has(group.id)){const optgroup=document.createElement('optgroup');optgroup.label=group.label;select.append(optgroup);buckets.set(group.id,optgroup)}buckets.get(group.id).append(option)}else select.append(option)}
|
|
170
|
+
trigger.textContent=chosen?(data.catalog.find(f=>f.key===chosen)?.label||chosen):'选择填写字段';
|
|
165
171
|
select.value=chosen;count.textContent=found.length?'匹配 '+found.length+' 个字段':'没有匹配字段,请更换关键词或维度';updateStatus();
|
|
166
172
|
};
|
|
167
|
-
|
|
173
|
+
const choose=()=>{chosen=select.value;manual=true;suggestions.replaceChildren();trigger.textContent=chosen?(data.catalog.find(f=>f.key===chosen)?.label||chosen):'不填写';updateStatus();$('mapping-next').hidden=true};
|
|
174
|
+
const finish=()=>{choose();picker.open=false;trigger.focus()};
|
|
175
|
+
select.onchange=choose;
|
|
176
|
+
select.ondblclick=finish;
|
|
177
|
+
select.onkeydown=event=>{if(event.key==='Enter'){event.preventDefault();finish()}};
|
|
168
178
|
search.oninput=options;dimension.onchange=options;
|
|
169
179
|
if(!chosen&&!manual){
|
|
170
|
-
const hints={'原文件导入名称':['company_name'],'单位':['company_name'],'名称':['company_name'],'网址':['contact_official_website']}[cell.label.trim()]||[];
|
|
180
|
+
const hints={'原文件导入名称':['company_name'],'单位':['company_name'],'名称':['company_name'],'法定代表人':['legal_person'],'登记状态':['business_status'],'地址':['registered_address'],'网址':['contact_official_website']}[cell.label.trim()]||[];
|
|
171
181
|
const recommended=(data.catalog||[]).filter(f=>hints.includes(f.key)||matches(f,cell.label)).slice(0,4);
|
|
172
182
|
if(recommended.length){const hint=document.createElement('span');hint.textContent='推荐(确认后采用):';suggestions.append(hint)}
|
|
173
|
-
|
|
183
|
+
for(const field of recommended){const button=document.createElement('button');button.type='button';button.textContent=field.label;button.onclick=()=>{chosen=field.key;manual=true;suggestions.replaceChildren();options();$('mapping-next').hidden=true;picker.open=false;trigger.focus()};suggestions.append(button)}
|
|
174
184
|
}
|
|
175
185
|
const filters=document.createElement('div');filters.className='ff-mapping-filters';filters.append(search,dimension);
|
|
176
|
-
|
|
186
|
+
select.size=8;
|
|
187
|
+
const done=document.createElement('button');done.type='button';done.textContent='确认选择';done.onclick=finish;
|
|
188
|
+
panel.append(suggestions,filters,select,count,done);
|
|
189
|
+
label.append(status,picker);options();fields.append(label);
|
|
177
190
|
}
|
|
178
191
|
};
|
|
179
192
|
header.onchange=showFields;section.append(header,fields);showFields();$('mapping').append(section);
|
|
@@ -192,6 +205,7 @@ function renderSettings(data){
|
|
|
192
205
|
for(const selection of data.configuration?.anchors||[]){const p=document.createElement('p');p.textContent=selection.sheet+' 第 '+selection.row+' 行:人工确认 '+selection.value;$('entities').append(p)}
|
|
193
206
|
}
|
|
194
207
|
function render(data){
|
|
208
|
+
$('mapping-next').hidden=true;
|
|
195
209
|
current=data;filename=(data.filename||'已填表格.xlsx').replace(/\.xlsx$/i,'');location.hash='task='+data.id;
|
|
196
210
|
if(gridTask!==data.id){gridTask=data.id;gridPageNumber=1;gridColumn=1;$('grid-sheet').replaceChildren();$('grid-query').value=''}$('grid').hidden=false;loadGrid();
|
|
197
211
|
if(parent!==window)parent.postMessage({type:'ff-task',taskId:data.id},location.origin);
|
|
@@ -219,7 +233,7 @@ function readMapping(){const configuration={sheets:[],headers:[],mappings:[]};fo
|
|
|
219
233
|
function mappingSignature(configuration){return JSON.stringify(configuration.headers.map(h=>({sheet:h.sheet,row:h.row,cells:current.structure.find(s=>s.name===h.sheet)?.rows.find(r=>r.number===h.row)?.cells}))) }
|
|
220
234
|
$('mapping-save').onclick=()=>{try{if(!current||busy)return;const configuration=readMapping();localStorage.setItem('ff-mapping:'+owner,JSON.stringify({schema:1,signature:mappingSignature(configuration),configuration}));$('status').textContent='字段规则已保存在本浏览器。'}catch{$('status').textContent='浏览器无法保存字段规则。'}};
|
|
221
235
|
$('mapping-load').onclick=async()=>{if(!current||busy)return;controls(true);try{const saved=JSON.parse(localStorage.getItem('ff-mapping:'+owner)||'null');if(saved?.schema!==1||saved.signature!==mappingSignature(saved.configuration))throw Error('没有与当前工作表及表头一致的规则,请手动设置。');render(await api('/configure',{id:current.id,configuration:saved.configuration}));$('status').textContent='字段规则已复用,请检查后重新核验。'}catch(e){$('status').textContent=e.message}finally{controls(false)}};
|
|
222
|
-
$('configure').onclick=async()=>{if(!current||busy)return;const configuration=readMapping();controls(true);try{render(await api('/configure',{id:current.id,configuration}));$('status').textContent='字段设置已应用,旧预览已清除,请重新核验。'}catch(e){$('status').textContent=e.message}finally{controls(false)}};
|
|
236
|
+
$('configure').onclick=async()=>{if(!current||busy)return;const configuration=readMapping();controls(true);$('mapping-next').hidden=true;try{render(await api('/configure',{id:current.id,configuration}));$('status').textContent='字段设置已应用,旧预览已清除,请重新核验。';$('mapping-next').hidden=false;$('mapping-next').scrollIntoView({block:'nearest'});}catch(e){$('status').textContent=e.message}finally{controls(false)}};
|
|
223
237
|
$('samples').onclick=async e=>{if(!e.target.dataset.name||busy)return;const name=e.target.dataset.name;try{const response=await fetch(basePath+'/fixture/'+encodeURIComponent(name));if(!response.ok)throw Error('模板读取失败');await preview(await response.arrayBuffer(),name+'.xlsx',true)}catch(e){$('status').textContent=e.message}};
|
|
224
238
|
$('confirm').onclick=async()=>{if(!current||busy)return;controls(true);try{await api('/confirm',{id:current.id,confirmChangeSetId:current.changeSet.changeSetId});current=await api('/task/'+current.id);render(current);downloads();$('status').textContent='副本已生成,原文件保持不变。'}catch(e){$('status').textContent=e.message}finally{controls(false)}};
|
|
225
239
|
$('selection').onclick=async()=>{if(!current||busy)return;controls(true);try{render(await api('/select',{id:current.id,selectedIds:[...$('changes').querySelectorAll('input:checked')].map(x=>x.value)}));$('status').textContent='选择已应用,请核对新的预览。'}catch(e){$('status').textContent=e.message}finally{controls(false)}};
|
|
@@ -243,5 +257,7 @@ $('mapping-search').oninput=()=>{const query=$('mapping-search').value.trim().to
|
|
|
243
257
|
$('result-search').oninput=filterResults;$('changes').onchange=filterResults;
|
|
244
258
|
window.addEventListener('message',e=>{if(e.origin!==location.origin||e.source!==parent)return;if(e.data?.type==='ff-theme'&&['light','dark'].includes(e.data.theme))document.body.dataset.ffTheme=e.data.theme;if(e.data?.type==='ff-draft-conflict'){expectedDraft=e.data.draft;if(!$('draft-conflict').open)$('draft-conflict').showModal()}if(e.data?.type==='ff-draft-result'){$('status').textContent=e.data.ok?'已回填,请在对话框修改或发送。':'回填失败,任务已保留。';if(e.data.ok)closeWizard(true)}if(e.data?.type==='ff-navigate'){if(!current&&location.hash)pendingNavigation=e.data.step;if(e.data.step==='history')$('history-tab').click();else navigate(e.data.step)}});
|
|
245
259
|
api('/health').then(s=>{$('connection').textContent=s.qccAvailable?'已发现企查查工商工具,可在对话中执行。':'尚未发现企查查工商工具;请先连接 MCP。合成模板仍可体验。'}).catch(()=>{});
|
|
260
|
+
$('mapping-continue').onclick=()=>{if(busy||!current)return;navigate('identity');$('wizard-open').focus()};
|
|
261
|
+
$('mapping').addEventListener('change',()=>{$('mapping-next').hidden=true});
|
|
246
262
|
navigate('import');restore();setInterval(()=>{if(!document.hidden&¤t&&!busy&&!$('wizard').open)restore(true)},2000);
|
|
247
263
|
</script></html>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-form-fill-agent",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "AI填表智能体:XLSX blank-cell preview, QCC enrichment and persistent tasks for DSH.",
|
|
6
6
|
"repository": { "type": "git", "url": "git+https://github.com/duhu2000/dsh-form-fill-agent.git", "directory": "packages/dsh-form-fill-agent" },
|