在准备环境前提交次全部更改。
This commit is contained in:
292
scripts/ops/fix_board_coach_dims.py
Normal file
292
scripts/ops/fix_board_coach_dims.py
Normal file
@@ -0,0 +1,292 @@
|
||||
"""
|
||||
board-coach.html: 将单一助教列表替换为按筛选分类的多个 dim-container,
|
||||
并添加 JS 切换逻辑。同时修复 board-customer.html 各维度指数标签。
|
||||
"""
|
||||
import re
|
||||
|
||||
# ============================================================
|
||||
# 1. board-coach.html — 多维度切换
|
||||
# ============================================================
|
||||
filepath = "docs/h5_ui/pages/board-coach.html"
|
||||
with open(filepath, "r", encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
|
||||
# 定位旧的助教列表 + 隐藏样式区域
|
||||
old_start = ' <!-- 助教列表'
|
||||
old_end = ' <!-- 悬浮助手按钮 -->'
|
||||
start_idx = content.index(old_start)
|
||||
end_idx = content.index(old_end)
|
||||
|
||||
# 6 位助教的基础信息(复用)
|
||||
coaches = [
|
||||
("小", "小燕", "from-blue-400 to-indigo-500", "星级", "bg-gradient-to-r from-amber-400 to-orange-400 text-white", "中🎱", "bg-primary/10 text-primary", ""),
|
||||
("泡", "泡芙", "from-green-400 to-emerald-500", "高级", "bg-gradient-to-r from-purple-400 to-violet-400 text-white", "斯诺克", "bg-success/10 text-success", ""),
|
||||
("A", "Amy", "from-pink-400 to-rose-500", "星级", "bg-gradient-to-r from-amber-400 to-orange-400 text-white", "中🎱", "bg-primary/10 text-primary", '<span class="px-1.5 py-0.5 bg-success/10 text-success text-xs rounded flex-shrink-0">斯诺克</span>'),
|
||||
("M", "Mia", "from-amber-400 to-orange-500", "中级", "bg-gradient-to-r from-blue-400 to-indigo-400 text-white", "麻将", "bg-warning/10 text-warning", ""),
|
||||
("糖", "糖糖", "from-purple-400 to-violet-500", "初级", "bg-gradient-to-r from-gray-400 to-gray-500 text-white", "中🎱", "bg-primary/10 text-primary", ""),
|
||||
("露", "露露", "from-cyan-400 to-teal-500", "中级", "bg-gradient-to-r from-blue-400 to-indigo-400 text-white", "团建", "bg-error/10 text-error", ""),
|
||||
]
|
||||
|
||||
clients = [
|
||||
("💖 王先生", "💖 李女士", "💛 赵总"),
|
||||
("💖 陈先生", "💛 刘女士", "💛 黄总"),
|
||||
("💖 张先生", "💛 周女士", "💛 吴总"),
|
||||
("💛 赵先生", "💛 吴女士", "💛 孙总"),
|
||||
("💛 钱先生", "💛 孙女士", "💛 周总"),
|
||||
("💛 郑先生", "💛 冯女士", "💛 陈总"),
|
||||
]
|
||||
|
||||
def coach_header(i):
|
||||
"""生成助教卡片的头像+昵称+标签行(通用)"""
|
||||
ch, name, grad, level, lvl_cls, skill, sk_cls, extra = coaches[i]
|
||||
return f''' <div class="w-11 h-11 rounded-full bg-gradient-to-br {grad} flex items-center justify-center flex-shrink-0">
|
||||
<span class="text-white font-semibold text-base">{ch}</span>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-1.5 flex-wrap">
|
||||
<span class="text-base font-semibold text-gray-13">{name}</span>
|
||||
<span class="px-1.5 py-0.5 {lvl_cls} text-xs rounded flex-shrink-0">{level}</span>
|
||||
<span class="px-1.5 py-0.5 {sk_cls} text-xs rounded flex-shrink-0">{skill}</span>
|
||||
{extra}
|
||||
</div>'''
|
||||
|
||||
def coach_row2(i, right_html):
|
||||
"""生成第二行:客户 + 右侧数据"""
|
||||
c1, c2, c3 = clients[i]
|
||||
return f''' <div class="flex items-center justify-between text-xs pt-2 border-t border-gray-100">
|
||||
<div class="flex items-center gap-2 text-gray-6 truncate">
|
||||
<span>{c1}</span><span>{c2}</span><span>{c3}</span>
|
||||
</div>
|
||||
{right_html}
|
||||
</div>'''
|
||||
|
||||
# 定档业绩数据
|
||||
perf_data = [
|
||||
("86.2", "13.8", "92.0"),
|
||||
("72.5", "7.5", "78.0"),
|
||||
("68.0", "32.0", "72.5"),
|
||||
("55.0", "5.0", ""),
|
||||
("42.0", "达标", "45.0"),
|
||||
("38.0", "22.0", ""),
|
||||
]
|
||||
perf_levels = [
|
||||
("星级", "王牌"),
|
||||
("高级", "星级"),
|
||||
("星级", "王牌"),
|
||||
("中级", "高级"),
|
||||
("初级", "中级"),
|
||||
("中级", "高级"),
|
||||
]
|
||||
|
||||
def make_perf_card(i):
|
||||
"""定档业绩最高/最低 卡片"""
|
||||
h, need, pre = perf_data[i]
|
||||
cur, nxt = perf_levels[i]
|
||||
if need == "达标":
|
||||
data_line = f''' <div class="mt-1 flex items-center gap-2 text-xs">
|
||||
<span class="font-bold text-success text-sm">{h}h</span>
|
||||
<span class="text-success font-medium">✅ 已达标</span>
|
||||
</div>'''
|
||||
else:
|
||||
data_line = f''' <div class="mt-1 flex items-center gap-2 text-xs">
|
||||
<span class="font-bold text-primary text-sm">{h}h</span>
|
||||
<span class="text-gray-7">下一档还需 <span class="text-warning font-medium">{need}h</span></span>
|
||||
</div>'''
|
||||
pre_html = f'<span class="text-gray-5">|</span>\n <span>折前 <b class="text-gray-10">{pre}h</b></span>' if pre else ''
|
||||
right = f'''<div class="flex items-center gap-2 text-gray-7 flex-shrink-0">
|
||||
<span>定档 <b class="text-gray-10">{h}h</b></span>
|
||||
{pre_html}
|
||||
</div>'''
|
||||
return f''' <a href="coach-detail.html" class="block bg-white rounded-2xl p-4 shadow-sm coach-card">
|
||||
<div class="flex items-start gap-3 mb-2.5">
|
||||
{coach_header(i)}
|
||||
{data_line}
|
||||
</div>
|
||||
</div>
|
||||
{coach_row2(i, right)}
|
||||
</a>'''
|
||||
|
||||
# 工资数据
|
||||
salary_data = ["¥12,680", "¥10,200", "¥9,800", "¥7,500", "¥6,200", "¥5,100"]
|
||||
|
||||
def make_salary_card(i):
|
||||
"""工资最高/最低 卡片"""
|
||||
sal = salary_data[i]
|
||||
h = perf_data[i][0]
|
||||
pre = perf_data[i][2]
|
||||
pre_html = f'<span class="text-gray-5">|</span>\n <span>折前 <b class="text-gray-10">{pre}h</b></span>' if pre else ''
|
||||
right = f'''<div class="flex items-center gap-2 text-gray-7 flex-shrink-0">
|
||||
<span>定档 <b class="text-gray-10">{h}h</b></span>
|
||||
{pre_html}
|
||||
</div>'''
|
||||
return f''' <a href="coach-detail.html" class="block bg-white rounded-2xl p-4 shadow-sm coach-card">
|
||||
<div class="flex items-start gap-3 mb-2.5">
|
||||
{coach_header(i)}
|
||||
<div class="mt-1 flex items-center gap-2">
|
||||
<span class="text-lg font-semibold text-gray-13">{sal}</span>
|
||||
<span class="px-1.5 py-0.5 bg-warning/10 text-warning text-xs rounded">预估</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{coach_row2(i, right)}
|
||||
</a>'''
|
||||
|
||||
# 客源储值数据
|
||||
sv_balance = ["¥45,200", "¥38,600", "¥32,100", "¥28,500", "¥22,000", "¥18,300"]
|
||||
sv_consume = ["¥8,600", "¥6,200", "¥5,800", "¥4,100", "¥3,500", "¥2,800"]
|
||||
|
||||
def make_sv_card(i):
|
||||
"""客源储值最高 卡片"""
|
||||
right = f'''<div class="flex items-center gap-2 text-gray-7 flex-shrink-0">
|
||||
<span>周期消耗 <b class="text-gray-10">{sv_consume[i]}</b></span>
|
||||
</div>'''
|
||||
return f''' <a href="coach-detail.html" class="block bg-white rounded-2xl p-4 shadow-sm coach-card">
|
||||
<div class="flex items-start gap-3 mb-2.5">
|
||||
{coach_header(i)}
|
||||
<div class="mt-1">
|
||||
<span class="text-lg font-semibold text-gray-13">{sv_balance[i]}</span>
|
||||
<span class="text-xs text-gray-6 ml-1">客户储值余额</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{coach_row2(i, right)}
|
||||
</a>'''
|
||||
|
||||
# 任务完成数据
|
||||
task_counts = [(32, 18), (28, 15), (25, 14), (20, 12), (18, 10), (15, 9)]
|
||||
|
||||
def make_task_card(i):
|
||||
"""任务完成最多 卡片"""
|
||||
tc, cc = task_counts[i]
|
||||
h = perf_data[i][0]
|
||||
pre = perf_data[i][2]
|
||||
pre_html = f'<span class="text-gray-5">|</span>\n <span>折前 <b class="text-gray-10">{pre}h</b></span>' if pre else ''
|
||||
right = f'''<div class="flex items-center gap-2 text-gray-7 flex-shrink-0">
|
||||
<span>定档 <b class="text-gray-10">{h}h</b></span>
|
||||
{pre_html}
|
||||
</div>'''
|
||||
return f''' <a href="coach-detail.html" class="block bg-white rounded-2xl p-4 shadow-sm coach-card">
|
||||
<div class="flex items-start gap-3 mb-2.5">
|
||||
{coach_header(i)}
|
||||
<div class="mt-1 flex items-center gap-3">
|
||||
<div><span class="text-lg font-semibold text-primary">{tc}</span><span class="text-xs text-gray-6 ml-0.5">个任务</span></div>
|
||||
<div class="w-px h-4 bg-gray-3"></div>
|
||||
<div><span class="text-lg font-semibold text-gray-13">{cc}</span><span class="text-xs text-gray-6 ml-0.5">位客户</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{coach_row2(i, right)}
|
||||
</a>'''
|
||||
|
||||
# 生成各维度容器
|
||||
dims = []
|
||||
|
||||
# 定档业绩最高
|
||||
cards = "\n\n".join(make_perf_card(i) for i in range(6))
|
||||
dims.append(f''' <!-- ====== 定档业绩最高/最低 ====== -->
|
||||
<div id="dim-perf" class="dim-container active p-4 space-y-3">
|
||||
{cards}
|
||||
</div>''')
|
||||
|
||||
# 工资最高
|
||||
cards = "\n\n".join(make_salary_card(i) for i in range(6))
|
||||
dims.append(f''' <!-- ====== 工资最高/最低 ====== -->
|
||||
<div id="dim-salary" class="dim-container p-4 space-y-3">
|
||||
{cards}
|
||||
</div>''')
|
||||
|
||||
# 客源储值最高
|
||||
cards = "\n\n".join(make_sv_card(i) for i in range(6))
|
||||
dims.append(f''' <!-- ====== 客源储值最高 ====== -->
|
||||
<div id="dim-sv" class="dim-container p-4 space-y-3">
|
||||
{cards}
|
||||
</div>''')
|
||||
|
||||
# 任务完成最多
|
||||
cards = "\n\n".join(make_task_card(i) for i in range(6))
|
||||
dims.append(f''' <!-- ====== 任务完成最多 ====== -->
|
||||
<div id="dim-task" class="dim-container p-4 space-y-3">
|
||||
{cards}
|
||||
</div>''')
|
||||
|
||||
new_section = "\n\n".join(dims) + "\n\n"
|
||||
|
||||
content = content[:start_idx] + new_section + content[end_idx:]
|
||||
|
||||
# 添加 dim-container CSS(如果不存在)
|
||||
if '.dim-container' not in content:
|
||||
content = content.replace(
|
||||
'.coach-card:active {',
|
||||
'.dim-container { display: none; }\n .dim-container.active { display: block; }\n .coach-card:active {'
|
||||
)
|
||||
|
||||
# 替换 selectSort JS 函数,添加维度切换逻辑
|
||||
old_select_sort = ''' function selectSort(value) {
|
||||
document.getElementById('sortLabel').textContent = value;
|
||||
closeAllFilters();
|
||||
}'''
|
||||
|
||||
new_select_sort = ''' function selectSort(value) {
|
||||
document.getElementById('sortLabel').textContent = value;
|
||||
closeAllFilters();
|
||||
// 切换维度容器
|
||||
var dimMap = {
|
||||
'定档业绩最高': 'dim-perf',
|
||||
'定档业绩最低': 'dim-perf',
|
||||
'工资最高': 'dim-salary',
|
||||
'工资最低': 'dim-salary',
|
||||
'客源储值最高': 'dim-sv',
|
||||
'任务完成最多': 'dim-task'
|
||||
};
|
||||
document.querySelectorAll('.dim-container').forEach(function(el) { el.classList.remove('active'); });
|
||||
var id = dimMap[value];
|
||||
if (id) document.getElementById(id).classList.add('active');
|
||||
}'''
|
||||
|
||||
content = content.replace(old_select_sort, new_select_sort)
|
||||
|
||||
with open(filepath, "w", encoding="utf-8") as f:
|
||||
f.write(content)
|
||||
print("OK — board-coach.html: 4 dim-containers + JS 切换")
|
||||
|
||||
# ============================================================
|
||||
# 2. board-customer.html — 修正各维度的指数标签
|
||||
# ============================================================
|
||||
filepath2 = "docs/h5_ui/pages/board-customer.html"
|
||||
with open(filepath2, "r", encoding="utf-8") as f:
|
||||
c2 = f.read()
|
||||
|
||||
# 最高余额维度:指数标签应该是"余额排名"而不是"消费潜力指数"
|
||||
# 最频繁维度:应该是"到店频率"
|
||||
# 最近到店:应该是"到店新鲜度"
|
||||
# 最专一:应该是"专一指数"
|
||||
# 最高消费近60天:应该是"消费力指数"
|
||||
|
||||
replacements = [
|
||||
# dim-balance 区域
|
||||
('id="dim-balance"', '消费潜力指数', '余额排名'),
|
||||
# dim-freq60 区域
|
||||
('id="dim-freq60"', '消费潜力指数', '到店频率'),
|
||||
# dim-recent 区域
|
||||
('id="dim-recent"', '消费潜力指数', '到店新鲜度'),
|
||||
# dim-loyal 区域
|
||||
('id="dim-loyal"', '消费潜力指数', '专一指数'),
|
||||
# dim-spend60 区域
|
||||
('id="dim-spend60"', '消费潜力指数', '消费力指数'),
|
||||
]
|
||||
|
||||
for dim_id, old_label, new_label in replacements:
|
||||
# 找到该维度区域的起始位置
|
||||
dim_start = c2.index(dim_id)
|
||||
# 找到下一个维度或文件末尾
|
||||
next_dim = c2.find('dim-container', dim_start + 50)
|
||||
if next_dim == -1:
|
||||
next_dim = len(c2)
|
||||
# 在该区域内替换标签
|
||||
section = c2[dim_start:next_dim]
|
||||
section = section.replace(old_label, new_label)
|
||||
c2 = c2[:dim_start] + section + c2[next_dim:]
|
||||
|
||||
with open(filepath2, "w", encoding="utf-8") as f:
|
||||
f.write(c2)
|
||||
print("OK — board-customer.html: 各维度指数标签已修正")
|
||||
Reference in New Issue
Block a user