图片现在能看了。
This commit is contained in:
198
main.py
198
main.py
@@ -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 <芒果酸> 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:
|
||||||
"""获取节次对应的时间(南邮标准时间)"""
|
"""获取节次对应的时间(南邮标准时间)"""
|
||||||
# 南邮标准作息时间,可根据需要调整
|
# 南邮标准作息时间,可根据需要调整
|
||||||
|
|||||||
Reference in New Issue
Block a user