#!/usr/bin/env python3 """ 批量修复 ~cu-modal / ~show 弹窗隐患。 替换策略: 1. 模板中所有 ~cu-modal → 对应的本地类名 2. 模板中所有 ~show → show (普通类) 3. 模板中所有 ~bottom-modal → (去除,样式合并到本地类) 4. 模板中所有 ~cu-dialog → 对应的本地类名 5. style 中追加完整的自包含弹窗样式 """ import re import os # 每个文件的修复配置 CONFIGS = { "src/components/uploadPics.wpy": { "type": "bottom", "modal_cls": "uploadpics-mask", "dialog_cls": "uploadpics-sheet", "trigger": "~show", "style_add": """ .uploadpics-mask { position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 1110; background: rgba(0,0,0,.6); opacity: 0; pointer-events: none; transition: all .3s ease; } .uploadpics-mask.show { opacity: 1; pointer-events: auto; } .uploadpics-sheet { position: absolute; left: 0; right: 0; bottom: 0; background: #fff; border-radius: 32rpx 32rpx 0 0; } ._item { padding: 32rpx; border-bottom: 1rpx solid #f5f5f5; font-size: 32rpx; color: #333; text-align: center; } ._cancel { border-top: 16rpx solid #f8f8f8; margin-bottom: 24rpx; color: #999; } """, }, "src/components/visitorModel.wpy": { "type": "center", "modal_cls": "visitormodel-mask", "dialog_cls": "visitormodel-dialog", "trigger": "~show", "style_add": """ .visitormodel-mask { position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 1110; background: rgba(0,0,0,.6); opacity: 0; pointer-events: none; transition: opacity .3s; } .visitormodel-mask.show { opacity: 1; pointer-events: auto; } .visitormodel-dialog { position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%) scale(.85); width: 680rpx; max-width: 100%; background: #fff; border-radius: 20rpx; overflow: hidden; transition: transform .3s; } .visitormodel-mask.show .visitormodel-dialog { transform: translate(-50%,-50%) scale(1); } """, }, "src/components/recommendDialog.wpy": { "type": "center", "modal_cls": "recommend-mask", "dialog_cls": "recommend-dialog", "trigger": "~show", "style_add": """ .recommend-mask { position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 1110; background: rgba(0,0,0,.6); opacity: 0; pointer-events: none; transition: opacity .3s; } .recommend-mask.show { opacity: 1; pointer-events: auto; } .recommend-dialog { position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%) scale(.85); width: 680rpx; max-width: 100%; background: #fff; border-radius: 20rpx; overflow: hidden; transition: transform .3s; } .recommend-mask.show .recommend-dialog { transform: translate(-50%,-50%) scale(1); } """, }, "src/components/shareComponent.wpy": { "type": "center", "modal_cls": "sharec-mask", "dialog_cls": "sharec-dialog", "trigger": "~show", "style_add": """ .sharec-mask { position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 1110; background: rgba(0,0,0,.6); opacity: 0; pointer-events: none; transition: opacity .3s; } .sharec-mask.show { opacity: 1; pointer-events: auto; } .sharec-dialog { position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%) scale(.85); width: 680rpx; max-width: 100%; background: #fff; border-radius: 20rpx; overflow: hidden; transition: transform .3s; } .sharec-mask.show .sharec-dialog { transform: translate(-50%,-50%) scale(1); } """, }, "src/components/wxShareCom.wpy": { "type": "center", "modal_cls": "wxsharec-mask", "dialog_cls": "wxsharec-dialog", "trigger": "~show", "style_add": """ .wxsharec-mask { position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 1110; background: rgba(0,0,0,.6); opacity: 0; pointer-events: none; transition: opacity .3s; } .wxsharec-mask.show { opacity: 1; pointer-events: auto; } .wxsharec-dialog { position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%) scale(.85); width: 680rpx; max-width: 100%; background: #fff; border-radius: 20rpx; overflow: hidden; transition: transform .3s; } .wxsharec-mask.show .wxsharec-dialog { transform: translate(-50%,-50%) scale(1); } """, }, "src/components/dynamicOperation.wpy": { "type": "bottom", "modal_cls": "dynop-mask", "dialog_cls": "dynop-sheet", "trigger": "~show", "style_add": """ .dynop-mask { position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 1110; background: rgba(0,0,0,.6); opacity: 0; pointer-events: none; transition: all .3s; } .dynop-mask.show { opacity: 1; pointer-events: auto; } .dynop-sheet { position: absolute; left: 0; right: 0; bottom: 0; background: #fff; border-radius: 30rpx 30rpx 0 0; width: 100%; z-index: 1111; view { height: 90rpx; text-align: center; line-height: 100rpx; margin: 0 30rpx; color: #333; } view:last-of-type { border-top: 1rpx solid #f5f5f5; color: #999; } } """, }, "src/components/UnlockingDialog.wpy": { "type": "center", "modal_cls": "unlock-mask", "dialog_cls": "unlock-dialog", "trigger": "~show", "style_add": """ .unlock-mask { position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 1110; background: rgba(0,0,0,.6); opacity: 0; pointer-events: none; transition: opacity .3s; } .unlock-mask.show { opacity: 1; pointer-events: auto; } .unlock-dialog { position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%) scale(.85); width: 680rpx; max-width: 100%; background: #fff; border-radius: 20rpx; overflow: hidden; transition: transform .3s; } .unlock-mask.show .unlock-dialog { transform: translate(-50%,-50%) scale(1); } """, }, "src/components/loginDialog.wpy": { "type": "center", "modal_cls": "logindlg-mask", "dialog_cls": "logindlg-dialog", "trigger": "~show", "style_add": """ .logindlg-mask { position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 9999; background: rgba(0,0,0,.6); opacity: 0; pointer-events: none; transition: opacity .3s; } .logindlg-mask.show { opacity: 1; pointer-events: auto; } .logindlg-dialog { position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%) scale(.85); width: 680rpx; max-width: 100%; background: #fff; border-radius: 20rpx; overflow: hidden; transition: transform .3s; } .logindlg-mask.show .logindlg-dialog { transform: translate(-50%,-50%) scale(1); } """, }, "src/components/residenceDialog.wpy": { "type": "bottom", "modal_cls": "residence-mask", "dialog_cls": "residence-sheet", "trigger": "~show", "style_add": """ .residence-mask { position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 1110; background: rgba(0,0,0,.6); opacity: 0; pointer-events: none; transition: all .3s; } .residence-mask.show { opacity: 1; pointer-events: auto; } .residence-sheet { position: absolute; left: 0; right: 0; bottom: 0; background: #fff; border-radius: 32rpx 32rpx 0 0; overflow: hidden; } """, }, "src/components/dynamicDiscuss.wpy": { "type": "bottom", "modal_cls": "discs-mask", "dialog_cls": "discs-sheet", "trigger": "~show", "style_add": """ .discs-mask { position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 1110; background: rgba(0,0,0,.6); opacity: 0; pointer-events: none; transition: all .3s; } .discs-mask.show { opacity: 1; pointer-events: auto; } .discs-sheet { position: absolute; left: 0; right: 0; bottom: 0; background: #fff; border-radius: 20rpx 20rpx 0 0; overflow: hidden; } """, }, "src/components/cu-custom.wpy": { "type": "center", "modal_cls": "cucust-mask", "dialog_cls": "cucust-dialog", "trigger": "~show", "style_add": """ .cucust-mask { position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 1110; background: rgba(0,0,0,.6); opacity: 0; pointer-events: none; transition: opacity .3s; } .cucust-mask.show { opacity: 1; pointer-events: auto; } .cucust-dialog { position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%) scale(.85); width: 680rpx; max-width: 100%; background: #fff; border-radius: 20rpx; overflow: hidden; transition: transform .3s; } .cucust-mask.show .cucust-dialog { transform: translate(-50%,-50%) scale(1); } """, }, "src/components/uploadVideo.wpy": { "type": "bottom", "modal_cls": "uploadvid-mask", "dialog_cls": "uploadvid-sheet", "trigger": "~show", "style_add": """ .uploadvid-mask { position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 1110; background: rgba(0,0,0,.6); opacity: 0; pointer-events: none; transition: all .3s; } .uploadvid-mask.show { opacity: 1; pointer-events: auto; } .uploadvid-sheet { position: absolute; left: 0; right: 0; bottom: 0; background: #fff; border-radius: 32rpx 32rpx 0 0; } """, }, } def transform_template(content, cfg): """把模板中的 ~cu-modal / ~show / ~bottom-modal / ~cu-dialog 替换掉""" modal = cfg["modal_cls"] dialog = cfg["dialog_cls"] lines = content.split("\n") result = [] for line in lines: orig = line # 1. ~cu-dialog → dialog类名 line = re.sub(r"~cu-dialog\b", dialog, line) # 2. ~bottom-modal → (去除,样式已在本地) line = re.sub(r"~\s*bottom-modal", "", line) # 3. ~cu-modal 处理 # 情况A: class="~cu-modal ..." (注意前面可能有其他class如 shareComponent的 cu-modal) # 情况B: :class="{'~show': ...}" class="~cu-modal" # 统一:去掉所有 ~cu-modal,保留其他已有class,在class属性末尾追加modal类名 if "~cu-modal" in line: # 先把 :class={'~show':cond} 里的 ~show 改成 show line = re.sub(r":class\s*=\s*\{'~show'\s*:", ":class=\"{'show':", line) # {{cond?'~show':''}} → {{cond?'show':''}} line = re.sub(r"\?'~show'", "? 'show'", line) # 去除 ~cu-modal,保留其他普通class # 匹配 class="... ~cu-modal ..." 或 class="~cu-modal" # WePY: class="xxx ~cu-modal yyy" → class="xxx yyy modal_cls" # class="~cu-modal xxx" → class="xxx modal_cls" # class="~cu-modal" → class="modal_cls" def fix_cu_modal(m): raw = m.group(0) # 提取已有class值 cls_val = re.search(r'class="([^"]*)"', raw) if not cls_val: return raw classes = cls_val.group(1) # 去掉 ~cu-modal 和多余的空格 classes = re.sub(r"~\s*cu-modal", "", classes) classes = re.sub(r"\s+", " ", classes).strip() # 去掉 shareComponent 的普通 cu-modal (不再需要) classes = re.sub(r"\bcu-modal\b", "", classes) classes = re.sub(r"\s+", " ", classes).strip() # 追加本地modal类 extra = " " + modal if classes else modal new_cls = (classes + extra).strip() return 'class="' + new_cls + '"' line = re.sub(r'class="[^"]*"', fix_cu_modal, line, count=1) # 4. 单独处理 :class="{'~show': ...}" 的情况(还没处理到的情况) line = re.sub(r":class\s*=\s*\{'~show'\s*:", ":class=\"{'show':", line) line = re.sub(r"\?'~show':", "? 'show':", line) result.append(line) return "\n".join(result) def append_style(content, style_add): """在 前追加样式""" marker = "" if marker in content: idx = content.index(marker) return content[:idx] + "\n" + style_add + "\n" + marker + content[idx + len(marker):] return content def process_file(filepath, cfg): with open(filepath, "r", encoding="utf-8") as f: content = f.read() new_content = transform_template(content, cfg) new_content = append_style(new_content, cfg["style_add"]) with open(filepath, "w", encoding="utf-8") as f: f.write(new_content) print(f"✓ {filepath}") def main(): base = "/Users/d/fulllink-project/ufutx.love.mp.v2" for rel_path, cfg in CONFIGS.items(): filepath = os.path.join(base, rel_path) if os.path.exists(filepath): process_file(filepath, cfg) else: print(f"✗ 文件不存在: {filepath}") if __name__ == "__main__": main()