🎉 新增商店模板及样式配置
297
resources/template/shop/main.css
Normal file
@ -0,0 +1,297 @@
|
||||
@font-face {
|
||||
font-family: fzrzFont;
|
||||
/* 导入的字体文件 */
|
||||
src: url("../../font/fzrzExtraBold.ttf");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: msyhFont;
|
||||
/* 导入的字体文件 */
|
||||
src: url("../../font/msyh.ttf");
|
||||
}
|
||||
@font-face {
|
||||
font-family: hywhFont;
|
||||
/* 导入的字体文件 */
|
||||
src: url("../../font/HYWenHei-85W.ttf");
|
||||
}
|
||||
@font-face {
|
||||
font-family: syhtFont;
|
||||
/* 导入的字体文件 */
|
||||
src: url("../../font/syht.otf");
|
||||
}
|
||||
|
||||
body {
|
||||
position: absolute;
|
||||
left: -8px;
|
||||
top: -8px;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
width: 800px;
|
||||
font-family: "hywhFont";
|
||||
padding: 10px 0;
|
||||
background-color: #fbe4e4;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.top-title {
|
||||
color: #e87692;
|
||||
font-size: 50px;
|
||||
text-align: center;
|
||||
font-family: "fzrzFont";
|
||||
}
|
||||
|
||||
.split {
|
||||
background-image: url("./res/img/split.png");
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
height: 41px;
|
||||
}
|
||||
|
||||
.top-head {
|
||||
background-image: url("./res/img/head.png");
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
.shop-item {
|
||||
padding-top: 30px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.shop-item-border {
|
||||
display: flex;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.shop-item-title {
|
||||
background-image: url("./res/img/title-bk.png");
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
height: 100px;
|
||||
margin-bottom: 20px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.shop-item-title-text {
|
||||
color: white;
|
||||
font-size: 30px;
|
||||
margin-top: 13px;
|
||||
}
|
||||
|
||||
.shop-item-left {
|
||||
min-height: 460px;
|
||||
position: relative;
|
||||
width: 140px;
|
||||
}
|
||||
|
||||
.shop-item-left-qq {
|
||||
position: absolute;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
.left-img {
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
.shop-item-right {
|
||||
width: 130px;
|
||||
}
|
||||
|
||||
.shop-item-right-zx {
|
||||
height: 460px;
|
||||
position: absolute;
|
||||
z-index: 3;
|
||||
top: 10px;
|
||||
}
|
||||
|
||||
.right-img {
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
.shop-item-mid {
|
||||
width: 480px;
|
||||
box-sizing: border-box;
|
||||
padding-top: 20px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.shop-item-mid-bk-inner {
|
||||
width: 520px;
|
||||
box-sizing: border-box;
|
||||
padding-top: 30px;
|
||||
background-color: #be5972;
|
||||
border: 1px solid #b14b5f;
|
||||
border-radius: 10px;
|
||||
position: absolute;
|
||||
right: -50px;
|
||||
top: 10px;
|
||||
z-index: 1;
|
||||
height: calc(100% - 20px);
|
||||
}
|
||||
|
||||
.shop-item-mid-bk-out {
|
||||
width: 520px;
|
||||
box-sizing: border-box;
|
||||
background-color: #f096a8;
|
||||
border: 1px solid #812528;
|
||||
border-radius: 10px;
|
||||
height: 100%;
|
||||
z-index: 2;
|
||||
position: relative;
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.goods-item {
|
||||
background-color: #f8cfd8;
|
||||
width: 100%;
|
||||
min-height: 130px;
|
||||
border-radius: 10px;
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
position: relative;
|
||||
border: 1px solid #994446;
|
||||
}
|
||||
|
||||
.goods-id {
|
||||
position: absolute;
|
||||
color: white;
|
||||
font-size: 15px;
|
||||
border-top-left-radius: 10px;
|
||||
top: 0;
|
||||
left: 0;
|
||||
border-right: 60px solid transparent;
|
||||
border-bottom: 60px solid transparent;
|
||||
border-top: 60px solid #ea7492;
|
||||
}
|
||||
|
||||
.goods-id-text {
|
||||
position: absolute;
|
||||
top: -54px;
|
||||
left: 9px;
|
||||
color: white;
|
||||
font-size: 16px;
|
||||
font-family: "fzrzFont";
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
.goods-item-left {
|
||||
height: 100%;
|
||||
min-height: 130px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
padding-top: 30px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.goods-item-left-o {
|
||||
height: 24px;
|
||||
width: 20px;
|
||||
background-color: #e99eab;
|
||||
border-radius: 40%;
|
||||
border: 1px solid #994446;
|
||||
}
|
||||
|
||||
.goods-item-icon {
|
||||
background-color: #fefefe;
|
||||
border: 1px solid #994446;
|
||||
margin-left: 20px;
|
||||
width: 120px;
|
||||
border-radius: 10px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.goods-item-icon-img {
|
||||
height: 104px;
|
||||
width: 104px;
|
||||
}
|
||||
|
||||
.goods-item-right-des {
|
||||
width: 272px;
|
||||
min-height: 80px;
|
||||
background-color: #fefefe;
|
||||
border: 1px solid #994446;
|
||||
margin-left: 10px;
|
||||
border-radius: 10px;
|
||||
padding: 5px;
|
||||
font-family: "msyhFont";
|
||||
}
|
||||
|
||||
.goods-item-right-price {
|
||||
min-height: 30px;
|
||||
background-color: #fefefe;
|
||||
border-radius: 30px;
|
||||
border: 1px solid #994446;
|
||||
height: 20px;
|
||||
margin-left: 10px;
|
||||
margin-top: 5px;
|
||||
font-size: 15px;
|
||||
font-family: "msyhFont";
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 10px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.goods-item-right-btn {
|
||||
min-height: 30px;
|
||||
background-color: #bf9ac6;
|
||||
color: white;
|
||||
border-radius: 30px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.goods-item-right-btn-line {
|
||||
width: 1px;
|
||||
height: 20px;
|
||||
background-color: #994446;
|
||||
margin: 0 10px;
|
||||
}
|
||||
|
||||
.shop-item-mid-bag1 {
|
||||
position: absolute;
|
||||
width: 70px;
|
||||
height: 78px;
|
||||
bottom: -35px;
|
||||
left: -35px;
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
.shop-item-mid-bag2 {
|
||||
position: absolute;
|
||||
width: 121px;
|
||||
height: 89px;
|
||||
right: -35px;
|
||||
bottom: -35px;
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
.bottom-s {
|
||||
margin-top: 70px;
|
||||
}
|
||||
|
||||
.goods-item-name {
|
||||
font-size: 18px;
|
||||
font-family: "syhtFont";
|
||||
}
|
||||
|
||||
.goods-item-name-line {
|
||||
height: 2px;
|
||||
width: 100%;
|
||||
margin: 3px 0;
|
||||
background-color: #731c1c;
|
||||
border-radius: 10px;
|
||||
}
|
||||
130
resources/template/shop/main.html
Normal file
@ -0,0 +1,130 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-cn">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>test</title>
|
||||
<!-- <link rel="stylesheet" href="./res/font-awesome/css/font-awesome.min.css"> -->
|
||||
<link rel="stylesheet" href="main.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="wrapper">
|
||||
<div class="top-title">
|
||||
{{name}}的神秘商店
|
||||
</div>
|
||||
<div class="split"></div>
|
||||
<div class="top-head"></div>
|
||||
<div class="shop-border">
|
||||
{% for data in data_list %}
|
||||
<div class="shop-item">
|
||||
<div class="shop-item-title">
|
||||
<span class="shop-item-title-text">{{data.partition}}</span>
|
||||
</div>
|
||||
<div class="shop-item-border">
|
||||
<div class="shop-item-left">
|
||||
<img src="./res/img/{{data.left_image[2]}}" class="{{data.left_image[1]}} left-img"
|
||||
style="top:{{data.left_image[0]}}px" />
|
||||
</div>
|
||||
<div class="shop-item-mid">
|
||||
<div class="shop-item-mid-bk-inner"></div>
|
||||
<div class="shop-item-mid-bk-out">
|
||||
{% for goods in data['goods_list'] %}
|
||||
<div class="goods-item">
|
||||
<div class="goods-id">
|
||||
<div class="goods-id-text">{{goods.id}}</div>
|
||||
</div>
|
||||
<div class="goods-item-left">
|
||||
<div class="goods-item-left-o"></div>
|
||||
<div class="goods-item-left-o"></div>
|
||||
<div class="goods-item-left-o"></div>
|
||||
</div>
|
||||
<div class="goods-item-icon">
|
||||
<img src="{{goods.icon}}" class="goods-item-icon-img" />
|
||||
</div>
|
||||
<div class="goods-item-right">
|
||||
<div class="goods-item-right-des">
|
||||
<div class="goods-item-name">
|
||||
{{goods.name}}
|
||||
</div>
|
||||
<div class="goods-item-name-line"></div>
|
||||
{{goods.description}}
|
||||
</div>
|
||||
<div class="goods-item-right-price">
|
||||
<span>{{goods.price}}金币</span>
|
||||
<span class="goods-item-right-btn">
|
||||
<span class="goods-item-right-btn-buy">立即购买</span>
|
||||
<span class="goods-item-right-btn-line"></span>
|
||||
<span class="goods-item-right-btn-limit">限购: {{goods.daily_limit}}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<img src="./res/img/bag1.png" class="shop-item-mid-bag1" />
|
||||
<img src="./res/img/bag2.png" class="shop-item-mid-bag2" />
|
||||
</div>
|
||||
<div class="shop-item-right">
|
||||
<img src="./res/img/{{data.right_image[2]}}" class="{{data.right_image[1]}} right-img"
|
||||
style="top:{{data.right_image[0]}}px" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <div class="shop-item-border">
|
||||
<div class="shop-item-left">
|
||||
<img src="./res/img/2.png" class="shop-item-right-zx" />
|
||||
</div>
|
||||
<div class="shop-item-mid">
|
||||
<div class="shop-item-mid-bk-inner"></div>
|
||||
<div class="shop-item-mid-bk-out">
|
||||
<div class="goods-item">
|
||||
<div class="goods-id">
|
||||
<div class="goods-id-text">11</div>
|
||||
</div>
|
||||
<div class="goods-item-left">
|
||||
<div class="goods-item-left-o"></div>
|
||||
<div class="goods-item-left-o"></div>
|
||||
<div class="goods-item-left-o"></div>
|
||||
</div>
|
||||
<div class="goods-item-icon">
|
||||
<img src="./res/img/bag1.png" class="goods-item-icon-img" />
|
||||
</div>
|
||||
<div class="goods-item-right">
|
||||
<div class="goods-item-right-des">
|
||||
<div class="goods-item-name">
|
||||
签到道具
|
||||
</div>
|
||||
<div class="goods-item-name-line"></div>
|
||||
背包
|
||||
</div>
|
||||
<div class="goods-item-right-price">
|
||||
<span>100金币</span>
|
||||
<span class="goods-item-right-btn">
|
||||
<span class="goods-item-right-btn-buy">立即购买</span>
|
||||
<span class="goods-item-right-btn-line"></span>
|
||||
<span class="goods-item-right-btn-limit">限购: 0</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<img src="./res/img/bag1.png" class="shop-item-mid-bag1" />
|
||||
<img src="./res/img/bag2.png" class="shop-item-mid-bag2" />
|
||||
</div>
|
||||
<div class="shop-item-right">
|
||||
<img src="./res/img/1.png" class="shop-item-right-zx" />
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="split bottom-s"></div>
|
||||
</div>
|
||||
</body>
|
||||
<script type="text/javascript" src="main.js">
|
||||
</script>
|
||||
|
||||
</html>
|
||||
0
resources/template/shop/main.js
Normal file
BIN
resources/template/shop/res/img/1.png
Normal file
|
After Width: | Height: | Size: 122 KiB |
BIN
resources/template/shop/res/img/2.png
Normal file
|
After Width: | Height: | Size: 142 KiB |
BIN
resources/template/shop/res/img/bag1.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
resources/template/shop/res/img/bag2.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
resources/template/shop/res/img/bag3.png
Normal file
|
After Width: | Height: | Size: 6.7 KiB |
BIN
resources/template/shop/res/img/goods-bk.png
Normal file
|
After Width: | Height: | Size: 5.8 KiB |
BIN
resources/template/shop/res/img/head.png
Normal file
|
After Width: | Height: | Size: 125 KiB |
BIN
resources/template/shop/res/img/item-bk1.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
resources/template/shop/res/img/item-bk2.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
resources/template/shop/res/img/item-bk3.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
resources/template/shop/res/img/qq.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
resources/template/shop/res/img/split.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
resources/template/shop/res/img/title-bk.png
Normal file
|
After Width: | Height: | Size: 8.6 KiB |
@ -16,7 +16,7 @@ from nonebot_plugin_alconna import (
|
||||
)
|
||||
from nonebot_plugin_uninfo import Uninfo
|
||||
|
||||
from zhenxun.configs.utils import BaseBlock, PluginExtraData
|
||||
from zhenxun.configs.utils import BaseBlock, PluginExtraData, RegisterConfig
|
||||
from zhenxun.services.log import logger
|
||||
from zhenxun.utils.depends import UserName
|
||||
from zhenxun.utils.enum import BlockType, PluginType
|
||||
@ -45,6 +45,14 @@ __plugin_meta__ = PluginMetadata(
|
||||
plugin_type=PluginType.NORMAL,
|
||||
menu_type="商店",
|
||||
limits=[BaseBlock(check_type=BlockType.GROUP)],
|
||||
configs=[
|
||||
RegisterConfig(
|
||||
key="style",
|
||||
value="zhenxun",
|
||||
help="商店样式类型,[normal, zhenxun]",
|
||||
default_value="zhenxun",
|
||||
)
|
||||
],
|
||||
).dict(),
|
||||
)
|
||||
|
||||
@ -108,7 +116,7 @@ _matcher.shortcut(
|
||||
|
||||
@_matcher.assign("$main")
|
||||
async def _(session: Uninfo, arparma: Arparma):
|
||||
image = await ShopManage.build_shop_image()
|
||||
image = await ShopManage.get_shop_image()
|
||||
logger.info("查看商店", arparma.header_result, session=session)
|
||||
await MessageUtils.build_message(image).send()
|
||||
|
||||
|
||||
@ -10,7 +10,6 @@ from nonebot_plugin_alconna import UniMessage, UniMsg
|
||||
from nonebot_plugin_uninfo import Uninfo
|
||||
from pydantic import BaseModel, create_model
|
||||
|
||||
from zhenxun.configs.path_config import IMAGE_PATH
|
||||
from zhenxun.models.friend_user import FriendUser
|
||||
from zhenxun.models.goods_info import GoodsInfo
|
||||
from zhenxun.models.group_member_info import GroupInfoUser
|
||||
@ -19,19 +18,12 @@ from zhenxun.models.user_gold_log import UserGoldLog
|
||||
from zhenxun.models.user_props_log import UserPropsLog
|
||||
from zhenxun.services.log import logger
|
||||
from zhenxun.utils.enum import GoldHandle, PropHandle
|
||||
from zhenxun.utils.image_utils import BuildImage, ImageTemplate, text2image
|
||||
from zhenxun.utils.image_utils import BuildImage, ImageTemplate
|
||||
from zhenxun.utils.platform import PlatformUtils
|
||||
|
||||
ICON_PATH = IMAGE_PATH / "shop_icon"
|
||||
|
||||
RANK_ICON_PATH = IMAGE_PATH / "_icon"
|
||||
|
||||
PLATFORM_PATH = {
|
||||
"dodo": RANK_ICON_PATH / "dodo.png",
|
||||
"discord": RANK_ICON_PATH / "discord.png",
|
||||
"kaiheila": RANK_ICON_PATH / "kook.png",
|
||||
"qq": RANK_ICON_PATH / "qq.png",
|
||||
}
|
||||
from .config import ICON_PATH, PLATFORM_PATH, base_config
|
||||
from .html_image import html_image
|
||||
from .normal_image import normal_image
|
||||
|
||||
|
||||
class Goods(BaseModel):
|
||||
@ -137,6 +129,12 @@ async def gold_rank(
|
||||
class ShopManage:
|
||||
uuid2goods: dict[str, Goods] = {} # noqa: RUF012
|
||||
|
||||
@classmethod
|
||||
async def get_shop_image(cls) -> bytes:
|
||||
if base_config.get("style") == "zhenxun":
|
||||
return await html_image()
|
||||
return await normal_image()
|
||||
|
||||
@classmethod
|
||||
def __build_params(
|
||||
cls,
|
||||
@ -484,200 +482,3 @@ class ShopManage:
|
||||
"""
|
||||
user = await UserConsole.get_user(user_id, platform)
|
||||
return user.gold
|
||||
|
||||
@classmethod
|
||||
async def build_shop_image(cls) -> BuildImage:
|
||||
"""制作商店图片
|
||||
|
||||
返回:
|
||||
BuildImage: 商店图片
|
||||
"""
|
||||
goods_lst = await GoodsInfo.get_all_goods()
|
||||
h = 10
|
||||
_list: list[GoodsInfo] = [
|
||||
goods
|
||||
for goods in goods_lst
|
||||
if goods.goods_limit_time == 0 or time.time() < goods.goods_limit_time
|
||||
]
|
||||
# A = BuildImage(1100, h, color="#f9f6f2")
|
||||
total_n = 0
|
||||
image_list = []
|
||||
for idx, goods in enumerate(_list):
|
||||
name_image = BuildImage(
|
||||
580, 40, font_size=25, color="#e67b6b", font="CJGaoDeGuo.otf"
|
||||
)
|
||||
await name_image.text(
|
||||
(15, 0), f"{idx + 1}.{goods.goods_name}", center_type="height"
|
||||
)
|
||||
await name_image.line((380, -5, 280, 45), "#a29ad6", 5)
|
||||
await name_image.text((390, 0), "售价:", center_type="height")
|
||||
if goods.goods_discount != 1:
|
||||
discount_price = int(goods.goods_discount * goods.goods_price)
|
||||
old_price_image = await BuildImage.build_text_image(
|
||||
str(goods.goods_price), font_color=(194, 194, 194), size=15
|
||||
)
|
||||
await old_price_image.line(
|
||||
(
|
||||
0,
|
||||
int(old_price_image.height / 2),
|
||||
old_price_image.width + 1,
|
||||
int(old_price_image.height / 2),
|
||||
),
|
||||
(0, 0, 0),
|
||||
)
|
||||
await name_image.paste(old_price_image, (440, 0))
|
||||
await name_image.text((440, 15), str(discount_price), (255, 255, 255))
|
||||
else:
|
||||
await name_image.text(
|
||||
(440, 0),
|
||||
str(goods.goods_price),
|
||||
(255, 255, 255),
|
||||
center_type="height",
|
||||
)
|
||||
_tmp = await BuildImage.build_text_image(str(goods.goods_price), size=25)
|
||||
await name_image.text(
|
||||
(
|
||||
440 + _tmp.width,
|
||||
0,
|
||||
),
|
||||
" 金币",
|
||||
center_type="height",
|
||||
)
|
||||
des_image = None
|
||||
font_img = BuildImage(600, 80, font_size=20, color="#a29ad6")
|
||||
p = font_img.getsize("简介:")[0] + 20
|
||||
if goods.goods_description:
|
||||
des_list = goods.goods_description.split("\n")
|
||||
desc = ""
|
||||
for des in des_list:
|
||||
if font_img.getsize(des)[0] > font_img.width - p - 20:
|
||||
msg = ""
|
||||
tmp = ""
|
||||
for i in range(len(des)):
|
||||
if font_img.getsize(tmp)[0] < font_img.width - p - 20:
|
||||
tmp += des[i]
|
||||
else:
|
||||
msg += tmp + "\n"
|
||||
tmp = des[i]
|
||||
desc += msg
|
||||
if tmp:
|
||||
desc += tmp
|
||||
else:
|
||||
desc += des + "\n"
|
||||
if desc[-1] == "\n":
|
||||
desc = desc[:-1]
|
||||
des_image = await text2image(desc, color="#a29ad6")
|
||||
goods_image = BuildImage(
|
||||
600,
|
||||
(50 + des_image.height) if des_image else 50,
|
||||
font_size=20,
|
||||
color="#a29ad6",
|
||||
font="CJGaoDeGuo.otf",
|
||||
)
|
||||
if des_image:
|
||||
await goods_image.text((15, 50), "简介:")
|
||||
await goods_image.paste(des_image, (p, 50))
|
||||
await name_image.circle_corner(5)
|
||||
await goods_image.paste(name_image, (0, 5), center_type="width")
|
||||
await goods_image.circle_corner(20)
|
||||
bk = BuildImage(
|
||||
1180,
|
||||
(50 + des_image.height) if des_image else 50,
|
||||
font_size=15,
|
||||
color="#f9f6f2",
|
||||
font="CJGaoDeGuo.otf",
|
||||
)
|
||||
if goods.icon and (ICON_PATH / goods.icon).exists():
|
||||
icon = BuildImage(70, 70, background=ICON_PATH / goods.icon)
|
||||
await bk.paste(icon)
|
||||
await bk.paste(goods_image, (70, 0))
|
||||
n = 0
|
||||
_w = 650
|
||||
# 添加限时图标和时间
|
||||
if goods.goods_limit_time > 0:
|
||||
n += 140
|
||||
_limit_time_logo = BuildImage(
|
||||
40, 40, background=f"{IMAGE_PATH}/other/time.png"
|
||||
)
|
||||
await bk.paste(_limit_time_logo, (_w + 50, 0))
|
||||
_time_img = await BuildImage.build_text_image("限时!", size=23)
|
||||
await bk.paste(
|
||||
_time_img,
|
||||
(_w + 90, 10),
|
||||
)
|
||||
limit_time = time.strftime(
|
||||
"%Y-%m-%d %H:%M", time.localtime(goods.goods_limit_time)
|
||||
).split()
|
||||
y_m_d = limit_time[0]
|
||||
_h_m = limit_time[1].split(":")
|
||||
h_m = f"{_h_m[0]}时 {_h_m[1]}分"
|
||||
await bk.text((_w + 55, 38), str(y_m_d))
|
||||
await bk.text((_w + 65, 57), str(h_m))
|
||||
_w += 140
|
||||
if goods.goods_discount != 1:
|
||||
n += 140
|
||||
_discount_logo = BuildImage(
|
||||
30, 30, background=f"{IMAGE_PATH}/other/discount.png"
|
||||
)
|
||||
await bk.paste(_discount_logo, (_w + 50, 10))
|
||||
_tmp = await BuildImage.build_text_image("折扣!", size=23)
|
||||
await bk.paste(_tmp, (_w + 90, 15))
|
||||
_tmp = await BuildImage.build_text_image(
|
||||
f"{10 * goods.goods_discount:.1f} 折",
|
||||
size=30,
|
||||
font_color=(85, 156, 75),
|
||||
)
|
||||
await bk.paste(_tmp, (_w + 50, 44))
|
||||
_w += 140
|
||||
if goods.daily_limit != 0:
|
||||
n += 140
|
||||
_daily_limit_logo = BuildImage(
|
||||
35, 35, background=f"{IMAGE_PATH}/other/daily_limit.png"
|
||||
)
|
||||
await bk.paste(_daily_limit_logo, (_w + 50, 10))
|
||||
_tmp = await BuildImage.build_text_image(
|
||||
"限购!",
|
||||
size=23,
|
||||
)
|
||||
await bk.paste(_tmp, (_w + 90, 20))
|
||||
_tmp = await BuildImage.build_text_image(
|
||||
f"{goods.daily_limit}", size=30
|
||||
)
|
||||
await bk.paste(_tmp, (_w + 72, 45))
|
||||
total_n = max(total_n, n)
|
||||
if n:
|
||||
await bk.line((650, -1, 650 + n, -1), "#a29ad6", 5)
|
||||
# await bk.aline((650, 80, 650 + n, 80), "#a29ad6", 5)
|
||||
|
||||
# 添加限时图标和时间
|
||||
image_list.append(bk)
|
||||
# await A.apaste(bk, (0, current_h), True)
|
||||
# current_h += 90
|
||||
current_h = 0
|
||||
h = sum(img.height + 10 for img in image_list) or 400
|
||||
A = BuildImage(1100, h, color="#f9f6f2")
|
||||
for img in image_list:
|
||||
await A.paste(img, (0, current_h))
|
||||
current_h += img.height + 10
|
||||
w = 950
|
||||
if total_n:
|
||||
w += total_n
|
||||
h = A.height + 230 + 100
|
||||
h = max(h, 1000)
|
||||
shop_logo = BuildImage(100, 100, background=f"{IMAGE_PATH}/other/shop_text.png")
|
||||
shop = BuildImage(w, h, font_size=20, color="#f9f6f2")
|
||||
await shop.paste(A, (20, 230))
|
||||
await shop.paste(shop_logo, (450, 30))
|
||||
tip = "注【通过 购买道具 序号 或者 商品名称 购买】"
|
||||
await shop.text(
|
||||
(
|
||||
int((1000 - shop.getsize(tip)[0]) / 2),
|
||||
170,
|
||||
),
|
||||
"注【通过 序号 或者 商品名称 购买】",
|
||||
)
|
||||
await shop.text(
|
||||
(20, h - 100),
|
||||
"神秘药水\t\t售价:9999999金币\n\t\t鬼知道会有什么效果~",
|
||||
)
|
||||
return shop
|
||||
|
||||
20
zhenxun/builtin_plugins/shop/config.py
Normal file
@ -0,0 +1,20 @@
|
||||
from zhenxun.configs.config import Config
|
||||
from zhenxun.configs.path_config import IMAGE_PATH, TEMPLATE_PATH
|
||||
|
||||
base_config = Config.get("shop")
|
||||
|
||||
ICON_PATH = IMAGE_PATH / "shop_icon"
|
||||
|
||||
|
||||
RANK_ICON_PATH = IMAGE_PATH / "_icon"
|
||||
|
||||
PLATFORM_PATH = {
|
||||
"dodo": RANK_ICON_PATH / "dodo.png",
|
||||
"discord": RANK_ICON_PATH / "discord.png",
|
||||
"kaiheila": RANK_ICON_PATH / "kook.png",
|
||||
"qq": RANK_ICON_PATH / "qq.png",
|
||||
}
|
||||
|
||||
LEFT_RIGHT_IMAGE = ["1.png", "2.png", "qq.png"]
|
||||
|
||||
LEFT_RIGHT_PATH = TEMPLATE_PATH / "shop" / "res" / "img"
|
||||
91
zhenxun/builtin_plugins/shop/html_image.py
Normal file
@ -0,0 +1,91 @@
|
||||
import random
|
||||
import time
|
||||
|
||||
from nonebot_plugin_htmlrender import template_to_pic
|
||||
from pydantic import BaseModel
|
||||
|
||||
from zhenxun.configs.config import BotConfig
|
||||
from zhenxun.configs.path_config import TEMPLATE_PATH
|
||||
from zhenxun.models.goods_info import GoodsInfo
|
||||
from zhenxun.utils._build_image import BuildImage
|
||||
|
||||
from .config import ICON_PATH, LEFT_RIGHT_IMAGE
|
||||
|
||||
|
||||
class GoodsItem(BaseModel):
|
||||
goods_list: list[dict]
|
||||
"""商品列表"""
|
||||
partition: str
|
||||
"""分区名称"""
|
||||
left_image: tuple[int, str, str]
|
||||
"""左图"""
|
||||
right_image: tuple[int, str, str]
|
||||
"""右图"""
|
||||
|
||||
|
||||
def get_left_right_image() -> tuple[tuple[int, str, str], tuple[int, str, str]]:
|
||||
qq_top = random.randint(0, 280)
|
||||
img_top = random.randint(10, 80)
|
||||
left_image = random.choice(LEFT_RIGHT_IMAGE)
|
||||
right_image = None
|
||||
if left_image == "qq.png":
|
||||
left_top = qq_top
|
||||
right_top = img_top
|
||||
left_css = "shop-item-left-qq"
|
||||
right_css = "shop-item-right-zx"
|
||||
right_image = random.choice(LEFT_RIGHT_IMAGE[:-1])
|
||||
else:
|
||||
left_top = img_top
|
||||
right_top = qq_top
|
||||
right_image = "qq.png"
|
||||
left_css = "shop-item-right-zx"
|
||||
right_css = "shop-item-left-qq"
|
||||
return (left_top, left_css, left_image), (right_top, right_css, right_image)
|
||||
|
||||
|
||||
async def html_image() -> bytes:
|
||||
"""构建图片"""
|
||||
goods_list: list[tuple[int, GoodsInfo]] = [
|
||||
(i + 1, goods)
|
||||
for i, goods in enumerate(await GoodsInfo.get_all_goods())
|
||||
if goods.goods_limit_time == 0 or time.time() < goods.goods_limit_time
|
||||
]
|
||||
partition_dict: dict[str, list[dict]] = {}
|
||||
for goods in goods_list:
|
||||
if not goods[1].partition:
|
||||
goods[1].partition = "默认分区"
|
||||
if goods[1].partition not in partition_dict:
|
||||
partition_dict[goods[1].partition] = []
|
||||
partition_dict[goods[1].partition].append(
|
||||
{
|
||||
"id": goods[0],
|
||||
"price": goods[1].goods_price,
|
||||
"daily_limit": goods[1].daily_limit or "∞",
|
||||
"name": goods[1].goods_name,
|
||||
"icon": "data:image/png;base64,"
|
||||
+ BuildImage.open(ICON_PATH / goods[1].icon).pic2bs4()[9:],
|
||||
"description": goods[1].goods_description,
|
||||
}
|
||||
)
|
||||
data_list = []
|
||||
for partition in partition_dict:
|
||||
left, right = get_left_right_image()
|
||||
data_list.append(
|
||||
GoodsItem(
|
||||
goods_list=partition_dict[partition],
|
||||
partition=partition,
|
||||
left_image=left,
|
||||
right_image=right,
|
||||
)
|
||||
)
|
||||
|
||||
return await template_to_pic(
|
||||
template_path=str((TEMPLATE_PATH / "shop").absolute()),
|
||||
template_name="main.html",
|
||||
templates={"name": BotConfig.self_nickname, "data_list": data_list},
|
||||
pages={
|
||||
"viewport": {"width": 800, "height": 1024},
|
||||
"base_url": f"file://{TEMPLATE_PATH}",
|
||||
},
|
||||
wait=2,
|
||||
)
|
||||
203
zhenxun/builtin_plugins/shop/normal_image.py
Normal file
@ -0,0 +1,203 @@
|
||||
import time
|
||||
|
||||
from zhenxun.configs.path_config import IMAGE_PATH
|
||||
from zhenxun.models.goods_info import GoodsInfo
|
||||
from zhenxun.utils._build_image import BuildImage
|
||||
from zhenxun.utils.image_utils import text2image
|
||||
|
||||
from .config import ICON_PATH
|
||||
|
||||
|
||||
async def normal_image() -> bytes:
|
||||
"""制作商店图片
|
||||
|
||||
返回:
|
||||
BuildImage: 商店图片
|
||||
"""
|
||||
goods_lst = await GoodsInfo.get_all_goods()
|
||||
h = 10
|
||||
_list: list[GoodsInfo] = [
|
||||
goods
|
||||
for goods in goods_lst
|
||||
if goods.goods_limit_time == 0 or time.time() < goods.goods_limit_time
|
||||
]
|
||||
# A = BuildImage(1100, h, color="#f9f6f2")
|
||||
total_n = 0
|
||||
image_list = []
|
||||
for idx, goods in enumerate(_list):
|
||||
name_image = BuildImage(
|
||||
580, 40, font_size=25, color="#e67b6b", font="CJGaoDeGuo.otf"
|
||||
)
|
||||
await name_image.text(
|
||||
(15, 0), f"{idx + 1}.{goods.goods_name}", center_type="height"
|
||||
)
|
||||
await name_image.line((380, -5, 280, 45), "#a29ad6", 5)
|
||||
await name_image.text((390, 0), "售价:", center_type="height")
|
||||
if goods.goods_discount != 1:
|
||||
discount_price = int(goods.goods_discount * goods.goods_price)
|
||||
old_price_image = await BuildImage.build_text_image(
|
||||
str(goods.goods_price), font_color=(194, 194, 194), size=15
|
||||
)
|
||||
await old_price_image.line(
|
||||
(
|
||||
0,
|
||||
int(old_price_image.height / 2),
|
||||
old_price_image.width + 1,
|
||||
int(old_price_image.height / 2),
|
||||
),
|
||||
(0, 0, 0),
|
||||
)
|
||||
await name_image.paste(old_price_image, (440, 0))
|
||||
await name_image.text((440, 15), str(discount_price), (255, 255, 255))
|
||||
else:
|
||||
await name_image.text(
|
||||
(440, 0),
|
||||
str(goods.goods_price),
|
||||
(255, 255, 255),
|
||||
center_type="height",
|
||||
)
|
||||
_tmp = await BuildImage.build_text_image(str(goods.goods_price), size=25)
|
||||
await name_image.text(
|
||||
(
|
||||
440 + _tmp.width,
|
||||
0,
|
||||
),
|
||||
" 金币",
|
||||
center_type="height",
|
||||
)
|
||||
des_image = None
|
||||
font_img = BuildImage(600, 80, font_size=20, color="#a29ad6")
|
||||
p = font_img.getsize("简介:")[0] + 20
|
||||
if goods.goods_description:
|
||||
des_list = goods.goods_description.split("\n")
|
||||
desc = ""
|
||||
for des in des_list:
|
||||
if font_img.getsize(des)[0] > font_img.width - p - 20:
|
||||
msg = ""
|
||||
tmp = ""
|
||||
for i in range(len(des)):
|
||||
if font_img.getsize(tmp)[0] < font_img.width - p - 20:
|
||||
tmp += des[i]
|
||||
else:
|
||||
msg += tmp + "\n"
|
||||
tmp = des[i]
|
||||
desc += msg
|
||||
if tmp:
|
||||
desc += tmp
|
||||
else:
|
||||
desc += des + "\n"
|
||||
if desc[-1] == "\n":
|
||||
desc = desc[:-1]
|
||||
des_image = await text2image(desc, color="#a29ad6")
|
||||
goods_image = BuildImage(
|
||||
600,
|
||||
(50 + des_image.height) if des_image else 50,
|
||||
font_size=20,
|
||||
color="#a29ad6",
|
||||
font="CJGaoDeGuo.otf",
|
||||
)
|
||||
if des_image:
|
||||
await goods_image.text((15, 50), "简介:")
|
||||
await goods_image.paste(des_image, (p, 50))
|
||||
await name_image.circle_corner(5)
|
||||
await goods_image.paste(name_image, (0, 5), center_type="width")
|
||||
await goods_image.circle_corner(20)
|
||||
bk = BuildImage(
|
||||
1180,
|
||||
(50 + des_image.height) if des_image else 50,
|
||||
font_size=15,
|
||||
color="#f9f6f2",
|
||||
font="CJGaoDeGuo.otf",
|
||||
)
|
||||
if goods.icon and (ICON_PATH / goods.icon).exists():
|
||||
icon = BuildImage(70, 70, background=ICON_PATH / goods.icon)
|
||||
await bk.paste(icon)
|
||||
await bk.paste(goods_image, (70, 0))
|
||||
n = 0
|
||||
_w = 650
|
||||
# 添加限时图标和时间
|
||||
if goods.goods_limit_time > 0:
|
||||
n += 140
|
||||
_limit_time_logo = BuildImage(
|
||||
40, 40, background=f"{IMAGE_PATH}/other/time.png"
|
||||
)
|
||||
await bk.paste(_limit_time_logo, (_w + 50, 0))
|
||||
_time_img = await BuildImage.build_text_image("限时!", size=23)
|
||||
await bk.paste(
|
||||
_time_img,
|
||||
(_w + 90, 10),
|
||||
)
|
||||
limit_time = time.strftime(
|
||||
"%Y-%m-%d %H:%M", time.localtime(goods.goods_limit_time)
|
||||
).split()
|
||||
y_m_d = limit_time[0]
|
||||
_h_m = limit_time[1].split(":")
|
||||
h_m = f"{_h_m[0]}时 {_h_m[1]}分"
|
||||
await bk.text((_w + 55, 38), str(y_m_d))
|
||||
await bk.text((_w + 65, 57), str(h_m))
|
||||
_w += 140
|
||||
if goods.goods_discount != 1:
|
||||
n += 140
|
||||
_discount_logo = BuildImage(
|
||||
30, 30, background=f"{IMAGE_PATH}/other/discount.png"
|
||||
)
|
||||
await bk.paste(_discount_logo, (_w + 50, 10))
|
||||
_tmp = await BuildImage.build_text_image("折扣!", size=23)
|
||||
await bk.paste(_tmp, (_w + 90, 15))
|
||||
_tmp = await BuildImage.build_text_image(
|
||||
f"{10 * goods.goods_discount:.1f} 折",
|
||||
size=30,
|
||||
font_color=(85, 156, 75),
|
||||
)
|
||||
await bk.paste(_tmp, (_w + 50, 44))
|
||||
_w += 140
|
||||
if goods.daily_limit != 0:
|
||||
n += 140
|
||||
_daily_limit_logo = BuildImage(
|
||||
35, 35, background=f"{IMAGE_PATH}/other/daily_limit.png"
|
||||
)
|
||||
await bk.paste(_daily_limit_logo, (_w + 50, 10))
|
||||
_tmp = await BuildImage.build_text_image(
|
||||
"限购!",
|
||||
size=23,
|
||||
)
|
||||
await bk.paste(_tmp, (_w + 90, 20))
|
||||
_tmp = await BuildImage.build_text_image(f"{goods.daily_limit}", size=30)
|
||||
await bk.paste(_tmp, (_w + 72, 45))
|
||||
total_n = max(total_n, n)
|
||||
if n:
|
||||
await bk.line((650, -1, 650 + n, -1), "#a29ad6", 5)
|
||||
# await bk.aline((650, 80, 650 + n, 80), "#a29ad6", 5)
|
||||
|
||||
# 添加限时图标和时间
|
||||
image_list.append(bk)
|
||||
# await A.apaste(bk, (0, current_h), True)
|
||||
# current_h += 90
|
||||
current_h = 0
|
||||
h = sum(img.height + 10 for img in image_list) or 400
|
||||
A = BuildImage(1100, h, color="#f9f6f2")
|
||||
for img in image_list:
|
||||
await A.paste(img, (0, current_h))
|
||||
current_h += img.height + 10
|
||||
w = 950
|
||||
if total_n:
|
||||
w += total_n
|
||||
h = A.height + 230 + 100
|
||||
h = max(h, 1000)
|
||||
shop_logo = BuildImage(100, 100, background=f"{IMAGE_PATH}/other/shop_text.png")
|
||||
shop = BuildImage(w, h, font_size=20, color="#f9f6f2")
|
||||
await shop.paste(A, (20, 230))
|
||||
await shop.paste(shop_logo, (450, 30))
|
||||
tip = "注【通过 购买道具 序号 或者 商品名称 购买】"
|
||||
await shop.text(
|
||||
(
|
||||
int((1000 - shop.getsize(tip)[0]) / 2),
|
||||
170,
|
||||
),
|
||||
"注【通过 序号 或者 商品名称 购买】",
|
||||
)
|
||||
await shop.text(
|
||||
(20, h - 100),
|
||||
"神秘药水\t\t售价:9999999金币\n\t\t鬼知道会有什么效果~",
|
||||
)
|
||||
return shop.pic2bytes()
|
||||
@ -1,117 +1,117 @@
|
||||
import asyncio
|
||||
import secrets
|
||||
# import asyncio
|
||||
# import secrets
|
||||
|
||||
from fastapi import APIRouter, FastAPI
|
||||
import nonebot
|
||||
from nonebot.log import default_filter, default_format
|
||||
from nonebot.plugin import PluginMetadata
|
||||
# from fastapi import APIRouter, FastAPI
|
||||
# import nonebot
|
||||
# from nonebot.log import default_filter, default_format
|
||||
# from nonebot.plugin import PluginMetadata
|
||||
|
||||
from zhenxun.configs.config import Config as gConfig
|
||||
from zhenxun.configs.utils import PluginExtraData, RegisterConfig
|
||||
from zhenxun.services.log import logger, logger_
|
||||
from zhenxun.utils.enum import PluginType
|
||||
# from zhenxun.configs.config import Config as gConfig
|
||||
# from zhenxun.configs.utils import PluginExtraData, RegisterConfig
|
||||
# from zhenxun.services.log import logger, logger_
|
||||
# from zhenxun.utils.enum import PluginType
|
||||
|
||||
from .api.logs import router as ws_log_routes
|
||||
from .api.logs.log_manager import LOG_STORAGE
|
||||
from .api.tabs.dashboard import router as dashboard_router
|
||||
from .api.tabs.database import router as database_router
|
||||
from .api.tabs.main import router as main_router
|
||||
from .api.tabs.main import ws_router as status_routes
|
||||
from .api.tabs.manage import router as manage_router
|
||||
from .api.tabs.manage.chat import ws_router as chat_routes
|
||||
from .api.tabs.plugin_manage import router as plugin_router
|
||||
from .api.tabs.plugin_manage.store import router as store_router
|
||||
from .api.tabs.system import router as system_router
|
||||
from .auth import router as auth_router
|
||||
from .public import init_public
|
||||
# from .api.logs import router as ws_log_routes
|
||||
# from .api.logs.log_manager import LOG_STORAGE
|
||||
# from .api.tabs.dashboard import router as dashboard_router
|
||||
# from .api.tabs.database import router as database_router
|
||||
# from .api.tabs.main import router as main_router
|
||||
# from .api.tabs.main import ws_router as status_routes
|
||||
# from .api.tabs.manage import router as manage_router
|
||||
# from .api.tabs.manage.chat import ws_router as chat_routes
|
||||
# from .api.tabs.plugin_manage import router as plugin_router
|
||||
# from .api.tabs.plugin_manage.store import router as store_router
|
||||
# from .api.tabs.system import router as system_router
|
||||
# from .auth import router as auth_router
|
||||
# from .public import init_public
|
||||
|
||||
__plugin_meta__ = PluginMetadata(
|
||||
name="WebUi",
|
||||
description="WebUi API",
|
||||
usage="""
|
||||
""".strip(),
|
||||
extra=PluginExtraData(
|
||||
author="HibiKier",
|
||||
version="0.1",
|
||||
plugin_type=PluginType.HIDDEN,
|
||||
configs=[
|
||||
RegisterConfig(
|
||||
module="web-ui",
|
||||
key="username",
|
||||
value="admin",
|
||||
help="前端管理用户名",
|
||||
type=str,
|
||||
default_value="admin",
|
||||
),
|
||||
RegisterConfig(
|
||||
module="web-ui",
|
||||
key="password",
|
||||
value=None,
|
||||
help="前端管理密码",
|
||||
type=str,
|
||||
default_value=None,
|
||||
),
|
||||
RegisterConfig(
|
||||
module="web-ui",
|
||||
key="secret",
|
||||
value=secrets.token_urlsafe(32),
|
||||
help="JWT密钥",
|
||||
type=str,
|
||||
default_value=None,
|
||||
),
|
||||
],
|
||||
).dict(),
|
||||
)
|
||||
# __plugin_meta__ = PluginMetadata(
|
||||
# name="WebUi",
|
||||
# description="WebUi API",
|
||||
# usage="""
|
||||
# """.strip(),
|
||||
# extra=PluginExtraData(
|
||||
# author="HibiKier",
|
||||
# version="0.1",
|
||||
# plugin_type=PluginType.HIDDEN,
|
||||
# configs=[
|
||||
# RegisterConfig(
|
||||
# module="web-ui",
|
||||
# key="username",
|
||||
# value="admin",
|
||||
# help="前端管理用户名",
|
||||
# type=str,
|
||||
# default_value="admin",
|
||||
# ),
|
||||
# RegisterConfig(
|
||||
# module="web-ui",
|
||||
# key="password",
|
||||
# value=None,
|
||||
# help="前端管理密码",
|
||||
# type=str,
|
||||
# default_value=None,
|
||||
# ),
|
||||
# RegisterConfig(
|
||||
# module="web-ui",
|
||||
# key="secret",
|
||||
# value=secrets.token_urlsafe(32),
|
||||
# help="JWT密钥",
|
||||
# type=str,
|
||||
# default_value=None,
|
||||
# ),
|
||||
# ],
|
||||
# ).dict(),
|
||||
# )
|
||||
|
||||
driver = nonebot.get_driver()
|
||||
# driver = nonebot.get_driver()
|
||||
|
||||
|
||||
gConfig.set_name("web-ui", "web-ui")
|
||||
# gConfig.set_name("web-ui", "web-ui")
|
||||
|
||||
|
||||
BaseApiRouter = APIRouter(prefix="/zhenxun/api")
|
||||
# BaseApiRouter = APIRouter(prefix="/zhenxun/api")
|
||||
|
||||
|
||||
BaseApiRouter.include_router(auth_router)
|
||||
BaseApiRouter.include_router(store_router)
|
||||
BaseApiRouter.include_router(dashboard_router)
|
||||
BaseApiRouter.include_router(main_router)
|
||||
BaseApiRouter.include_router(manage_router)
|
||||
BaseApiRouter.include_router(database_router)
|
||||
BaseApiRouter.include_router(plugin_router)
|
||||
BaseApiRouter.include_router(system_router)
|
||||
# BaseApiRouter.include_router(auth_router)
|
||||
# BaseApiRouter.include_router(store_router)
|
||||
# BaseApiRouter.include_router(dashboard_router)
|
||||
# BaseApiRouter.include_router(main_router)
|
||||
# BaseApiRouter.include_router(manage_router)
|
||||
# BaseApiRouter.include_router(database_router)
|
||||
# BaseApiRouter.include_router(plugin_router)
|
||||
# BaseApiRouter.include_router(system_router)
|
||||
|
||||
|
||||
WsApiRouter = APIRouter(prefix="/zhenxun/socket")
|
||||
# WsApiRouter = APIRouter(prefix="/zhenxun/socket")
|
||||
|
||||
WsApiRouter.include_router(ws_log_routes)
|
||||
WsApiRouter.include_router(status_routes)
|
||||
WsApiRouter.include_router(chat_routes)
|
||||
# WsApiRouter.include_router(ws_log_routes)
|
||||
# WsApiRouter.include_router(status_routes)
|
||||
# WsApiRouter.include_router(chat_routes)
|
||||
|
||||
|
||||
@driver.on_startup
|
||||
async def _():
|
||||
try:
|
||||
# @driver.on_startup
|
||||
# async def _():
|
||||
# try:
|
||||
|
||||
async def log_sink(message: str):
|
||||
loop = None
|
||||
if not loop:
|
||||
try:
|
||||
loop = asyncio.get_running_loop()
|
||||
except Exception as e:
|
||||
logger.warning("Web Ui log_sink", e=e)
|
||||
if not loop:
|
||||
loop = asyncio.new_event_loop()
|
||||
loop.create_task(LOG_STORAGE.add(message.rstrip("\n"))) # noqa: RUF006
|
||||
# async def log_sink(message: str):
|
||||
# loop = None
|
||||
# if not loop:
|
||||
# try:
|
||||
# loop = asyncio.get_running_loop()
|
||||
# except Exception as e:
|
||||
# logger.warning("Web Ui log_sink", e=e)
|
||||
# if not loop:
|
||||
# loop = asyncio.new_event_loop()
|
||||
# loop.create_task(LOG_STORAGE.add(message.rstrip("\n")))
|
||||
|
||||
logger_.add(
|
||||
log_sink, colorize=True, filter=default_filter, format=default_format
|
||||
)
|
||||
# logger_.add(
|
||||
# log_sink, colorize=True, filter=default_filter, format=default_format
|
||||
# )
|
||||
|
||||
app: FastAPI = nonebot.get_app()
|
||||
app.include_router(BaseApiRouter)
|
||||
app.include_router(WsApiRouter)
|
||||
await init_public(app)
|
||||
logger.info("<g>API启动成功</g>", "Web UI")
|
||||
except Exception as e:
|
||||
logger.error("<g>API启动失败</g>", "Web UI", e=e)
|
||||
# app: FastAPI = nonebot.get_app()
|
||||
# app.include_router(BaseApiRouter)
|
||||
# app.include_router(WsApiRouter)
|
||||
# await init_public(app)
|
||||
# logger.info("<g>API启动成功</g>", "Web UI")
|
||||
# except Exception as e:
|
||||
# logger.error("<g>API启动失败</g>", "Web UI", e=e)
|
||||
|
||||
@ -27,10 +27,12 @@ class GoodsInfo(Model):
|
||||
"""每日限购"""
|
||||
is_passive = fields.BooleanField(default=False)
|
||||
"""是否为被动道具"""
|
||||
partition = fields.CharField(255, null=True)
|
||||
"""分区名称"""
|
||||
icon = fields.TextField(null=True)
|
||||
"""图标路径"""
|
||||
|
||||
class Meta:
|
||||
class Meta: # type: ignore
|
||||
table = "goods_info"
|
||||
table_description = "商品数据表"
|
||||
|
||||
@ -159,4 +161,5 @@ class GoodsInfo(Model):
|
||||
"ALTER TABLE goods_info ADD icon VARCHAR(255);",
|
||||
# 删除 daily_purchase_limit 字段
|
||||
"ALTER TABLE goods_info DROP daily_purchase_limit;",
|
||||
"ALTER TABLE goods_info ADD partition VARCHAR(255);",
|
||||
]
|
||||
|
||||