11
This commit is contained in:
@@ -4,6 +4,8 @@ import matplotlib.pyplot as plt
|
|||||||
from matplotlib.font_manager import FontProperties
|
from matplotlib.font_manager import FontProperties
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
import base64
|
import base64
|
||||||
|
from datetime import datetime
|
||||||
|
import calendar
|
||||||
|
|
||||||
def load_template(template_name):
|
def load_template(template_name):
|
||||||
"""
|
"""
|
||||||
@@ -165,3 +167,39 @@ def plot_line_chart_base64(data, x_field, y_field, title=None, reverse_x=False):
|
|||||||
|
|
||||||
img_base64 = base64.b64encode(buffer.getvalue()).decode('utf-8')
|
img_base64 = base64.b64encode(buffer.getvalue()).decode('utf-8')
|
||||||
return f"data:image/png;base64,{img_base64}"
|
return f"data:image/png;base64,{img_base64}"
|
||||||
|
|
||||||
|
|
||||||
|
def build_calendar_items(start_date_str, data):
|
||||||
|
start_date = datetime.datetime.strptime(start_date_str, "%Y-%m-%d").date()
|
||||||
|
weekday = start_date.weekday() # 周一0 ~ 周日6
|
||||||
|
weekday = (weekday + 1) % 7 # 调整:周日=0, 周一=1 ... 周六=6
|
||||||
|
|
||||||
|
result = []
|
||||||
|
row = []
|
||||||
|
|
||||||
|
# 第一行补空
|
||||||
|
for _ in range(weekday):
|
||||||
|
row.append({"date": "", "items": [], "is_today": False})
|
||||||
|
|
||||||
|
# 排数据
|
||||||
|
for i, day in enumerate(data):
|
||||||
|
# 识别今天
|
||||||
|
is_today = (day["date"] == start_date_str)
|
||||||
|
|
||||||
|
row.append({
|
||||||
|
"date": day["day"],
|
||||||
|
"items": [day],
|
||||||
|
"is_today": is_today,
|
||||||
|
})
|
||||||
|
|
||||||
|
if len(row) == 7:
|
||||||
|
result.append(row)
|
||||||
|
row = []
|
||||||
|
|
||||||
|
# 最后一行剩余补空
|
||||||
|
if row:
|
||||||
|
while len(row) < 7:
|
||||||
|
row.append({"date": "", "items": [], "is_today": False})
|
||||||
|
result.append(row)
|
||||||
|
|
||||||
|
return result
|
||||||
+10
-5
@@ -7,7 +7,7 @@ from astrbot.api import AstrBotConfig
|
|||||||
|
|
||||||
from .request import APIClient
|
from .request import APIClient
|
||||||
from .aiosqlite import AsyncSQLite
|
from .aiosqlite import AsyncSQLite
|
||||||
from .function_basic import load_template,flatten_field,extract_fields,gold_to_string
|
from .function_basic import load_template,gold_to_string,build_calendar_items
|
||||||
|
|
||||||
class JX3Service:
|
class JX3Service:
|
||||||
def __init__(self, api_config, config:AstrBotConfig):
|
def __init__(self, api_config, config:AstrBotConfig):
|
||||||
@@ -159,19 +159,24 @@ class JX3Service:
|
|||||||
data: Optional[Dict[str, Any]] = await self._base_request(
|
data: Optional[Dict[str, Any]] = await self._base_request(
|
||||||
"jx3_richangyuche", "GET", params=params
|
"jx3_richangyuche", "GET", params=params
|
||||||
)
|
)
|
||||||
logger.info(f"richang 接口返回数据: {data}")
|
|
||||||
if not data:
|
if not data:
|
||||||
return_data["msg"] = "获取接口信息失败"
|
return_data["msg"] = "获取接口信息失败"
|
||||||
return return_data
|
return return_data
|
||||||
|
|
||||||
# 3. 处理返回数据
|
# 3. 处理返回数据
|
||||||
try:
|
try:
|
||||||
# 格式化字符串,利用字典的 get 方法提供默认值
|
return_data["data"]["items"] = build_calendar_items(data["today"]["date"],data["data"])
|
||||||
|
|
||||||
return_data["code"] = 0
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"richang 数据处理时出错: {e}")
|
logger.error(f"richang 数据处理时出错: {e}")
|
||||||
return_data["msg"] = "处理接口返回信息时出错"
|
return_data["msg"] = "处理接口返回信息时出错"
|
||||||
|
# 加载模板
|
||||||
|
try:
|
||||||
|
return_data["temp"] = load_template("richangyuche.html")
|
||||||
|
except FileNotFoundError as e:
|
||||||
|
logger.error(f"加载模板失败: {e}")
|
||||||
|
return_data["msg"] = "系统错误:模板文件不存在"
|
||||||
|
|
||||||
|
return_data["code"] = 200
|
||||||
|
|
||||||
return return_data
|
return return_data
|
||||||
|
|
||||||
|
|||||||
@@ -154,8 +154,10 @@ class Jx3ApiPlugin(Star):
|
|||||||
"""剑三 日常预测 服务器 """
|
"""剑三 日常预测 服务器 """
|
||||||
try:
|
try:
|
||||||
data= await self.jx3fun.richangyuche()
|
data= await self.jx3fun.richangyuche()
|
||||||
|
logger.info(data)
|
||||||
if data["code"] == 200:
|
if data["code"] == 200:
|
||||||
yield event.plain_result(data["data"])
|
url = await self.html_render(data["temp"], data["data"], options={})
|
||||||
|
yield event.image_result(url)
|
||||||
else:
|
else:
|
||||||
yield event.plain_result(data["msg"])
|
yield event.plain_result(data["msg"])
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>未来战场日程表</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0; padding: 20px;
|
||||||
|
background: #f5f7fb; color: #1f2333;
|
||||||
|
font-family: "Microsoft YaHei", Arial, sans-serif;
|
||||||
|
}
|
||||||
|
.calendar {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
table-layout: fixed;
|
||||||
|
}
|
||||||
|
.calendar th {
|
||||||
|
background: #4f7cff;
|
||||||
|
color: white;
|
||||||
|
padding: 10px 0;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
.calendar td {
|
||||||
|
border: 1px solid #dce1eb;
|
||||||
|
vertical-align: top;
|
||||||
|
padding: 8px;
|
||||||
|
background: #ffffff;
|
||||||
|
}
|
||||||
|
.today {
|
||||||
|
background: #fff6d1;
|
||||||
|
border: 2px solid #ffb100;
|
||||||
|
}
|
||||||
|
.date-num {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 16px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.item-block {
|
||||||
|
font-size: 12px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
padding: 4px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #f0f3fa;
|
||||||
|
}
|
||||||
|
.item-block span {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h1 style="margin-bottom:20px;">未来战场日程表</h1>
|
||||||
|
|
||||||
|
<table class="calendar">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>日</th><th>一</th><th>二</th><th>三</th><th>四</th><th>五</th><th>六</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for week in items %}
|
||||||
|
<tr>
|
||||||
|
{% for day in week %}
|
||||||
|
{% if day.date %}
|
||||||
|
<td class="{% if day.is_today %}today{% endif %}">
|
||||||
|
<span class="date-num">{{ day.date }}</span>
|
||||||
|
|
||||||
|
{% for obj in day.items %}
|
||||||
|
<div class="item-block">
|
||||||
|
<div><span>战场:</span>{{ obj.battle }}</div>
|
||||||
|
<div><span>战役:</span>{{ obj.war }}</div>
|
||||||
|
<div><span>运车:</span>{{ obj.orecar }}</div>
|
||||||
|
<div><span>门派:</span>{{ obj.school }}</div>
|
||||||
|
<div><span>救援:</span>{{ obj.rescue }}</div>
|
||||||
|
{% if obj.card %}
|
||||||
|
<div><span>卡牌:</span>{{ obj.card | join('、') }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
</td>
|
||||||
|
{% else %}
|
||||||
|
<td style="background:#f0f2f7;"></td>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
+105
-123
@@ -1,145 +1,127 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="zh-CN">
|
<html lang="zh-CN">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>角色奇遇一览</title>
|
<title>未来战场日历</title>
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
padding: 24px;
|
|
||||||
background: #f5f7fb;
|
|
||||||
color: #2c2c33;
|
|
||||||
font-family: "Microsoft YaHei", Arial, sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section {
|
<style>
|
||||||
margin-bottom: 32px;
|
body {
|
||||||
}
|
font-family: "Microsoft YaHei", Arial, sans-serif;
|
||||||
|
background: #f1f2f6;
|
||||||
|
padding: 20px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.section-title {
|
h1 {
|
||||||
font-size: 36px;
|
text-align: center;
|
||||||
font-weight: bold;
|
font-size: 32px;
|
||||||
margin-bottom: 16px;
|
font-weight: 800;
|
||||||
border-left: 4px solid #4f7cff;
|
margin-bottom: 25px;
|
||||||
padding-left: 10px;
|
color: #222;
|
||||||
color: #1f2a44;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.card-container {
|
.calendar {
|
||||||
display: grid;
|
width: 100%;
|
||||||
grid-template-columns: repeat(4, 1fr);
|
max-width: 1200px;
|
||||||
gap: 16px;
|
margin: 0 auto;
|
||||||
}
|
border-collapse: collapse;
|
||||||
|
background: white;
|
||||||
|
border-radius: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 4px 16px rgba(0,0,0,0.08);
|
||||||
|
}
|
||||||
|
|
||||||
.card {
|
.calendar th {
|
||||||
background: #ffffff;
|
background: #d93939;
|
||||||
border-radius: 8px;
|
color: white;
|
||||||
padding: 16px 12px;
|
padding: 12px;
|
||||||
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.08);
|
font-size: 18px;
|
||||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
border: 1px solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
display: flex;
|
.calendar td {
|
||||||
flex-direction: column;
|
vertical-align: top;
|
||||||
align-items: center;
|
padding: 6px;
|
||||||
justify-content: center;
|
width: 14.2%;
|
||||||
text-align: center;
|
border: 1px solid #eee;
|
||||||
min-height: 90px;
|
min-height: 120px;
|
||||||
}
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
.card:hover {
|
.date-label {
|
||||||
transform: translateY(-4px);
|
font-size: 14px;
|
||||||
box-shadow: 0 8px 18px rgba(0, 0, 0, 0.12);
|
color: #666;
|
||||||
}
|
font-weight: bold;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
.event {
|
.event-card {
|
||||||
font-size: 28px;
|
background: #fff7f7;
|
||||||
font-weight: 600;
|
border: 1px solid #f0dada;
|
||||||
margin-bottom: 6px;
|
border-radius: 6px;
|
||||||
color: #2b3a67;
|
padding: 6px;
|
||||||
}
|
margin-top: 6px;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.4em;
|
||||||
|
}
|
||||||
|
|
||||||
.time {
|
.event-title {
|
||||||
font-size: 22px;
|
font-weight: bold;
|
||||||
color: #7a7f99;
|
color: #222;
|
||||||
}
|
}
|
||||||
|
|
||||||
.empty {
|
/* 鼠标悬停卡片高亮 */
|
||||||
color: #999;
|
.event-card:hover {
|
||||||
font-size: 14px;
|
background: #ffeaea;
|
||||||
padding: 10px 0;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 1000px) {
|
/* 当日高亮,可选 */
|
||||||
.card-container {
|
.today {
|
||||||
grid-template-columns: repeat(2, 1fr);
|
background: #fef3c7;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 600px) {
|
</style>
|
||||||
.card-container {
|
|
||||||
grid-template-columns: repeat(1, 1fr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<!-- 普通奇遇 -->
|
<h1>未来战场日历</h1>
|
||||||
<div class="section">
|
|
||||||
<div class="section-title">
|
|
||||||
普通奇遇({{ ptqy|length if ptqy else 0 }})
|
|
||||||
</div>
|
|
||||||
{% if ptqy %}
|
|
||||||
<div class="card-container">
|
|
||||||
{% for item in ptqy %}
|
|
||||||
<div class="card">
|
|
||||||
<div class="event">{{ item.event }}</div>
|
|
||||||
<div class="time">{{ item.time }}</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
{% else %}
|
|
||||||
<div class="empty">暂无普通奇遇</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 绝世奇遇 -->
|
<table class="calendar">
|
||||||
<div class="section">
|
|
||||||
<div class="section-title">
|
|
||||||
绝世奇遇({{ jsqy|length if jsqy else 0 }})
|
|
||||||
</div>
|
|
||||||
{% if jsqy %}
|
|
||||||
<div class="card-container">
|
|
||||||
{% for item in jsqy %}
|
|
||||||
<div class="card">
|
|
||||||
<div class="event">{{ item.event }}</div>
|
|
||||||
<div class="time">{{ item.time }}</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
{% else %}
|
|
||||||
<div class="empty">暂无绝世奇遇</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 宠物奇遇 -->
|
<thead>
|
||||||
<div class="section">
|
<tr>
|
||||||
<div class="section-title">
|
<th>周日</th>
|
||||||
宠物奇遇({{ cwqy|length if cwqy else 0 }})
|
<th>周一</th>
|
||||||
</div>
|
<th>周二</th>
|
||||||
{% if cwqy %}
|
<th>周三</th>
|
||||||
<div class="card-container">
|
<th>周四</th>
|
||||||
{% for item in cwqy %}
|
<th>周五</th>
|
||||||
<div class="card">
|
<th>周六</th>
|
||||||
<div class="event">{{ item.event }}</div>
|
</tr>
|
||||||
<div class="time">{{ item.time }}</div>
|
</thead>
|
||||||
</div>
|
|
||||||
{% endfor %}
|
<tbody>
|
||||||
</div>
|
|
||||||
{% else %}
|
{% for week in calendar_rows %}
|
||||||
<div class="empty">暂无宠物奇遇</div>
|
<tr>
|
||||||
{% endif %}
|
{% for cell in week %}
|
||||||
</div>
|
<td class="{% if cell.is_today %}today{% endif %}">
|
||||||
|
{% if cell.date %}
|
||||||
|
<div class="date-label">{{ cell.date }}</div>
|
||||||
|
{% for ev in cell.items %}
|
||||||
|
<div class="event-card">
|
||||||
|
<div class="event-title">{{ ev.war }}</div>
|
||||||
|
<div>{{ ev.battle }}</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
{% endfor %}
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user