ufutx_love_mp/scripts/fix_modal_bug.py
2026-08-18 17:57:07 +08:00

520 lines
13 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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):
"""在 </style> 前追加样式"""
marker = "</style>"
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()