This commit is contained in:
qsc
2026-07-29 23:47:04 +08:00
parent ad379a965a
commit fb6320b23b
9 changed files with 2157 additions and 422 deletions
+9 -1
View File
@@ -28,7 +28,15 @@
试炼排行:试炼排行 服务器 心法 试炼排行:试炼排行 服务器 心法
【物价交易】 【物价交易】
阵营拍卖:阵营拍卖 服务器 [物品] [数量] 阵营拍卖:阵营拍卖 服务器 [物品] [数量]
的卢拍卖:的卢 服务器
金价行情:金价 服务器
物品价格:物价 外观名称 [服务器]
成本计算:成本 服务器 物品名称
编号搜索:看号 万宝楼编号
【阵营战场】
帮战记录:帮战 服务器
阵营沙盘:沙盘 服务器
诛恶事件:诛恶 服务器
## 安装与依赖 ## 安装与依赖
+153
View File
@@ -0,0 +1,153 @@
import json
import html
import re
from datetime import datetime, timedelta
from typing import Dict, Any, Optional, List, Union
from inspect import isawaitable
from typing import Any, Awaitable, Callable, Dict, Optional
from astrbot.api import logger
from astrbot.api import AstrBotConfig
import astrbot.api.message_components as Comp
from .request import APIClient
from .sqlite import AsyncSQLiteDB
from .fun_basic import load_template,gold_to_parts,week_to_num,compare_date_str,format_time,format_remaining
class AIJX3Service:
def __init__(self, config: AstrBotConfig, sqlite: AsyncSQLiteDB, cache_sqlite: Optional[AsyncSQLiteDB] = None):
# 实例化 API Client
self._api: APIClient = APIClient()
# 引用插件配置文件
self._config = config
# 引用sqlite
self._sql_db = sqlite
self._cache_db = cache_sqlite or sqlite
async def close(self):
"""释放底层 APIClient 资源"""
if self._api:
await self._api.close()
def _init_return_data(self) -> Dict[str, Any]:
"""初始化标准的返回数据结构"""
return {
"code": 0,
"msg": "功能函数未执行",
"data": {},
"temp": "",
"icons": {}
}
async def _base_request(
self,
api_path: str,
params: Optional[Dict[str, Any]] = None,
out: Optional[str] = "data"
) -> Optional[Any]:
"""
基础请求封装,处理配置获取和API调用。
"""
try:
if not self._api:
logger.error("API client is not initialized")
return None
base_url = "https://www.jianxiachaguan.cn"
api_url = base_url + api_path
data = await self._api.post(api_url, data=params, out_key=out)
if not data:
logger.warning(f"获取接口信息失败或返回空数据: {api_url}")
return data
except Exception as e:
logger.error(f"基础请求调用出错 ({api_path}): {e}")
return None
async def _request_api(
self,
path: str,
params: Dict[str, Any],
processor: Optional[
Callable[[Any, Dict[str, Any]], Any | Awaitable[Any]]
] = None,
template: Optional[str] = None,
) -> Dict[str, Any]:
"""通用接口请求与模板处理。"""
return_data = self._init_return_data()
data = await self._base_request(path, params)
if data is None:
return_data["msg"] = "获取接口信息失败"
return return_data
try:
await processor(data, return_data)
except Exception as e:
logger.exception(f"数据处理时出错: {e}")
return_data["msg"] = "处理接口返回信息时出错"
return return_data
# template 为空时不加载模板
if template:
try:
return_data["temp"] = await load_template(template)
except FileNotFoundError as e:
logger.error(f"加载模板失败: {e}")
return_data["msg"] = "系统错误:模板文件不存在"
return return_data
return_data["code"] = 200
return return_data
async def shapan(self, server: str ) -> Dict[str, Any]:
"""区服沙盘"""
async def processor(data: Any, return_data: Dict[str, Any]) -> None:
pic_url = data.get("picUrl")
if pic_url:
return_data["data"] = pic_url
else:
return_data["msg"] = "接口未返回图片URL"
return return_data
return await self._request_api(
path="/api2/aijx3-jxcg/game/get-sand-table-img",
params={"serverName": server},
processor=processor,
template=""
)
return_data = self._init_return_data()
# 1. 构造请求参数
params = {"serverName": server}
# 2. 调用基础请求
data: Optional[Dict[str, Any]] = await self._base_request(
"aijx3_shapan", "POST", params=params
)
if not data:
return_data["msg"] = "获取接口信息失败"
return return_data
# 3. 处理返回数据 (直接提取图片 URL)
pic_url = data.get("picUrl")
if pic_url:
return_data["data"] = pic_url
else:
return_data["msg"] = "接口未返回图片URL"
return return_data
return_data["code"] = 200
return return_data
+163 -212
View File
@@ -1,4 +1,6 @@
import json import json
import html
import re
from datetime import datetime, timedelta from datetime import datetime, timedelta
from typing import Dict, Any, Optional, List, Union from typing import Dict, Any, Optional, List, Union
from inspect import isawaitable from inspect import isawaitable
@@ -563,6 +565,167 @@ class JX3APIService:
) )
async def jinjia(self, server: str, limit:str) -> Dict[str, Any]:
"""金价行情"""
# 数据处理
async def processor(data: Any, return_data: Dict[str, Any]) -> None:
return_data["data"]["items"] = data
return await self._request_api(
path="/trade/demon",
params={"server": server, "limit": limit, "token": self.token},
processor=processor,
template="jinjia.html"
)
async def wujia(self, Name: str, server:str) -> Dict[str, Any]:
"""物价查询"""
# 数据处理
async def processor(data: Any, return_data: Dict[str, Any]) -> None:
return_data["data"] = data
return await self._request_api(
path="/trade/records",
params={"name": Name,"token": self.token, "server": server},
processor=processor,
template="wujia.html"
)
async def chengbeng(self, Name: str, server:str, source: int) -> Dict[str, Any]:
"""成本计算"""
# 数据处理
async def processor(data: Any, return_data: Dict[str, Any]) -> None:
return_data["data"] = data
return await self._request_api(
path="/trade/manufacture",
params={"name": Name,"token": self.token, "server": server, "source": source},
processor=processor,
template="chengbeng.html"
)
async def bianhao(self, id: str) -> Dict[str, Any]:
"""编号搜索"""
# 数据处理
async def processor(data: Any, return_data: Dict[str, Any]) -> None:
if not isinstance(data, dict):
return_data["data"] = "账号角色数据格式错误"
return
# 同时兼容完整接口数据和直接传入 data 字段
data = data.get("data", data)
if not isinstance(data, dict):
return_data["data"] = "账号角色数据为空"
return
# 将 replyContent 中的 HTML 转换为纯文本
detail = str(data.get("replyContent") or "")
detail = re.sub(r"<br\s*/?>", "\n", detail, flags=re.IGNORECASE)
detail = re.sub(r"<[^>]+>", "", detail)
detail = html.unescape(detail).strip() or "暂无账号详细信息"
# 交易状态
trade_status = {
1: "公示中",
2: "出售中",
3: "出售中",
4: "已售出",
5: "已下架",
}.get(data.get("tradeStatus"), f"状态码 {data.get('tradeStatus', '未知')}")
# 调价记录,接口中的时间为毫秒时间戳
update_prices = data.get("updatePrices") or []
update_price_text = "\n".join(
f"{index}. {format_time(int(item.get('updateTime') or 0) // 1000)}"
f"{item.get('updatePrice', 0)}"
for index, item in enumerate(update_prices, start=1)
if isinstance(item, dict)
) or "暂无调价记录"
return_data["data"] = (
f"【万宝楼账号】\n"
f"{data.get('replyTitle') or '暂无标题'}\n\n"
f"【角色信息】\n"
f"区服:{data.get('serverName') or '未知'}\n"
f"角色:{data.get('roleName') or '未知'}\n"
f"等级:{data.get('roleLevel') or 0}\n"
f"门派:{data.get('forceName') or '未知'}\n"
f"体型:{data.get('bodyName') or '未知'}\n"
f"阵营:{data.get('campName') or '未知'}\n\n"
f"【账号数据】\n"
f"装备分数:{data.get('equipScore') or 0}\n"
f"江湖资历:{data.get('seniorityNum') or 0}\n"
f"约见次数:{data.get('meetingNum') or 0}\n"
f"关注人数:{data.get('followNum') or 0}\n\n"
f"【交易信息】\n"
f"挂牌价格:{data.get('priceNum') or 0}\n"
f"交易状态:{trade_status}\n"
f"商品编号:{data.get('id') or '未知'}\n"
f"发布时间:{format_time(data.get('replyTime') or 0)}\n\n"
f"【调价记录】\n"
f"{update_price_text}\n\n"
f"【账号详情】\n"
f"{detail}"
)
return await self._request_api(
path="/trade/wanbaolou",
params={"id": id,"token": self.token},
processor=processor,
template=""
)
async def bangzhanjilu(self, server: str) -> Dict[str, Any]:
"""帮战记录"""
async def processor(data: Any, return_data: Dict[str, Any]) -> None:
for item in data:
item["startTime"] = format_time(item["startTime"])
item["durationSeconds"] = format_remaining(item["durationSeconds"])
item["endTime"] = format_time(item["endTime"])
return_data["data"] = {
"items": data,
"server": server,
"update_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
}
return await self._request_api(
path="/battle/records",
params={"server": server},
processor=processor,
template="bangzhanjilu.html"
)
async def zhueevent(self,server: str,limit: str) -> Dict[str, Any]:
"""诛恶事件"""
async def processor(data: Any, return_data: Dict[str, Any]) -> None:
for item in data:
item["time"] = format_time(item["time"])
return_data["data"] = {
"items": data,
"update_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}
return await self._request_api(
path="/wicked/records",
params={"token": self.token, "server": server, "limit": limit},
processor=processor,
template="zhueevent.html"
)
@@ -1313,33 +1476,7 @@ class JX3APIService:
return return_data return return_data
async def shapan(self, server: str ) -> Dict[str, Any]:
"""区服沙盘"""
return_data = self._init_return_data()
# 1. 构造请求参数
params = {"serverName": server}
# 2. 调用基础请求
data: Optional[Dict[str, Any]] = await self._base_request(
"aijx3_shapan", "POST", params=params
)
if not data:
return_data["msg"] = "获取接口信息失败"
return return_data
# 3. 处理返回数据 (直接提取图片 URL)
pic_url = data.get("picUrl")
if pic_url:
return_data["data"] = pic_url
else:
return_data["msg"] = "接口未返回图片URL"
return return_data
return_data["code"] = 200
return return_data
@@ -1417,60 +1554,6 @@ class JX3APIService:
return return_data return return_data
async def zhueevent(self) -> Dict[str, Any]:
"""诛恶事件"""
return_data = self._init_return_data()
params = {"token": self.token}
data: Optional[List[Dict[str, Any]]] = await self._base_request(
"jx3_zhueevent", "GET", params=params
)
if not data or not isinstance(data, list):
return_data["msg"] = "未查询到诛恶事件信息"
return return_data
try:
items = []
for item in data:
if not isinstance(item, dict):
continue
event_time = item.get("time")
if event_time:
try:
item["time"] = datetime.fromtimestamp(int(event_time)).strftime("%Y-%m-%d %H:%M:%S")
except (TypeError, ValueError, OSError):
item["time"] = str(event_time)
else:
item["time"] = ""
items.append(item)
if not items:
return_data["msg"] = "未查询到诛恶事件信息"
return return_data
return_data["data"] = {
"items": items,
"update_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}
except Exception as e:
logger.error(f"处理诛恶事件数据失败: {e}")
return_data["msg"] = "处理诛恶事件数据失败"
return return_data
try:
return_data["temp"] = await load_template("zhueevent.html")
except FileNotFoundError as e:
logger.error(f"加载模板失败: {e}")
return_data["msg"] = "系统错误:模板文件不存在"
return return_data
return_data["code"] = 200
return return_data
@@ -1488,84 +1571,8 @@ class JX3APIService:
async def bangzhanjilu(self, server: str) -> Dict[str, Any]:
"""帮战记录"""
return_data = self._init_return_data()
params = {
"server": server,
"token": self.token,
}
data: Optional[List[Dict[str, Any]]] = await self._base_request(
"jx3_bangzhanjilu", "GET", params=params
)
if not data or not isinstance(data, list):
return_data["msg"] = "未查询到帮战记录"
return return_data
try:
def format_time(value: Any) -> str:
if not value:
return ""
try:
return datetime.fromtimestamp(int(value)).strftime("%Y-%m-%d %H:%M:%S")
except (TypeError, ValueError, OSError):
return str(value)
def format_duration(value: Any) -> str:
if value in (None, ""):
return ""
try:
seconds = max(0, int(value))
except (TypeError, ValueError):
return str(value)
hours = seconds // 3600
minutes = (seconds % 3600) // 60
secs = seconds % 60
return f"{hours}{minutes:02d}{secs:02d}"
items = []
for item in data:
if not isinstance(item, dict):
continue
items.append({
"zoneName": item.get("zoneName", ""),
"serverName": item.get("serverName", ""),
"declaringTongName": item.get("declaringTongName", ""),
"acceptingTongName": item.get("acceptingTongName", ""),
"startTime": format_time(item.get("startTime")),
"matchDuration": format_duration(item.get("matchDuration")),
"endTime": format_time(item.get("endTime")),
})
if not items:
return_data["msg"] = "未查询到帮战记录"
return return_data
return_data["data"] = {
"items": items,
"server": server,
"update_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
}
except Exception as e:
logger.error(f"处理帮战记录数据失败: {e}")
return_data["msg"] = "处理帮战记录数据失败"
return return_data
try:
return_data["temp"] = await load_template("bangzhanjilu.html")
except FileNotFoundError as e:
logger.error(f"加载模板失败: {e}")
return_data["msg"] = "系统错误:模板文件不存在"
return return_data
return_data["code"] = 200
return return_data
async def tongzhanyy(self, server: str) -> Dict[str, Any]: async def tongzhanyy(self, server: str) -> Dict[str, Any]:
@@ -2626,65 +2633,9 @@ class JX3APIService:
async def jinjia(self, server: str, limit:str) -> Dict[str, Any]:
"""区服金价"""
return_data = self._init_return_data()
params = {"server": server, "limit": limit, "token": self.token}
data_list: Optional[List[Dict[str, Any]]] = await self._base_request("jx3_jinjia", "GET", params=params)
if not data_list or not isinstance(data_list, list):
return_data["msg"] = "获取接口信息失败或数据格式错误"
return return_data
# 加载模板
try:
return_data["temp"] = await load_template("jinjia.html")
except FileNotFoundError as e:
logger.error(f"加载模板失败: {e}")
return_data["msg"] = "系统错误:模板文件不存在"
return return_data
# 准备模板渲染数据
try:
return_data["data"]["items"] = data_list
except Exception as e:
logger.error(f"模板数据准备失败: {e}")
return_data["msg"] = "系统错误:模板渲染数据准备失败"
return return_data
return_data["code"] = 200
return return_data
async def wujia(self, Name: str, server:str) -> Dict[str, Any]:
"""物价查询"""
return_data = self._init_return_data()
# 2. 确定外观名称和 ID
params_search = {"name": Name,"token": self.token, "server": server}
search_data: Optional[Dict[str, Any]] = await self._base_request("jx3_wujia", "GET", params=params_search)
if not search_data:
return_data["msg"] = "未找到该外观"
return return_data
return_data["data"] = search_data
# 5. 加载模板
try:
return_data["temp"] = await load_template("wujia.html")
return_data["code"] = 200
except FileNotFoundError as e:
logger.error(f"加载模板失败: {e}")
return_data["msg"] = "系统错误:模板文件不存在"
return return_data
return return_data
async def jiaoyihang(self, name: str , server: str) -> Dict[str, Any]: async def jiaoyihang(self, name: str , server: str) -> Dict[str, Any]:
+38 -16
View File
@@ -7,6 +7,7 @@ from astrbot.core.utils.session_waiter import (
) )
from .jx3api_data import JX3APIService from .jx3api_data import JX3APIService
from .aijx3_data import AIJX3Service
from .async_task import AsyncTask from .async_task import AsyncTask
from .bilei_data import BiLeidata from .bilei_data import BiLeidata
@@ -36,9 +37,10 @@ class MessageBuilder:
"18:剑侠录总览" "18:剑侠录总览"
) )
def __init__(self, server: str, jx3api: JX3APIService, bilei: BiLeidata, jx3at: AsyncTask, icons: dict[str, dict[str, str]]): def __init__(self, server: str, jx3api: JX3APIService, aijx3: AIJX3Service,bilei: BiLeidata, jx3at: AsyncTask, icons: dict[str, dict[str, str]]):
self.server = server self.server = server
self.jx3api = jx3api self.jx3api = jx3api
self.aijx3 = aijx3
self.bilei = bilei self.bilei = bilei
self.jx3at = jx3at self.jx3at = jx3at
self.icons = icons self.icons = icons
@@ -419,6 +421,36 @@ class MessageBuilder:
""" 的卢 服务器""" """ 的卢 服务器"""
return await self.T2I_image_msg(event, lambda: self.jx3api.dilujilu(server)) return await self.T2I_image_msg(event, lambda: self.jx3api.dilujilu(server))
async def jinjia(self, event: AstrMessageEvent,server: str , limit:str = "15"):
""" 金价 服务器"""
return await self.T2I_image_msg(event, lambda: self.jx3api.jinjia( server,limit))
async def wujia(self, event: AstrMessageEvent,Name: str , server: str = ""):
""" 物价 外观名称 服务器"""
return await self.T2I_image_msg(event, lambda: self.jx3api.wujia(Name, server))
async def chengbeng(self, event: AstrMessageEvent, server: str ,Name: str ,source : int = 0):
""" 成本 服务器 物品名称 """
return await self.T2I_image_msg(event, lambda: self.jx3api.chengbeng(Name, server,source))
async def kanhao(self, event: AstrMessageEvent,id: str):
""" 看号 万宝楼编号 """
return await self.plain_msg(event, lambda: self.jx3api.bianhao(id))
async def bangzhanjilu(self, event: AstrMessageEvent, server: str):
""" 帮战 服务器"""
return await self.T2I_image_msg(event, lambda: self.jx3api.bangzhanjilu(server))
async def shapan(self, event: AstrMessageEvent,server: str = ""):
""" 沙盘 服务器"""
return await self.image_msg(event, lambda: self.aijx3.shapan(server))
async def zhueevent(self, event: AstrMessageEvent, server: str):
""" 诛恶事件 服务器"""
return await self.T2I_image_msg(event, lambda: self.jx3api.zhueevent(server,20))
async def keju(self, event: AstrMessageEvent,subject: str, limit: int = 5): async def keju(self, event: AstrMessageEvent,subject: str, limit: int = 5):
""" 科举""" """ 科举"""
@@ -516,9 +548,7 @@ class MessageBuilder:
return await self.plain_msg(event, self.jx3api.jiemi) return await self.plain_msg(event, self.jx3api.jiemi)
async def shapan(self, event: AstrMessageEvent,server: str = ""):
""" 沙盘 服务器"""
return await self.image_msg(event, lambda: self.jx3api.shapan(self.serverdefault(server)))
async def baizhan(self, event: AstrMessageEvent): async def baizhan(self, event: AstrMessageEvent):
@@ -531,9 +561,6 @@ class MessageBuilder:
return await self.plain_msg(event, lambda: self.jx3api.fuyaojjiutian( self.serverdefault(server))) return await self.plain_msg(event, lambda: self.jx3api.fuyaojjiutian( self.serverdefault(server)))
async def zhueevent(self, event: AstrMessageEvent):
""" 诛恶事件"""
return await self.T2I_image_msg(event, self.jx3api.zhueevent)
@@ -546,9 +573,8 @@ class MessageBuilder:
async def bangzhanjilu(self, event: AstrMessageEvent, server: str = ""):
""" 帮战记录 服务器"""
return await self.T2I_image_msg(event, lambda: self.jx3api.bangzhanjilu(self.serverdefault(server)))
async def tongzhanyy(self, event: AstrMessageEvent, server: str = ""): async def tongzhanyy(self, event: AstrMessageEvent, server: str = ""):
@@ -650,14 +676,10 @@ class MessageBuilder:
async def jinjia(self, event: AstrMessageEvent,server: str = "", limit:str = "15"):
""" 金价 服务器"""
return await self.T2I_image_msg(event, lambda: self.jx3api.jinjia( self.serverdefault(server),limit))
async def wujia(self, event: AstrMessageEvent,Name: str = "秃盒", server: str = ""):
""" 物价 外观名称"""
return await self.T2I_image_msg(event, lambda: self.jx3api.wujia(Name, self.serverdefault(server)))
async def jiaoyihang(self, event: AstrMessageEvent,Name: str = "守缺式",server: str = ""): async def jiaoyihang(self, event: AstrMessageEvent,Name: str = "守缺式",server: str = ""):
+18 -6
View File
@@ -9,6 +9,7 @@ from astrbot.api import AstrBotConfig
from .core.sqlite import AsyncSQLiteDB from .core.sqlite import AsyncSQLiteDB
from .core.jx3api_data import JX3APIService from .core.jx3api_data import JX3APIService
from .core.aijx3_data import AIJX3Service
from .core.async_task import AsyncTask from .core.async_task import AsyncTask
from .core.bilei_data import BiLeidata from .core.bilei_data import BiLeidata
from .core.message import MessageBuilder from .core.message import MessageBuilder
@@ -86,6 +87,9 @@ class Jx3ApiPlugin(Star):
if self.jx3api: if self.jx3api:
await self.jx3api.close() await self.jx3api.close()
if self.aijx3:
await self.aijx3.close()
if self.local_sql_db: if self.local_sql_db:
await self.local_sql_db.close() await self.local_sql_db.close()
@@ -144,8 +148,9 @@ class Jx3ApiPlugin(Star):
# 剑网三功能实例化 # 剑网三功能实例化
self.bilei = BiLeidata(self.local_sql_db) self.bilei = BiLeidata(self.local_sql_db)
self.jx3api = JX3APIService(self.conf, self.plugin_sql_db, self.local_sql_db) self.jx3api = JX3APIService(self.conf, self.plugin_sql_db, self.local_sql_db)
self.aijx3 = AIJX3Service(self.conf, self.plugin_sql_db, self.local_sql_db)
self.jx3at = AsyncTask(cast(Context, self.context), self.conf, self.jx3api, self.local_sql_db) self.jx3at = AsyncTask(cast(Context, self.context), self.conf, self.jx3api, self.local_sql_db)
self.jx3cmd = MessageBuilder(self.server, self.jx3api, self.bilei, self.jx3at, self.icons) self.jx3cmd = MessageBuilder(self.server, self.jx3api, self.aijx3, self.bilei, self.jx3at, self.icons)
async def init_bilei_data(self): async def init_bilei_data(self):
@@ -233,6 +238,13 @@ class Jx3ApiPlugin(Star):
"试炼排行": self. jx3cmd.shilianpaixing, "试炼排行": self. jx3cmd.shilianpaixing,
"阵营拍卖": self. jx3cmd.zhengyingpaimai, "阵营拍卖": self. jx3cmd.zhengyingpaimai,
"的卢": self. jx3cmd.dilujilu, "的卢": self. jx3cmd.dilujilu,
"金价": self. jx3cmd.jinjia,
"物价": self. jx3cmd.wujia,
"成本": self. jx3cmd.chengbeng,
"看号": self. jx3cmd.kanhao,
"帮战": self. jx3cmd.bangzhanjilu,
"沙盘": self. jx3cmd.shapan,
"诛恶": self. jx3cmd.zhueevent,
"科举": self. jx3cmd.keju, "科举": self. jx3cmd.keju,
@@ -255,17 +267,17 @@ class Jx3ApiPlugin(Star):
"骚话": self. jx3cmd.shaohua, "骚话": self. jx3cmd.shaohua,
"资历": self. jx3cmd.zili, "资历": self. jx3cmd.zili,
"解密": self. jx3cmd.jiemi, "解密": self. jx3cmd.jiemi,
"沙盘": self. jx3cmd.shapan,
"攻略": self. jx3cmd.qiyugonglue, "攻略": self. jx3cmd.qiyugonglue,
"": self. jx3cmd.hong, "": self. jx3cmd.hong,
"配装": self. jx3cmd.peizhuang, "配装": self. jx3cmd.peizhuang,
"百战": self. jx3cmd.baizhan, "百战": self. jx3cmd.baizhan,
"扶摇": self. jx3cmd.fuyaojjiutian, "扶摇": self. jx3cmd.fuyaojjiutian,
"诛恶": self. jx3cmd.zhueevent,
"帮战记录": self. jx3cmd.bangzhanjilu,
"统战": self. jx3cmd.tongzhanyy, "统战": self. jx3cmd.tongzhanyy,
@@ -286,8 +298,8 @@ class Jx3ApiPlugin(Star):
"所有名片": self. jx3cmd.shuoyoumingpian, "所有名片": self. jx3cmd.shuoyoumingpian,
"随机名片": self. jx3cmd.shuijimingpian, "随机名片": self. jx3cmd.shuijimingpian,
"金价": self. jx3cmd.jinjia,
"物价": self. jx3cmd.wujia,
"八卦": self. jx3cmd.bagua, "八卦": self. jx3cmd.bagua,
"交易行": self. jx3cmd.jiaoyihang, "交易行": self. jx3cmd.jiaoyihang,
"贴吧物价": self. jx3cmd.tiebawujia, "贴吧物价": self. jx3cmd.tiebawujia,
+3 -7
View File
@@ -104,8 +104,6 @@
<table> <table>
<thead> <thead>
<tr> <tr>
<th>区服</th>
<th>服务器</th>
<th>宣战帮会</th> <th>宣战帮会</th>
<th>应战帮会</th> <th>应战帮会</th>
<th>开始时间</th> <th>开始时间</th>
@@ -117,12 +115,10 @@
<tbody> <tbody>
{% for item in items %} {% for item in items %}
<tr> <tr>
<td class="zone-col">{{ item.zoneName }}</td> <td class="tong-col">{{ item.declaringName }}</td>
<td class="server-col">{{ item.serverName }}</td> <td class="tong-col">{{ item.acceptingName }}</td>
<td class="tong-col">{{ item.declaringTongName }}</td>
<td class="tong-col">{{ item.acceptingTongName }}</td>
<td class="time-col">{{ item.startTime }}</td> <td class="time-col">{{ item.startTime }}</td>
<td class="duration-col">{{ item.matchDuration }}</td> <td class="duration-col">{{ item.durationSeconds }}</td>
<td class="time-col">{{ item.endTime }}</td> <td class="time-col">{{ item.endTime }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
File diff suppressed because it is too large Load Diff
+434 -75
View File
@@ -2,9 +2,15 @@
<html lang="zh-CN"> <html lang="zh-CN">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ name }} - 万宝楼行情</title> <title>{{ name }} - 万宝楼行情</title>
<style> <style>
* {
box-sizing: border-box;
}
body { body {
font-family: "Microsoft YaHei", Arial, sans-serif; font-family: "Microsoft YaHei", Arial, sans-serif;
background: #f1f2f6; background: #f1f2f6;
@@ -22,26 +28,31 @@
h1 { h1 {
font-size: 32px; font-size: 32px;
font-weight: 800; font-weight: 800;
margin-bottom: 12px; margin: 0 0 12px;
} }
.goods-image { .goods-image {
display: block;
width: 100%; width: 100%;
border-radius: 16px; border-radius: 16px;
box-shadow: 0 6px 24px rgba(0,0,0,0.12); box-shadow: 0 6px 24px rgba(0, 0, 0, 0.12);
margin-bottom: 14px; margin-bottom: 14px;
} }
.goods-desc { .goods-desc {
font-size: 16px; font-size: 16px;
line-height: 1.8;
color: #444; color: #444;
margin-bottom: 10px; margin: 0 0 10px;
text-align: left;
} }
.meta-row { .meta-row {
display: flex; display: flex;
justify-content: center; justify-content: center;
gap: 40px; align-items: center;
flex-wrap: wrap;
gap: 20px 40px;
font-size: 18px; font-size: 18px;
margin-bottom: 30px; margin-bottom: 30px;
} }
@@ -53,12 +64,14 @@
.table-wrapper { .table-wrapper {
display: grid; display: grid;
grid-template-columns: repeat(3, 1fr); grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 20px; gap: 20px;
align-items: start;
} }
.table-card { .table-card {
width: 100%; width: 100%;
min-width: 0;
} }
.table-title { .table-title {
@@ -66,15 +79,21 @@
font-weight: 700; font-weight: 700;
margin-bottom: 8px; margin-bottom: 8px;
text-align: center; text-align: center;
color: #d93939;
}
.table-scroll {
width: 100%;
overflow-x: auto;
border-radius: 12px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
} }
table { table {
width: 100%; width: 100%;
min-width: 420px;
border-collapse: collapse; border-collapse: collapse;
background: #ffffff; background: #ffffff;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 4px 16px rgba(0,0,0,0.08);
text-align: left; text-align: left;
} }
@@ -84,10 +103,20 @@
font-size: 16px; font-size: 16px;
} }
th, td { th,
td {
padding: 12px 10px; padding: 12px 10px;
border-bottom: 1px solid #eee; border-bottom: 1px solid #eeeeee;
font-size: 15px; font-size: 15px;
white-space: nowrap;
}
th {
font-weight: 700;
}
tbody tr:last-child td {
border-bottom: none;
} }
tbody tr:hover { tbody tr:hover {
@@ -103,100 +132,289 @@
font-weight: 700; font-weight: 700;
} }
.empty-row {
height: 80px;
padding: 28px 10px;
text-align: center;
color: #999999;
font-weight: 400;
}
/* ===== 万宝楼公示(蓝色) ===== */ /* ===== 万宝楼公示(蓝色) ===== */
.table-card.notice .table-title { .table-card.notice .table-title {
color: #1e6bd6; color: #1e6bd6;
} }
.table-card.notice .price-col { .table-card.notice .price-col {
color: #1e6bd6; color: #1e6bd6;
} }
.table-card.notice thead { .table-card.notice thead {
background: #1e6bd6; background: #1e6bd6;
} }
/* ===== 万宝楼在售(绿色) ===== */ /* ===== 万宝楼在售(绿色) ===== */
.table-card.sale .table-title { .table-card.sale .table-title {
color: #2e8b57; color: #2e8b57;
} }
.table-card.sale .price-col { .table-card.sale .price-col {
color: #2e8b57; color: #2e8b57;
} }
.table-card.sale thead { .table-card.sale thead {
background: #2e8b57; background: #2e8b57;
} }
/* ===== 查询区服(紫色) ===== */
.table-card.query .table-title {
color: #8a4fd3;
}
.table-card.query .price-col {
color: #8a4fd3;
}
.table-card.query thead {
background: #8a4fd3;
}
@media (max-width: 1100px) {
.table-wrapper {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (max-width: 720px) {
body {
padding: 12px;
}
h1 {
font-size: 24px;
}
.goods-desc {
font-size: 14px;
}
.meta-row {
gap: 12px 20px;
font-size: 16px;
}
.table-wrapper {
grid-template-columns: 1fr;
}
}
</style> </style>
</head> </head>
<body> <body>
{#
先根据分组名称识别对应数据。
查询区服不固定使用 list[3]:
除电信区、双线区、无界区、公示期、出售期外,
其他分组都视为查询区服。
即使某个分组不存在,对应表格区域仍然会显示。
#}
{% set ns = namespace(
notice=none,
sale=none,
query=none,
telecom=none,
dual=none,
boundless=none
) %}
{% for group in list %}
{% if group.name == "公示期" %}
{% set ns.notice = group %}
{% elif group.name == "出售期" %}
{% set ns.sale = group %}
{% elif group.name == "电信区" %}
{% set ns.telecom = group %}
{% elif group.name == "双线区" %}
{% set ns.dual = group %}
{% elif group.name == "无界区" %}
{% set ns.boundless = group %}
{% elif ns.query is none %}
{% set ns.query = group %}
{% endif %}
{% endfor %}
<div class="container"> <div class="container">
<h1>{{ name }} ({{ alias }})</h1> <h1>
{{ name }}
{% if alias %}
{{ alias }}
{% endif %}
</h1>
<img src="{{ view }}" alt="{{ name }}" class="goods-image"> {% if view %}
<img
src="{{ view }}"
alt="{{ name }}"
class="goods-image"
>
{% endif %}
{% if desc %}
<p class="goods-desc">{{ desc }}</p> <p class="goods-desc">{{ desc }}</p>
{% endif %}
<div class="meta-row"> <div class="meta-row">
<span>分类:{{ category }}</span>
<span>发售时间:{{ date }}</span> <span>发售时间:{{ date }}</span>
<span class="price">参考价格:{{ cost }} 元</span> <span class="price">参考价格:{{ retail }} 元</span>
</div> </div>
<div class="table-wrapper"> <div class="table-wrapper">
<!-- 1 万宝楼公示 --> <!-- ==================================================
1. 万宝楼公示
区域始终保留
=================================================== -->
<div class="table-card notice"> <div class="table-card notice">
<div class="table-title">万宝楼公示</div> <div class="table-title">万宝楼公示</div>
<div class="table-scroll">
<table> <table>
<thead> <thead>
<tr> <tr>
<th>时间</th> <th>时间</th>
<th>区服</th>
<th>服务器</th> <th>服务器</th>
<th>价格</th> <th>价格</th>
<th>状态</th> <th>状态</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for item in list[3] %} {% if ns.notice and ns.notice.list %}
{% for item in ns.notice.list %}
<tr> <tr>
<td class="server-col">{{ item.date }}</td> <td>{{ item.date }}</td>
<td class="server-col">{{ item.server }}</td>
<td class="price-col">{{ item.value }}</td> <td>{{ item.zone }}</td>
<td class="server-col">公示</td>
<td class="server-col">
{{ item.server }}
</td>
<td class="price-col">
{{ item.value }} 元
</td>
<td class="server-col">
公示
</td>
</tr> </tr>
{% endfor %} {% endfor %}
{% else %}
<tr>
<td colspan="5" class="empty-row">
暂无公示数据
</td>
</tr>
{% endif %}
</tbody> </tbody>
</table> </table>
</div> </div>
</div>
<!-- ==================================================
2. 万宝楼在售
区域始终保留
=================================================== -->
<!-- 2 万宝楼在售 -->
<div class="table-card sale"> <div class="table-card sale">
<div class="table-title">万宝楼在售</div> <div class="table-title">万宝楼在售</div>
<div class="table-scroll">
<table> <table>
<thead> <thead>
<tr> <tr>
<th>时间</th> <th>时间</th>
<th>区服</th>
<th>服务器</th> <th>服务器</th>
<th>价格</th> <th>价格</th>
<th>状态</th> <th>状态</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for item in list[4] %} {% if ns.sale and ns.sale.list %}
{% for item in ns.sale.list %}
<tr> <tr>
<td class="server-col">{{ item.date }}</td> <td>{{ item.date }}</td>
<td class="server-col">{{ item.server }}</td>
<td class="price-col">{{ item.value }}</td> <td>{{ item.zone }}</td>
<td class="server-col">在售</td>
<td class="server-col">
{{ item.server }}
</td>
<td class="price-col">
{{ item.value }} 元
</td>
<td class="server-col">
在售
</td>
</tr> </tr>
{% endfor %} {% endfor %}
{% else %}
<tr>
<td colspan="5" class="empty-row">
暂无在售数据
</td>
</tr>
{% endif %}
</tbody> </tbody>
</table> </table>
</div> </div>
</div>
<!-- 3 查询区服 -->
<div class="table-card"> <!-- ==================================================
<div class="table-title">查询区服</div> 3. 查询区服
没有查询区服时,表格仍然保留
=================================================== -->
<div class="table-card query">
<div class="table-title">
查询区服
{% if ns.query %}
{{ ns.query.name }}
{% endif %}
</div>
<div class="table-scroll">
<table> <table>
<thead> <thead>
<tr> <tr>
@@ -206,31 +424,68 @@
<th>状态</th> <th>状态</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for item in list[5] %} {% if ns.query and ns.query.list %}
{% for item in ns.query.list %}
<tr> <tr>
<td class="server-col">{{ item.date }}</td> <td>{{ item.date }}</td>
<td class="server-col">{{ item.server }}</td>
<td class="price-col">{{ item.value }}</td>
<td class="server-col"> <td class="server-col">
{% if item.source == 1 %}出售 {{ item.server }}
{% elif item.source == 2 %}收购 </td>
{% elif item.source == 3 %}想出
{% elif item.source == 4 %}想收 <td class="price-col">
{% elif item.source == 5 %}成交 {{ item.value }} 元
{% elif item.source == 6 %}正出 </td>
{% else %}未知
<td class="server-col">
{% if item.sale == 1 %}
出售
{% elif item.sale == 2 %}
收购
{% elif item.sale == 3 %}
想出
{% elif item.sale == 4 %}
想收
{% elif item.sale == 5 %}
成交
{% elif item.sale == 6 %}
正出
{% elif item.sale == 7 %}
公示
{% else %}
未知
{% endif %} {% endif %}
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
{% else %}
<tr>
<td colspan="4" class="empty-row">
暂无查询区服数据
</td>
</tr>
{% endif %}
</tbody> </tbody>
</table> </table>
</div> </div>
</div>
<!-- ==================================================
4. 电信区
区域始终保留
=================================================== -->
<!-- 4 电信区 -->
<div class="table-card"> <div class="table-card">
<div class="table-title">电信区</div> <div class="table-title">电信区</div>
<div class="table-scroll">
<table> <table>
<thead> <thead>
<tr> <tr>
@@ -240,31 +495,68 @@
<th>状态</th> <th>状态</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for item in list[0] %} {% if ns.telecom and ns.telecom.list %}
{% for item in ns.telecom.list %}
<tr> <tr>
<td class="server-col">{{ item.date }}</td> <td>{{ item.date }}</td>
<td class="server-col">{{ item.server }}</td>
<td class="price-col">{{ item.value }}</td>
<td class="server-col"> <td class="server-col">
{% if item.source == 1 %}出售 {{ item.server }}
{% elif item.source == 2 %}收购 </td>
{% elif item.source == 3 %}想出
{% elif item.source == 4 %}想收 <td class="price-col">
{% elif item.source == 5 %}成交 {{ item.value }} 元
{% elif item.source == 6 %}正出 </td>
{% else %}未知
<td class="server-col">
{% if item.sale == 1 %}
出售
{% elif item.sale == 2 %}
收购
{% elif item.sale == 3 %}
想出
{% elif item.sale == 4 %}
想收
{% elif item.sale == 5 %}
成交
{% elif item.sale == 6 %}
正出
{% elif item.sale == 7 %}
公示
{% else %}
未知
{% endif %} {% endif %}
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
{% else %}
<tr>
<td colspan="4" class="empty-row">
暂无电信区数据
</td>
</tr>
{% endif %}
</tbody> </tbody>
</table> </table>
</div> </div>
</div>
<!-- ==================================================
5. 双线区
区域始终保留
=================================================== -->
<!-- 5 双线区 -->
<div class="table-card"> <div class="table-card">
<div class="table-title">双线区</div> <div class="table-title">双线区</div>
<div class="table-scroll">
<table> <table>
<thead> <thead>
<tr> <tr>
@@ -274,31 +566,68 @@
<th>状态</th> <th>状态</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for item in list[1] %} {% if ns.dual and ns.dual.list %}
{% for item in ns.dual.list %}
<tr> <tr>
<td class="server-col">{{ item.date }}</td> <td>{{ item.date }}</td>
<td class="server-col">{{ item.server }}</td>
<td class="price-col">{{ item.value }}</td>
<td class="server-col"> <td class="server-col">
{% if item.source == 1 %}出售 {{ item.server }}
{% elif item.source == 2 %}收购 </td>
{% elif item.source == 3 %}想出
{% elif item.source == 4 %}想收 <td class="price-col">
{% elif item.source == 5 %}成交 {{ item.value }} 元
{% elif item.source == 6 %}正出 </td>
{% else %}未知
<td class="server-col">
{% if item.sale == 1 %}
出售
{% elif item.sale == 2 %}
收购
{% elif item.sale == 3 %}
想出
{% elif item.sale == 4 %}
想收
{% elif item.sale == 5 %}
成交
{% elif item.sale == 6 %}
正出
{% elif item.sale == 7 %}
公示
{% else %}
未知
{% endif %} {% endif %}
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
{% else %}
<tr>
<td colspan="4" class="empty-row">
暂无双线区数据
</td>
</tr>
{% endif %}
</tbody> </tbody>
</table> </table>
</div> </div>
</div>
<!-- ==================================================
6. 无界区
区域始终保留
=================================================== -->
<!-- 6 无界区 -->
<div class="table-card"> <div class="table-card">
<div class="table-title">无界区</div> <div class="table-title">无界区</div>
<div class="table-scroll">
<table> <table>
<thead> <thead>
<tr> <tr>
@@ -308,27 +637,57 @@
<th>状态</th> <th>状态</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for item in list[2] %} {% if ns.boundless and ns.boundless.list %}
{% for item in ns.boundless.list %}
<tr> <tr>
<td class="server-col">{{ item.date }}</td> <td>{{ item.date }}</td>
<td class="server-col">{{ item.server }}</td>
<td class="price-col">{{ item.value }}</td>
<td class="server-col"> <td class="server-col">
{% if item.source == 1 %}出售 {{ item.server }}
{% elif item.source == 2 %}收购 </td>
{% elif item.source == 3 %}想出
{% elif item.source == 4 %}想收 <td class="price-col">
{% elif item.source == 5 %}成交 {{ item.value }} 元
{% elif item.source == 6 %}正出 </td>
{% else %}未知
<td class="server-col">
{% if item.sale == 1 %}
出售
{% elif item.sale == 2 %}
收购
{% elif item.sale == 3 %}
想出
{% elif item.sale == 4 %}
想收
{% elif item.sale == 5 %}
成交
{% elif item.sale == 6 %}
正出
{% elif item.sale == 7 %}
公示
{% else %}
未知
{% endif %} {% endif %}
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
{% else %}
<tr>
<td colspan="4" class="empty-row">
暂无无界区数据
</td>
</tr>
{% endif %}
</tbody> </tbody>
</table> </table>
</div> </div>
</div>
</div> </div>
+1 -1
View File
@@ -104,7 +104,7 @@
{% for item in items %} {% for item in items %}
<tr> <tr>
<td class="server-col">{{ item.server }}</td> <td class="server-col">{{ item.server }}</td>
<td class="map-col">{{ item.map_name }}</td> <td class="map-col">{{ item.mapName }}</td>
<td class="time-col">{{ item.time }}</td> <td class="time-col">{{ item.time }}</td>
</tr> </tr>
{% endfor %} {% endfor %}