refactor: add store mixin into city regions & refactor buying action
This commit is contained in:
@@ -5,9 +5,8 @@ from typing import TYPE_CHECKING, Tuple, Any
|
||||
from src.classes.action import InstantAction
|
||||
from src.classes.event import Event
|
||||
from src.classes.region import CityRegion
|
||||
from src.classes.elixir import Elixir, get_elixirs_by_realm
|
||||
from src.classes.elixir import Elixir
|
||||
from src.classes.prices import prices
|
||||
from src.classes.cultivation import Realm
|
||||
from src.classes.weapon import Weapon
|
||||
from src.classes.auxiliary import Auxiliary
|
||||
from src.classes.material import Material
|
||||
@@ -28,8 +27,7 @@ class Buy(InstantAction):
|
||||
|
||||
ACTION_NAME = "购买"
|
||||
EMOJI = "💸"
|
||||
elixir_names_str = ", ".join([e.name for e in get_elixirs_by_realm(Realm.Qi_Refinement)])
|
||||
DESC = f"在城镇购买物品/装备(丹药购买后将立即服用)。可选丹药:{elixir_names_str}"
|
||||
DESC = f"在城镇购买物品/装备/丹药。"
|
||||
DOABLES_REQUIREMENTS = "在城镇且金钱足够"
|
||||
PARAMS = {"target_name": "str"}
|
||||
|
||||
@@ -42,6 +40,15 @@ class Buy(InstantAction):
|
||||
if not res.is_valid:
|
||||
return False, f"未知物品: {target_name}"
|
||||
|
||||
# 检查商店是否售卖
|
||||
# 必须是 StoreMixin (CityRegion 混入了 StoreMixin)
|
||||
if hasattr(region, "is_selling"):
|
||||
if not region.is_selling(res.obj.name):
|
||||
return False, f"{region.name} 不出售 {res.obj.name}"
|
||||
else:
|
||||
# 如果不是商店区域(虽然前面已经检查了 CityRegion,但为了安全)
|
||||
return False, "该区域没有商店"
|
||||
|
||||
# 核心逻辑委托给 Avatar
|
||||
return self.avatar.can_buy_item(res.obj)
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@ class Auxiliary(Item):
|
||||
full_desc = f"{full_desc} (已吞噬魂魄:{souls})"
|
||||
|
||||
return {
|
||||
"id": str(self.id),
|
||||
"name": self.name,
|
||||
"desc": full_desc,
|
||||
"grade": self.realm.value,
|
||||
|
||||
@@ -185,10 +185,6 @@ class InventoryMixin:
|
||||
|
||||
# 2. 丹药特殊检查
|
||||
if isinstance(obj, Elixir):
|
||||
# 商店业务规则:当前仅开放练气期丹药购买
|
||||
if obj.realm != Realm.Qi_Refinement:
|
||||
return False, "当前仅开放练气期丹药购买"
|
||||
|
||||
# 境界限制
|
||||
if obj.realm > self.cultivation_progress.realm:
|
||||
return False, f"境界不足,无法承受药力 ({obj.realm.value})"
|
||||
|
||||
@@ -63,6 +63,7 @@ class Elixir(Item):
|
||||
|
||||
def get_structured_info(self) -> dict:
|
||||
return {
|
||||
"id": str(self.id),
|
||||
"name": self.name,
|
||||
"desc": self.desc,
|
||||
"grade": self.realm.value,
|
||||
|
||||
@@ -11,6 +11,7 @@ from src.classes.animal import Animal, animals_by_id
|
||||
from src.classes.plant import Plant, plants_by_id
|
||||
from src.classes.lode import Lode, lodes_by_id
|
||||
from src.classes.sect import sects_by_name
|
||||
from src.classes.store import StoreMixin
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from src.classes.avatar import Avatar
|
||||
@@ -212,18 +213,48 @@ class CultivateRegion(Region):
|
||||
|
||||
|
||||
@dataclass(eq=False)
|
||||
class CityRegion(Region):
|
||||
class CityRegion(Region, StoreMixin):
|
||||
"""城市区域"""
|
||||
sell_items: str = field(default="[]")
|
||||
|
||||
def __post_init__(self):
|
||||
super().__post_init__()
|
||||
try:
|
||||
import ast
|
||||
items_list = ast.literal_eval(self.sell_items)
|
||||
if isinstance(items_list, list):
|
||||
self.init_store(items_list)
|
||||
else:
|
||||
self.init_store([])
|
||||
except Exception:
|
||||
self.init_store([])
|
||||
|
||||
def get_region_type(self) -> str:
|
||||
return "city"
|
||||
|
||||
def _get_desc(self) -> str:
|
||||
store_info = self.get_store_info()
|
||||
if store_info:
|
||||
return f"({store_info})"
|
||||
return ""
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"城市区域:{self.name} - {self.desc}"
|
||||
store_info = self.get_store_info()
|
||||
desc_part = f" | {store_info}" if store_info else ""
|
||||
return f"城市区域:{self.name} - {self.desc}{desc_part}"
|
||||
|
||||
def get_structured_info(self) -> dict:
|
||||
info = super().get_structured_info()
|
||||
info["type_name"] = "城市区域"
|
||||
|
||||
store_items_info = []
|
||||
if hasattr(self, 'store_items'):
|
||||
from src.classes.prices import prices
|
||||
for item in self.store_items:
|
||||
item_info = item.get_structured_info()
|
||||
# Inject price
|
||||
item_info["price"] = prices.get_buying_price(item, None)
|
||||
store_items_info.append(item_info)
|
||||
|
||||
info["store_items"] = store_items_info
|
||||
return info
|
||||
|
||||
72
src/classes/store.py
Normal file
72
src/classes/store.py
Normal file
@@ -0,0 +1,72 @@
|
||||
from collections import defaultdict
|
||||
from typing import Any, List
|
||||
|
||||
from src.utils.resolution import resolve_query
|
||||
from src.classes.elixir import Elixir
|
||||
from src.classes.weapon import Weapon
|
||||
from src.classes.auxiliary import Auxiliary
|
||||
from src.classes.prices import prices
|
||||
|
||||
class StoreMixin:
|
||||
"""
|
||||
商店功能混入类
|
||||
赋予区域售卖物品的能力
|
||||
"""
|
||||
|
||||
def init_store(self, item_names: list[str]):
|
||||
"""
|
||||
初始化商店物品
|
||||
:param item_names: 物品名称列表
|
||||
"""
|
||||
self.store_items = []
|
||||
if not item_names:
|
||||
return
|
||||
|
||||
for name in item_names:
|
||||
# 期望类型:丹药、武器、辅助
|
||||
res = resolve_query(name, expected_types=[Elixir, Weapon, Auxiliary])
|
||||
if res.is_valid and res.obj:
|
||||
self.store_items.append(res.obj)
|
||||
|
||||
def get_store_info(self) -> str:
|
||||
"""
|
||||
获取商店信息描述
|
||||
例如:交易:练气剑、练气刀(100灵石);练气破境丹(50灵石)
|
||||
"""
|
||||
# 如果没有初始化或者没有物品
|
||||
if not hasattr(self, 'store_items') or not self.store_items:
|
||||
return ""
|
||||
|
||||
# 按价格分组
|
||||
items_by_price = defaultdict(list)
|
||||
for item in self.store_items:
|
||||
# 获取该物品的标准购买价格(作为标价,买家为 None)
|
||||
price = prices.get_buying_price(item, None)
|
||||
items_by_price[price].append(item.name)
|
||||
|
||||
if not items_by_price:
|
||||
return ""
|
||||
|
||||
# 格式化输出
|
||||
parts = []
|
||||
# 按价格从低到高排序
|
||||
for price in sorted(items_by_price.keys()):
|
||||
names = items_by_price[price]
|
||||
# 去重并保持顺序 (Python 3.7+ dict key insertion order)
|
||||
unique_names = list(dict.fromkeys(names))
|
||||
names_str = "、".join(unique_names)
|
||||
parts.append(f"{names_str}({price}灵石)")
|
||||
|
||||
return "交易:" + ";".join(parts)
|
||||
|
||||
def is_selling(self, item_name: str) -> bool:
|
||||
"""
|
||||
检查商店是否出售该物品
|
||||
"""
|
||||
if not hasattr(self, 'store_items'):
|
||||
return False
|
||||
|
||||
# 简单的名字匹配 (Assuming item.name is what we look for)
|
||||
# 如果需要更严格的匹配(如 normalized name),需要在这里处理,
|
||||
# 但通常 resolve_query 解析出的 obj.name 是标准名。
|
||||
return any(item.name == item_name for item in self.store_items)
|
||||
@@ -48,6 +48,7 @@ class Weapon(Item):
|
||||
|
||||
def get_structured_info(self) -> dict:
|
||||
return {
|
||||
"id": str(self.id),
|
||||
"name": self.name,
|
||||
"desc": self.desc,
|
||||
"grade": self.realm.value,
|
||||
|
||||
@@ -104,6 +104,10 @@ def _load_and_assign_regions(game_map: Map, region_coords: dict[int, list[tuple[
|
||||
elif type_tag == "cultivate":
|
||||
params["essence_type"] = EssenceType.from_str(get_str(row, "root_type"))
|
||||
params["essence_density"] = get_int(row, "root_density")
|
||||
elif type_tag == "city":
|
||||
sell_items_str = get_str(row, "sell_items")
|
||||
if sell_items_str:
|
||||
params["sell_items"] = sell_items_str
|
||||
elif type_tag == "sect":
|
||||
sect_id = get_int(row, "sect_id")
|
||||
params["sect_id"] = sect_id
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
id,name,desc
|
||||
ID必须以3开头,,
|
||||
301,青云城,繁华都市,人烟稠密,商贾云集。此地是交易天材地宝、寻找机缘的重要场所。
|
||||
302,沙月城,沙漠绿洲中的贸易重镇,各路商队在此集结,是修士补给和交流的重要据点。
|
||||
303,翠林城,森林深处的修仙重镇,众多修士在此栖居,是修炼和炼宝的理想之地。
|
||||
304,沧澜城,坐落于大河入海口的三角洲,百川归海,水运昌隆,是水系修士往来最为频繁的宝地。
|
||||
305,揽月城,屹立于连绵群山之巅,终年云雾缭绕,灵气纯净,是苦修之士感悟天道的绝佳场所。
|
||||
id,name,desc,sell_items
|
||||
ID必须以3开头,,,
|
||||
301,青云城,繁华都市,人烟稠密,商贾云集。此地是交易天材地宝、寻找机缘的重要场所。,"['练气破境丹', '练气长生丹']"
|
||||
302,沙月城,沙漠绿洲中的贸易重镇,各路商队在此集结,是修士补给和交流的重要据点。,"['练气燃血丹', '练气回春丹']"
|
||||
303,翠林城,森林深处的修仙重镇,众多修士在此栖居,是修炼和炼宝的理想之地。,"['练气剑', '练气刀', '练气枪']"
|
||||
304,沧澜城,坐落于大河入海口的三角洲,百川归海,水运昌隆,是水系修士往来最为频繁的宝地。,"['练气棍', '练气扇', '练气鞭']"
|
||||
305,揽月城,屹立于连绵群山之巅,终年云雾缭绕,灵气纯净,是苦修之士感悟天道的绝佳场所。,"['练气琴', '练气笛', '练气暗器']"
|
||||
|
||||
|
@@ -12,25 +12,33 @@ def test_buy_item_success(avatar_in_city, mock_item_data):
|
||||
materials_mock = mock_item_data["materials"]
|
||||
test_material = mock_item_data["obj_material"]
|
||||
|
||||
with patch("src.utils.resolution.elixirs_by_name", elixirs_mock), \
|
||||
patch("src.utils.resolution.materials_by_name", materials_mock):
|
||||
|
||||
action = Buy(avatar_in_city, avatar_in_city.world)
|
||||
|
||||
# 1. 检查是否可购买
|
||||
can_start, reason = action.can_start("铁矿石")
|
||||
assert can_start is True
|
||||
|
||||
# 2. 执行购买
|
||||
initial_money = avatar_in_city.magic_stone
|
||||
# 练气期材料基础价格 10,倍率 1.5 -> 15
|
||||
expected_price = int(10 * 1.5)
|
||||
|
||||
action._execute("铁矿石")
|
||||
|
||||
# 3. 验证结果
|
||||
assert avatar_in_city.magic_stone == initial_money - expected_price
|
||||
assert avatar_in_city.get_material_quantity(test_material) == 1
|
||||
# 模拟 CityRegion.is_selling 方法
|
||||
# 直接在 avatar_in_city.tile.region 上 mock 或者动态添加属性
|
||||
# 由于 avatar_in_city 使用了 mock_region,我们需要确保它有 is_selling
|
||||
# 假设 conftest 中 avatar_in_city.tile.region 是一个 CityRegion 实例或者 Mock
|
||||
|
||||
# 我们这里动态 patch is_selling
|
||||
with patch.object(avatar_in_city.tile.region, 'is_selling', return_value=True) as mock_is_selling:
|
||||
with patch("src.utils.resolution.elixirs_by_name", elixirs_mock), \
|
||||
patch("src.utils.resolution.materials_by_name", materials_mock):
|
||||
|
||||
action = Buy(avatar_in_city, avatar_in_city.world)
|
||||
|
||||
# 1. 检查是否可购买
|
||||
can_start, reason = action.can_start("铁矿石")
|
||||
assert can_start is True
|
||||
mock_is_selling.assert_called_with("铁矿石")
|
||||
|
||||
# 2. 执行购买
|
||||
initial_money = avatar_in_city.magic_stone
|
||||
# 练气期材料基础价格 10,倍率 1.5 -> 15
|
||||
expected_price = int(10 * 1.5)
|
||||
|
||||
action._execute("铁矿石")
|
||||
|
||||
# 3. 验证结果
|
||||
assert avatar_in_city.magic_stone == initial_money - expected_price
|
||||
assert avatar_in_city.get_material_quantity(test_material) == 1
|
||||
|
||||
def test_buy_elixir_success(avatar_in_city, mock_item_data):
|
||||
"""测试购买并服用丹药成功"""
|
||||
@@ -38,26 +46,43 @@ def test_buy_elixir_success(avatar_in_city, mock_item_data):
|
||||
materials_mock = mock_item_data["materials"]
|
||||
test_elixir = mock_item_data["obj_elixir"]
|
||||
|
||||
with patch("src.utils.resolution.elixirs_by_name", elixirs_mock), \
|
||||
patch("src.utils.resolution.materials_by_name", materials_mock):
|
||||
|
||||
action = Buy(avatar_in_city, avatar_in_city.world)
|
||||
|
||||
can_start, reason = action.can_start("聚气丹")
|
||||
assert can_start is True
|
||||
|
||||
initial_money = avatar_in_city.magic_stone
|
||||
expected_price = int(test_elixir.price * 1.5)
|
||||
|
||||
# 模拟服用丹药的行为
|
||||
action._execute("聚气丹")
|
||||
|
||||
assert avatar_in_city.magic_stone == initial_money - expected_price
|
||||
# 背包里不应该有丹药
|
||||
assert len(avatar_in_city.materials) == 0
|
||||
# 已服用列表应该有
|
||||
assert len(avatar_in_city.elixirs) == 1
|
||||
assert avatar_in_city.elixirs[0].elixir.name == "聚气丹"
|
||||
with patch.object(avatar_in_city.tile.region, 'is_selling', return_value=True):
|
||||
with patch("src.utils.resolution.elixirs_by_name", elixirs_mock), \
|
||||
patch("src.utils.resolution.materials_by_name", materials_mock):
|
||||
|
||||
action = Buy(avatar_in_city, avatar_in_city.world)
|
||||
|
||||
can_start, reason = action.can_start("聚气丹")
|
||||
assert can_start is True
|
||||
|
||||
initial_money = avatar_in_city.magic_stone
|
||||
expected_price = int(test_elixir.price * 1.5)
|
||||
|
||||
# 模拟服用丹药的行为
|
||||
action._execute("聚气丹")
|
||||
|
||||
assert avatar_in_city.magic_stone == initial_money - expected_price
|
||||
# 背包里不应该有丹药
|
||||
assert len(avatar_in_city.materials) == 0
|
||||
# 已服用列表应该有
|
||||
assert len(avatar_in_city.elixirs) == 1
|
||||
assert avatar_in_city.elixirs[0].elixir.name == "聚气丹"
|
||||
|
||||
def test_buy_fail_item_not_sold(avatar_in_city, mock_item_data):
|
||||
"""测试商品不在商店售卖列表中"""
|
||||
elixirs_mock = mock_item_data["elixirs"]
|
||||
materials_mock = mock_item_data["materials"]
|
||||
|
||||
# Mock is_selling 返回 False
|
||||
with patch.object(avatar_in_city.tile.region, 'is_selling', return_value=False):
|
||||
with patch("src.utils.resolution.elixirs_by_name", elixirs_mock), \
|
||||
patch("src.utils.resolution.materials_by_name", materials_mock):
|
||||
|
||||
action = Buy(avatar_in_city, avatar_in_city.world)
|
||||
can_start, reason = action.can_start("铁矿石")
|
||||
|
||||
assert can_start is False
|
||||
assert "不出售" in reason
|
||||
|
||||
def test_buy_fail_not_in_city(dummy_avatar, mock_item_data):
|
||||
"""测试不在城市无法购买"""
|
||||
@@ -83,14 +108,15 @@ def test_buy_fail_no_money(avatar_in_city, mock_item_data):
|
||||
|
||||
avatar_in_city.magic_stone = 0 # 没钱
|
||||
|
||||
with patch("src.utils.resolution.elixirs_by_name", elixirs_mock), \
|
||||
patch("src.utils.resolution.materials_by_name", materials_mock):
|
||||
|
||||
action = Buy(avatar_in_city, avatar_in_city.world)
|
||||
can_start, reason = action.can_start("铁矿石")
|
||||
|
||||
assert can_start is False
|
||||
assert "灵石不足" in reason
|
||||
with patch.object(avatar_in_city.tile.region, 'is_selling', return_value=True):
|
||||
with patch("src.utils.resolution.elixirs_by_name", elixirs_mock), \
|
||||
patch("src.utils.resolution.materials_by_name", materials_mock):
|
||||
|
||||
action = Buy(avatar_in_city, avatar_in_city.world)
|
||||
can_start, reason = action.can_start("铁矿石")
|
||||
|
||||
assert can_start is False
|
||||
assert "灵石不足" in reason
|
||||
|
||||
def test_buy_fail_unknown_item(avatar_in_city, mock_item_data):
|
||||
"""测试未知物品"""
|
||||
@@ -119,14 +145,16 @@ def test_buy_elixir_fail_high_level_restricted(avatar_in_city, mock_item_data):
|
||||
assert avatar_in_city.cultivation_progress.realm == Realm.Qi_Refinement
|
||||
assert high_level_elixir.realm == Realm.Foundation_Establishment
|
||||
|
||||
with patch("src.utils.resolution.elixirs_by_name", elixirs_mock), \
|
||||
patch("src.utils.resolution.materials_by_name", materials_mock):
|
||||
|
||||
action = Buy(avatar_in_city, avatar_in_city.world)
|
||||
can_start, reason = action.can_start("筑基丹")
|
||||
|
||||
assert can_start is False
|
||||
assert "当前仅开放练气期丹药购买" in reason
|
||||
with patch.object(avatar_in_city.tile.region, 'is_selling', return_value=True):
|
||||
with patch("src.utils.resolution.elixirs_by_name", elixirs_mock), \
|
||||
patch("src.utils.resolution.materials_by_name", materials_mock):
|
||||
|
||||
action = Buy(avatar_in_city, avatar_in_city.world)
|
||||
can_start, reason = action.can_start("筑基丹")
|
||||
|
||||
assert can_start is False
|
||||
# 错误信息变了,现在是通用的境界限制
|
||||
assert "境界不足" in reason
|
||||
|
||||
def test_buy_elixir_fail_duplicate_active(avatar_in_city, mock_item_data):
|
||||
"""测试药效尚存无法重复购买"""
|
||||
@@ -139,14 +167,15 @@ def test_buy_elixir_fail_duplicate_active(avatar_in_city, mock_item_data):
|
||||
|
||||
avatar_in_city.elixirs.append(consumed)
|
||||
|
||||
with patch("src.utils.resolution.elixirs_by_name", elixirs_mock), \
|
||||
patch("src.utils.resolution.materials_by_name", materials_mock):
|
||||
|
||||
action = Buy(avatar_in_city, avatar_in_city.world)
|
||||
can_start, reason = action.can_start("聚气丹")
|
||||
|
||||
assert can_start is False
|
||||
assert "药效尚存" in reason
|
||||
with patch.object(avatar_in_city.tile.region, 'is_selling', return_value=True):
|
||||
with patch("src.utils.resolution.elixirs_by_name", elixirs_mock), \
|
||||
patch("src.utils.resolution.materials_by_name", materials_mock):
|
||||
|
||||
action = Buy(avatar_in_city, avatar_in_city.world)
|
||||
can_start, reason = action.can_start("聚气丹")
|
||||
|
||||
assert can_start is False
|
||||
assert "药效尚存" in reason
|
||||
|
||||
def test_buy_weapon_trade_in(avatar_in_city, mock_item_data):
|
||||
"""测试购买新武器时自动卖出旧武器"""
|
||||
@@ -158,17 +187,6 @@ def test_buy_weapon_trade_in(avatar_in_city, mock_item_data):
|
||||
materials_mock = mock_item_data["materials"]
|
||||
new_weapon = mock_item_data["obj_weapon"]
|
||||
|
||||
# 手动添加武器到 materials_mock (Buy logic looks up weapons in materials too? Or just assumes unique names?)
|
||||
# Buy code checks `get_item_by_name` which checks all dicts.
|
||||
# In test_buy_action we only mocked elixirs and materials.
|
||||
# Let's ensure '青云剑' is findable. Ideally it should be in weapons_by_name but maybe Buy logic is flexible?
|
||||
# Original test put it in materials_mock["青云剑"] = new_weapon. Let's follow that pattern for now or better: mock weapons too.
|
||||
|
||||
# Wait, original test: materials_mock["青云剑"] = new_weapon
|
||||
# But `src.utils.resolution.get_item_by_name` checks materials, weapons, auxiliaries.
|
||||
# Let's do it properly by mocking weapons_by_name as well if possible, or just stick to materials for simplicity if Buy allows.
|
||||
# Buy uses `get_item_by_name`.
|
||||
|
||||
materials_mock["青云剑"] = new_weapon
|
||||
|
||||
# 构造旧武器
|
||||
@@ -190,20 +208,21 @@ def test_buy_weapon_trade_in(avatar_in_city, mock_item_data):
|
||||
|
||||
expected_money = initial_money - buy_cost + sell_refund
|
||||
|
||||
with patch("src.utils.resolution.elixirs_by_name", elixirs_mock), \
|
||||
patch("src.utils.resolution.materials_by_name", materials_mock):
|
||||
|
||||
action = Buy(avatar_in_city, avatar_in_city.world)
|
||||
|
||||
# 验证 Event 描述
|
||||
event = action.start("青云剑")
|
||||
assert "青云剑" in event.content
|
||||
assert "铁剑" in event.content
|
||||
assert "折价售出" in event.content
|
||||
|
||||
# 执行购买
|
||||
action._execute("青云剑")
|
||||
|
||||
assert avatar_in_city.weapon.name == "青云剑"
|
||||
assert avatar_in_city.weapon != old_weapon
|
||||
assert avatar_in_city.magic_stone == expected_money
|
||||
with patch.object(avatar_in_city.tile.region, 'is_selling', return_value=True):
|
||||
with patch("src.utils.resolution.elixirs_by_name", elixirs_mock), \
|
||||
patch("src.utils.resolution.materials_by_name", materials_mock):
|
||||
|
||||
action = Buy(avatar_in_city, avatar_in_city.world)
|
||||
|
||||
# 验证 Event 描述
|
||||
event = action.start("青云剑")
|
||||
assert "青云剑" in event.content
|
||||
assert "铁剑" in event.content
|
||||
assert "折价售出" in event.content
|
||||
|
||||
# 执行购买
|
||||
action._execute("青云剑")
|
||||
|
||||
assert avatar_in_city.weapon.name == "青云剑"
|
||||
assert avatar_in_city.weapon != old_weapon
|
||||
assert avatar_in_city.magic_stone == expected_money
|
||||
|
||||
@@ -107,6 +107,21 @@ function jumpToAvatar(id: string) {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Store Items -->
|
||||
<div class="section" v-if="data.store_items?.length">
|
||||
<div class="section-title">坊市交易</div>
|
||||
<div class="list">
|
||||
<EntityRow
|
||||
v-for="item in data.store_items"
|
||||
:key="item.id || item.name"
|
||||
:item="item"
|
||||
:meta="`${item.price}灵石`"
|
||||
compact
|
||||
@click="showDetail(item)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ const typeMap: Record<string, string> = {
|
||||
};
|
||||
|
||||
const displayType = computed(() => {
|
||||
if (props.item?.type_name) return props.item.type_name; // 优先使用后端传回的中文类型名
|
||||
if (!props.item?.type) return '';
|
||||
return typeMap[props.item.type] || props.item.type;
|
||||
});
|
||||
|
||||
@@ -24,6 +24,7 @@ export interface EffectEntity extends EntityBase {
|
||||
grade?: string;
|
||||
rarity?: string; // e.g., 'SSR', 'R', '上品'
|
||||
type?: string;
|
||||
type_name?: string; // 新增:中文类型名,如"丹药"、"破境"等
|
||||
color?: string | number[]; // 某些实体自带颜色
|
||||
drops?: EffectEntity[];
|
||||
hq_name?: string;
|
||||
@@ -167,6 +168,7 @@ export interface RegionDetail extends EntityBase {
|
||||
animals: EffectEntity[];
|
||||
plants: EffectEntity[];
|
||||
lodes: EffectEntity[];
|
||||
store_items?: (EffectEntity & { price: number })[];
|
||||
}
|
||||
|
||||
// --- 天地灵机 ---
|
||||
|
||||
Reference in New Issue
Block a user