Files
SignatureSystem/lib/__pycache__/batch_processor.cpython-39.pyc

225 lines
20 KiB
Plaintext
Raw Normal View History

2026-07-20 13:16:17 +08:00
a
yeOj<4F>y<00>@s8dZddlZddlZddlZddlZddlZddlZddlZddlm Z ddl
m
Z
ddl m Z ddl mZddlmZddlmZdd lmZdd
lmZe<05>e<18>Zd d d dddd<11>ddd dddd<11>ddd dddd<11>ddd dddd<11>gZdd dd ddd<1C>ddddddd<1C>ddd dddd<1C>d!d"d#d$d%dd&d'<27>d(d)d*d+d,dd<1C>d-dd.dddd<1C>d/d0d1d2ddd<1C>d3d4d5d6ddd<1C>gZd7d8<64>Zdfd9d:<3A>Zdgd;d<<3C>Zdhd=d><3E>Zd?d@<40>Z dAdB<64>Z!dCdD<64>Z"dEdF<64>Z#dGdH<64>Z$didIdJ<64>Z%dKdL<64>Z&dMdN<64>Z'dOdP<64>Z(dQdR<64>Z)djdTdU<64>Z*dVdW<64>Z+dXdY<64>Z,dZd[<5B>Z-d\d]<5D>Z.d^d_<64>Z/d`da<64>Z0dbdc<64>Z1dkddde<64>Z2dS)lu<6C>批量 Word 转换与自动签名核心模块。
实现 SRS 第 11、14 章:
- 加载/保存 rules.configJSON 格式),损坏文件不自动覆盖。
- 递归扫描 Word 文件夹,只处理 .docx。
- 多条正则规则:捕获组序号 >=1cell_mode (single/horizontal/vertical)cell_match (partial/whole)。
- 表格逻辑网格:识别 gridSpan 横向合并 / vMerge 纵向合并。
- 命中后将可见姓名替换为隐藏的 ``SET USER_<name> \* MERGEFORMAT`` 域代码 + 补偿空格。
- 调用 word_signer.sign_word 以 auto 模式完成自动签名。
- 输出 _signed.docx冲突时自动生成 _signed_001、_signed_002 等不冲突文件名。
- 单文件失败跳过 + WARN批量任务继续。
<EFBFBD>N)<01>deepcopy)<01>datetime)<01>Document)<01>qn)<01> OxmlElement)<01> field_codes)<01> validate_rule)<01> sign_wordu编制:姓名/标识u,编制[:]\s*([一-龥A-Za-z0-9._-]{1,20})<29><00>single<6C>partialT<6C><06>name<6D>pattern<72> capture_group<75> cell_mode<64>
cell_match<EFBFBD>enabledu审核:姓名/标识u,审核[:]\s*([一-龥A-Za-z0-9._-]{1,20})u签字人:姓名/标识u/签字人[:]\s*([一-龥A-Za-z0-9._-]{1,20})u表格值整格u^([一-龥A-Za-z0-9._-]{1,20})$<24>wholeFZsingle_compiled_nameu}适用于正文中"编制:张三"或"编制: zhang_san1"的标签加姓名组合;表格方式选 single部分匹配。)<06>id<69>label<65>helprrrZaudit_compiled_nameuK适用于"审核:李四"组合;表格方式选 single部分匹配。Zsigner_compiled_nameuN适用于"签字人:王五"组合;表格方式选 single部分匹配。Zhorizontal_label_valueu表格横向相邻两格u<E6A0BC>同一行:左格"编制:",右格"张三"。规则匹配标签,捕获组指向右值;表格方式选 horizontal整格匹配。u 编制[:]<5D>
horizontalu<在表格中通过相邻右格文本另用通用片段提取)rrrrrrZcapture_group_hintZvertical_label_valueu表格纵向相邻两格u<E6A0BC>同一列:上格"审核:",下格"李四"。规则匹配标签,从下格提取;表格方式选 vertical整格匹配。u 审核[:]<5D>verticalZwhole_name_in_cellu\姓名/标识单独占据整个单元格时使用;表格方式选 single整格匹配。Zpartial_name_in_cellu表格值部分u\姓名/标识只是单元格部分文本时使用;表格方式选 single部分匹配。<E9858D>([一-龥A-Za-z0-9._-]{1,20})Zchinese_only_2_4u纯中文姓名 2-4 字uQ仅匹配 2-4 字中文姓名;表格方式选 single整格或部分均可。u([一-龥]{2,4})cCs*tj<01>tj<01>tj<01>t<04><01><01>}tj<01>|d<01>S)Nz rules.config)<06>os<6F>path<74>dirname<6D>abspath<74>__file__<5F>join)<01> project_root<6F>r"<00>dE:\projects\wxwx\projects_job\GeneralRequirement\SignatureSystem\BackEnd\Code\lib\batch_processor.py<70>get_default_rules_path<74>sr$cCsD|s
t<00>Stj<02>|<00>s@tj<02>tj<02>tj<02>t<06><01><01>}tj<02>||<00>S|S<00>N)r$rr<00>isabsrrrr )rr!r"r"r#<00>resolve_rules_path<74>s  r'c
Cs$t|<00>}tj<02>|<01>s<tjd|ddid<04>tt<07>d|<01><00>d<06>Sz<>t|ddd <09><03>}t <09>
|<02>}Wd
<00>n1sl0Yt |t <0C>r<>|<03> d <0B>n|}t |t<0E>s<>td <0C><01>t|<04>\}}|r<>d <0A>|<06>nd
}||d<06>WSt<12>y}z<tjd|t|<08>ddid<04>tt<07>d|<08>d<10>d<06>WYd
}~Sd
}~00d
S)uc加载规则文件损坏或不存在时返回默认规则并提示不自动覆盖原文件。u4规则文件不存在,加载内置默认规则: %s<>
log_source<EFBFBD>批量<E689B9><01>extrau0规则文件不存在,已加载默认规则:)<02>rules<65>warning<6E>r<>utf-8<><01>encodingNr,u.规则文件格式非法:缺少 rules 列表<E58897>; u$规则文件损坏或非法 (%s): %su规则文件损坏或非法u<。已加载内置默认规则,请修复或重新选择。)r'rr<00>exists<74>loggerr-r<00> DEFAULT_RULES<45>open<65>json<6F>load<61>
isinstance<EFBFBD>dict<63>get<65>list<73>
ValueError<EFBFBD>_normalize_rulesr <00> Exception<6F>str) r<00>target<65>f<>datar,<00>
normalized<EFBFBD>errorsr-<00>er"r"r#<00>
load_rules<EFBFBD>s$ (
  
<EFBFBD>rGcCs t|<01>}t|<00>\}}tj<03>|<02>r<>z<t|ddd<03><03>}t<06>|<05>Wd<00>n1sP0YWn4ty<>t j
d|ddid<08>t d |<02><00><02><01>Yn0tj tj<03> |<02>d
d <0B>t|d dd<03><03>&}tjd |i|ddd<10>Wd<00>n1s<>0Yt jd|ddid<08>|||d<12>S)uE保存规则文件若文件已存在且解析失败则不覆盖。r.r/r0Nu(规则文件已损坏,拒绝覆盖: %sr(r)r*u$规则文件已损坏未覆盖T)<01>exist_ok<6F>wr,F<>)<02> ensure_ascii<69>indentu规则已保存到 %s)r,r<00>warnings)r'r>rrr3r6r7r8r?r4<00>error<6F> RuntimeError<6F>makedirsr<00>dump<6D>info)r,rrArDrErBr"r"r#<00>
save_rules<EFBFBD>s  , 4rSc Cs<>g}g}t|<00>D]<5D>\}}t|t<02>s:|<02>d|d<00>d<03><03>qt|<04>d<04>pHd<05><01><06>t|<04>d<06>p\d<05><01><06>|<04>dd<02>|<04>dd <09>|<04>d
d <0B>t|<04>d d <0A><02>d<0E>}t|<05>}|r<>|<02>d|d<00>d|dp<>d<10>dd<12> |<06><01><00><06>d|d <|<01>|<05>q||fS)N<>规则r
u: 非对象跳过r<00>rrrr rr rTr z (u 未命名z): r2F)
<EFBFBD> enumerater9r:<00>appendr@r;<00>strip<69>boolrr )r,rDrE<00>idx<64>ruleZ norm_ruleZ rule_errorsr"r"r#r><00>s&



<0E>. r>cCsdtiS)NZsnippets)<01>REGEX_SNIPPETSr"r"r"r#<00>get_regex_snippets<74>sr]cs"t|<00>\}}g}g}t|<02>D<00>]<5D>\}}|<07>d<01>s2qzt<03>|d<00>}WnLtjy<>} z2|<03>d|d<00>d| <09><00><04>WYd} ~ qWYd} ~ n
d} ~ 00|<08>|p<>d<07>D<00>]l}
z|
<EFBFBD>|d<00>} Wn<t t
<EFBFBD>fy<>|<03>d|d<00>d |d<00>d
<EFBFBD><05>Yq<>Yn0| du<00>rq<>| <0B> <0B>} | <0C>sq<>|
<EFBFBD> |d<00>|
<EFBFBD> |d<00>f<02>t<0E>fd d <0C>|D<00><01><01>rd|<03>d|d<00>d | <0C>d<0E><05>q<>|<05><06><00>d| <0C>d<10>} |td|
<EFBFBD> |d<00>d<00>|
<EFBFBD> |d<00><01>}||
<EFBFBD> |d<00>|
<EFBFBD> |d<00>d<00>}|<04>||d|
<EFBFBD>d<11>| d| <0C><00>| |d|d|<0E>d| <0C>d|<0F><00>d<19> <09>q<>q|t|<04>|d<1A>S)u6在纯文本上测试规则,不修改 Word 文件。rrrTr
u: 正则错误 NrUru : 捕获组 <20> 越界c3s|]}t<00>|<01>VqdSr%)<01>_spans_overlap)<02>.0Zexisting<6E><01>spanr"r#<00> <genexpr><3E><00>ztest_rules.<locals>.<genexpr>u 命中 'u ' 与已有命中重叠跳过z {{ SET USER_z \* MERGEFORMAT }}r<00>r<00>USER_rr<00><<3C>>) Z
rule_indexZ rule_name<6D>
match_text<EFBFBD>capturedZ user_marker<65>
field_coderrZpreview)<03>matchesZ match_countrE)r>rVr;<00>re<72>compilerNrW<00>finditer<65>group<75>
IndexError<EFBFBD>error_group_error_classrX<00>start<72>end<6E>any<6E>max<61>len)r,<00>textrDrErlZ matched_spansrZr[rrF<00>mrjrrkZ preview_headZ preview_tailr"rar#<00>
test_rules<EFBFBD>sT 
" 


 *$<12> rzcCstSr%)rqr"r"r"r#rr srrcCs"|d|dkp|d|dk S)Nr
rr")<02>a<>br"r"r#r_ sr_c Cstj<01>|<00>}tj<01>|<00>s(gd|<00><00>gfSg}g}|r<>t<00>|<00>D]n\}}}|D]^}tj<01>||<07>}|<07><06><00>d<02>rx|<02>|<08>qL|<07><06><00>d<03>r<>|<03>|<08>qL|<07><06><00>d<04>rL|<03>|<08>qLq>n\t<00> |<00>D]P}tj<01>||<07>}tj<01>
|<08>r<>|<07><06><00>d<02>r<>|<02>|<08>q<>|<07><06><00>d<05>r<>|<03>|<08>q<>||fS)u:递归扫描 .docx 文件,跳过 .doc 与其他格式。u文件夹不存在: <20>.docx<63>.doc)<03>.wps<70>.pdf<64>.rtf)r~rr<>r<>) rrr<00>isdir<69>walkr <00>lower<65>endswithrW<00>listdir<69>isfile) <09>folder<65> recursive<76>files<65>skipped<65>root<6F>dirs<72>namesrZfullr"r"r#<00>scan_docx_filess.       r<>c Csjt|d<01>r|n|}t|d<01>r"|j}|<01>td<02><01>}g}i}|D<00>]"}|<05>td<03><01>}g}d}t|<06>} i}
||
vr<>|<07>|
|<00>|d7}qdz t| <09>} Wnty<>Y<00>qVYn0| <0B>td<06><01>} d} d}| du<01>rN| <0C>td<08><01>}|du<01>rzt |<0F>
td <09><01>p<>d
<EFBFBD>} Wnt <0B>yd} Yn0| <0C>td <0B><01>}|du<01>rN|<10>
td <09><01>}|d k<02>rJd nd }t | <0B>}| || |t |<03>|d<0E>}|d k<02>r<>| |t |<03>|gd<0F>||<d|d<d|d<nz|d k<02>r<>||v<00>r<>||}|d<00>|<13>|d|d<|d|d<d|d<d|d<n&||v<00>r
|<04>|d<07>d|d<d|d<|<07>|<13>td| <0A>D]}||
||<|<07>|<13><00>q.|| 7}qd|<03>|<07>q<||fS)u<>基于 gridSpan 和 vMerge 构建"逻辑网格"。
返回 ``(rows, grid)``grid[row][col] = {
'tc': <w:tc element>, 'text': str, 'is_origin': bool (vMerge origin),
'is_continue': bool (vMerge continue)
}
<20>_elementzw:trzw:tcrr
zw:tcPrNz
w:gridSpanzw:val<61>1zw:vMerge<67>restart<72>continue)<06>tcrx<00> grid_span<61> vmerge_kind<6E>row<6F>col)<04> origin_tc<74> origin_textZ
origin_row<EFBFBD>rowsTZ is_originFZ is_continuer<65>r<>Z merged_originr<6E>Zmerged_origin_text)<10>hasattrr<72><00>findallr<00>iterrW<00>next<78> StopIteration<6F>find<6E>intr;r=<00>_extract_cell_textrw<00>pop<6F>range)<16>table<6C>tblr<6C><00>gridZpending_vmerge<67>trZ cells_in_rowZ row_cellsZ col_indexZ cell_iterZcol_fillr<6C><00>tcPrr<72>r<><00>gsZvm<76>valrxZ cell_info<66>origin<69>kr"r"r#<00>_build_table_grid-s<>

   



<02>
<04>



  

 
 
 r<>cCs`g}|<00>td<01><01>D]>}g}|<02>td<02><01>D]}|jr(|<03>|j<03>q(|<01>d<03>|<03><01>qd<04>|<01><01><06>S)N<>w:p<>w:trU<00>
)r<>rr<>rxrWr rX)r<><00>parts<74>p<>buf<75>tr"r"r#r<><00>sr<>ccst<00>|<00>EdHdSr%)r<00>_iter_all_paragraph_elements<74><01>docr"r"r#<00>_iter_paragraphs_in_doc<6F>sr<>ccst<00>|<00>EdHdSr%)r<00>_iter_all_tablesr<73>r"r"r#<00>_iter_tables_in_doc<6F>sr<>r)c Cs6t|<01>\}}t|<05>}d}t<02>}t<02>} |D<00>]}
|
<EFBFBD>d<02>s:q(zt<04>|
d<00>} WnLtjy<>} z2|<06>d|
d<00>d| <0C><00><04>WYd} ~ q(WYd} ~ n
d} ~ 00|
dd kr<>|t|| |
||||d
<EFBFBD>7}|t || |
| |||d
<EFBFBD>7}q(|
dd k<02>r|t
|| |
| |||d
<EFBFBD>7}q(|
dd kr(|t || |
| |||d
<EFBFBD>7}q(||fS) uH对单个 Document 应用规则,返回 (替换条数, 告警列表)。rrr<00>规则 'ru' 正则错误: Nrr )r(<00>trace_idrMrr) r>r<<00>setr;rmrnrNrW<00>_apply_rule_to_paragraphs<68>_apply_rule_single_cell_tables<65>_apply_rule_horizontal_cells<6C>_apply_rule_vertical_cells) r<>r,r(r<>rDrErM<00>replacedZconsumed_paragraph_runsZconsumed_table_cellsr[rrFr"r"r#<00>process_document<6E>s: 

"  <06> <06>
 <06>
  <06>
r<>c Cs<>d}t|<02>dd<03><02>}|<02>dd<05>} t|<00>D<00>]<5D>}
|
<EFBFBD>td<06><01>} g} | D]0} | <0A>td<07><01>}| <0C>|durn|jrn|jnd <09>qDd <09>| <0C>}|s<>q(| d
kr<>|<01> |<0F>}|r<>|gng}nt
|<01> |<0F><01>}|D]<5D>}z|<10> |<08>}Wn2t y<>|<06>d |d <00>d |<08>d<0E><05>Yq<>Yn0|<12>sq<>|<12><0E>}|<13>sq<>|<10>|<08>}|<10>|<08>}t| ||<15>\}}}}|du<00>rLq<4C>t|
<EFBFBD>||||f}||v<00>rjq<6A>|<03>|<1A>tj|
||||||dd<10>}|r<>|d7}tjd||d ||d<12>d<13>q<>q(|S)uK对正文段落与文本框/页眉页脚段落应用 single 模式规则。rrr
rr <00>w:rr<72>NrUrr<>ru ' 捕获组 r^T)<01>compensate_spacesu2[批量] 段落匹配替换为 USER_%s (规则=%s)<29>r(r<>r*)r<>r;r<>r<>rr<>rWrxr <00> fullmatchr<rorprqrXrsrt<00>_map_text_to_runsr<00>addr<00>replace_text_with_set_fieldr4rR)r<>rr[<00>consumedr(r<>rM<00>countrr<00>para<72>runs<6E> run_textsr.r<><00> full_textryrlrjr<00> start_offset<65>
end_offset<EFBFBD> start_run_idx<64> start_off<66> end_run_idx<64>end_off<66>key<65>okr"r"r#r<><00>s\  

 





<02><10>
r<>c Cs<>d}d}d}d}d}t|<00>D]T\}} |t| <09>}
|durL||
krL|}||}||
krl|durl|}||}qr|
}q|dus<>|dur<>dS||||fS)uO将整段字符串中的字符偏移映射回 (run_index, offset_in_run) 对。rN)NNNN)rVrw) r<>r<>r<>Z
cumulativer<EFBFBD>r<>r<>r<>rZrxZnew_cumr"r"r#r<><00>s$ r<>cCsdS)u<>single 模式下补充:表格单元格内/整格匹配基于段落处理已能覆盖单格这里仅对合并单元格特例。rr")r<>rr[r<>r(r<>rMr"r"r#r<> sr<>c Cs<>d}t<00>d<02>}|<02>dd<04>} t|<00>D<00>]<5D>}
zt|
<EFBFBD>\} } Wn@tyx} z(|<06>d| <0A><00><02>WYd} ~ q"WYd} ~ n
d} ~ 00| D<00>]$}tt|<0E>d<00>D<00>] }||}||d}||us<>|dur<>q<EFBFBD>|<10>dd <09>p<>d }|<01> |<12>s<>q<EFBFBD>|<11>dd <09>p<>d }|s<>q<EFBFBD>| dk<02>r|<08>
|<13>n|<08> |<13>}|<14>sq<>|<14> d<07><01> <0C>}|<15>s.q<>d
t |d <00>f}||v<00>rJq<4A>|<03>|<16>t|d |<14> d<07>|| d k|<14> d<07>d <0A>}|r<>|d7}tjd||d||d<10>d<11>q<>q~q"|S)u横向相邻两格:左格匹配标签 + 右格作为值。
假设规则 pattern 仅匹配标签(如 ``编制[:]``),值在右相邻格中。
捕获组在右格文本上重新应用通用片段 ``([一-龥A-Za-z0-9._-]{1,20})`` 提取。
rrrr<00> 表格逻辑网格构建失败: Nr
rxrU<00>hr<68>r <00>r riu8[批量] 横向相邻匹配替换为 USER_%s (规则=%s)rr<>r*)rmrnr;r<>r<>r?rWr<>rw<00>searchr<68>rprXrr<><00>!_replace_cell_text_with_set_fieldr4rR)r<>rr[r<>r(r<>rMr<><00> value_patternrr<><00>_rowsr<73>rFr.<00>c<>left<66>rightZ left_textZ
right_text<EFBFBD>m_valrr<>r<>r"r"r#r<>sT
 "
 


<08><08> r<>c Cs<>d}t<00>d<02>}|<02>dd<04>} t|<00>D<00>]<5D>}
zt|
<EFBFBD>\} } Wn@tyx} z(|<06>d| <0A><00><02>WYd} ~ q"WYd} ~ n
d} ~ 00tdd<08>| D<00>dd <09>}t|<0E>D<00>]\}tt | <0C>d
<00>D<00>]D}|t | |<00>ks<>|t | |d
<00>kr<>q<EFBFBD>| ||}| |d
|}||us<>|du<00>r
q<EFBFBD>|<11>d d <0C><02>pd }|<01>
|<13><01>s*q<>|<12>d d <0C><02>p:d }|<14>sDq<44>| dk<02>rX|<08> |<14>n|<08>
|<14>}|<15>sjq<6A>|<15> d
<EFBFBD><01> <0A>}|<16>s<>q<EFBFBD>d t|d<00>f}||v<00>r<>q<EFBFBD>|<03>|<17>t|d|<15> d
<EFBFBD>|| dk|<15> d
<EFBFBD>d<10>}|r<>|d
7}tjd||d||d<13>d<14>q<>q<EFBFBD>q"|S)u<纵向相邻两格:上格匹配标签 + 下格作为值。rrrrr<>Ncss|]}t|<01>VqdSr%)rw)r`r.r"r"r#rcNrdz-_apply_rule_vertical_cells.<locals>.<genexpr>)<01>defaultr
rxrU<00>vr<76>r r<>u8[批量] 纵向相邻匹配替换为 USER_%s (规则=%s)rr<>r*)rmrnr;r<>r<>r?rWrvr<>rwr<>r<>rprXrr<>r<>r4rR)r<>rr[r<>r(r<>rMr<>r<>rr<>r<>r<>rFZmax_colsr<73>r.<00>top<6F>bottomZtop_textZ bottom_textr<74>rr<>r<>r"r"r#r<>BsZ
 "$  

<08><08> r<>cCs&|<00>td<01><01>D<00>]}|<05>td<02><01>}t|<06>D]<5D>\}}|<08>td<03><01>} | dus*| jsPq*|| jvr\q*| j}
|
<EFBFBD>|<04>} |
d| <0B>} |
| t|<04>d<04>} t<06>|<02>}t<06>dt|<01><00>}|}|}t |<10><01>
|<11>}|<10> |<11>t<06>| <0C>}t<06>| <0A>}|}|g|||gD]$}|du<00>rq<>|<10> ||<16>|d7}q<>dSqdS) u<>将单元格中的 match_text 替换为 SET USER_<name> 域 + 补偿空格。
简化策略:定位单元格中第一个包含 match_text 的段落与 run。
r<>r<>r<>N<> r
TF) r<>rrVr<>rxrwr<00>build_set_field_runs<6E>_make_text_runr<<00>index<65>remove<76>insert)r<>rjrr rir<>r<>Zr_idxr.r<>rx<00>pos<6F>head<61>tail<69>
field_runs<EFBFBD>compensate_run<75>parent<6E>anchorrZ<00>head_run<75>tail_run<75>
insert_idx<EFBFBD>elemr"r"r#r<>rs8

 




 

r<>cCs<>tj<01>|<00>s|Stj<01>|<00>}tj<01>tj<01>|<00><01>\}}|s<d}d}tj<01>||<02>d|d<04>|<03><00><04>}tj<01>|<05>sn|S|d7}|dkr@tj<01>||<02>dt<07><08><00> d<06><01>|<03><00><04>Sq@dS)uT生成不冲突的输出文件路径a/_signed.docx → a/_signed_001.docx → ...r}r
<00>_Z03di<64>z %Y%m%d%H%M%SN)
rrr3r<00>splitext<78>basenamer r<00>now<6F>strftime)<06> base_path<74> directoryr<00>extZcounter<65> candidater"r"r#<00>_next_available_path<74>s   rc Cst||d<01>\}}t|<07>dt|<08>dgd<03>} tjd|t|<07>t|<08>||d<05>d<06>|D] }
| d<00>|
ddd d
gd <0B><05>qN|D<00>]N} | d dd gd <0B>} <0C>zlt| d <0A><02>} | <0A><06>}Wd<00>n1s<>0Ytt<08> |<0E><01>}t
||p<>g||d<05>\}}|| d<| d<00> |<11>t<08> <09>}|<0F> |<12>|<12> <0A>}|<02>r<>|dk<04>r<>tj<0F>tj<0F>| <0B><01>d}|<14>d<11>}|dgd<13>}|<16>|<04>p`i<00>t||||d<05>\}}|<18>r<>d| d<| d<00>d|<18>d<17><01><00><02>|}|<14>d<11>}n>|d}|d}| d<00> |<17>dg<00><02>|<17>d<10><01>s<>dnd| d<n*|}tj<0F>tj<0F>| <0B><01>d<00>d<11>}d| d<tj<0F>tj<0F>| <0B>|<1A>}t|<1B>}zlt|d<1C><02>} | <0A>|<19>Wd<00>n1<00>sf0Y|| d<| dd7<tjd | ||||d<05>d<06>WnPt<19>y<>d| d<| d<00>d!<21>| dd7<tjd"|||d<05>d<06>Yn0Wn<>t<19>yHd| d<| d<00>d#<23>| dd7<tjd$| ||d<05>d<06>Ynnt<1B>y<>}zTd%| d<| d<00>d&|<1C><00><02>| d%d7<tjd'| t|<1C>||d<05>d<06>WYd}~n
d}~00| d<00>| <0C>qt| d%dk| d<tjd(| d)| d| d| d%||d<05>d<06>| S)*u批量处理整个文件夹。)r<>r)<05>scanned<65> processedr<64><00>failedr<64>uM[批量] 开始处理文件夹 %s (扫描 %d 个 docx, 跳过 %d 个非 docx)r<>r*r<>r<>rUu!类型不支持,仅处理 .docx)r<00>status<75>markers<72>outputrM<00>running<6E>rbNr rMz _signed.docx<63>auto)<03> docx_name<6D>
match_mode<EFBFBD>stampsr ru自动签名失败: <20>messagerC<00>filename<6D>success<73> converted<65>wbr
rr
u1[批量] 文件处理完成: %s -> %s (标记 %d)u输出文件被锁定跳过u[批量] 输出文件锁定: %su源文件被锁定跳过u[批量] 源文件锁定: %sru处理异常: u"[批量] 文件处理失败 %s: %suJ[批量] 文件夹处理完成: 扫描 %d, 处理 %d, 跳过 %d, 失败 %dr)r<>rwr4rRrWr6<00>readr<00>io<69>BytesIOr<4F><00>extend<6E>save<76>getvaluerrr<>r<><00>updater r;r rr<00>write<74>PermissionErrorr-r?rNr@)r<>r<><00> auto_signr,<00>request_optionsr(r<>r<>r<><00>summaryrZ docx_pathZ
file_entryrBZ
docx_bytesr<EFBFBD>r<>rMZ converted_bufZconverted_bytes<65> base_namerZ sign_params<6D>resultrNZ final_bytes<65> output_nameZ output_pathrFr"r"r#<00>process_folder<65>s<><02><08><04>

<04> & <0C>


<02><04>
  *<08>
<08><08>
<08><08>r%)N)N)N)T)r)N)TTNNr)N)3<>__doc__rrrmr7<00>logging<6E>shutil<69>tempfile<6C>copyrr<00>docxrZ docx.oxml.nsrZ docx.oxmlr<00>libr<00>lib.validatorsr<00>lib.word_signerr <00> getLogger<65>__name__r4r5r\r$r'rGrSr>r]rzrrr_r<>r<>r<>r<>r<>r<>r<>r<>r<>r<>r<>r<>rr%r"r"r"r#<00><module>s         
<02> <02> <02> <02><04>%<02> <02> <02> <02>
<02> <02> <02> <02><04>E

.
\ 
!910&<00>