🎨 将文本内容同一更新

🐛 修复偷菜无法正常计算的BUG
This commit is contained in:
2025-06-06 10:56:22 +08:00
parent ba2ecf19fc
commit ac13ab9280
20 changed files with 1284 additions and 699 deletions
+12 -8
View File
@@ -1,4 +1,3 @@
import math
import os
import re
from contextlib import asynccontextmanager
@@ -13,9 +12,9 @@ from ..config import g_sDBFilePath, g_sDBPath
class CSqlManager:
def __init__(self):
dbPath = Path(g_sDBPath)
if dbPath and not dbPath.exists():
os.makedirs(dbPath, exist_ok=True)
dbPath = Path(g_sDBPath)
if dbPath and not dbPath.exists():
os.makedirs(dbPath, exist_ok=True)
@classmethod
async def cleanup(cls):
@@ -46,7 +45,7 @@ class CSqlManager:
@classmethod
async def getTableInfo(cls, tableName: str) -> list:
if not re.match(r'^[A-Za-z_][A-Za-z0-9_]*$', tableName):
if not re.match(r"^[A-Za-z_][A-Za-z0-9_]*$", tableName):
raise ValueError(f"Illegal table name: {tableName}")
try:
cursor = await cls.m_pDB.execute(f'PRAGMA table_info("{tableName}")')
@@ -70,7 +69,7 @@ class CSqlManager:
"""
info = await cls.getTableInfo(tableName)
existing = {col['name']: col['type'].upper() for col in info}
existing = {col["name"]: col["type"].upper() for col in info}
desired = {k: v.upper() for k, v in columns.items() if k != "PRIMARY KEY"}
primaryKey = columns.get("PRIMARY KEY", "")
@@ -83,7 +82,9 @@ class CSqlManager:
toAdd = [k for k in desired if k not in existing]
toRemove = [k for k in existing if k not in desired]
typeMismatch = [k for k in desired if k in existing and existing[k] != desired[k]]
typeMismatch = [
k for k in desired if k in existing and existing[k] != desired[k]
]
if toAdd and not toRemove and not typeMismatch:
for col in toAdd:
@@ -106,7 +107,9 @@ class CSqlManager:
f'INSERT INTO "{tmpTable}" ({colsStr}) SELECT {colsStr} FROM "{tableName}";'
)
await cls.m_pDB.execute(f'DROP TABLE "{tableName}";')
await cls.m_pDB.execute(f'ALTER TABLE "{tmpTable}" RENAME TO "{tableName}";')
await cls.m_pDB.execute(
f'ALTER TABLE "{tmpTable}" RENAME TO "{tableName}";'
)
return True
@classmethod
@@ -131,4 +134,5 @@ class CSqlManager:
logger.warning(f"数据库语句执行出错: {command}", e=e)
return False
g_pSqlManager = CSqlManager()
+10 -10
View File
@@ -1,8 +1,5 @@
import ast
import os
import re
from contextlib import asynccontextmanager
from unittest import result
import aiosqlite
@@ -29,7 +26,9 @@ class CPlantManager:
_ = os.path.exists(g_sPlantPath)
if g_bIsDebug:
cls.m_pDB = await aiosqlite.connect(str(g_sPlantPath.parent / "plant-test.db"))
cls.m_pDB = await aiosqlite.connect(
str(g_sPlantPath.parent / "plant-test.db")
)
else:
cls.m_pDB = await aiosqlite.connect(str(g_sPlantPath))
@@ -73,7 +72,6 @@ class CPlantManager:
logger.warning(f"数据库语句执行出错: {command}", e=e)
return False
@classmethod
async def getPlantByName(cls, name: str) -> dict | None:
"""根据作物名称查询记录
@@ -113,7 +111,7 @@ class CPlantManager:
if not row:
return []
phase = row[0].split(',')
phase = row[0].split(",")
seen = set()
result = []
@@ -149,9 +147,9 @@ class CPlantManager:
if not row:
return -1
phase = row[0].split(',')
phase = row[0].split(",")
#去重
# 去重
seen = set()
result = []
for x in phase:
@@ -184,7 +182,7 @@ class CPlantManager:
if not row:
return -1
phase = row[0].split(',')
phase = row[0].split(",")
again = phase[-1] - phase[3] / 60 / 60
return again
@@ -241,7 +239,9 @@ class CPlantManager:
async def listPlants(cls) -> list[dict]:
"""查询所有作物记录"""
try:
async with cls.m_pDB.execute("SELECT * FROM plant ORDER BY level") as cursor:
async with cls.m_pDB.execute(
"SELECT * FROM plant ORDER BY level"
) as cursor:
rows = await cursor.fetchall()
return [dict(r) for r in rows]
except Exception as e:
+20 -17
View File
@@ -1,6 +1,4 @@
import math
from typing import List, Union
from unittest import result
from zhenxun.services.log import logger
@@ -13,19 +11,21 @@ class CUserDB(CSqlManager):
async def initDB(cls):
"""初始化用户表结构,确保user表存在且字段完整"""
userInfo = {
"uid": "TEXT PRIMARY KEY", #用户Uid
"name": "TEXT NOT NULL", #农场名称
"exp": "INTEGER DEFAULT 0", #经验值
"point": "INTEGER DEFAULT 0", #金币
"vipPoint": "INTEGER DEFAULT 0", #点券
"soil": "INTEGER DEFAULT 3", #解锁土地数量
"stealTime": "TEXT DEFAULT ''", #偷菜时间字符串
"stealCount": "INTEGER DEFAULT 0" #剩余偷菜次数
"uid": "TEXT PRIMARY KEY", # 用户Uid
"name": "TEXT NOT NULL", # 农场名称
"exp": "INTEGER DEFAULT 0", # 经验值
"point": "INTEGER DEFAULT 0", # 金币
"vipPoint": "INTEGER DEFAULT 0", # 点券
"soil": "INTEGER DEFAULT 3", # 解锁土地数量
"stealTime": "TEXT DEFAULT ''", # 偷菜时间字符串
"stealCount": "INTEGER DEFAULT 0", # 剩余偷菜次数
}
await cls.ensureTableSchema("user", userInfo)
@classmethod
async def initUserInfoByUid(cls, uid: str, name: str = "", exp: int = 0, point: int = 500) -> Union[bool, str]:
async def initUserInfoByUid(
cls, uid: str, name: str = "", exp: int = 0, point: int = 500
) -> bool | str:
"""初始化用户信息,包含初始偷菜时间字符串与次数
Args:
@@ -37,7 +37,7 @@ class CUserDB(CSqlManager):
Returns:
Union[bool, str]: False 表示失败,字符串表示成功信息
"""
nowStr = g_pToolManager.dateTime().date().today().strftime('%Y-%m-%d')
nowStr = g_pToolManager.dateTime().date().today().strftime("%Y-%m-%d")
sql = (
f"INSERT INTO user (uid, name, exp, point, soil, stealTime, stealCount) "
f"VALUES ({uid}, '{name}', {exp}, {point}, 3, '{nowStr}', 5)"
@@ -51,7 +51,7 @@ class CUserDB(CSqlManager):
return False
@classmethod
async def getAllUsers(cls) -> List[str]:
async def getAllUsers(cls) -> list[str]:
"""获取所有用户UID列表
Returns:
@@ -395,8 +395,7 @@ class CUserDB(CSqlManager):
return ""
try:
async with cls.m_pDB.execute(
"SELECT stealTime FROM user WHERE uid = ?", (uid,
)
"SELECT stealTime FROM user WHERE uid = ?", (uid,)
) as cursor:
row = await cursor.fetchone()
return row[0] if row and row[0] else ""
@@ -451,11 +450,14 @@ class CUserDB(CSqlManager):
return -1
@classmethod
async def updateStealCountByUid(cls, uid: str, stealCount: int) -> bool:
async def updateStealCountByUid(
cls, uid: str, stealTime: str, stealCount: int
) -> bool:
"""根据用户Uid更新剩余偷菜次数
Args:
uid (str): 用户Uid
stealTime (str): 偷菜日期
stealCount (int): 新剩余偷菜次数
Returns:
@@ -467,7 +469,8 @@ class CUserDB(CSqlManager):
try:
async with cls._transaction():
await cls.m_pDB.execute(
"UPDATE user SET stealCount = ? WHERE uid = ?", (stealCount, uid)
"UPDATE user SET stealTime = ?, stealCount = ? WHERE uid = ?",
(stealTime, stealCount, uid),
)
return True
except Exception as e:
+19 -26
View File
@@ -1,5 +1,3 @@
from typing import Optional
from zhenxun.services.log import logger
from .database import CSqlManager
@@ -9,16 +7,16 @@ class CUserItemDB(CSqlManager):
@classmethod
async def initDB(cls):
userItem = {
"uid": "TEXT NOT NULL", #用户Uid
"item": "TEXT NOT NULL", #物品名称
"count": "INTEGER NOT NULL DEFAULT 0", #数量
"PRIMARY KEY": "(uid, item)"
"uid": "TEXT NOT NULL", # 用户Uid
"item": "TEXT NOT NULL", # 物品名称
"count": "INTEGER NOT NULL DEFAULT 0", # 数量
"PRIMARY KEY": "(uid, item)",
}
await cls.ensureTableSchema("userItem", userItem)
@classmethod
async def getUserItemByName(cls, uid: str, item: str) -> Optional[int]:
async def getUserItemByName(cls, uid: str, item: str) -> int | None:
"""根据道具名称查询某一项数量
Args:
@@ -32,13 +30,12 @@ class CUserItemDB(CSqlManager):
return None
try:
async with cls.m_pDB.execute(
"SELECT count FROM userItem WHERE uid = ? AND item = ?",
(uid, item)
"SELECT count FROM userItem WHERE uid = ? AND item = ?", (uid, item)
) as cursor:
row = await cursor.fetchone()
return row[0] if row else None
except Exception as e:
logger.warning(f"getUserItemByName查询失败!", e=e)
logger.warning("getUserItemByName查询失败!", e=e)
return None
@classmethod
@@ -55,13 +52,12 @@ class CUserItemDB(CSqlManager):
return {}
try:
cursor = await cls.m_pDB.execute(
"SELECT item, count FROM userItem WHERE uid = ?",
(uid,)
"SELECT item, count FROM userItem WHERE uid = ?", (uid,)
)
rows = await cursor.fetchall()
return {row["item"]: row["count"] for row in rows}
except Exception as e:
logger.warning(f"getUserItemByUid查询失败!", e=e)
logger.warning("getUserItemByUid查询失败!", e=e)
return {}
@classmethod
@@ -80,12 +76,11 @@ class CUserItemDB(CSqlManager):
try:
async with cls._transaction():
await cls.m_pDB.execute(
"DELETE FROM userItem WHERE uid = ? AND item = ?",
(uid, item)
"DELETE FROM userItem WHERE uid = ? AND item = ?", (uid, item)
)
return True
except Exception as e:
logger.warning(f"deleteUserItemByName失败!", e=e)
logger.warning("deleteUserItemByName失败!", e=e)
return False
@classmethod
@@ -106,17 +101,16 @@ class CUserItemDB(CSqlManager):
async with cls._transaction():
if count <= 0:
await cls.m_pDB.execute(
"DELETE FROM userItem WHERE uid = ? AND item = ?",
(uid, item)
"DELETE FROM userItem WHERE uid = ? AND item = ?", (uid, item)
)
else:
await cls.m_pDB.execute(
"UPDATE userItem SET count = ? WHERE uid = ? AND item = ?",
(count, uid, item)
(count, uid, item),
)
return True
except Exception as e:
logger.warning(f"updateUserItemByName失败!", e=e)
logger.warning("updateUserItemByName失败!", e=e)
return False
@classmethod
@@ -136,8 +130,7 @@ class CUserItemDB(CSqlManager):
try:
async with cls._transaction():
async with cls.m_pDB.execute(
"SELECT count FROM userItem WHERE uid = ? AND item = ?",
(uid, item)
"SELECT count FROM userItem WHERE uid = ? AND item = ?", (uid, item)
) as cursor:
row = await cursor.fetchone()
@@ -146,20 +139,20 @@ class CUserItemDB(CSqlManager):
if newCount <= 0:
await cls.m_pDB.execute(
"DELETE FROM userItem WHERE uid = ? AND item = ?",
(uid, item)
(uid, item),
)
else:
await cls.m_pDB.execute(
"UPDATE userItem SET count = ? WHERE uid = ? AND item = ?",
(newCount, uid, item)
(newCount, uid, item),
)
else:
if count > 0:
await cls.m_pDB.execute(
"INSERT INTO userItem (uid, item, count) VALUES (?, ?, ?)",
(uid, item, count)
(uid, item, count),
)
return True
except Exception as e:
logger.warning(f"addUserItemByUid失败!", e=e)
logger.warning("addUserItemByUid失败!", e=e)
return False
+20 -25
View File
@@ -1,5 +1,3 @@
from typing import Dict, Optional
from zhenxun.services.log import logger
from .database import CSqlManager
@@ -9,10 +7,10 @@ class CUserPlantDB(CSqlManager):
@classmethod
async def initDB(cls):
userPlant = {
"uid": "TEXT NOT NULL", #用户Uid
"plant": "TEXT NOT NULL", #作物名称
"count": "INTEGER NOT NULL DEFAULT 0", #数量
"PRIMARY KEY": "(uid, plant)"
"uid": "TEXT NOT NULL", # 用户Uid
"plant": "TEXT NOT NULL", # 作物名称
"count": "INTEGER NOT NULL DEFAULT 0", # 数量
"PRIMARY KEY": "(uid, plant)",
}
await cls.ensureTableSchema("userPlant", userPlant)
@@ -31,33 +29,33 @@ class CUserPlantDB(CSqlManager):
"""
try:
async with cls._transaction():
#检查是否已存在该作物
# 检查是否已存在该作物
async with cls.m_pDB.execute(
"SELECT count FROM userPlant WHERE uid = ? AND plant = ?",
(uid, plant)
(uid, plant),
) as cursor:
row = await cursor.fetchone()
if row:
#如果作物已存在,则更新数量
# 如果作物已存在,则更新数量
new_count = row[0] + count
await cls.m_pDB.execute(
"UPDATE userPlant SET count = ? WHERE uid = ? AND plant = ?",
(new_count, uid, plant)
(new_count, uid, plant),
)
else:
#如果作物不存在,则插入新记录
# 如果作物不存在,则插入新记录
await cls.m_pDB.execute(
"INSERT INTO userPlant (uid, plant, count) VALUES (?, ?, ?)",
(uid, plant, count)
(uid, plant, count),
)
return True
except Exception as e:
logger.warning(f"addUserPlantByUid 失败!", e=e)
logger.warning("addUserPlantByUid 失败!", e=e)
return False
@classmethod
async def getUserPlantByUid(cls, uid: str) -> Dict[str, int]:
async def getUserPlantByUid(cls, uid: str) -> dict[str, int]:
"""根据用户uid获取全部作物信息
Args:
@@ -67,14 +65,13 @@ class CUserPlantDB(CSqlManager):
Dict[str, int]: 作物名称和数量
"""
cursor = await cls.m_pDB.execute(
"SELECT plant, count FROM userPlant WHERE uid=?",
(uid,)
"SELECT plant, count FROM userPlant WHERE uid=?", (uid,)
)
rows = await cursor.fetchall()
return {row["plant"]: row["count"] for row in rows}
@classmethod
async def getUserPlantByName(cls, uid: str, plant: str) -> Optional[int]:
async def getUserPlantByName(cls, uid: str, plant: str) -> int | None:
"""根据作物名称获取用户的作物数量
Args:
@@ -86,13 +83,12 @@ class CUserPlantDB(CSqlManager):
"""
try:
async with cls.m_pDB.execute(
"SELECT count FROM userPlant WHERE uid = ? AND plant = ?",
(uid, plant)
"SELECT count FROM userPlant WHERE uid = ? AND plant = ?", (uid, plant)
) as cursor:
row = await cursor.fetchone()
return row[0] if row else None
except Exception as e:
logger.warning(f"getUserPlantByName 查询失败!", e=e)
logger.warning("getUserPlantByName 查询失败!", e=e)
return None
@classmethod
@@ -114,11 +110,11 @@ class CUserPlantDB(CSqlManager):
async with cls._transaction():
await cls.m_pDB.execute(
"UPDATE userPlant SET count = ? WHERE uid = ? AND plant = ?",
(count, uid, plant)
(count, uid, plant),
)
return True
except Exception as e:
logger.warning(f"updateUserPlantByName失败!", e=e)
logger.warning("updateUserPlantByName失败!", e=e)
return False
@classmethod
@@ -135,10 +131,9 @@ class CUserPlantDB(CSqlManager):
try:
async with cls._transaction():
await cls.m_pDB.execute(
"DELETE FROM userPlant WHERE uid = ? AND plant = ?",
(uid, plant)
"DELETE FROM userPlant WHERE uid = ? AND plant = ?", (uid, plant)
)
return True
except Exception as e:
logger.warning(f"deleteUserPlantByName 失败!", e=e)
logger.warning("deleteUserPlantByName 失败!", e=e)
return False
+23 -32
View File
@@ -1,5 +1,3 @@
from typing import Optional
from zhenxun.services.log import logger
from .database import CSqlManager
@@ -9,10 +7,10 @@ class CUserSeedDB(CSqlManager):
@classmethod
async def initDB(cls):
userSeed = {
"uid": "TEXT NOT NULL", #用户Uid
"seed": "TEXT NOT NULL", #种子名称
"count": "INTEGER NOT NULL DEFAULT 0", #数量
"PRIMARY KEY": "(uid, seed)"
"uid": "TEXT NOT NULL", # 用户Uid
"seed": "TEXT NOT NULL", # 种子名称
"count": "INTEGER NOT NULL DEFAULT 0", # 数量
"PRIMARY KEY": "(uid, seed)",
}
await cls.ensureTableSchema("userSeed", userSeed)
@@ -32,8 +30,7 @@ class CUserSeedDB(CSqlManager):
try:
async with cls._transaction():
async with cls.m_pDB.execute(
"SELECT count FROM userSeed WHERE uid = ? AND seed = ?",
(uid, seed)
"SELECT count FROM userSeed WHERE uid = ? AND seed = ?", (uid, seed)
) as cursor:
row = await cursor.fetchone()
@@ -41,23 +38,22 @@ class CUserSeedDB(CSqlManager):
newCount = row[0] + count
await cls.m_pDB.execute(
"UPDATE userSeed SET count = ? WHERE uid = ? AND seed = ?",
(newCount, uid, seed)
(newCount, uid, seed),
)
else:
newCount = count
await cls.m_pDB.execute(
"INSERT INTO userSeed (uid, seed, count) VALUES (?, ?, ?)",
(uid, seed, count)
(uid, seed, count),
)
if newCount <= 0:
await cls.m_pDB.execute(
"DELETE FROM userSeed WHERE uid = ? AND seed = ?",
(uid, seed)
"DELETE FROM userSeed WHERE uid = ? AND seed = ?", (uid, seed)
)
return True
except Exception as e:
logger.warning(f"addUserSeedByUid 失败!", e=e)
logger.warning("addUserSeedByUid 失败!", e=e)
return False
@classmethod
@@ -72,7 +68,7 @@ class CUserSeedDB(CSqlManager):
else:
await cls.m_pDB.execute(
"INSERT INTO userSeed (uid, seed, count) VALUES (?, ?, ?)",
(uid, seed, newCount)
(uid, seed, newCount),
)
if newCount <= 0:
@@ -80,12 +76,11 @@ class CUserSeedDB(CSqlManager):
return True
except Exception as e:
logger.warning(f"_addUserSeedByUid 失败!", e=e)
logger.warning("_addUserSeedByUid 失败!", e=e)
return False
@classmethod
async def getUserSeedByName(cls, uid: str, seed: str) -> Optional[int]:
async def getUserSeedByName(cls, uid: str, seed: str) -> int | None:
"""根据种子名称获取种子数量
Args:
@@ -98,13 +93,12 @@ class CUserSeedDB(CSqlManager):
try:
async with cls.m_pDB.execute(
"SELECT count FROM userSeed WHERE uid = ? AND seed = ?",
(uid, seed)
"SELECT count FROM userSeed WHERE uid = ? AND seed = ?", (uid, seed)
) as cursor:
row = await cursor.fetchone()
return row[0] if row else None
except Exception as e:
logger.warning(f"getUserSeedByName 查询失败!", e=e)
logger.warning("getUserSeedByName 查询失败!", e=e)
return None
@classmethod
@@ -119,8 +113,7 @@ class CUserSeedDB(CSqlManager):
"""
cursor = await cls.m_pDB.execute(
"SELECT seed, count FROM userSeed WHERE uid=?",
(uid,)
"SELECT seed, count FROM userSeed WHERE uid=?", (uid,)
)
rows = await cursor.fetchall()
return {row["seed"]: row["count"] for row in rows}
@@ -144,11 +137,11 @@ class CUserSeedDB(CSqlManager):
async with cls._transaction():
await cls.m_pDB.execute(
"UPDATE userSeed SET count = ? WHERE uid = ? AND seed = ?",
(count, uid, seed)
(count, uid, seed),
)
return True
except Exception as e:
logger.warning(f"updateUserSeedByName失败!", e=e)
logger.warning("updateUserSeedByName失败!", e=e)
return False
@classmethod
@@ -170,11 +163,11 @@ class CUserSeedDB(CSqlManager):
async with cls._transaction():
await cls.m_pDB.execute(
"UPDATE userSeed SET count = ? WHERE uid = ? AND seed = ?",
(count, uid, seed)
(count, uid, seed),
)
return True
except Exception as e:
logger.warning(f"updateUserSeedByName失败!", e=e)
logger.warning("updateUserSeedByName失败!", e=e)
return False
@classmethod
@@ -191,12 +184,11 @@ class CUserSeedDB(CSqlManager):
try:
async with cls._transaction():
await cls.m_pDB.execute(
"DELETE FROM userSeed WHERE uid = ? AND seed = ?",
(uid, seed)
"DELETE FROM userSeed WHERE uid = ? AND seed = ?", (uid, seed)
)
return True
except Exception as e:
logger.warning(f"deleteUserSeedByName 删除失败!", e=e)
logger.warning("deleteUserSeedByName 删除失败!", e=e)
return False
@classmethod
@@ -212,10 +204,9 @@ class CUserSeedDB(CSqlManager):
"""
try:
await cls.m_pDB.execute(
"DELETE FROM userSeed WHERE uid = ? AND seed = ?",
(uid, seed)
"DELETE FROM userSeed WHERE uid = ? AND seed = ?", (uid, seed)
)
return True
except Exception as e:
logger.warning(f"deleteUserSeedByName 删除失败!", e=e)
logger.warning("deleteUserSeedByName 删除失败!", e=e)
return False
+73 -42
View File
@@ -1,7 +1,6 @@
import calendar
import random
from datetime import date, datetime, timedelta
from typing import Optional
from datetime import timedelta
from zhenxun.services.log import logger
from zhenxun.utils._build_image import BuildImage
@@ -16,27 +15,27 @@ from .database import CSqlManager
class CUserSignDB(CSqlManager):
@classmethod
async def initDB(cls):
#userSignLog 表结构,每条为一次签到事件
# userSignLog 表结构,每条为一次签到事件
userSignLog = {
"uid": "TEXT NOT NULL", #用户ID
"signDate": "DATE NOT NULL", #签到日期
"isSupplement": "TINYINT NOT NULL DEFAULT 0", #是否补签
"exp": "INT NOT NULL DEFAULT 0", #当天签到经验
"point": "INT NOT NULL DEFAULT 0", #当天签到金币
"createdAt": "DATETIME NOT NULL DEFAULT (datetime(CURRENT_TIMESTAMP, 'localtime'))",#创建时间
"PRIMARY KEY": "(uid, signDate)"
"uid": "TEXT NOT NULL", # 用户ID
"signDate": "DATE NOT NULL", # 签到日期
"isSupplement": "TINYINT NOT NULL DEFAULT 0", # 是否补签
"exp": "INT NOT NULL DEFAULT 0", # 当天签到经验
"point": "INT NOT NULL DEFAULT 0", # 当天签到金币
"createdAt": "DATETIME NOT NULL DEFAULT (datetime(CURRENT_TIMESTAMP, 'localtime'))", # 创建时间
"PRIMARY KEY": "(uid, signDate)",
}
#userSignSummary 表结构,每用户一行用于缓存签到状态
# userSignSummary 表结构,每用户一行用于缓存签到状态
userSignSummary = {
"uid": "TEXT PRIMARY KEY NOT NULL", #用户ID
"totalSignDays": "INT NOT NULL DEFAULT 0", #累计签到天数
"currentMonth": "CHAR(7) NOT NULL DEFAULT ''", #当前月份(如2025-05)
"monthSignDays": "INT NOT NULL DEFAULT 0", #本月签到次数
"lastSignDate": "DATE DEFAULT NULL", #上次签到日期
"continuousDays": "INT NOT NULL DEFAULT 0", #连续签到天数
"supplementCount": "INT NOT NULL DEFAULT 0", #补签次数
"updatedAt": "DATETIME NOT NULL DEFAULT (datetime(CURRENT_TIMESTAMP, 'localtime'))"#更新时间
"uid": "TEXT PRIMARY KEY NOT NULL", # 用户ID
"totalSignDays": "INT NOT NULL DEFAULT 0", # 累计签到天数
"currentMonth": "CHAR(7) NOT NULL DEFAULT ''", # 当前月份(如2025-05)
"monthSignDays": "INT NOT NULL DEFAULT 0", # 本月签到次数
"lastSignDate": "DATE DEFAULT NULL", # 上次签到日期
"continuousDays": "INT NOT NULL DEFAULT 0", # 连续签到天数
"supplementCount": "INT NOT NULL DEFAULT 0", # 补签次数
"updatedAt": "DATETIME NOT NULL DEFAULT (datetime(CURRENT_TIMESTAMP, 'localtime'))", # 更新时间
}
await cls.ensureTableSchema("userSignLog", userSignLog)
@@ -57,15 +56,15 @@ class CUserSignDB(CSqlManager):
async with cls._transaction():
async with cls.m_pDB.execute(
"SELECT exp, point FROM userSignLog WHERE uid=? AND signDate=?",
(uid, date)
(uid, date),
) as cursor:
row = await cursor.fetchone()
if row is None:
return 0, 0
exp = row['exp']
point = row['point']
exp = row["exp"]
point = row["point"]
return exp, point
except Exception as e:
@@ -114,7 +113,7 @@ class CUserSignDB(CSqlManager):
return False
@classmethod
async def sign(cls, uid: str, signDate: str = '') -> int:
async def sign(cls, uid: str, signDate: str = "") -> int:
"""签到
Args:
@@ -151,20 +150,35 @@ class CUserSignDB(CSqlManager):
async with cls._transaction():
await cls.m_pDB.execute(
"INSERT INTO userSignLog (uid, signDate, isSupplement, exp, point) VALUES (?, ?, ?, ?, ?)",
(uid, signDate, isSupplement, exp, point)
(uid, signDate, isSupplement, exp, point),
)
cursor = await cls.m_pDB.execute("SELECT * FROM userSignSummary WHERE uid=?", (uid,))
cursor = await cls.m_pDB.execute(
"SELECT * FROM userSignSummary WHERE uid=?", (uid,)
)
row = await cursor.fetchone()
currentMonth = signDate[:7]
if row:
monthSignDays = row['monthSignDays'] + 1 if row['currentMonth'] == currentMonth else 1
totalSignDays = row['totalSignDays']
lastDate = row['lastSignDate']
prevDate = (g_pToolManager.dateTime().strptime(signDate, "%Y-%m-%d") - timedelta(days=1)).strftime("%Y-%m-%d")
continuousDays = row['continuousDays'] + 1 if lastDate == prevDate else 1
supplementCount = row['supplementCount'] + 1 if isSupplement else row['supplementCount']
monthSignDays = (
row["monthSignDays"] + 1
if row["currentMonth"] == currentMonth
else 1
)
totalSignDays = row["totalSignDays"]
lastDate = row["lastSignDate"]
prevDate = (
g_pToolManager.dateTime().strptime(signDate, "%Y-%m-%d")
- timedelta(days=1)
).strftime("%Y-%m-%d")
continuousDays = (
row["continuousDays"] + 1 if lastDate == prevDate else 1
)
supplementCount = (
row["supplementCount"] + 1
if isSupplement
else row["supplementCount"]
)
await cls.m_pDB.execute(
"""
UPDATE userSignSummary
@@ -176,7 +190,14 @@ class CUserSignDB(CSqlManager):
supplementCount=?
WHERE uid=?
""",
(currentMonth, monthSignDays, signDate, continuousDays, supplementCount, uid)
(
currentMonth,
monthSignDays,
signDate,
continuousDays,
supplementCount,
uid,
),
)
else:
totalSignDays = 1
@@ -186,18 +207,26 @@ class CUserSignDB(CSqlManager):
(uid, totalSignDays, currentMonth, monthSignDays, lastSignDate, continuousDays, supplementCount)
VALUES (?, ?, ?, ?, ?, ?, ?)
""",
(uid, 1, currentMonth, 1, signDate, 1, 1 if isSupplement else 0)
(
uid,
1,
currentMonth,
1,
signDate,
1,
1 if isSupplement else 0,
),
)
#计算累签奖励
reward = g_pJsonManager.m_pSign['continuou'].get(f"{totalSignDays}", None)
# 计算累签奖励
reward = g_pJsonManager.m_pSign["continuou"].get(f"{totalSignDays}", None)
if reward:
point += reward.get('point', 0)
exp += reward.get('exp', 0)
vipPoint = reward.get('vipPoint', 0)
point += reward.get("point", 0)
exp += reward.get("exp", 0)
vipPoint = reward.get("vipPoint", 0)
plant = reward.get('plant', {})
plant = reward.get("plant", {})
if plant:
for key, value in plant.items():
@@ -206,7 +235,7 @@ class CUserSignDB(CSqlManager):
if g_bIsDebug:
exp += 9999
#向数据库更新
# 向数据库更新
currentExp = await g_pDBService.user.getUserExpByUid(uid)
await g_pDBService.user.updateUserExpByUid(uid, currentExp + exp)
@@ -215,7 +244,9 @@ class CUserSignDB(CSqlManager):
if vipPoint > 0:
currentVipPoint = await g_pDBService.user.getUserVipPointByUid(uid)
await g_pDBService.user.updateUserVipPointByUid(uid, currentVipPoint + vipPoint)
await g_pDBService.user.updateUserVipPointByUid(
uid, currentVipPoint + vipPoint
)
return 1
except Exception as e:
@@ -224,7 +255,7 @@ class CUserSignDB(CSqlManager):
@classmethod
async def drawSignCalendarImage(cls, uid: str, year: int, month: int):
#绘制签到图,自动提取数据库中该用户该月的签到天数
# 绘制签到图,自动提取数据库中该用户该月的签到天数
cellSize = 80
padding = 40
titleHeight = 80
+60 -54
View File
@@ -1,10 +1,7 @@
from typing import Optional
from zhenxun.services.log import logger
from ..config import g_bIsDebug
from ..dbService import g_pDBService
from ..json import g_pJsonManager
from ..tool import g_pToolManager
from .database import CSqlManager
@@ -14,17 +11,17 @@ class CUserSoilDB(CSqlManager):
async def initDB(cls):
userSoil = {
"uid": "TEXT NOT NULL",
"soilIndex": "INTEGER NOT NULL", #地块索引从1开始
"plantName": "TEXT DEFAULT ''", #作物名称
"plantTime": "INTEGER DEFAULT 0", #播种时间
"matureTime": "INTEGER DEFAULT 0", #成熟时间
"soilLevel": "INTEGER DEFAULT 0", #土地等级 0=普通地,1=红土地,2=黑土地,3=金土地
"wiltStatus": "INTEGER DEFAULT 0", #枯萎状态 0=未枯萎,1=枯萎
"fertilizerStatus": "INTEGER DEFAULT 0",#施肥状态 0=未施肥,1=施肥 2=增肥
"bugStatus": "INTEGER DEFAULT 0", #虫害状态 0=无虫害,1=有虫害
"weedStatus": "INTEGER DEFAULT 0", #杂草状态 0=无杂草,1=有杂草
"waterStatus": "INTEGER DEFAULT 0", #缺水状态 0=不缺水,1=缺水
"harvestCount": "INTEGER DEFAULT 0", #收获次数
"soilIndex": "INTEGER NOT NULL", # 地块索引从1开始
"plantName": "TEXT DEFAULT ''", # 作物名称
"plantTime": "INTEGER DEFAULT 0", # 播种时间
"matureTime": "INTEGER DEFAULT 0", # 成熟时间
"soilLevel": "INTEGER DEFAULT 0", # 土地等级 0=普通地,1=红土地,2=黑土地,3=金土地
"wiltStatus": "INTEGER DEFAULT 0", # 枯萎状态 0=未枯萎,1=枯萎
"fertilizerStatus": "INTEGER DEFAULT 0", # 施肥状态 0=未施肥,1=施肥 2=增肥
"bugStatus": "INTEGER DEFAULT 0", # 虫害状态 0=无虫害,1=有虫害
"weedStatus": "INTEGER DEFAULT 0", # 杂草状态 0=无杂草,1=有杂草
"waterStatus": "INTEGER DEFAULT 0", # 缺水状态 0=不缺水,1=缺水
"harvestCount": "INTEGER DEFAULT 0", # 收获次数
"PRIMARY KEY": "(uid, soilIndex)",
}
@@ -45,30 +42,30 @@ class CUserSoilDB(CSqlManager):
if not soilInfo:
return
plantInfo = await g_pDBService.plant.getPlantByName(soilInfo['plantName'])
plantInfo = await g_pDBService.plant.getPlantByName(soilInfo["plantName"])
if not plantInfo:
return
currentTime = g_pToolManager.dateTime().now().timestamp()
phaseList = await g_pDBService.plant.getPlantPhaseByName(soilInfo['plantName'])
phaseList = await g_pDBService.plant.getPlantPhaseByName(soilInfo["plantName"])
if currentTime >= soilInfo['matureTime']:
if currentTime >= soilInfo["matureTime"]:
return
elapsedTime = currentTime - soilInfo['plantTime']
elapsedTime = currentTime - soilInfo["plantTime"]
currentStage = currentStage = sum(1 for thr in phaseList if elapsedTime >= thr)
t = int(soilInfo['plantTime']) - phaseList[currentStage]
s = int(soilInfo['matureTime']) - phaseList[currentStage]
t = int(soilInfo["plantTime"]) - phaseList[currentStage]
s = int(soilInfo["matureTime"]) - phaseList[currentStage]
await cls.updateUserSoilFields(uid, soilIndex,
{
"plantTime": t,
"matureTime": s
})
await cls.updateUserSoilFields(
uid, soilIndex, {"plantTime": t, "matureTime": s}
)
logger.debug(f"当前阶段{currentStage}, 阶段时间{phaseList[currentStage]}, 播种时间{t}, 收获时间{s}")
logger.debug(
f"当前阶段{currentStage}, 阶段时间{phaseList[currentStage]}, 播种时间{t}, 收获时间{s}"
)
@classmethod
async def getUserFarmByUid(cls, uid: str) -> dict:
@@ -95,7 +92,7 @@ class CUserSoilDB(CSqlManager):
Returns:
bool: 如果旧表不存在则返回 False,否则迁移并删除后返回 True
"""
#检查旧表是否存在
# 检查旧表是否存在
cursor = await cls.m_pDB.execute(
"SELECT name FROM sqlite_master WHERE type='table' AND name='soil'"
)
@@ -184,31 +181,31 @@ class CUserSoilDB(CSqlManager):
None
"""
await cls.m_pDB.execute(
"""
"""
INSERT INTO userSoil
(uid, soilIndex, plantName, plantTime, matureTime,
soilLevel, wiltStatus, fertilizerStatus, bugStatus,
weedStatus, waterStatus, harvestCount)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?)
""",
(
soilInfo["uid"],
soilInfo["soilIndex"],
soilInfo.get("plantName", ""),
soilInfo.get("plantTime", 0),
soilInfo.get("matureTime", 0),
soilInfo.get("soilLevel", 0),
soilInfo.get("wiltStatus", 0),
soilInfo.get("fertilizerStatus", 0),
soilInfo.get("bugStatus", 0),
soilInfo.get("weedStatus", 0),
soilInfo.get("waterStatus", 0),
soilInfo.get("harvestCount", 0),
),
(
soilInfo["uid"],
soilInfo["soilIndex"],
soilInfo.get("plantName", ""),
soilInfo.get("plantTime", 0),
soilInfo.get("matureTime", 0),
soilInfo.get("soilLevel", 0),
soilInfo.get("wiltStatus", 0),
soilInfo.get("fertilizerStatus", 0),
soilInfo.get("bugStatus", 0),
soilInfo.get("weedStatus", 0),
soilInfo.get("waterStatus", 0),
soilInfo.get("harvestCount", 0),
),
)
@classmethod
async def getUserSoil(cls, uid: str, soilIndex: int) -> Optional[dict]:
async def getUserSoil(cls, uid: str, soilIndex: int) -> dict | None:
"""获取指定用户某块土地的详细信息
Args:
@@ -230,7 +227,7 @@ class CUserSoilDB(CSqlManager):
return dict(zip(columns, row))
@classmethod
async def _getUserSoil(cls, uid: str, soilIndex: int) -> Optional[dict]:
async def _getUserSoil(cls, uid: str, soilIndex: int) -> dict | None:
"""获取指定用户某块土地的详细信息
Args:
@@ -288,7 +285,9 @@ class CUserSoilDB(CSqlManager):
)
@classmethod
async def updateUserSoilFields(cls, uid: str, soilIndex: int, updates: dict) -> bool:
async def updateUserSoilFields(
cls, uid: str, soilIndex: int, updates: dict
) -> bool:
"""批量更新指定用户土地的多个字段
Args:
@@ -299,11 +298,18 @@ class CUserSoilDB(CSqlManager):
Returns:
bool: 如果无可更新字段则返回 False,否则更新成功返回 True
"""
#允许更新的列白名单
# 允许更新的列白名单
allowedFields = {
"plantName", "plantTime", "matureTime", "soilLevel",
"wiltStatus", "fertilizerStatus", "bugStatus",
"weedStatus", "waterStatus", "harvestCount"
"plantName",
"plantTime",
"matureTime",
"soilLevel",
"wiltStatus",
"fertilizerStatus",
"bugStatus",
"weedStatus",
"waterStatus",
"harvestCount",
}
setClauses = []
values = []
@@ -316,7 +322,7 @@ class CUserSoilDB(CSqlManager):
return False
values.extend([uid, soilIndex])
sql = f'UPDATE userSoil SET {", ".join(setClauses)} WHERE uid = ? AND soilIndex = ?'
sql = f"UPDATE userSoil SET {', '.join(setClauses)} WHERE uid = ? AND soilIndex = ?"
try:
async with cls._transaction():
@@ -386,12 +392,12 @@ class CUserSoilDB(CSqlManager):
Returns:
bool: 播种成功返回 True,否则返回 False
"""
#校验土地区是否已种植
# 校验土地区是否已种植
soilRecord = await cls.getUserSoil(uid, soilIndex)
if soilRecord and soilRecord.get("plantName"):
return False
#获取植物配置
# 获取植物配置
plantCfg = await g_pDBService.plant.getPlantByName(plantName)
if not plantCfg:
logger.error(f"未知植物: {plantName}")
@@ -417,12 +423,12 @@ class CUserSoilDB(CSqlManager):
"bugStatus": prev.get("bugStatus", 0),
"weedStatus": prev.get("weedStatus", 0),
"waterStatus": prev.get("waterStatus", 0),
"harvestCount": 0
"harvestCount": 0,
}
)
return True
except Exception as e:
logger.error(f"播种失败!", e=e)
logger.error("播种失败!", e=e)
return False
@classmethod
+24 -20
View File
@@ -7,17 +7,19 @@ class CUserStealDB(CSqlManager):
@classmethod
async def initDB(cls):
userSteal = {
"uid": "TEXT NOT NULL", #被偷用户Uid
"soilIndex": "INTEGER NOT NULL", #被偷的地块索引 从1开始
"stealerUid": "TEXT NOT NULL", #偷菜用户Uid
"stealCount": "INTEGER NOT NULL", #被偷数量
"stealTime": "INTEGER NOT NULL", #被偷时间
"PRIMARY KEY": "(uid, soilIndex, stealerUid)"
"uid": "TEXT NOT NULL", # 被偷用户Uid
"soilIndex": "INTEGER NOT NULL", # 被偷的地块索引 从1开始
"stealerUid": "TEXT NOT NULL", # 偷菜用户Uid
"stealCount": "INTEGER NOT NULL", # 被偷数量
"stealTime": "INTEGER NOT NULL", # 被偷时间
"PRIMARY KEY": "(uid, soilIndex, stealerUid)",
}
await cls.ensureTableSchema("userSteal", userSteal)
@classmethod
async def addStealRecord(cls, uid: str, soilIndex: int, stealerUid: str, stealCount: int, stealTime: int) -> bool:
async def addStealRecord(
cls, uid: str, soilIndex: int, stealerUid: str, stealCount: int, stealTime: int
) -> bool:
"""添加偷菜记录
Args:
@@ -34,7 +36,7 @@ class CUserStealDB(CSqlManager):
async with cls._transaction():
await cls.m_pDB.execute(
'INSERT INTO "userSteal"(uid, soilIndex, stealerUid, stealCount, stealTime) VALUES(?, ?, ?, ?, ?);',
(uid, soilIndex, stealerUid, stealCount, stealTime)
(uid, soilIndex, stealerUid, stealCount, stealTime),
)
return True
except Exception as e:
@@ -55,7 +57,7 @@ class CUserStealDB(CSqlManager):
async with cls._transaction():
cursor = await cls.m_pDB.execute(
'SELECT soilIndex, stealerUid, stealCount, stealTime FROM "userSteal" WHERE uid=?;',
(uid,)
(uid,),
)
rows = await cursor.fetchall()
return [
@@ -64,7 +66,7 @@ class CUserStealDB(CSqlManager):
"soilIndex": row[0],
"stealerUid": row[1],
"stealCount": row[2],
"stealTime": row[3]
"stealTime": row[3],
}
for row in rows
]
@@ -87,7 +89,7 @@ class CUserStealDB(CSqlManager):
async with cls._transaction():
cursor = await cls.m_pDB.execute(
'SELECT stealerUid, stealCount, stealTime FROM "userSteal" WHERE uid=? AND soilIndex=?;',
(uid, soilIndex)
(uid, soilIndex),
)
rows = await cursor.fetchall()
return [
@@ -96,7 +98,7 @@ class CUserStealDB(CSqlManager):
"soilIndex": soilIndex,
"stealerUid": row[0],
"stealCount": row[1],
"stealTime": row[2]
"stealTime": row[2],
}
for row in rows
]
@@ -119,10 +121,10 @@ class CUserStealDB(CSqlManager):
async with cls._transaction():
cursor = await cls.m_pDB.execute(
'SELECT SUM(stealCount) FROM "userSteal" WHERE uid=? AND soilIndex=?;',
(uid, soilIndex)
(uid, soilIndex),
)
row = await cursor.fetchone()
return row[0] or 0 # type: ignore
return row[0] or 0 # type: ignore
except Exception as e:
logger.warning("计算总偷菜数量失败", e=e)
return 0
@@ -142,10 +144,10 @@ class CUserStealDB(CSqlManager):
async with cls._transaction():
cursor = await cls.m_pDB.execute(
'SELECT COUNT(DISTINCT stealerUid) FROM "userSteal" WHERE uid=? AND soilIndex=?;',
(uid, soilIndex)
(uid, soilIndex),
)
row = await cursor.fetchone()
return row[0] or 0 # type: ignore
return row[0] or 0 # type: ignore
except Exception as e:
logger.warning("计算偷菜者数量失败", e=e)
return 0
@@ -166,7 +168,7 @@ class CUserStealDB(CSqlManager):
async with cls._transaction():
cursor = await cls.m_pDB.execute(
'SELECT 1 FROM "userSteal" WHERE uid=? AND soilIndex=? AND stealerUid=? LIMIT 1;',
(uid, soilIndex, stealerUid)
(uid, soilIndex, stealerUid),
)
row = await cursor.fetchone()
return bool(row)
@@ -175,7 +177,9 @@ class CUserStealDB(CSqlManager):
return False
@classmethod
async def updateStealRecord(cls, uid: str, soilIndex: int, stealerUid: str, stealCount: int, stealTime: int) -> bool:
async def updateStealRecord(
cls, uid: str, soilIndex: int, stealerUid: str, stealCount: int, stealTime: int
) -> bool:
"""更新偷菜记录的数量和时间
Args:
@@ -192,7 +196,7 @@ class CUserStealDB(CSqlManager):
async with cls._transaction():
await cls.m_pDB.execute(
'UPDATE "userSteal" SET stealCount=?, stealTime=? WHERE uid=? AND soilIndex=? AND stealerUid=?;',
(stealCount, stealTime, uid, soilIndex, stealerUid)
(stealCount, stealTime, uid, soilIndex, stealerUid),
)
return True
except Exception as e:
@@ -214,7 +218,7 @@ class CUserStealDB(CSqlManager):
async with cls._transaction():
await cls.m_pDB.execute(
'DELETE FROM "userSteal" WHERE uid=? AND soilIndex=?;',
(uid, soilIndex)
(uid, soilIndex),
)
return True
except Exception as e: