图片现在能看了。

This commit is contained in:
2026-04-02 20:28:49 +08:00
parent bf53af975b
commit fd948ca897

198
main.py
View File

@@ -43,6 +43,10 @@ class SuanPlugin(Star):
# 生成 HTML 内容 # 生成 HTML 内容
html_content = self._generate_schedule_html(schedule_dict, title) html_content = self._generate_schedule_html(schedule_dict, title)
# 额外保存一份到指定路径,用于样式调试
with open('/home/fanfan/test.html', 'w', encoding='utf-8') as f:
f.write(html_content)
# 创建临时文件 # 创建临时文件
with tempfile.NamedTemporaryFile(mode='w', suffix='.html', delete=False, encoding='utf-8') as f: with tempfile.NamedTemporaryFile(mode='w', suffix='.html', delete=False, encoding='utf-8') as f:
f.write(html_content) f.write(html_content)
@@ -57,9 +61,10 @@ class SuanPlugin(Star):
# 尝试使用 wkhtmltoimage如果安装了 # 尝试使用 wkhtmltoimage如果安装了
cmd = [ cmd = [
'wkhtmltoimage', 'wkhtmltoimage',
'--width', '1200', '--width', '1680',
'--quality', '90', '--quality', '90',
'--enable-local-file-access', '--enable-local-file-access',
'--transparent',
html_path, html_path,
png_path png_path
] ]
@@ -159,30 +164,24 @@ class SuanPlugin(Star):
logger.warning(f"清理临时文件失败 {path}: {e}") logger.warning(f"清理临时文件失败 {path}: {e}")
def _generate_schedule_html(self, schedule: list[dict], title: str) -> str: def _generate_schedule_html(self, schedule: list[dict], title: str) -> str:
"""生成课程表 HTML""" """生成课程表 HTML - 清新薄荷绿风格(静态图片版)"""
# 星期映射
weekdays = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'] weekdays = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
weekday_short = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
# 初始化课表网格: 12节课 x 7天
# grid[节次][星期] = 课程列表
grid = [[[] for _ in range(7)] for _ in range(12)] grid = [[[] for _ in range(7)] for _ in range(12)]
# 填充课程数据
for course in schedule: for course in schedule:
name = course.get('name', '未知课程') name = course.get('name', '未知课程')
teacher = course.get('teacher') or '' teacher = course.get('teacher') or ''
classroom = course.get('classroom') or '' classroom = course.get('classroom') or ''
weeks = course.get('weeks', []) weeks = course.get('weeks', [])
day = course.get('day', 1) # 1-7 day = course.get('day', 1)
classes = course.get('classes', []) classes = course.get('classes', [])
# 调整 day 为 0-based 索引
day_idx = day - 1 day_idx = day - 1
if day_idx < 0 or day_idx > 6: if day_idx < 0 or day_idx > 6:
continue continue
# 构建课程显示文本
course_text = f"<b>{name}</b>" course_text = f"<b>{name}</b>"
if teacher: if teacher:
course_text += f"<br><small>{teacher}</small>" course_text += f"<br><small>{teacher}</small>"
@@ -191,12 +190,10 @@ class SuanPlugin(Star):
if weeks: if weeks:
course_text += f"<br><small>第{self._format_weeks(weeks)}周</small>" course_text += f"<br><small>第{self._format_weeks(weeks)}周</small>"
# 放入对应格子
for class_idx in classes: for class_idx in classes:
if 1 <= class_idx <= 12: if 1 <= class_idx <= 12:
grid[class_idx - 1][day_idx].append(course_text) grid[class_idx - 1][day_idx].append(course_text)
# 构建 HTML
html = f'''<!DOCTYPE html> html = f'''<!DOCTYPE html>
<html> <html>
<head> <head>
@@ -208,79 +205,151 @@ class SuanPlugin(Star):
padding: 0; padding: 0;
box-sizing: border-box; box-sizing: border-box;
}} }}
body {{ body {{
font-family: "Microsoft YaHei", "SimHei", sans-serif; font-family: "WenQuanYi Micro Hei", "Noto Sans CJK SC", "Microsoft YaHei", sans-serif;
padding: 20px; background: transparent;
background: #fff; padding: 40px;
}} }}
.container {{ .container {{
width: 100%; width: 1600px;
max-width: 1200px; background: #1a1a2e;
margin: 0 auto; border-radius: 20px;
padding: 40px;
}} }}
h1 {{
.header {{
text-align: center; text-align: center;
font-size: 24px; margin-bottom: 30px;
margin-bottom: 20px;
color: #333;
}} }}
h1 {{
font-size: 32px;
color: #e0f7fa;
letter-spacing: 2px;
}}
table {{ table {{
width: 100%; width: 100%;
border-collapse: collapse; table-layout: fixed;
font-size: 12px; border-collapse: separate;
border-spacing: 10px;
font-size: 14px;
}} }}
th, td {{
border: 1px solid #ccc; col.time-col {{
padding: 8px; width: 90px;
text-align: center;
vertical-align: middle;
}} }}
col.day-col {{
width: 14.28%;
}}
th {{ th {{
background: #f5f5f5; background: #006064;
color: #e0f7fa;
font-weight: bold; font-weight: bold;
color: #333; padding: 15px 10px;
border-radius: 12px;
}} }}
.time-col {{
background: #f9f9f9; th .weekday-en {{
font-weight: bold;
width: 60px;
}}
.course-cell {{
min-height: 60px;
}}
.course-item {{
background: #e3f2fd;
border-radius: 4px;
padding: 4px;
margin: 2px 0;
line-height: 1.4;
}}
.course-item b {{
color: #1976d2;
font-size: 11px; font-size: 11px;
display: block;
margin-top: 4px;
color: #80deea;
}} }}
td.time-col {{
background: #00796b;
color: #e0f7fa;
font-weight: bold;
padding: 15px 10px;
border-radius: 12px;
text-align: center;
}}
td.time-col .period-num {{
font-size: 18px;
display: block;
}}
td.time-col .period-time {{
font-size: 11px;
display: block;
margin-top: 4px;
color: #b2ebf2;
}}
td.day-cell {{
background: #263238;
border-radius: 12px;
padding: 10px;
vertical-align: top;
height: 110px;
}}
.course-item {{
background: #00838f;
border-radius: 10px;
padding: 6px;
margin: 2px 0;
color: #e0f7fa;
line-height: 1.1;
font-size: 17px;
height: 180px;
}}
.course-item b {{
display: block;
font-size: 20px;
font-weight: bold;
margin-bottom: 1px;
color: #ffffff;
}}
.course-item small {{ .course-item small {{
color: #666; display: block;
font-size: 9px; font-size: 14px;
}}tr:nth-child(even) td {{ color: #b2ebf2;
background: #fafafa;
}} }}
.course-item small + small {{
margin-top: 0px;
}}
.course-item.type-a {{ background: #0277bd; }}
.course-item.type-b {{ background: #2e7d32; }}
.course-item.type-c {{ background: #7b1fa2; }}
.course-item.type-d {{ background: #c6278e; }}
.course-item.type-e {{ background: #ef6c00; }}
</style> </style>
</head> </head>
<body> <body>
<div class="container"> <div class="container">
<div class="header">
<h1>{title}</h1> <h1>{title}</h1>
</div>
<table> <table>
<colgroup>
<col class="time-col">
<col class="day-col"><col class="day-col"><col class="day-col">
<col class="day-col"><col class="day-col"><col class="day-col">
<col class="day-col">
</colgroup>
<thead> <thead>
<tr> <tr>
<th>节次</th> <th>TIME</th>
{''.join(f'<th>{w}</th>' for w in weekdays)} {''.join(f'<th>{w}<span class="weekday-en">{weekday_short[i]}</span></th>' for i, w in enumerate(weekdays))}
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{self._generate_table_body(grid)} {self._generate_table_body(grid)}
</tbody> </tbody>
</table> </table>
<div style="text-align: right; margin-top: 20px; font-size: 12px; color: #b0bec5;">Powered by &lt;芒果酸&gt; suan.mangofanfan.cn</div>
</div> </div>
</body> </body>
</html>''' </html>'''
@@ -290,30 +359,37 @@ class SuanPlugin(Star):
def _generate_table_body(self, grid: list) -> str: def _generate_table_body(self, grid: list) -> str:
"""生成表格主体 HTML""" """生成表格主体 HTML"""
rows = [] rows = []
course_type_counter = 0
type_classes = ['type-a', 'type-b', 'type-c', 'type-d', 'type-e']
for period in range(12): for period in range(12):
# 计算时间显示
start_time = self._get_period_time(period + 1) start_time = self._get_period_time(period + 1)
row_html = f'<tr><td class="time-col">{period + 1}<br><small>{start_time}</small></td>' row_html = f'''<tr>
<td class="time-col">
<span class="period-num">{period + 1}</span>
<span class="period-time">{start_time}</span>
</td>'''
for day in range(7): for day in range(7):
courses = grid[period][day] courses = grid[period][day]
if courses: if courses:
cell_content = ''.join( cell_content = ''
f'<div class="course-item">{c}</div>' for c in courses:
for c in courses type_class = type_classes[course_type_counter % len(type_classes)]
) course_type_counter += 1
cell_content += f'<div class="course-item {type_class}">{c}</div>'
else: else:
cell_content = '' cell_content = ''
row_html += f'<td class="course-cell">{cell_content}</td>' row_html += f'<td class="day-cell">{cell_content}</td>'
row_html += '</tr>' row_html += '</tr>'
rows.append(row_html) rows.append(row_html)
return '\n'.join(rows) return '\n'.join(rows)
def _get_period_time(self, period: int) -> str: def _get_period_time(self, period: int) -> str:
"""获取节次对应的时间(南邮标准时间)""" """获取节次对应的时间(南邮标准时间)"""
# 南邮标准作息时间,可根据需要调整 # 南邮标准作息时间,可根据需要调整