diff --git a/command.py b/command.py index bc1ef6b..05a40e0 100644 --- a/command.py +++ b/command.py @@ -98,6 +98,7 @@ diuse_farm = on_alconna( Subcommand("my-vipPoint", help_text="我的点券"), Subcommand("farm-help", help_text="农场帮助"), Subcommand("vipSeed-shop", Args["res?", MultiVar(str)], help_text="种子商店"), + Subcommand("my-plantcount", help_text="我的作物收获次数"), ), priority=5, block=True, @@ -776,3 +777,50 @@ async def _(session: Uninfo, res: Match[tuple[str, ...]]): image = await g_pShopManager.getSeedShopImage(filterKey, page, 1) await MessageUtils.build_message(image).send() + + +diuse_farm.shortcut( + "我的收获次数", + command="我的农场", + arguments=["my-plantcount"], + prefix=True, +) + + +@diuse_farm.assign("my-plantcount") +async def _(session: Uninfo, res: Match[tuple[str, ...]]): + uid = str(session.user.id) + player = await g_pToolManager.getPlayerByUid(uid) + if player is None or not await player.isRegistered(): + await g_pToolManager.repeat() + return + + if res.result is inspect._empty: + raw = [] + else: + raw = res.result + + filterKey: str | int | None = None + page: int = 1 + + if len(raw) >= 1 and raw[0] is not None: + first = raw[0] + if isinstance(first, str) and first.isdigit(): + page = int(first) + else: + filterKey = first + + if ( + len(raw) >= 2 + and raw[1] is not None + and isinstance(raw[1], str) + and raw[1].isdigit() + ): + page = int(raw[1]) + + if filterKey is None: + image = await g_pFarmManager.getUserPlantCountImage(uid, page, 0) + else: + image = await g_pFarmManager.getUserPlantCountImage(uid, filterKey, page) + + await MessageUtils.build_message(image).send() diff --git a/core/database/userPlantCount.py b/core/database/userPlantCount.py new file mode 100644 index 0000000..5e7d41e --- /dev/null +++ b/core/database/userPlantCount.py @@ -0,0 +1,124 @@ +from zhenxun.services.log import logger + +from .database import CSqlManager + + +class CUserPlantCountDB(CSqlManager): + @classmethod + async def initDB(cls): + userPlantCount = { + "uid": "TEXT NOT NULL", # 用户Uid + "plant": "TEXT NOT NULL", # 植物名称 + "count": "INTEGER NOT NULL DEFAULT 0", # 数量 + "PRIMARY KEY": "(uid, plant)", + } + + await cls.ensureTableSchema("userPlantCount", userPlantCount) + + @classmethod + async def addUserPlantCountByUid(cls, uid: str, plant: str, count: int = 1) -> bool: + """根据用户uid添加植物的收获次数 + + Args: + uid (str): 用户uid + plant (str): 植物名称 + count (int): 数量 + + Returns: + bool: 是否添加成功 + """ + try: + async with cls._transaction(): + async with cls.m_pDB.execute( + "SELECT count FROM userPlantCount WHERE uid = ? AND plant = ?", + (uid, plant), + ) as cursor: + row = await cursor.fetchone() + + if row: + newCount = row[0] + count + await cls.m_pDB.execute( + "UPDATE userPlantCount SET count = ? WHERE uid = ? AND plant = ?", + (newCount, uid, plant), + ) + else: + newCount = count + await cls.m_pDB.execute( + "INSERT INTO userPlantCount (uid, plant, count) VALUES (?, ?, ?)", + (uid, plant, count), + ) + + if newCount <= 0: + await cls.m_pDB.execute( + "DELETE FROM userPlantCount WHERE uid = ? AND plant = ?", + (uid, plant), + ) + return True + except Exception as e: + logger.warning("addUserPlantByUid 失败!", e=e) + return False + + @classmethod + async def getUserPlantCountByUid(cls, uid: str) -> dict: + """根据用户Uid获取该用户的所有植物的收获次数 + + Args: + uid (str): 用户uid + + Returns: + dict: 植物信息 + """ + + cursor = await cls.m_pDB.execute( + "SELECT plant, count FROM userPlantCount WHERE uid=?", (uid,) + ) + rows = await cursor.fetchall() + return {row["plant"]: row["count"] for row in rows} + + @classmethod + async def updateUserPlantCountByName(cls, uid: str, plant: str, count: int) -> bool: + """根据植物名称更新植物的收获次数 + + Args: + uid (str): 用户uid + plant (str): 植物名称 + count (int): 收获次数 + + Returns: + bool: 是否成功 + """ + try: + if count <= 0: + return await cls.deleteUserPlantCountByName(uid, plant) + + async with cls._transaction(): + await cls.m_pDB.execute( + "UPDATE userPlantCount SET count = ? WHERE uid = ? AND plant = ?", + (count, uid, plant), + ) + return True + except Exception as e: + logger.warning("updateUserPlantByName失败!", e=e) + return False + + @classmethod + async def deleteUserPlantCountByName(cls, uid: str, plant: str) -> bool: + """根据植物名称从植物仓库中删除植物 + + Args: + uid (str): 用户uid + seed (str): 种子名称 + + Returns: + bool: 是否成功 + """ + try: + async with cls._transaction(): + await cls.m_pDB.execute( + "DELETE FROM userPlantCount WHERE uid = ? AND plant = ?", + (uid, plant), + ) + return True + except Exception as e: + logger.warning("deleteUserPlantCountByName 删除失败!", e=e) + return False diff --git a/core/dbService.py b/core/dbService.py index cba82d9..a0928f4 100644 --- a/core/dbService.py +++ b/core/dbService.py @@ -4,6 +4,7 @@ class CDBService: from .database.user import CUserDB from .database.userItem import CUserItemDB from .database.userPlant import CUserPlantDB + from .database.userPlantCount import CUserPlantCountDB from .database.userSeed import CUserSeedDB from .database.userSign import CUserSignDB from .database.userSoil import CUserSoilDB @@ -33,6 +34,9 @@ class CDBService: self.userSign = CUserSignDB() await self.userSign.initDB() + self.userPlantCount = CUserPlantCountDB() + await self.userPlantCount.initDB() + async def cleanup(self): await self.plant.cleanup() diff --git a/core/farm.py b/core/farm.py index 0d66ebc..98efe8f 100644 --- a/core/farm.py +++ b/core/farm.py @@ -629,6 +629,15 @@ class CFarmManager: uid, soilInfo["plantName"], number ) + # 统计收获次数 + try: + await g_pDBService.userPlantCount.addUserPlantCountByUid( + uid, soilInfo["plantName"] + ) + except Exception: + # 忽略统计异常,避免影响主流程 + pass + # 如果到达收获次数上限 if soilInfo["harvestCount"] + 1 >= plantInfo["crop"]: await g_pDBService.userSoil.updateUserSoil( @@ -1221,5 +1230,80 @@ class CFarmManager: return f"兑换{num}点券成功,当前点券:{number},赠送点券:{giftPoints},当前农场币:{point}" + @classmethod + async def getUserPlantCountImage( + cls, uid: str, filterKey: str | int = 1, num: int = 1 + ) -> bytes: + """获取用户作物收获次数图片 + + Args: + filterKey (str|int): + - 字符串: 根据关键字筛选种子名称 + - 整数: 翻至对应页(无筛选) + num (int, optional): 当 filterKey 为字符串时,用于指定页码。Defaults to 1. + + Returns: + bytes: 返回商店图片bytes + """ + # 解析参数:区分筛选关键字和页码 + filterStr = None + if isinstance(filterKey, int): + page = filterKey + else: + filterStr = filterKey + page = num + + # 表头定义 + columnName = [ + "-", + "种子名称", + "收获次数", + ] + + # 查询用户作物收获次数(返回 dict: {plant: count})并根据筛选关键字过滤 + plants = await g_pDBService.userPlantCount.getUserPlantCountByUid(uid) or {} + filteredPlants = [] + + for name, cnt in plants.items(): + # 字符串筛选 + if filterStr and filterStr not in name: + continue + filteredPlants.append({"plant": name, "count": cnt}) + + # 计算分页 + totalCount = len(filteredPlants) + pageCount = math.ceil(totalCount / 15) if totalCount else 1 + startIndex = (page - 1) * 15 + pageItems = filteredPlants[startIndex : startIndex + 15] + + # 构建数据行 + dataList = [] + for plant in pageItems: + # 图标处理 + icon = "" + iconPath = g_sResourcePath / f"plant/{plant['plant']}/icon.png" + if iconPath.exists(): + icon = (iconPath, 33, 33) + + dataList.append( + [ + icon, + plant["plant"], # 种子名称 + plant["count"], # 收获次数 + ] + ) + + # 页码标题 + title = f"收获次数 页数: {page}/{pageCount}" + + # 渲染表格并返回图片bytes + result = await ImageTemplate.table_page( + title, + "", + columnName, + dataList, + ) + return result.pic2bytes() + g_pFarmManager = CFarmManager() diff --git a/utils/config.py b/utils/config.py index 8afdca7..9804e96 100644 --- a/utils/config.py +++ b/utils/config.py @@ -41,6 +41,7 @@ g_sTranslation = { "success": "✅ 农场开通成功!\n💼 初始资金:{point}农场币 🥳🎉", "repeat": "🎉 您已经开通农场啦~ 😄", "error": "⚠️ 开通失败,请稍后再试 💔", + "already": "🚜 你已经开通农场啦~ 快去种田吧 🌱", }, "buySeed": { "notSeed": "🌱 请在指令后跟需要购买的种子名称",