wwt-certificate-tool 1.2.32 → 1.2.34
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/dist/app.html +162 -10
- package/dist/version.json +6 -6
- package/package.json +1 -1
package/dist/app.html
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
6
|
-
<title>WWT 金蝶凭证工具 · 纯前端版 P1.2.
|
|
6
|
+
<title>WWT 金蝶凭证工具 · 纯前端版 P1.2.34</title>
|
|
7
7
|
<style>*{box-sizing:border-box;margin:0;padding:0}
|
|
8
8
|
body{font-family:"Microsoft YaHei","PingFang SC",-apple-system,Segoe UI,sans-serif;font-size:13px;color:#1f2328;background:#f4f6f9;line-height:1.6}
|
|
9
9
|
h1{font-size:17px;font-weight:600}
|
|
@@ -305,7 +305,7 @@ tr.bad:hover td{background:#fbe9e9}
|
|
|
305
305
|
<div class="brand">
|
|
306
306
|
<span class="logo">WWT</span>
|
|
307
307
|
<div>
|
|
308
|
-
<h1>金蝶凭证工具 <span class="ver">P1.2.
|
|
308
|
+
<h1>金蝶凭证工具 <span class="ver">P1.2.34</span></h1>
|
|
309
309
|
<div class="sub">纯前端离线版 · 双击即用 · 数据只存在本机,不上传任何服务器</div>
|
|
310
310
|
</div>
|
|
311
311
|
</div>
|
|
@@ -2263,10 +2263,15 @@ window.WWT_ENGINE = (function () {
|
|
|
2263
2263
|
|
|
2264
2264
|
/* ---------------- 金额表达式 ---------------- */
|
|
2265
2265
|
function isAutoDiff(line) { return clean(line && line.amountField) === "__AUTO_DIFF__"; }
|
|
2266
|
+
|
|
2267
|
+
// 兼容旧接口:返回 { parts: [{fld, sign}], auto? }。新逻辑统一走 evalAmtExpr,
|
|
2268
|
+
// 这里只为了不让外部旧调用点(如果有)报错。
|
|
2266
2269
|
function parseAmtExpr(expr) {
|
|
2267
2270
|
const e = clean(expr);
|
|
2268
2271
|
if (!e || e === "-") return null;
|
|
2269
2272
|
if (e === "__AUTO_DIFF__") return { auto: true };
|
|
2273
|
+
// 含 * / ( ) 时视为新语法(按 evalAmtExpr 处理),parts 留空
|
|
2274
|
+
if (/[*\/()]/.test(e)) return { parts: [], v2: true };
|
|
2270
2275
|
const parts = [];
|
|
2271
2276
|
for (let p of e.split("+")) {
|
|
2272
2277
|
p = p.trim();
|
|
@@ -2277,12 +2282,103 @@ window.WWT_ENGINE = (function () {
|
|
|
2277
2282
|
}
|
|
2278
2283
|
return parts.length ? { parts } : null;
|
|
2279
2284
|
}
|
|
2285
|
+
|
|
2286
|
+
// ============== 表达式解析器(支持 + - * / 括号 与 字段名/数字常量) ==============
|
|
2287
|
+
// 语法:
|
|
2288
|
+
// expr := term ( ('+'|'-') term )*
|
|
2289
|
+
// term := atom ( ('*'|'/') atom )*
|
|
2290
|
+
// atom := '-' atom | number | identifier | '(' expr ')'
|
|
2291
|
+
// identifier := 除空白与运算符之外的连续字符(即字段名)
|
|
2292
|
+
//
|
|
2293
|
+
// 设计目标:会计场景常见公式——`实收金额+折扣费` / `-折扣费` / `实收金额*0.13` / `金额/数量` / `(金额+税额)*0.13`
|
|
2294
|
+
// tokenize 时跳过空白;遇到运算符边界时,前一段连续字符要么是字段名,要么是数字。
|
|
2295
|
+
function tokenizeExpr(s) {
|
|
2296
|
+
const toks = [];
|
|
2297
|
+
let i = 0;
|
|
2298
|
+
while (i < s.length) {
|
|
2299
|
+
const c = s.charAt(i);
|
|
2300
|
+
if (c === ' ' || c === '\t') { i++; continue; }
|
|
2301
|
+
if (c === '+' || c === '*' || c === '/' || c === '(' || c === ')') { toks.push({ t: c }); i++; continue; }
|
|
2302
|
+
if (c === '-') {
|
|
2303
|
+
// 单目 vs 二元判断:若前一个 token 是操作符/左括号/开头,则是单目
|
|
2304
|
+
const prev = toks[toks.length - 1];
|
|
2305
|
+
const isUnary = !prev || (prev.t !== ')' && !/^\d/.test(prev.v || '') && prev.t !== 'num' && prev.t !== 'id');
|
|
2306
|
+
toks.push({ t: isUnary ? 'unary-' : '-' });
|
|
2307
|
+
i++; continue;
|
|
2308
|
+
}
|
|
2309
|
+
// 读一段连续字符
|
|
2310
|
+
let j = i;
|
|
2311
|
+
while (j < s.length) {
|
|
2312
|
+
const cj = s.charAt(j);
|
|
2313
|
+
if (cj === ' ' || cj === '\t') break;
|
|
2314
|
+
if ('+*-/()'.indexOf(cj) >= 0) break;
|
|
2315
|
+
j++;
|
|
2316
|
+
}
|
|
2317
|
+
const seg = s.slice(i, j);
|
|
2318
|
+
i = j;
|
|
2319
|
+
if (seg) {
|
|
2320
|
+
// 判断是数字(允许可选前导 0/小数点)
|
|
2321
|
+
if (/^-?\d+(\.\d+)?$/.test(seg) || /^\.\d+$/.test(seg)) toks.push({ t: 'num', v: parseFloat(seg) });
|
|
2322
|
+
else toks.push({ t: 'id', v: seg });
|
|
2323
|
+
}
|
|
2324
|
+
}
|
|
2325
|
+
return toks;
|
|
2326
|
+
}
|
|
2327
|
+
|
|
2328
|
+
function evalAmtExpr(row, expr) {
|
|
2329
|
+
const e = clean(expr);
|
|
2330
|
+
if (!e || e === "-") return 0;
|
|
2331
|
+
const toks = tokenizeExpr(e);
|
|
2332
|
+
let pos = 0;
|
|
2333
|
+
function peek() { return toks[pos]; }
|
|
2334
|
+
function eat(t) { if (toks[pos] && toks[pos].t === t) { pos++; return true; } return false; }
|
|
2335
|
+
function err(m) { throw new Error('金额表达式错误: ' + m + ' (pos=' + pos + ', expr=' + e + ')'); }
|
|
2336
|
+
|
|
2337
|
+
function parseExpr() {
|
|
2338
|
+
let v = parseTerm();
|
|
2339
|
+
while (true) {
|
|
2340
|
+
const p = peek();
|
|
2341
|
+
if (!p) break;
|
|
2342
|
+
if (p.t === '+') { pos++; v = v + parseTerm(); }
|
|
2343
|
+
else if (p.t === '-') { pos++; v = v - parseTerm(); }
|
|
2344
|
+
else break;
|
|
2345
|
+
}
|
|
2346
|
+
return v;
|
|
2347
|
+
}
|
|
2348
|
+
function parseTerm() {
|
|
2349
|
+
let v = parseAtom();
|
|
2350
|
+
while (true) {
|
|
2351
|
+
const p = peek();
|
|
2352
|
+
if (!p) break;
|
|
2353
|
+
if (p.t === '*') { pos++; v = v * parseAtom(); }
|
|
2354
|
+
else if (p.t === '/') {
|
|
2355
|
+
pos++;
|
|
2356
|
+
const d = parseAtom();
|
|
2357
|
+
if (d === 0) throw new Error('金额表达式除零 (expr=' + e + ')');
|
|
2358
|
+
v = v / d;
|
|
2359
|
+
}
|
|
2360
|
+
else break;
|
|
2361
|
+
}
|
|
2362
|
+
return v;
|
|
2363
|
+
}
|
|
2364
|
+
function parseAtom() {
|
|
2365
|
+
const p = peek();
|
|
2366
|
+
if (!p) err('缺少操作数');
|
|
2367
|
+
if (p.t === 'unary-') { pos++; return -parseAtom(); }
|
|
2368
|
+
if (p.t === '(') { pos++; const v = parseExpr(); if (!eat(')')) err('缺少右括号'); return v; }
|
|
2369
|
+
if (p.t === 'num') { pos++; return p.v; }
|
|
2370
|
+
if (p.t === 'id') { pos++; return num(row[p.v]); }
|
|
2371
|
+
err('非法 token: ' + JSON.stringify(p));
|
|
2372
|
+
}
|
|
2373
|
+
const v = parseExpr();
|
|
2374
|
+
if (pos !== toks.length) err('未消费完: ' + toks.slice(pos).map(t => t.v || t.t).join(' '));
|
|
2375
|
+
return v;
|
|
2376
|
+
}
|
|
2377
|
+
|
|
2280
2378
|
function sumAmtExpr(row, expr) {
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
for (const it of pe.parts) s += num(row[it.fld]) * it.sign;
|
|
2285
|
-
return s;
|
|
2379
|
+
if (isAutoDiff({ amountField: expr })) return 0;
|
|
2380
|
+
try { return round2(evalAmtExpr(row, expr)); }
|
|
2381
|
+
catch (e) { console.warn(e.message); return 0; }
|
|
2286
2382
|
}
|
|
2287
2383
|
|
|
2288
2384
|
/* ---------------- 映射查表 ---------------- */
|
|
@@ -2547,6 +2643,16 @@ window.WWT_ENGINE = (function () {
|
|
|
2547
2643
|
}
|
|
2548
2644
|
return (rule.lines || []).slice();
|
|
2549
2645
|
}
|
|
2646
|
+
|
|
2647
|
+
// 【P1.2.34】规则级排除:当一行满足 rule.excludeWhen 全部条件时,
|
|
2648
|
+
// 本规则不处理,且不计入「被本规则排除」/「应处理子集漏命中」任何审计统计——
|
|
2649
|
+
// 业务上等同于这条行从未出现在本规则的视野里(用于「厂牌=资产工具库」这类
|
|
2650
|
+
// 由其他专门流程处理的合法跳过场景,避免覆盖率审计误报警报)。
|
|
2651
|
+
function isExcludedByRule(row, rule, curSrc, idx) {
|
|
2652
|
+
const ex = rule && rule.excludeWhen;
|
|
2653
|
+
if (!ex || !ex.length) return false;
|
|
2654
|
+
return evalConditions(row, ex, rule.excludeLogic || "AND", curSrc, idx);
|
|
2655
|
+
}
|
|
2550
2656
|
function linesKey(lines) {
|
|
2551
2657
|
return JSON.stringify(lines, (k, v) => (k === "_uid" ? undefined : v));
|
|
2552
2658
|
}
|
|
@@ -2609,6 +2715,8 @@ window.WWT_ENGINE = (function () {
|
|
|
2609
2715
|
for (let i = 0; i < rowsAll.length; i++) {
|
|
2610
2716
|
if (usedRows[curSrc].has(i)) continue;
|
|
2611
2717
|
const row = rowsAll[i];
|
|
2718
|
+
// 【P1.2.34】规则级排除:满足 excludeWhen 的行整条跳过,不进 rowsIn、不进 audit
|
|
2719
|
+
if (isExcludedByRule(row, rule, curSrc, idx)) continue;
|
|
2612
2720
|
if (evalConditions(row, rule.conditions || [], rule.logic || "AND", curSrc, idx)) {
|
|
2613
2721
|
rowsIn.push({ row: row, _i: i });
|
|
2614
2722
|
}
|
|
@@ -2919,6 +3027,8 @@ window.WWT_ENGINE = (function () {
|
|
|
2919
3027
|
for (let i = 0; i < rowsAll.length; i++) {
|
|
2920
3028
|
if (usedRows.has(i)) continue;
|
|
2921
3029
|
const row = rowsAll[i];
|
|
3030
|
+
// 【P1.2.34】规则级排除:跳过 excludeWhen 命中的行
|
|
3031
|
+
if (isExcludedByRule(row, r, curSrc, idx)) continue;
|
|
2922
3032
|
if (evalConditions(row, r.conditions || [], r.logic || "AND", curSrc, idx)) {
|
|
2923
3033
|
rowsIn.push({ row: row, _i: i });
|
|
2924
3034
|
}
|
|
@@ -3071,9 +3181,16 @@ window.WWT_ENGINE = (function () {
|
|
|
3071
3181
|
* excludedRows = 源表里不满足本规则的全部 = 条件 → 按规则就不该处理,不算遗漏
|
|
3072
3182
|
* neverMatchedRows = candidatesMissed(兼容旧字段名) */
|
|
3073
3183
|
const candidatesMissed = [], excludedRows = [];
|
|
3184
|
+
let ruleExcludedCount = 0, ruleExcludedAmount = 0;
|
|
3074
3185
|
for (let i = 0; i < rowsAll.length; i++) {
|
|
3075
3186
|
if (matchedIdxs.has(i)) continue;
|
|
3076
3187
|
const row = rowsAll[i];
|
|
3188
|
+
// 【P1.2.34】规则级排除:满足 excludeWhen 的行不进任何 audit 统计
|
|
3189
|
+
if (isExcludedByRule(row, rule, curSrc, idx)) {
|
|
3190
|
+
ruleExcludedCount++;
|
|
3191
|
+
if (amountCol) ruleExcludedAmount += num(row[amountCol]);
|
|
3192
|
+
continue;
|
|
3193
|
+
}
|
|
3077
3194
|
const rec = {
|
|
3078
3195
|
原单号: clean(row[meta.no]) || clean(row["原单号"]),
|
|
3079
3196
|
付款方式: clean(row["付款方式"]) || clean(row["支付方式"]),
|
|
@@ -3123,6 +3240,9 @@ window.WWT_ENGINE = (function () {
|
|
|
3123
3240
|
candidate_missed_clipped: candidatesMissed.length >= 200, // 是否被 200 上限截断
|
|
3124
3241
|
excluded: excludedRows.length, // 被本规则排除(不算遗漏)
|
|
3125
3242
|
excluded_clipped: excludedRows.length >= 200,
|
|
3243
|
+
// 【P1.2.34】规则级排除:满足 excludeWhen 的行彻底从 audit 视野消失(业务上合法跳过)
|
|
3244
|
+
rule_excluded: ruleExcludedCount,
|
|
3245
|
+
rule_excluded_amount: round2(ruleExcludedAmount),
|
|
3126
3246
|
// 兼容旧字段(仍叫 never_matched,但其内容仅含真正应处理子集漏命中的行)
|
|
3127
3247
|
never_matched: candidatesMissed.length,
|
|
3128
3248
|
unmatched_amount: round2(unmatchedAmt),
|
|
@@ -3296,8 +3416,9 @@ window.WWT_ENGINE = (function () {
|
|
|
3296
3416
|
return {
|
|
3297
3417
|
clean, num, round2, normPay, pad3,
|
|
3298
3418
|
buildIndex, getField, compare, evalConditions, applyTransform,
|
|
3299
|
-
parseAmtExpr, sumAmtExpr, isAutoDiff, splitFieldsOf,
|
|
3419
|
+
parseAmtExpr, sumAmtExpr, evalAmtExpr, isAutoDiff, splitFieldsOf,
|
|
3300
3420
|
calcDimValues, leafSubject, resolveEffectiveLines, lookupTypeDim,
|
|
3421
|
+
isExcludedByRule,
|
|
3301
3422
|
generate, balanceCheck, buildKingdee, detect, auditRule,
|
|
3302
3423
|
lookupMap, lookupTypeMap,
|
|
3303
3424
|
};
|
|
@@ -3322,7 +3443,7 @@ const S = window.__STATE__ = {
|
|
|
3322
3443
|
};
|
|
3323
3444
|
|
|
3324
3445
|
/* ---------------- 版本 & 框架自动更新(只更新程序本身,本地数据/规则不动) ---------------- */
|
|
3325
|
-
const WWT_VER=(function(){const raw='P1.2.
|
|
3446
|
+
const WWT_VER=(function(){const raw='P1.2.34';return raw.indexOf('__WVER__')>=0?'P1.2.10':raw;})();
|
|
3326
3447
|
const UPD_URL_KEY='wwt_fe_updurl';
|
|
3327
3448
|
// 默认更新源:Gitee 上本项目的 version.json(API 接口,浏览器可直接跨域读)
|
|
3328
3449
|
const DEFAULT_UPD_URL='https://gitee.com/api/v5/repos/wwtmrhu/certificate-generation/contents/dist/version.json';
|
|
@@ -4607,6 +4728,10 @@ function renderRules(){
|
|
|
4607
4728
|
const conds=(r.conditions||[]).map(c=>'<span class="cond"><b>'+esc(c.field)+'</b> '+esc(c.op)+' '+esc(c.value)+'</span>').join('');
|
|
4608
4729
|
let body='<div class="rulebody" id="rb'+i+'">';
|
|
4609
4730
|
body+='<div style="margin:6px 0"><b>命中条件</b>('+(r.logic||'AND')+'):'+(conds||'<span style="color:#8b949e">无条件(全表命中)</span>')+'</div>';
|
|
4731
|
+
if((r.excludeWhen||[]).length){
|
|
4732
|
+
const exc=r.excludeWhen.map(c=>'<span class="cond"><b>'+esc(c.field)+'</b> '+esc(c.op)+' '+esc(c.value)+'</span>').join('');
|
|
4733
|
+
body+='<div style="background:#fff7e6;padding:6px 8px;border-radius:4px;margin:4px 0"><b style="color:#d46b08">排除条件</b>('+(r.excludeLogic||'AND')+'):'+exc+' <span style="color:#888;font-size:11px">→ 满足的行整条跳过,不进 audit</span></div>';
|
|
4734
|
+
}
|
|
4610
4735
|
if((r.branches||[]).length){
|
|
4611
4736
|
body+='<div><b>分支</b>:'+r.branches.map((b,bi)=>
|
|
4612
4737
|
'<div class="linechip"><span class="tag b">分支'+(bi+1)+' '+esc(b.name||'')+'</span>'+
|
|
@@ -4876,6 +5001,18 @@ function ruleFormHTML(){
|
|
|
4876
5001
|
(r.conditions||[]).map((c,i)=>condRowHTML(i,c)).join('')+'</div>'+
|
|
4877
5002
|
'<button class="mini" onclick="UI.addCond()">+ 加条件</button></div>';
|
|
4878
5003
|
|
|
5004
|
+
// 【P1.2.34】规则级排除:满足条件的行整条规则不处理,且不计入覆盖率审计
|
|
5005
|
+
h+='<div class="sec" style="background:#fff7e6;border-left:3px solid #fa8c16"><h4>排除条件(满足这些条件的行<b>整条不处理</b>,不计入审计·不显示在排除/漏命中里)</h4>'+
|
|
5006
|
+
'<div style="font-size:11.5px;color:#888;margin:3px 0">典型场景:「厂牌 = 资产工具库」时由其他流程直接处理,本规则不参与。留空 = 不启用排除。</div>'+
|
|
5007
|
+
'<div class="row"><span class="w60">逻辑</span>'+
|
|
5008
|
+
'<select class="w80" id="rf_exclogic">'+
|
|
5009
|
+
'<option value="AND"'+((r.excludeLogic||'AND')==='AND'?' selected':'')+'>AND(全部满足)</option>'+
|
|
5010
|
+
'<option value="OR"'+(r.excludeLogic==='OR'?' selected':'')+'>OR(任一满足)</option>'+
|
|
5011
|
+
'</select></div>'+
|
|
5012
|
+
'<div id="rf_exconds">'+
|
|
5013
|
+
(r.excludeWhen||[]).map((c,i)=>condRowHTML(i,c)).join('')+'</div>'+
|
|
5014
|
+
'<button class="mini" onclick="UI.addExcludeCond()">+ 加排除条件</button></div>';
|
|
5015
|
+
|
|
4879
5016
|
h+='<div class="sec"><h4>分支(可选:按条件走不同分录;命中第一个分支就停)</h4><div id="rf_branches">'+
|
|
4880
5017
|
(r.branches||[]).map((b,bi)=>branchHTML(bi,b)).join('')+'</div>'+
|
|
4881
5018
|
'<button class="mini" onclick="UI.addBranch()">+ 加分支</button></div>';
|
|
@@ -4913,7 +5050,7 @@ function lineHTML(bi,li,l){
|
|
|
4913
5050
|
return '<div class="sec linerow" data-bi="'+bi+'" data-li="'+li+'" style="background:#fff;margin:5px 0">'+
|
|
4914
5051
|
'<div class="row"><select class="w60" data-lf="side">'+sideOpts+'</select>'+
|
|
4915
5052
|
'<span class="w60">科目</span><input class="w140" data-lf="subject" value="'+esc(l.subject||'')+'" placeholder="如 1122 / 6002" list="dlSubjects" title="可下拉选会计科目表里的编码;也可手动输入">'+
|
|
4916
|
-
'<span class="w60">金额</span><input class="w180" data-lf="amountField" value="'+esc(l.amountField||'')+'" placeholder="实收金额+折扣费 / -折扣费 /
|
|
5053
|
+
'<span class="w60">金额</span><input class="w180" data-lf="amountField" value="'+esc(l.amountField||'')+'" placeholder="实收金额+折扣费 / -折扣费 / 金额*0.13 / 金额/数量" list="dlBizFields" title="支持四则运算与括号:字段名/数字常量;例:实收金额+折扣费、-折扣费、金额*0.13、金额/数量、(金额+税额)*0.13。特殊值:__AUTO_DIFF__ 自动补差额">'+
|
|
4917
5054
|
'<button class="mini del" onclick="UI.delRow(this,\'linerow\')">删除分录</button></div>'+
|
|
4918
5055
|
'<div class="row"><span class="w60">摘要</span><input class="grow" data-lf="summary" value="'+esc(l.summary||'')+'" placeholder="{单位名称}{收入板块}对帐S{原单号}"></div>'+
|
|
4919
5056
|
'<div style="font-size:11.5px;color:#57606a;margin:3px 0">辅助核算维度:</div>'+
|
|
@@ -4943,6 +5080,14 @@ function syncFormToObj(){
|
|
|
4943
5080
|
return {field:g('field').value.trim(),op:g('op').value,value:g('value').value.trim(),
|
|
4944
5081
|
logic:g('logic').value||undefined};
|
|
4945
5082
|
});
|
|
5083
|
+
// 【P1.2.34】排除条件:满足时整条规则不处理、不进 audit
|
|
5084
|
+
r.excludeLogic=$('rf_exclogic') ? $('rf_exclogic').value : 'AND';
|
|
5085
|
+
const exConds=[...document.querySelectorAll('#rf_exconds > .condrow')].map(row=>{
|
|
5086
|
+
const g=f=>row.querySelector('[data-f="'+f+'"]');
|
|
5087
|
+
return {field:g('field').value.trim(),op:g('op').value,value:g('value').value.trim(),
|
|
5088
|
+
logic:g('logic').value||undefined};
|
|
5089
|
+
});
|
|
5090
|
+
r.excludeWhen=exConds.length ? exConds : undefined;
|
|
4946
5091
|
// 分支
|
|
4947
5092
|
const bsecs=[...document.querySelectorAll('#rf_branches > [data-bi]')];
|
|
4948
5093
|
r.branches=bsecs.map(sec=>{
|
|
@@ -6584,6 +6729,13 @@ window.UI={
|
|
|
6584
6729
|
else editing.conditions.push({field:'',op:'=',value:'',logic:''});
|
|
6585
6730
|
redrawRuleForm();
|
|
6586
6731
|
},
|
|
6732
|
+
// 【P1.2.34】加排除条件:写到 #rf_exconds
|
|
6733
|
+
addExcludeCond:()=>{
|
|
6734
|
+
syncFormToObj();
|
|
6735
|
+
if(!editing.excludeWhen) editing.excludeWhen=[];
|
|
6736
|
+
editing.excludeWhen.push({field:'',op:'=',value:'',logic:''});
|
|
6737
|
+
redrawRuleForm();
|
|
6738
|
+
},
|
|
6587
6739
|
addBranch:()=>{
|
|
6588
6740
|
syncFormToObj();
|
|
6589
6741
|
editing.branches.push({name:'分支'+((editing.branches||[]).length+1),logic:'AND',conditions:[{field:'',op:'=',value:''}],lines:[]});
|
package/dist/version.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
-
"ver": "P1.2.
|
|
3
|
-
"npm": "1.2.
|
|
4
|
-
"url": "https://cdn.jsdelivr.net/npm/wwt-certificate-tool@1.2.
|
|
5
|
-
"url_unpkg": "https://unpkg.com/wwt-certificate-tool@1.2.
|
|
6
|
-
"url_gh": "https://api.github.com/repos/huweipei745839/certificate-generation/contents/dist/WWT%E5%87%AD%E8%AF%81%E5%B7%A5%E5%85%B7_P1.2.
|
|
7
|
-
"note": "
|
|
2
|
+
"ver": "P1.2.34",
|
|
3
|
+
"npm": "1.2.34",
|
|
4
|
+
"url": "https://cdn.jsdelivr.net/npm/wwt-certificate-tool@1.2.34/dist/app.html",
|
|
5
|
+
"url_unpkg": "https://unpkg.com/wwt-certificate-tool@1.2.34/dist/app.html",
|
|
6
|
+
"url_gh": "https://api.github.com/repos/huweipei745839/certificate-generation/contents/dist/WWT%E5%87%AD%E8%AF%81%E5%B7%A5%E5%85%B7_P1.2.34.html",
|
|
7
|
+
"note": "① 新增「规则级排除」机制:规则上加 excludeWhen 字段(结构同 conditions,含 excludeLogic),满足条件的行整条规则不处理,**且不进覆盖率审计**(不进 excluded_rows、不进 candidate_missed、不进任何 audit 统计);用于「厂牌=资产工具库」等由其他流程直接处理的合法跳过场景。② UI:规则编辑面板增加「排除条件」独立配置区(橙底强调),规则列表同步显示摘要;「+ 加排除条件」按钮一键加。③ auditRule 返回值新增 rule_excluded/rule_excluded_amount 字段(供后续 UI 展示)。例:「厂牌 = 资产工具库」时整条不处理、不计入审计。"
|
|
8
8
|
}
|