11
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
def load_template(template_name):
|
||||
"""
|
||||
从模板文件加载模板内容
|
||||
|
||||
Args:
|
||||
template_name: 模板文件名(不带路径)
|
||||
|
||||
Returns:
|
||||
str: 模板内容
|
||||
"""
|
||||
# 获取模板文件路径
|
||||
plugin_dir = Path(__file__).parent.parent
|
||||
template_path = plugin_dir / "templates" / template_name
|
||||
|
||||
# 检查文件是否存在
|
||||
if not template_path.exists():
|
||||
raise FileNotFoundError(f"模板文件不存在: {template_path}")
|
||||
|
||||
# 读取模板内容
|
||||
with open(template_path, 'r', encoding='utf-8') as f:
|
||||
return f.read()
|
||||
|
||||
|
||||
def extract_field(data_list, field_name):
|
||||
"""
|
||||
从列表中的字典提取指定字段的所有值
|
||||
|
||||
Args:
|
||||
data_list (list): 数据列表,每个元素是 dict
|
||||
field_name (str): 要提取的字段名
|
||||
|
||||
Returns:
|
||||
list: 提取出来的字段值列表
|
||||
"""
|
||||
extracted_data = []
|
||||
for item in data_list:
|
||||
if field_name in item and item[field_name]:
|
||||
# 如果是 list,展开
|
||||
if isinstance(item[field_name], list):
|
||||
extracted_data.extend(item[field_name])
|
||||
else:
|
||||
extracted_data.append(item[field_name])
|
||||
return extracted_data
|
||||
+185
-3
@@ -3,11 +3,13 @@ from datetime import datetime
|
||||
from astrbot.api import logger
|
||||
|
||||
from .api_data import APIClient
|
||||
from .load_template import load_template
|
||||
from .sql_data import AsyncMySQL
|
||||
from .basic_Function import load_template, extract_field
|
||||
|
||||
class JX3Function:
|
||||
def __init__(self, api_config):
|
||||
def __init__(self, api_config,db: AsyncMySQL ):
|
||||
self.__api = APIClient()
|
||||
self.__db = db
|
||||
self.__api_config = api_config
|
||||
|
||||
async def richang(self,server: str = "眉间雪",num: int = 0):
|
||||
@@ -199,4 +201,184 @@ class JX3Function:
|
||||
return_data["msg"] = "系统错误:模板渲染数据准备失败"
|
||||
return return_data
|
||||
return_data["code"] = 200
|
||||
return return_data
|
||||
return return_data
|
||||
|
||||
|
||||
async def SearchData(self):
|
||||
return_data = {
|
||||
"code": 0,
|
||||
"msg": "功能函数未执行",
|
||||
"data": {}
|
||||
}
|
||||
#在配置文件中获取接口配置
|
||||
api_config = self.__api_config["aijx3_SearchData"]
|
||||
# 获取数据
|
||||
data = await self.__api.post(api_config["url"],api_config["params"],"data")
|
||||
if not data:
|
||||
return_data["msg"] = "获取接口信息失败"
|
||||
return return_data
|
||||
# 提取数据
|
||||
try:
|
||||
extracted_data = extract_field(data, "dataModels")
|
||||
except FileNotFoundError as e:
|
||||
logger.error(f"提取数据失败: {e}")
|
||||
return_data["msg"] = "提取指定数据字段失败"
|
||||
return return_data
|
||||
# 准备SQL和批量数据
|
||||
sql = """
|
||||
INSERT INTO searchdata
|
||||
(typeName, name, showName, picUrl, searchId, searchDescType)
|
||||
VALUES (%s, %s, %s, %s, %s, %s)
|
||||
"""
|
||||
values_list = [
|
||||
(
|
||||
item['typeName'],
|
||||
item['name'],
|
||||
item['showName'],
|
||||
item['picUrl'],
|
||||
item['searchId'],
|
||||
item['searchDescType']
|
||||
)
|
||||
for item in extracted_data
|
||||
]
|
||||
# 插入数据
|
||||
try:
|
||||
await self.__db.truncate_table("searchdata")
|
||||
await self.__db.executemany(sql, values_list)
|
||||
except FileNotFoundError as e:
|
||||
logger.error(f"数据插入失败: {e}")
|
||||
return_data["msg"] = "数据插入数据库失败"
|
||||
return return_data
|
||||
return_data["msg"] = f"成功批量插入 {len(extracted_data)} 条数据!"
|
||||
return_data["code"] = 200
|
||||
return return_data
|
||||
|
||||
|
||||
async def wujia(self,Name: str = "秃盒"):
|
||||
return_data = {
|
||||
"code": 0,
|
||||
"msg": "功能函数未执行",
|
||||
"data": {}
|
||||
}
|
||||
#在配置文件中获取接口配置
|
||||
api_config = self.__api_config["jx3box_exterior"]
|
||||
#更新参数
|
||||
api_config["params"]["keyword"] = Name
|
||||
# 获取查找信息
|
||||
data = await self.__api.get(api_config["url"],api_config["params"],"data")
|
||||
if data["total"] == 0:
|
||||
try:
|
||||
sql = "SELECT showName, searchId FROM searchdata WHERE name = %s OR showName = %s"
|
||||
sqldata = await self.__db.fetch_one(sql, (Name,Name))
|
||||
searchId=sqldata["searchId"]
|
||||
showName=sqldata["showName"]
|
||||
return_data["data"]["searchId"]=searchId
|
||||
return_data["data"]["showName"]=showName
|
||||
except Exception as e:
|
||||
logger.error(f"获取外观信息错误: {e}")
|
||||
return_data["msg"] = "未找到该外观信息"
|
||||
return return_data
|
||||
else:
|
||||
# 查询魔盒获取外观名称
|
||||
try:
|
||||
showName=data["list"][0]["name"]
|
||||
return_data["data"]["showName"]=showName
|
||||
except Exception as e:
|
||||
logger.error(f"获取外观名称错误: {e}")
|
||||
return_data["msg"] = "未找到该外观信息"
|
||||
return return_data
|
||||
# 查询爱剑三获取外观ID
|
||||
try:
|
||||
sql = "SELECT searchId FROM searchdata WHERE showName=%s"
|
||||
sqldata = await self.__db.fetch_one(sql, (return_data["data"]["showName"],))
|
||||
searchId=sqldata["searchId"]
|
||||
return_data["data"]["searchId"]=searchId
|
||||
except Exception as e:
|
||||
logger.error(f"获取外观ID错误: {e}\n{return_data['data']['showName']}")
|
||||
return_data["msg"] = "未找到该外观信息"
|
||||
return return_data
|
||||
|
||||
#在配置文件中获取接口配置
|
||||
api_config = self.__api_config["aijx3_GoodsDetail"]
|
||||
#更新参数
|
||||
api_config["params"]["goodsName"] = showName
|
||||
# 获取数据外观详细数据
|
||||
data = await self.__api.post(api_config["url"],api_config["params"],"data")
|
||||
if not data:
|
||||
return_data["msg"] = "获取外观详细数据失败"
|
||||
return return_data
|
||||
# 提取外观详细数据
|
||||
try:
|
||||
imgs = data.get("imgs", [])
|
||||
return_data["data"]["goodsDesc"]=data.get("goodsDesc", "无描述")
|
||||
return_data["data"]["publishTime"]=data.get("publishTime", "无价格")
|
||||
return_data["data"]["priceNum"]=data.get("priceNum", 0)
|
||||
return_data["data"]["goodsId"]=data.get("goodsId", "无数据")
|
||||
return_data["data"]["imgs"]=imgs[0] if imgs else ""
|
||||
return_data["data"]["goodsAlias"]=data.get("goodsAlias", "无别名")
|
||||
except Exception as e:
|
||||
logger.error(f"提取外观详细数据失败: {e}")
|
||||
return_data["msg"] = "提取外观详细数据失败"
|
||||
return return_data
|
||||
|
||||
# 查询万宝楼数据(公示和在售)
|
||||
wbl_data = await self.__get_wbl_data(searchId)
|
||||
if not wbl_data:
|
||||
return_data["msg"] = "获取万宝楼数据失败"
|
||||
return return_data
|
||||
if wbl_data:
|
||||
return_data["data"]["wblgs"]=wbl_data["wblgs"]
|
||||
return_data["data"]["wblzs"]=wbl_data["wblzs"]
|
||||
return_data["msg"] = "获取万宝楼数据完成"
|
||||
# 加载模板
|
||||
try:
|
||||
return_data["temp"] = load_template("wujia.html")
|
||||
except FileNotFoundError as e:
|
||||
logger.error(f"加载模板失败: {e}")
|
||||
return_data["msg"] = "系统错误:模板文件不存在"
|
||||
return return_data
|
||||
return_data["code"] = 200
|
||||
return return_data
|
||||
|
||||
async def __get_wbl_data(self,search_id):
|
||||
"""获取万宝楼数据(公示和在售)"""
|
||||
try:
|
||||
#在配置文件中获取接口配置
|
||||
api_config = self.__api_config["aijx3_wblwg"]
|
||||
#更新参数
|
||||
api_config["params"]["searchId"] = [search_id]
|
||||
# 获取公示数据
|
||||
api_config["params"]["tradeStatus"] = "3"
|
||||
datawblgs = await self.__api.post(api_config["url"], api_config["params"], "data")
|
||||
# 获取在售数据
|
||||
api_config["params"]["tradeStatus"] = "5"
|
||||
datawblzs = await self.__api.post(api_config["url"], api_config["params"], "data")
|
||||
|
||||
return {
|
||||
"wblgs": await self.__process_wbl_records(datawblgs.get("records", [])),
|
||||
"wblzs": await self.__process_wbl_records(datawblzs.get("records", []))
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"获取万宝楼数据出错: {e}")
|
||||
return None
|
||||
|
||||
async def __process_wbl_records(self,records):
|
||||
"""处理万宝楼记录数据"""
|
||||
processed = []
|
||||
for record in records:
|
||||
try:
|
||||
# 转换时间戳为可读格式
|
||||
timestamp = record.get("replyTime", 0)
|
||||
dt = datetime.fromtimestamp(timestamp / 1000) if timestamp else datetime.now()
|
||||
|
||||
processed.append({
|
||||
"priceNum": record.get("priceNum", 0),
|
||||
"belongQf2": record.get("belongQf2", "无数据"),
|
||||
"replyTime": dt.strftime("%Y-%m-%d %H:%M:%S"),
|
||||
"discountRate": record.get("discountRate", 0.0),
|
||||
})
|
||||
except Exception as e:
|
||||
logger.error(f"处理万宝楼记录出错: {e}")
|
||||
continue
|
||||
|
||||
return processed
|
||||
+1
-2
@@ -4,7 +4,6 @@ from urllib.parse import quote
|
||||
from datetime import datetime
|
||||
|
||||
from .api_data import api_data_get, api_data_post
|
||||
from .sql_data import sql_data_searchdata,sql_data_select
|
||||
|
||||
|
||||
def fetch_all_pages(base_url, initial_params, max_pages=None):
|
||||
@@ -204,7 +203,7 @@ def jx3_data_wujia(inname="秃盒"):
|
||||
|
||||
try:
|
||||
# 1. 获取物品ID和名称
|
||||
idname = sql_data_select(inname)
|
||||
idname = api_data_get(inname)
|
||||
if not idname:
|
||||
datas.update({"code": 201, "msg": "未找到该外观信息"})
|
||||
return datas
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
def load_template(template_name):
|
||||
"""
|
||||
从模板文件加载模板内容
|
||||
|
||||
Args:
|
||||
template_name: 模板文件名(不带路径)
|
||||
|
||||
Returns:
|
||||
str: 模板内容
|
||||
"""
|
||||
# 获取模板文件路径
|
||||
plugin_dir = Path(__file__).parent.parent
|
||||
template_path = plugin_dir / "templates" / template_name
|
||||
|
||||
# 检查文件是否存在
|
||||
if not template_path.exists():
|
||||
raise FileNotFoundError(f"模板文件不存在: {template_path}")
|
||||
|
||||
# 读取模板内容
|
||||
with open(template_path, 'r', encoding='utf-8') as f:
|
||||
return f.read()
|
||||
+57
-101
@@ -1,107 +1,63 @@
|
||||
import pymysql
|
||||
import time
|
||||
from astrbot.api import logger
|
||||
from .api_data import api_data_get, api_data_post
|
||||
import aiomysql
|
||||
|
||||
|
||||
#连接数据库配置
|
||||
db_config = {
|
||||
'host': '154.201.70.116',
|
||||
'port': 3306,
|
||||
'user': 'asrtbot',
|
||||
'password': 'qsc123456',
|
||||
'database': 'asrtbot',
|
||||
'charset': 'utf8mb4',
|
||||
'cursorclass': pymysql.cursors.DictCursor #返回字典格式数据
|
||||
}
|
||||
class AsyncMySQL:
|
||||
def __init__(self, db_config: dict):
|
||||
self.db_config = db_config
|
||||
self.pool = None
|
||||
|
||||
# 提取所有 dataModels 中的数据
|
||||
def extract_data_models(source_data):
|
||||
extracted_data = []
|
||||
for category in source_data:
|
||||
if "dataModels" in category and category["dataModels"]:
|
||||
extracted_data.extend(category["dataModels"])
|
||||
return extracted_data
|
||||
async def init_pool(self):
|
||||
"""初始化连接池"""
|
||||
if self.pool is None:
|
||||
self.pool = await aiomysql.create_pool(**self.db_config)
|
||||
|
||||
# 获取并存储搜索数据
|
||||
def sql_data_searchdata():
|
||||
# 接口配置
|
||||
custom_url = "https://www.aijx3.cn/api2/aijx3-wblwg/basedata/getSearchData"
|
||||
params = {}
|
||||
|
||||
try:
|
||||
# 获取数据
|
||||
source_data = api_data_post(custom_url, params, "data")
|
||||
if not source_data:
|
||||
return "获取数据失败或数据为空"
|
||||
|
||||
# 处理数据
|
||||
extracted_data = extract_data_models(source_data)
|
||||
if not extracted_data: # 修正:应该是extracted_data而不是source_data
|
||||
return "未提取到数据"
|
||||
|
||||
# 连接数据库并插入数据
|
||||
with pymysql.connect(**db_config) as connection:
|
||||
with connection.cursor() as cursor:
|
||||
# 清空表数据
|
||||
cursor.execute("TRUNCATE TABLE searchdata")
|
||||
|
||||
# 准备SQL和批量数据
|
||||
sql = """
|
||||
INSERT INTO searchdata
|
||||
(typeName, name, showName, picUrl, searchId, searchDescType)
|
||||
VALUES (%s, %s, %s, %s, %s, %s)
|
||||
"""
|
||||
|
||||
# 使用列表推导式简化数据准备
|
||||
values_list = [
|
||||
(
|
||||
item['typeName'],
|
||||
item['name'],
|
||||
item['showName'],
|
||||
item['picUrl'],
|
||||
item['searchId'],
|
||||
item['searchDescType']
|
||||
)
|
||||
for item in extracted_data
|
||||
]
|
||||
|
||||
# 批量插入
|
||||
cursor.executemany(sql, values_list)
|
||||
connection.commit()
|
||||
|
||||
return f"成功批量插入 {len(extracted_data)} 条数据!"
|
||||
|
||||
except pymysql.Error as e:
|
||||
return f"数据库操作失败: {e}"
|
||||
except Exception as e:
|
||||
return f"操作失败: {e}"
|
||||
async def close_pool(self):
|
||||
"""关闭连接池"""
|
||||
if self.pool:
|
||||
self.pool.close()
|
||||
await self.pool.wait_closed()
|
||||
self.pool = None
|
||||
|
||||
# 根据搜索字符串查询匹配的数据
|
||||
def sql_data_select(search_string):
|
||||
"""
|
||||
根据搜索字符串查询匹配的数据
|
||||
|
||||
Args:
|
||||
search_string: 搜索字符串
|
||||
|
||||
Returns:
|
||||
匹配的第一条记录,如果没有匹配则返回None
|
||||
"""
|
||||
try:
|
||||
with pymysql.connect(**db_config) as connection:
|
||||
with connection.cursor() as cursor:
|
||||
sql = """
|
||||
SELECT searchId, showName, name
|
||||
FROM searchdata
|
||||
WHERE name = %s OR showName = %s
|
||||
LIMIT 1
|
||||
"""
|
||||
params = (search_string, search_string)
|
||||
async def fetch_one(self, sql: str, params=None):
|
||||
"""查询单条数据"""
|
||||
await self.init_pool()
|
||||
async with self.pool.acquire() as conn:
|
||||
async with conn.cursor(aiomysql.DictCursor) as cursor:
|
||||
await cursor.execute(sql, params or ())
|
||||
return await cursor.fetchone()
|
||||
|
||||
cursor.execute(sql, params)
|
||||
return cursor.fetchone()
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"查询数据时出错: {e}")
|
||||
return None
|
||||
async def fetch_all(self, sql: str, params=None):
|
||||
"""查询多条数据"""
|
||||
await self.init_pool()
|
||||
async with self.pool.acquire() as conn:
|
||||
async with conn.cursor(aiomysql.DictCursor) as cursor:
|
||||
await cursor.execute(sql, params or ())
|
||||
return await cursor.fetchall()
|
||||
|
||||
async def execute(self, sql: str, params=None):
|
||||
"""执行单条 SQL(insert/update/delete)"""
|
||||
await self.init_pool()
|
||||
async with self.pool.acquire() as conn:
|
||||
async with conn.cursor() as cursor:
|
||||
await cursor.execute(sql, params or ())
|
||||
await conn.commit()
|
||||
return cursor.rowcount
|
||||
|
||||
async def executemany(self, sql: str, params_list):
|
||||
"""批量执行 SQL"""
|
||||
await self.init_pool()
|
||||
async with self.pool.acquire() as conn:
|
||||
async with conn.cursor() as cursor:
|
||||
await cursor.executemany(sql, params_list)
|
||||
await conn.commit()
|
||||
return cursor.rowcount
|
||||
|
||||
async def truncate_table(self, table_name: str):
|
||||
"""清空指定表的内容"""
|
||||
await self.init_pool()
|
||||
async with self.pool.acquire() as conn:
|
||||
async with conn.cursor() as cursor:
|
||||
sql = f"TRUNCATE TABLE `{table_name}`"
|
||||
await cursor.execute(sql)
|
||||
await conn.commit()
|
||||
return True
|
||||
|
||||
Reference in New Issue
Block a user