This commit is contained in:
Putoo
2026-05-27 18:26:50 +08:00
parent 36a7575990
commit 0d5443ef36
28 changed files with 1043 additions and 25 deletions

View File

@@ -9,7 +9,7 @@ namespace Application.Domain.Entity;
public class unit_user_equ_log public class unit_user_equ_log
{ {
[SugarColumn(IsPrimaryKey = true)] public string logId { get; set; } [SugarColumn(IsPrimaryKey = true)] public string logId { get; set; }
[SugarColumn(Length = 50, IsNullable = true)] [SugarColumn(Length = 50, IsNullable = true)]
public string? ueId { get; set; } public string? ueId { get; set; }
@@ -19,11 +19,11 @@ public class unit_user_equ_log
[SugarColumn(Length = 50, IsNullable = true)] [SugarColumn(Length = 50, IsNullable = true)]
public string? code { get; set; } public string? code { get; set; }
[SugarColumn(ColumnDataType = "varchar(max)", IsNullable = true, IsJson = true)] [SugarColumn(ColumnDataType = "longtext", IsNullable = true, IsJson = true)]
public unit_user_equ? equData { get; set; } public unit_user_equ? equData { get; set; }
[SugarColumn(Length = 255, IsNullable = true)] [SugarColumn(Length = 255, IsNullable = true)]
public string? remark { get; set; } public string? remark { get; set; }
public DateTime? addTime { get; set; } [SugarColumn(IsNullable = true)] public DateTime? addTime { get; set; }
} }

View File

@@ -0,0 +1,7 @@
namespace Application.Domain.Entity;
public class NpcBus
{
public string name { get; set; }
public string url { get; set; }
}

View File

@@ -57,7 +57,7 @@ namespace Application.Domain.Entity
/// <summary> /// <summary>
/// bus /// bus
/// </summary> /// </summary>
[SugarColumn(IsNullable = true)] [SugarColumn(IsNullable = true,IsJson = true)]
public string? bus { get; set; } public List<NpcBus>? bus { get; set; }
} }
} }

View File

@@ -0,0 +1,63 @@
using SqlSugar;
using System;
namespace Application.Domain.Entity
{
[Tenant("Kg.SeaTime.Resource")]
public class game_city_npc_store
{
/// <summary>
/// storeId
/// </summary>
[SugarColumn(IsPrimaryKey = true, Length = 50)]
public string storeId { get; set; }
/// <summary>
/// npcId
/// </summary>
[SugarColumn(IsNullable = true)]
public int? npcId { get; set; }
/// <summary>
/// areaId
/// </summary>
[SugarColumn(Length = 50, IsNullable = true)]
public string? areaId { get; set; }
/// <summary>
/// type
/// </summary>
[SugarColumn(Length = 50, IsNullable = true)]
public string? type { get; set; }
/// <summary>
/// name
/// </summary>
[SugarColumn(Length = 50, IsNullable = true)]
public string? name { get; set; }
/// <summary>
/// parameter
/// </summary>
[SugarColumn(Length = 11, IsNullable = true)]
public string? parameter { get; set; }
/// <summary>
/// price
/// </summary>
[SugarColumn(IsNullable = true)]
public long? price { get; set; }
/// <summary>
/// payType
/// </summary>
[SugarColumn(Length = 50, IsNullable = true)]
public string? payType { get; set; }
/// <summary>
/// sort
/// </summary>
[SugarColumn(IsNullable = true)]
public int? sort { get; set; }
}
}

View File

@@ -2,6 +2,43 @@
public static class GameEnum public static class GameEnum
{ {
public enum PropCode//游戏资源编码
{
Monster,//怪物
Goods,//物品
Equ,//装备
Rare,//奇珍
copper,//铜
exp,//经验
renown,//声望
teach,//师德
cowry,//海贝
gold,//金
Mark,//圣痕
Palace,//九宫
skill,//技能
map,//城市地图
maxName,//称号
badge,//徽章
Points,//随从点数
expType,//经验类型
lev,//等级
vip,//VIP等级
vigour,//活力
Attire,//装扮
Attend,//随从
Constell,//星宿
Sacred,//圣物
Daily,//日常积分
CryAcc,//水晶积分
Seed,//花园花朵
SeedLev,//花园等级
Coin,//花园花币
RegTime,//注册时间
StartTime,//开始时间
EndTime,//结束时间
Pet,//宠物
}
public enum LogCode public enum LogCode
{ {
, ,

View File

@@ -10,9 +10,12 @@ public interface IGameEquService
#region #region
Task<List<unit_user_equ>> GetUserEquData(string userId, int type, string equName, int PageIndex, int PageSize, Task<List<unit_user_equ>> GetUserEquData(string userId, int type, string equName, int PageIndex, int PageSize,
RefAsync<int> Total); RefAsync<int> Total, bool isRemOn = false);
Task<List<unit_user_equ>> GetUserEquData(string userId, int equId); Task<List<unit_user_equ>> GetUserEquData(string userId, int equId);
Task<unit_user_equ> GetUserEquInfo(string ueId);
Task<int> GetUserEquByEquIdCount(string userId, int equId);
Task<List<unit_user_equ>> GetUserEquByEquId(string userId, int equId);
Task<bool> AddUserEqu(string userId, int equId, int count, string remark); Task<bool> AddUserEqu(string userId, int equId, int count, string remark);
Task<bool> UpdateUserEquInfo(unit_user_equ equData, bool isAddLog = false, string code = "", Task<bool> UpdateUserEquInfo(unit_user_equ equData, bool isAddLog = false, string code = "",

View File

@@ -0,0 +1,9 @@
namespace Application.Domain;
public interface IGameStoreService
{
Task<List<game_city_npc_store>> GetStoreData(int npc, int area, int page, int limit,
RefAsync<int> total);
Task<game_city_npc_store> GetStoreInfo(string storeId);
}

View File

@@ -23,7 +23,7 @@ public class GameEquService(ISqlSugarClient DbClient, IRedisCache redis) : IGame
#region #region
public async Task<List<unit_user_equ>> GetUserEquData(string userId, int type, string equName, int PageIndex, public async Task<List<unit_user_equ>> GetUserEquData(string userId, int type, string equName, int PageIndex,
int PageSize, RefAsync<int> Total) int PageSize, RefAsync<int> Total, bool isRemOn = false)
{ {
long onTime = TimeExtend.GetTimeStampSeconds; long onTime = TimeExtend.GetTimeStampSeconds;
var db = DbClient.AsTenant().GetConnectionWithAttr<unit_user_equ>(); var db = DbClient.AsTenant().GetConnectionWithAttr<unit_user_equ>();
@@ -31,6 +31,7 @@ public class GameEquService(ISqlSugarClient DbClient, IRedisCache redis) : IGame
.WhereIF(type == 2, it => it.useEndTime < onTime) .WhereIF(type == 2, it => it.useEndTime < onTime)
.WhereIF(type == 1, it => it.isOn == 1) .WhereIF(type == 1, it => it.isOn == 1)
.WhereIF(type == 3, it => it.isAppr == 0) .WhereIF(type == 3, it => it.isAppr == 0)
.WhereIF(isRemOn, it => it.isOn == 0)
.WhereIF(!string.IsNullOrEmpty(equName), .WhereIF(!string.IsNullOrEmpty(equName),
it => it.equName.Contains(equName) || it.unitEquName.Contains(equName)) it => it.equName.Contains(equName) || it.unitEquName.Contains(equName))
.OrderByDescending(it => it.lev) .OrderByDescending(it => it.lev)
@@ -44,6 +45,26 @@ public class GameEquService(ISqlSugarClient DbClient, IRedisCache redis) : IGame
return await db.Queryable<unit_user_equ>().Where(it => it.userId == userId && it.equId == equId).ToListAsync(); return await db.Queryable<unit_user_equ>().Where(it => it.userId == userId && it.equId == equId).ToListAsync();
} }
public async Task<unit_user_equ> GetUserEquInfo(string ueId)
{
var db = DbClient.AsTenant().GetConnectionWithAttr<unit_user_equ>();
return await db.Queryable<unit_user_equ>().Where(i => i.ueId == ueId).SingleAsync();
}
public async Task<int> GetUserEquByEquIdCount(string userId, int equId)
{
int result = 0;
var data = await GetUserEquByEquId(userId, equId);
result = data.Count;
return result;
}
public async Task<List<unit_user_equ>> GetUserEquByEquId(string userId, int equId)
{
var db = DbClient.AsTenant().GetConnectionWithAttr<unit_user_equ>();
return await db.Queryable<unit_user_equ>().Where(i => i.userId == userId && i.equId == equId).ToListAsync();
}
public async Task<bool> AddUserEqu(string userId, int equId, int count, string remark) public async Task<bool> AddUserEqu(string userId, int equId, int count, string remark)
{ {
bool result = false; bool result = false;
@@ -109,6 +130,7 @@ public class GameEquService(ISqlSugarClient DbClient, IRedisCache redis) : IGame
ue.EquAwaken = new List<EquAwaken>(); ue.EquAwaken = new List<EquAwaken>();
ue.GemMent = new List<EquGem>(); ue.GemMent = new List<EquGem>();
ue.useEndTime = TimeExtend.GetTimeStampBySeconds(DateTime.Now.AddYears(20)); ue.useEndTime = TimeExtend.GetTimeStampBySeconds(DateTime.Now.AddYears(20));
ue.isOn = 0;
adds.Add(ue); adds.Add(ue);
} }
@@ -234,7 +256,7 @@ public class GameEquService(ISqlSugarClient DbClient, IRedisCache redis) : IGame
log.remark = remark; log.remark = remark;
var db = DbClient.AsTenant().GetConnectionWithAttr<unit_user_equ_log>(); var db = DbClient.AsTenant().GetConnectionWithAttr<unit_user_equ_log>();
await db.Insertable(log).ExecuteCommandAsync(); await db.Insertable(log).SplitTable().ExecuteCommandAsync();
} }
private async Task AddEquLogs(List<unit_user_equ> ues, int code, string remark, private async Task AddEquLogs(List<unit_user_equ> ues, int code, string remark,
@@ -261,13 +283,13 @@ public class GameEquService(ISqlSugarClient DbClient, IRedisCache redis) : IGame
} }
var db = DbClient.AsTenant().GetConnectionWithAttr<unit_user_equ_log>(); var db = DbClient.AsTenant().GetConnectionWithAttr<unit_user_equ_log>();
await db.Insertable(adds).ExecuteCommandAsync(); await db.Insertable(adds).SplitTable().ExecuteCommandAsync();
} }
private async Task AddEquLogs(List<unit_user_equ_log> logs) private async Task AddEquLogs(List<unit_user_equ_log> logs)
{ {
var db = DbClient.AsTenant().GetConnectionWithAttr<unit_user_equ_log>(); var db = DbClient.AsTenant().GetConnectionWithAttr<unit_user_equ_log>();
await db.Insertable(logs).ExecuteCommandAsync(); await db.Insertable(logs).SplitTable().ExecuteCommandAsync();
} }
#endregion #endregion

View File

@@ -153,7 +153,7 @@ public class GameMapService(ISqlSugarClient DbClient, IRedisCache redis) : IGame
onLine.userId = userId; onLine.userId = userId;
onLine.mapId = mapId; onLine.mapId = mapId;
onLine.ip = ip; onLine.ip = ip;
onLine.upTime = TimeAssist.GetTimeStampNum; onLine.upTime = TimeExtend.GetTimeStampSeconds;
string key = string.Format(UserCache.BaseCacheKey, "UserOnline"); string key = string.Format(UserCache.BaseCacheKey, "UserOnline");
if (await redis.AddHashAsync(key, userId, onLine)) if (await redis.AddHashAsync(key, userId, onLine))
{ {
@@ -165,7 +165,7 @@ public class GameMapService(ISqlSugarClient DbClient, IRedisCache redis) : IGame
public async Task<bool> UpdateUserOnMap(unit_user_online data, string mapId) public async Task<bool> UpdateUserOnMap(unit_user_online data, string mapId)
{ {
data.mapId = mapId; data.mapId = mapId;
data.upTime = TimeAssist.GetTimeStampNum; data.upTime = TimeExtend.GetTimeStampSeconds;
string key = string.Format(UserCache.BaseCacheKey, "UserOnline"); string key = string.Format(UserCache.BaseCacheKey, "UserOnline");
if (await redis.AddHashAsync(key, data.userId, data)) if (await redis.AddHashAsync(key, data.userId, data))
{ {

View File

@@ -0,0 +1,20 @@
namespace Application.Domain;
public class GameStoreService(ISqlSugarClient DbClient, IRedisCache redis) : IGameStoreService, ITransient
{
public async Task<List<game_city_npc_store>> GetStoreData(int npc, int area, int page, int limit,
RefAsync<int> total)
{
string _area = area.ToString();
var db = DbClient.AsTenant().GetConnectionWithAttr<game_city_npc_store>();
return await db.Queryable<game_city_npc_store>()
.Where(it => it.npcId == npc && (it.areaId == "0" || it.areaId == _area))
.ToPageListAsync(page, limit, total);
}
public async Task<game_city_npc_store> GetStoreInfo(string storeId)
{
var db = DbClient.AsTenant().GetConnectionWithAttr<game_city_npc_store>();
return await db.Queryable<game_city_npc_store>().Where(it => it.storeId == storeId).SingleAsync();
}
}

View File

@@ -0,0 +1,72 @@
namespace Application.Domain;
public class GameBus
{
#region
public static async Task<bool> UpdateBag(string userId, int operate, string goodsType, string parameter, long count,
string remark)
{
bool isok = false;
if (goodsType.Equals(nameof(GameEnum.PropCode.Goods)))
{
var goodsService = App.GetService<IGameGoodsService>();
isok = await goodsService.UpdateUserGoods(userId, operate, Convert.ToInt32(parameter), (int)count, remark);
}
else if (goodsType.Equals(nameof(GameEnum.PropCode.Equ)))
{
var equService = App.GetService<IGameEquService>();
if (operate == 1)
{
isok = await equService.AddUserEqu(userId, Convert.ToInt32(parameter), (int)count, remark);
}
else
{
isok = await equService.DeductUserEqu(userId, Convert.ToInt32(parameter), (int)count, remark);
}
}
else if (goodsType.Equals(nameof(GameEnum.PropCode.copper)))
{
var accService = App.GetService<IUnitUserAccService>();
isok = await accService.UpdateUserCopper(userId, operate, count);
}
else if (goodsType.Equals(nameof(GameEnum.PropCode.gold)))
{
var accService = App.GetService<IUnitUserAccService>();
isok = await accService.UpdateUserAcc(userId, operate, nameof(AccEnum.AccType.gold), count,
nameof(AccEnum.Name.), remark);
}
else if (goodsType.Equals(nameof(GameEnum.PropCode.cowry)))
{
var accService = App.GetService<IUnitUserAccService>();
isok = await accService.UpdateUserAcc(userId, operate, nameof(AccEnum.AccType.cowry), count,
nameof(AccEnum.Name.), remark);
}
else if (goodsType.Equals(nameof(GameEnum.PropCode.vigour)))
{
var attrService = App.GetService<IUnitUserAttrService>();
isok = await attrService.UpdateUserVigour(userId, operate, count);
}
else if (goodsType.Equals(nameof(GameEnum.PropCode.exp)))
{
var attrService = App.GetService<IUnitUserAttrService>();
isok = await attrService.UpdateUserExp(userId, count, operate);
}
else if (goodsType.Equals(nameof(GameEnum.PropCode.renown)))
{
var accService = App.GetService<IUnitUserAccService>();
isok = await accService.UpdateUserAcc(userId, operate, nameof(AccEnum.AccType.renown), count,
nameof(AccEnum.Name.), remark);
}
else if (goodsType.Equals(nameof(GameEnum.PropCode.teach)))
{
var accService = App.GetService<IUnitUserAccService>();
isok = await accService.UpdateUserAcc(userId, operate, nameof(AccEnum.AccType.teach), count,
nameof(AccEnum.Name.), remark);
}
return isok;
}
#endregion
}

View File

@@ -1,5 +1,4 @@
namespace Application.Domain;
namespace Application.Domain;
public class GameTool public class GameTool
{ {
@@ -21,6 +20,7 @@ public class GameTool
data.levUpdate = TimeExtend.GetTimeStampSeconds; data.levUpdate = TimeExtend.GetTimeStampSeconds;
return data; return data;
} }
/// <summary> /// <summary>
/// 获取等级升级经验 /// 获取等级升级经验
/// </summary> /// </summary>
@@ -32,10 +32,59 @@ public class GameTool
return result; return result;
} }
public static bool AreaVerify( int area,string areas) public static bool AreaVerify(int area, string areas)
{ {
List<string> onArea = new List<string>() {"0",area.ToString() }; List<string> onArea = new List<string>() { "0", area.ToString() };
return onArea.Any(it => areas.Contains(it)); return onArea.Any(it => areas.Contains(it));
} }
public static string GetCurrencyName(string payCode)
{
string result = "";
switch (payCode)
{
case "gold":
result = "金元";
break;
case "cowry":
result = "金贝";
break;
case "copper":
result = "铜贝";
break;
case "teach":
result = "师德";
break;
case "renown":
result = "声望";
break;
}
return result;
}
public static async Task<int> GetPropWeight(string goodsType, string parameter)
{
int weight = 0;
if (goodsType.Equals(nameof(GameEnum.PropCode.Goods)))
{
var goodsService = App.GetService<IGameGoodsService>();
var info = await goodsService.GetGoodsInfo(Convert.ToInt32(parameter));
if (info != null)
{
weight = (int)info.weight;
}
}
else if (goodsType.Equals(nameof(GameEnum.PropCode.Equ)))
{
var equService = App.GetService<IGameEquService>();
var info = await equService.GetEquInfo(Convert.ToInt32(parameter));
if (info != null)
{
weight = (int)info.weight;
}
}
return weight;
}
} }

View File

@@ -162,4 +162,38 @@ public class MapController : ControllerBase
return PoAction.Message("无法自动寻路!"); return PoAction.Message("无法自动寻路!");
} }
} }
#region npc相关
/// <summary>
/// 获取NPC相关信息
/// </summary>
/// <param name="npcId"></param>
/// <returns></returns>
[HttpGet]
public async Task<IPoAction> GetNpcInfo(int npcId)
{
string userId = StateHelper.userId;
var data = await _mapService.GetNpcInfo(npcId);
if (data == null)
{
return PoAction.Message("Npc不存在!");
}
if (data.status != 1)
{
return PoAction.Message("Npc不存在!");
}
var onMap = await _mapService.GetUserOnMapId(userId);
if (data.mapId != onMap)
{
return PoAction.Message("Npc不存在!");
}
return PoAction.Ok(data);
}
#endregion
} }

View File

@@ -0,0 +1,284 @@
using Microsoft.AspNetCore.Mvc;
namespace Application.Web.Controllers.Map;
/// <summary>
/// 商店接口
/// </summary>
[ApiExplorerSettings(GroupName = "Map")]
[Route("Map/[controller]/[action]")]
[ApiController]
[Authorize]
public class StoreController : ControllerBase
{
private readonly IGameStoreService _storeService;
private readonly IGameMapService _mapService;
private readonly IUnitUserAccService _accService;
private readonly IUnitUserWeight _weightService;
private readonly IGameEquService _equService;
private readonly IGameGoodsService _goodsService;
public StoreController(IGameStoreService storeService, IGameMapService mapService, IUnitUserAccService accService,
IUnitUserWeight weightService, IGameEquService equService, IGameGoodsService goodsService)
{
_storeService = storeService;
_mapService = mapService;
_accService = accService;
_weightService = weightService;
_equService = equService;
_goodsService = goodsService;
}
/// <summary>
/// 获取npc商店信息
/// </summary>
/// <param name="npcId"></param>
/// <param name="page"></param>
/// <returns></returns>
[HttpGet]
public async Task<IPoAction> GetNpcStore(int npcId, int page)
{
string userId = StateHelper.userId;
int areaId = StateHelper.areaId;
var npcInfo = await _mapService.GetNpcInfo(npcId);
if (npcInfo == null)
{
return PoAction.Message("Npc不存在!");
}
if (npcInfo.status != 1)
{
return PoAction.Message("Npc不存在!");
}
var onMap = await _mapService.GetUserOnMapId(userId);
if (npcInfo.mapId != onMap)
{
return PoAction.Message("Npc不存在!");
}
RefAsync<int> Total = 0;
var data = await _storeService.GetStoreData(npcId, areaId, page, 10, Total);
return PoAction.Ok(new { data, total = Total.Value, npcInfo.npcName });
}
/// <summary>
/// 购买物品
/// </summary>
/// <param name="parms"></param>
/// <returns></returns>
[HttpPost]
public async Task<IPoAction> Buy([FromBody] StoreBuyParms parms)
{
parms.count = parms.count < 1 ? 1 : parms.count;
string userId = StateHelper.userId;
int areaId = StateHelper.areaId;
var npcInfo = await _mapService.GetNpcInfo(parms.npcId);
if (npcInfo == null)
{
return PoAction.Message("Npc不存在!");
}
if (npcInfo.status != 1)
{
return PoAction.Message("Npc不存在!");
}
var onMap = await _mapService.GetUserOnMapId(userId);
if (npcInfo.mapId != onMap)
{
return PoAction.Message("Npc不存在!");
}
var storeInfo = await _storeService.GetStoreInfo(parms.storeId);
if (storeInfo == null)
{
return PoAction.Message("商品已下架!");
}
if (!GameTool.AreaVerify(areaId, storeInfo.areaId))
{
return PoAction.Message("商品已下架!");
}
if (storeInfo.npcId != parms.npcId)
{
return PoAction.Message("商品已下架!");
}
//此处需要计算负重
var needWeight = await GameTool.GetPropWeight(storeInfo.type, storeInfo.parameter);
needWeight = needWeight * parms.count;
if (await _weightService.CheakUserWeight(userId, needWeight) == false)
{
return PoAction.Message("负重不足!");
}
long need = parms.count * (long)storeInfo.price;
var myAcc = await _accService.GetUserAccInfo(userId, storeInfo.payType);
if (myAcc < need)
{
return PoAction.Message($"您的{GameTool.GetCurrencyName(storeInfo.payType)}不足!");
}
if (await _accService.UpdateUserAccBath(userId, 0, storeInfo.payType, need, nameof(AccEnum.Name.Npc商城),
$"商城购买物品:{storeInfo.name}×{parms.count}"))
{
await GameBus.UpdateBag(userId, 1, storeInfo.type, storeInfo.parameter, parms.count, "Npc商店购买");
return PoAction.Ok(true);
}
else
{
return PoAction.Message("购买失败,请稍后尝试!");
}
}
/// <summary>
/// 出售物品
/// </summary>
/// <param name="npcId"></param>
/// <param name="type"></param>
/// <param name="query"></param>
/// <param name="page"></param>
/// <returns></returns>
[HttpGet]
public async Task<IPoAction> GetNpcSale(int npcId, int type, string? query, int page)
{
string userId = StateHelper.userId;
int areaId = StateHelper.areaId;
var npcInfo = await _mapService.GetNpcInfo(npcId);
if (npcInfo == null)
{
return PoAction.Message("Npc不存在!");
}
if (npcInfo.status != 1)
{
return PoAction.Message("Npc不存在!");
}
var onMap = await _mapService.GetUserOnMapId(userId);
if (npcInfo.mapId != onMap)
{
return PoAction.Message("Npc不存在!");
}
RefAsync<int> total = 0;
if (type == 0)
{
var data = await _equService.GetUserEquData(userId, 0, query, page, 10, total, true);
return PoAction.Ok(new { data, total.Value });
}
else if (type == 1)
{
List<string> code = new List<string>() { nameof(GoodsEnum.Code.Drug) };
var data = await _goodsService.GetUserGoodsData(userId, code, new List<string>(), query, page, 10, total);
return PoAction.Ok(new { data, total.Value });
}
else if (type == 2)
{
List<string> code = new List<string>();
List<string> noCode = new List<string>() { nameof(GoodsEnum.Code.Drug) };
var data = await _goodsService.GetUserGoodsData(userId, code, noCode, query, page, 10, total);
return PoAction.Ok(new { data, total.Value });
}
else
{
return PoAction.Ok(new { data = new List<string>(), total.Value });
}
}
/// <summary>
/// 出售物品
/// </summary>
/// <param name="parms"></param>
/// <returns></returns>
[HttpPost]
public async Task<IPoAction> Sale([FromBody] StoreSaleParms parms)
{
parms.count = parms.count < 1 ? 1 : parms.count;
string userId = StateHelper.userId;
int areaId = StateHelper.areaId;
var npcInfo = await _mapService.GetNpcInfo(parms.npcId);
if (npcInfo == null)
{
return PoAction.Message("Npc不存在!");
}
if (npcInfo.status != 1)
{
return PoAction.Message("Npc不存在!");
}
var onMap = await _mapService.GetUserOnMapId(userId);
if (npcInfo.mapId != onMap)
{
return PoAction.Message("Npc不存在!");
}
if (parms.type == 0)//装备
{
var equInfo = await _equService.GetUserEquInfo(parms.id);
if (equInfo == null)
{
return PoAction.Message("装备不存在!");
}
if (equInfo.userId != userId)
{
return PoAction.Message("装备不存在!");
}
if (equInfo.isOn == 1)
{
return PoAction.Message("穿戴中的装备无法出售!");
}
if (equInfo.isLock == 1)
{
return PoAction.Message("装备已锁定!");
}
if (await _equService.DeductUserEqu(userId, new List<unit_user_equ>() { equInfo }, "出售装备"))
{
await _accService.UpdateUserCopper(userId, 1, (int)equInfo.sysPrice, "出售装备");
return PoAction.Ok(true, $"出售成功,获得{equInfo.sysPrice}铜贝!");
}
else
{
return PoAction.Message("出售失败,请稍后尝试!");
}
}
else //物品
{
var goodsInfo = await _goodsService.GetUserGoodsInfo(parms.id);
if (goodsInfo == null)
{
return PoAction.Message("物品不存在!");
}
if (goodsInfo.userId != userId)
{
return PoAction.Message("物品不存在!");
}
if (goodsInfo.count < parms.count)
{
return PoAction.Message("物品不足!");
}
if (await _goodsService.UpdateUserGoods(userId, 0, (int)goodsInfo.goodsId, parms.count, "出售物品"))
{
long copper = (int)goodsInfo.sysPrice * parms.count;
await _accService.UpdateUserCopper(userId, 1, copper, "出售装备");
return PoAction.Ok(true, $"出售成功,获得{copper}铜贝!");
}
else
{
return PoAction.Message("出售失败,请稍后尝试!");
}
}
}
}

View File

@@ -70,7 +70,8 @@ public class UserController : ControllerBase
object acc = new { accInfo.teach }; object acc = new { accInfo.teach };
var online = await _mapService.GetUserOnMap(userInfo.userId); var online = await _mapService.GetUserOnMap(userInfo.userId);
int isOnline = online.upTime > TimeExtend.GetTimeStampBySeconds(DateTime.Now.AddMinutes(GameConfig.OnLineTime)) int isOnline = online.upTime >
TimeExtend.GetTimeStampBySeconds(DateTime.Now.AddMinutes(0 - GameConfig.OnLineTime))
? 1 ? 1
: 0; : 0;
var onMapInfo = await _mapService.GetMapInfo(online.mapId); var onMapInfo = await _mapService.GetMapInfo(online.mapId);

View File

@@ -0,0 +1,9 @@
namespace Application.Web;
public class StoreBuyParms
{
public int npcId { get; set; }
public string storeId { get; set; }
public int count { get; set; }
}

View File

@@ -0,0 +1,10 @@
namespace Application.Web;
public class StoreSaleParms
{
public int npcId { get; set; }
public int count { get; set; }
public string search { get; set; }
public int type { get; set; }
public string id { get; set; }
}

View File

@@ -0,0 +1,12 @@
export class LocalStorageHelper {
/**npc相关 */
private static key: string = 'OnNpc';
public static GetOnNpc() {
return LocalStorageExtend.Get(this.key);
}
public static SetOnNpc(npcId: String) {
LocalStorageExtend.Set(this.key, npcId);
}
}

View File

@@ -0,0 +1 @@
<template></template>

View File

@@ -0,0 +1 @@
<template></template>

View File

@@ -20,7 +20,7 @@
</div> </div>
<div class="content"> <div class="content">
<div class="item" v-for="item in npcData"> <div class="item" v-for="item in npcData">
<Abar href="">{{ item.npcName }}{{ item.tips }}</Abar> <Abar :href='"/npc?npc="+item.npcId'>{{ item.npcName }}{{ item.tips }}</Abar>
</div> </div>
</div> </div>

View File

@@ -0,0 +1,49 @@
<template>
<div class="content">
<div class="common">
{{ data.npcName }}
</div>
<div class="common">
{{ data.story }}
</div>
</div>
<div class="content">
<div class="item" v-for="item in data.bus">
<Abar :href="item.url">{{ item.name }}</Abar>
</div>
</div>
</template>
<script setup lang="ts">
definePageMeta({
layout: layout.default,
middleware: 'page-loading'
})
const data = ref<any>({});
onMounted(async () => {
try {
await BindData();
}
finally {
PageLoading.Close();
}
})
const BindData = async (): Promise<void> => {
let npc = PageExtend.QueryString("npc");
let result = await MapService.GetNpcInfo(Number(npc));
if (result.code == 0) {
data.value = result.data;
LocalStorageHelper.SetOnNpc(npc);//存储当前进的npc信息
}
else {
MessageExtend.ShowDialogEvent("提示", result.msg, () => {
PageExtend.Redirect("/map");
});
}
};
</script>

100
Web/src/pages/store/buy.vue Normal file
View File

@@ -0,0 +1,100 @@
<template>
<div class="content">
{{ npcName }}:看看有没有你需要的?
</div>
<div class="content">
<div class="item" v-for="(item, index) in data" :key="index">
{{ PageExtend.GetPageIndex(currentPage, 10, index + 1) }}.
<Abar :href='"/prop/equ?id=" + item.parameter' v-if="item.type == 'Equ'">
{{ item.name }}({{ GameTool.GetCurrencyNameAll(item.price, item.payType) }})</Abar>
<Abar :href='"/prop/goods?id=" + item.parameter' v-else>
{{ item.name }}({{ GameTool.GetCurrencyNameAll(item.price, item.payType) }})</Abar>
[<Abutton @click="ShopView(item)">购买</Abutton>]
</div>
</div>
<div class="content">
<Pagination :currentPage="currentPage" :limit="10" :total="total" @pageChange="handlePageChange" />
</div>
<!-- 购买 -->
<GamePopup v-model:show="showBuy" title="【购买】">
<!-- 自定义内容 -->
<div class="common">
物品名称{{ showGoods.name }}<br>
购买价格{{ GameTool.GetCurrencyNameAll(showGoods.price, showGoods.payType) }}<br>
</div>
<div class="common" style="text-align: center;">
购买数量<input type="number" class="search-ipt" v-model="count"><br>
<button class="ipt-btn" name="serch" @click="ShopOk" style="margin-top: 15px;">确认</button>
</div>
</GamePopup>
</template>
<script setup lang="ts">
definePageMeta({
layout: layout.default,
middleware: 'page-loading'
})
const currentPage = ref<number>(1);
const total = ref<number>(0);
const data = ref<Array<any>>([]);
const npcName = ref('');
const showBuy = ref(false);
const showGoods = ref<any>({});
const count = ref(1);
onMounted(async () => {
try {
await BindData();
}
finally {
PageLoading.Close();
}
})
const BindData = async (): Promise<void> => {
let npcId = LocalStorageHelper.GetOnNpc();
let result = await StoreService.GetNpcStore(Number(npcId), currentPage.value);
if (result.code == 0) {
data.value = result.data.data;
total.value = result.data.total;
npcName.value = result.data.npcName;
}
else {
MessageExtend.ShowDialog("提示", result.msg);
}
};
/**翻页 */
const handlePageChange = async (page: number): Promise<void> => {
currentPage.value = page;
await BindData();
};
//购买
const ShopView = (info: any) => {
showGoods.value = info;
showBuy.value = true;
count.value = 1;
}
const ShopOk = async (): Promise<void> => {
if (count.value < 1 || count.value > 99) {
MessageExtend.ShowToast("每次购买数量在1~99哦.");
return;
}
MessageExtend.LoadingToast("购买中...");
let npcId = LocalStorageHelper.GetOnNpc();
let result = await StoreService.Buy(Number(npcId), showGoods.value.storeId, count.value);
MessageExtend.LoadingClose();
if (result.code == 0) {
showBuy.value = false;
MessageExtend.Notify(`成功购买${showGoods.value.name}×${count.value}`, "success");
}
else {
MessageExtend.ShowDialog("提示", result.msg);
}
};
</script>

View File

@@ -0,0 +1,141 @@
<template>
<div class="content">
选择出售
<Acheak @click="Change('0')" :on-value="type" on-cheak="0">装备</Acheak>.
<Acheak @click="Change('1')" :on-value="type" on-cheak="1">药品</Acheak>.
<Acheak @click="Change('2')" :on-value="type" on-cheak="2">物品</Acheak>
</div>
<div class="common serch">
搜索内容<input type="text" class="search-ipt" v-model="serch">&nbsp;
<button class="ipt-btn" name="serch" @click="BindData">搜索</button>
</div>
<div class="content">
<div class="common" v-if="type == '0'">
<div class="item" v-for="(item, index) in data" :key="index">
{{ PageExtend.GetPageIndex(currentPage, 10, index + 1) }}.
<Abar :href='"/prop/goods?ue=" + item.ueId'>{{ item.equName }}({{ item.lev }})</Abar>
[<Abutton @click="SaleView(item)">出售</Abutton>]
</div>
</div>
<div class="common" v-if="type == '1'">
<div class="item" v-for="(item, index) in data" :key="index">
{{ PageExtend.GetPageIndex(currentPage, 10, index + 1) }}.
<Abar :href='"/prop/goods?id=" + item.goodsId'>{{ item.goodsName }}({{item.count}})</Abar>
[<Abutton @click="SaleView(item)">出售</Abutton>]
</div>
</div>
<div class="common" v-if="type == '2'">
<div class="item" v-for="(item, index) in data" :key="index">
{{ PageExtend.GetPageIndex(currentPage, 10, index + 1) }}.
<span v-if="item.code == 'Card'">
<Abar :href='"/prop/goods?id=" + item.goodsId'>{{ item.goodsName }}({{item.count}})</Abar>
</span>
<span v-else>
<Abar :href='"/prop/goods?id=" + item.goodsId'>{{ item.goodsName }}({{item.count}})</Abar>
</span>
[<Abutton @click="SaleView(item)">出售</Abutton>]
</div>
</div>
<span v-if="data.length == 0">暂无.</span>
</div>
<div class="content">
<Pagination :currentPage="currentPage" :limit="10" :total="total" @pageChange="handlePageChange" />
</div>
<!-- 购买 -->
<GamePopup v-model:show="showSale" title="【出售】">
<!-- 自定义内容 -->
<div class="common" v-if="type == '0'">
物品名称{{ showGoods.equName }}<br>
出售价格{{ GameTool.FormatCopper(showGoods.sysPrice) }}<br>
</div>
<div class="common" v-else>
物品名称{{ showGoods.goodsName }}<br>
出售价格{{ GameTool.FormatCopper(showGoods.sysPrice) }}<br>
背包数量{{ showGoods.count }}<br>
出售数量<input type="number" class="search-ipt" v-model="count"><br>
</div>
<div class="common" style="text-align: center;">
<button class="ipt-btn" name="serch" @click="SaleOk" style="margin-top: 15px;">确认</button>
</div>
</GamePopup>
</template>
<script setup lang="ts">
definePageMeta({
layout: layout.default,
middleware: 'page-loading'
})
const currentPage = ref<number>(1);
const total = ref<number>(0);
const data = ref<Array<any>>([]);
const serch = ref('');
const type = ref('0');
onMounted(async () => {
try {
await BindData();
}
finally {
PageLoading.Close();
}
})
const BindData = async (): Promise<void> => {
let npcId = LocalStorageHelper.GetOnNpc();
let result = await StoreService.GetNpcSale(Number(npcId), Number(type.value), serch.value, currentPage.value);
if (result.code == 0) {
data.value = result.data.data;
total.value = result.data.total;
}
else {
MessageExtend.ShowDialog("提示", result.msg);
}
};
/**翻页 */
const handlePageChange = async (page: number): Promise<void> => {
currentPage.value = page;
await BindData();
};
const Change = async (_type: string): Promise<void> => {
type.value = _type;
await BindData();
};
//出售
const showSale = ref(false);
const showGoods = ref<any>({});
const count = ref(1);
const SaleView = (info: any) => {
showGoods.value = info;
showSale.value = true;
count.value = 1;
}
const SaleOk = async (): Promise<void> => {
if (type.value != '0' && (count.value < 1 || count.value > showGoods.value.count)) {
MessageExtend.ShowToast("出售数量不正确.");
return;
}
MessageExtend.LoadingToast("出售中...");
let npcId = LocalStorageHelper.GetOnNpc();
let propId = '';
if (type.value == '0') {
propId = showGoods.value.ueId;
}
else {
propId = showGoods.value.ugId;
}
let result = await StoreService.Sale(Number(npcId), count.value, serch.value, Number(type.value), propId);
MessageExtend.LoadingClose();
if (result.code == 0) {
showSale.value = false;
MessageExtend.Notify(result.msg,"success");
await BindData();
}
else {
MessageExtend.ShowDialog("提示", result.msg);
}
};
</script>

View File

@@ -70,7 +70,7 @@ const BindData = async (): Promise<void> => {
userData.value = result.data.user; userData.value = result.data.user;
attrData.value = result.data.attr; attrData.value = result.data.attr;
accData.value = result.data.acc; accData.value = result.data.acc;
online.value = result.data.isOnline; online.value = result.data.isOnline;
onMap.value = result.data.onMapName; onMap.value = result.data.onMapName;
console.log(result); console.log(result);
} }

View File

@@ -30,4 +30,12 @@ export class MapService {
static async GetAutoMapPath(toMap: string) { static async GetAutoMapPath(toMap: string) {
return await ApiService.Request("get", "/Map/Map/GetAutoMapPath", { toMap }); return await ApiService.Request("get", "/Map/Map/GetAutoMapPath", { toMap });
} }
/**
* 获取NPC相关信息
* GET /Map/Map/GetNpcInfo
*/
static async GetNpcInfo(npcId: number) {
return await ApiService.Request("get", "/Map/Map/GetNpcInfo", { npcId });
}
} }

View File

@@ -0,0 +1,41 @@
export class StoreService {
/**
* 获取npc商店信息
* GET /Map/Store/GetNpcStore
*/
static async GetNpcStore(npcId: number, page: number) {
return await ApiService.Request("get", "/Map/Store/GetNpcStore", { npcId, page });
}
/**
* 购买物品
* POST /Map/Store/Buy
* @param npcId body
* @param storeId body
* @param count body
*/
static async Buy(npcId: number, storeId: string, count: number) {
return await ApiService.Request("post", "/Map/Store/Buy", { npcId, storeId, count });
}
/**
* 出售物品
* GET /Map/Store/GetNpcSale
*/
static async GetNpcSale(npcId: number, type: number, query: string, page: number) {
return await ApiService.Request("get", "/Map/Store/GetNpcSale", { npcId, type, query, page });
}
/**
* 出售物品
* POST /Map/Store/Sale
* @param npcId body
* @param count body
* @param search body
* @param type body
* @param id body
*/
static async Sale(npcId: number, count: number, search: string, type: number, id: string) {
return await ApiService.Request("post", "/Map/Store/Sale", { npcId, count, search, type, id });
}
}

View File

@@ -1,9 +1,9 @@
export class GameTool { export class GameTool {
/** /**
* 静态方法:将总铜数转换为 金/银/铜 字符串 * 静态方法:将总铜数转换为 金/银/铜 字符串
* @param totalCopper 总铜数量 * @param totalCopper 总铜数量
* @returns 格式化字符串1金 234银 567铜 * @returns 格式化字符串1金 234银 567铜
*/ */
public static FormatCopper(totalCopper: number | string): string { public static FormatCopper(totalCopper: number | string): string {
// 安全转为数字并取整(货币无小数) // 安全转为数字并取整(货币无小数)
let copper = Math.floor(Number(totalCopper) || 0); let copper = Math.floor(Number(totalCopper) || 0);
@@ -35,4 +35,49 @@ export class GameTool {
return result; return result;
} }
/**获取货币名称 */
public static GetCurrencyName(pay: string): string {
let result = "";
switch (pay) {
case 'gold':
result = '金元';
break;
case 'cowry':
result = '金贝';
break;
case 'copper':
result = '铜贝';
break;
case 'teach':
result = '师德';
break;
case 'renown':
result = '声望';
break;
}
return result;
}
public static GetCurrencyNameAll(num: number, pay: string): string {
let result = "";
switch (pay) {
case 'gold':
result = '金元';
break;
case 'cowry':
result = '金贝';
break;
case 'copper':
return this.FormatCopper(num);
break;
case 'teach':
result = '师德';
break;
case 'renown':
result = '声望';
break;
}
return `${num}${result}`;
}
} }