好友:一键申请提示
This commit is contained in:
@@ -1,13 +1,15 @@
|
||||
import { Application, BackendSession } from "pinus";
|
||||
import { resResult, getRandEelm } from "../../../pubUtils/util";
|
||||
import { STATUS, ROLE } from "../../../consts";
|
||||
import Role, { RoleModel, RoleType } from "../../../db/Role";
|
||||
import { resResult, getRandEelm, getResStr } from "../../../pubUtils/util";
|
||||
import { STATUS, ROLE, FRIEND_DROP_TYPE, FRIEND_RELATION_TYPE } from "../../../consts";
|
||||
import { RoleModel, RoleType } from "../../../db/Role";
|
||||
import { getBeforeDaySeconds } from "../../../pubUtils/timeUtil";
|
||||
import { FriendApplyModel } from "../../../db/FriendApply";
|
||||
import { FriendApplyParams, FriendListParam } from "../../../domain/roleField/friend";
|
||||
import { FriendApplyParams, FriendListParam, FriendRecommendParams } from "../../../domain/roleField/friend";
|
||||
import { FriendShipModel, FriendShipType } from "../../../db/FriendShip";
|
||||
import { FriendRelationModel } from "../../../db/FriendRelation";
|
||||
import { isRoleOnline } from "../../../services/redisService";
|
||||
import { increaseFrdCnt, getRecommendType } from "../../../services/friendService";
|
||||
import { FriendPointModel } from "../../../db/FriendPoint";
|
||||
|
||||
export default function (app: Application) {
|
||||
return new FriendHandler(app);
|
||||
@@ -25,9 +27,41 @@ export class FriendHandler {
|
||||
const day = getBeforeDaySeconds(1);
|
||||
|
||||
const { lv } = await RoleModel.findByRoleId(roleId, ROLE.GET_LV);
|
||||
const allList = await RoleModel.getRecommedList(roleId, lv - 5, lv + 5, day);
|
||||
let list = getRandEelm(allList, 10);
|
||||
if(!list.length) list = allList;
|
||||
let allList = await RoleModel.getRecommedList(lv - 5, lv + 5, day);
|
||||
|
||||
let myFriendRelation = await FriendRelationModel.findFriendByRole(roleId, false);
|
||||
|
||||
let paramAllList = new Array<FriendRecommendParams>();
|
||||
for(let role of allList) {
|
||||
let type = getRecommendType(myFriendRelation, roleId, role.roleId);
|
||||
if(type == FRIEND_RELATION_TYPE.NORMAL) {
|
||||
let param = new FriendRecommendParams(role);
|
||||
param.setType(type);
|
||||
paramAllList.push(param);
|
||||
}
|
||||
}
|
||||
|
||||
let list = getRandEelm(paramAllList, 6);
|
||||
if(!list.length) list = paramAllList;
|
||||
|
||||
return resResult(STATUS.SUCCESS, { list });
|
||||
}
|
||||
|
||||
// 搜索好友
|
||||
public async searchUser(msg: { value: string }, session: BackendSession) {
|
||||
let roleId: string = session.get('roleId');
|
||||
|
||||
let { value } = msg;
|
||||
let allList = await RoleModel.searchByNameOrId(value);
|
||||
let myFriendRelation = await FriendRelationModel.findFriendByRole(roleId, false);
|
||||
|
||||
let list = new Array<FriendRecommendParams>();
|
||||
for(let role of allList) {
|
||||
let type = getRecommendType(myFriendRelation, roleId, role.roleId);
|
||||
let param = new FriendRecommendParams(role);
|
||||
param.setType(type);
|
||||
list.push(param);
|
||||
}
|
||||
|
||||
return resResult(STATUS.SUCCESS, { list });
|
||||
}
|
||||
@@ -39,18 +73,38 @@ export class FriendHandler {
|
||||
let roleIds = msg.roleIds;
|
||||
|
||||
const role = await RoleModel.findByRoleId(roleId, ROLE.GET_ROLE_ID);
|
||||
let myFriendRelation = await FriendRelationModel.findFriendByRole(roleId, false);
|
||||
|
||||
let str = '', resultRoleIds = new Array<string>();
|
||||
for(let hisRoleId of roleIds) {
|
||||
let type = getRecommendType(myFriendRelation, roleId, hisRoleId);
|
||||
if(type == FRIEND_RELATION_TYPE.HAS_FRIEND) {
|
||||
str = getResStr(STATUS.FRIEND_HAS_ADD); continue;
|
||||
} else if(type == FRIEND_RELATION_TYPE.HAS_BLOCKED) {
|
||||
str = getResStr(STATUS.FRIEND_HAS_BLOCKED); continue;
|
||||
} else if (type == FRIEND_RELATION_TYPE.MYSELF) {
|
||||
str = getResStr(STATUS.FRIEND_YOURSELF); continue;
|
||||
}
|
||||
|
||||
let incResult = await RoleModel.increaseFriendApplyCnt(hisRoleId, 1, 50);
|
||||
if(!incResult) {
|
||||
str = getResStr(STATUS.FRIEND_HIS_APPLY_MAX); continue;
|
||||
}
|
||||
|
||||
await FriendApplyModel.createApply(hisRoleId, role);
|
||||
resultRoleIds.push(hisRoleId);
|
||||
}
|
||||
|
||||
return resResult(STATUS.SUCCESS, {
|
||||
isSuccess: true
|
||||
isSuccess: str == '',
|
||||
msg: str,
|
||||
roleIds: resultRoleIds
|
||||
});
|
||||
}
|
||||
|
||||
// 获取申请列表
|
||||
public async getApplyList(msg: { lastApplyCode: string }, session: BackendSession) {
|
||||
// TODO 分页
|
||||
public async getApplyList(msg: { }, session: BackendSession) {
|
||||
|
||||
let roleId: string = session.get('roleId');
|
||||
|
||||
let list = await FriendApplyModel.getApplyList(roleId);
|
||||
@@ -72,28 +126,58 @@ export class FriendHandler {
|
||||
let { applyCodeList, isPass } = msg;
|
||||
|
||||
let role = await RoleModel.findByRoleId(roleId);
|
||||
let friendCnt = role.friendCnt;
|
||||
|
||||
let myFriendRelation = await FriendRelationModel.findFriendByRole(roleId, false);
|
||||
|
||||
let applyList = await FriendApplyModel.getApplyListByCode(applyCodeList);
|
||||
let result = new Array<FriendApplyParams>();
|
||||
let list = new Array<FriendListParam>();
|
||||
|
||||
let str = '', resultApplyCodeList = new Array<string>();
|
||||
if(isPass) {
|
||||
for(let apply of applyList) {
|
||||
let type = getRecommendType(myFriendRelation, roleId, apply.frdRoleId);
|
||||
if(type == FRIEND_RELATION_TYPE.HAS_FRIEND) {
|
||||
str = getResStr(STATUS.FRIEND_HAS_ADD); continue;
|
||||
} else if(type == FRIEND_RELATION_TYPE.HAS_BLOCKED) {
|
||||
str = getResStr(STATUS.FRIEND_HAS_BLOCKED); continue;
|
||||
} else if (type == FRIEND_RELATION_TYPE.MYSELF) {
|
||||
str = getResStr(STATUS.FRIEND_YOURSELF); continue;
|
||||
}
|
||||
|
||||
// 好友数量校验
|
||||
let friend = <RoleType>apply.friend;
|
||||
// TODO检查我的好友人数上限,检查加过好友没有
|
||||
// TODO检查对方的好友人数上限
|
||||
str = await increaseFrdCnt(role, friend, friendCnt);
|
||||
if(str != '') continue;
|
||||
|
||||
// 创建friendShip
|
||||
let friendShip = await FriendShipModel.createFriendShip([roleId, friend.roleId]);
|
||||
if(!friendShip) continue;
|
||||
// 创建或push我的好友relation
|
||||
let result1 = await FriendRelationModel.addFriend(roleId, friend, friendShip);
|
||||
// 创建或push他的好友relation
|
||||
let result2 = await FriendRelationModel.addFriend(friend.roleId, role, friendShip);
|
||||
if(!friendShip) {
|
||||
str = getResStr(STATUS.FRIEND_SHIP_CREATE_ERROR); continue;
|
||||
}
|
||||
|
||||
await FriendRelationModel.addFriend(roleId, friend, friendShip);
|
||||
await FriendRelationModel.addFriend(friend.roleId, role, friendShip);
|
||||
|
||||
let param = new FriendListParam(friend, friendShip);
|
||||
let isOnline = await isRoleOnline(friend.roleId);
|
||||
param.setOnline(isOnline);
|
||||
|
||||
list.push(param);
|
||||
resultApplyCodeList.push(apply.applyCode);
|
||||
}
|
||||
} else {
|
||||
resultApplyCodeList = applyCodeList;
|
||||
}
|
||||
|
||||
// await FriendApplyModel.deleteApply(applyCodeList);
|
||||
await FriendApplyModel.deleteApply(resultApplyCodeList);
|
||||
|
||||
return resResult(STATUS.SUCCESS, {
|
||||
list: result
|
||||
isSuccess: str == '',
|
||||
msg: str,
|
||||
applyCodeList: resultApplyCodeList,
|
||||
list,
|
||||
friendCnt
|
||||
});
|
||||
}
|
||||
|
||||
@@ -127,9 +211,12 @@ export class FriendHandler {
|
||||
}
|
||||
|
||||
let { friendCnt = 0, blockCnt = 0 } = role;
|
||||
let frdPointRec = await FriendPointModel.getFrdPointRecToday(roleId, FRIEND_DROP_TYPE.SEND_GIFT);
|
||||
let { cnt: todayReceiveCnt = 0, sendCnt: todaySendCnt = 0 } = frdPointRec||{};
|
||||
|
||||
return resResult(STATUS.SUCCESS, {
|
||||
todayReceiveCnt: 0,
|
||||
todaySendCnt: 0,
|
||||
todayReceiveCnt,
|
||||
todaySendCnt,
|
||||
list,
|
||||
friendCnt, blockCnt
|
||||
});
|
||||
|
||||
51
game-server/app/services/friendService.ts
Normal file
51
game-server/app/services/friendService.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { gameData } from "../pubUtils/data";
|
||||
import { RoleType, RoleModel } from "../db/Role";
|
||||
import { FriendRelationType } from "../db/FriendRelation";
|
||||
import { getResStr } from "../pubUtils/util";
|
||||
import { STATUS, FRIEND_RELATION_TYPE } from "../consts";
|
||||
|
||||
/**
|
||||
* 增加双方好友数
|
||||
* @param role1 我方
|
||||
* @param role2 对方
|
||||
* @returns 是否添加成功
|
||||
*/
|
||||
export async function increaseFrdCnt(role1: RoleType, role2: RoleType, originalFriendCnt: number) {
|
||||
|
||||
let { roleId, lv, friendCnt } = role1;
|
||||
let dicFriend = gameData.roleFriend.get(lv);
|
||||
|
||||
if(friendCnt >= dicFriend.frdCnt) return getResStr(STATUS.FRIEND_MY_CNT_MAX);
|
||||
|
||||
let { roleId: _roleId, lv: _lv, friendCnt: _friendCnt } = role2;
|
||||
let _dicFriend = gameData.roleFriend.get(_lv);
|
||||
if(_friendCnt >= _dicFriend.frdCnt) return getResStr(STATUS.FRIEND_THEY_CNT_MAX);
|
||||
|
||||
let incMyFrdCnt = await RoleModel.increaseFriendCnt(roleId, 1, dicFriend.frdCnt);
|
||||
if(!incMyFrdCnt) return getResStr(STATUS.FRIEND_MY_CNT_MAX);
|
||||
let incHisFrdCnt = await RoleModel.increaseFriendCnt(_roleId, 1, _dicFriend.frdCnt);
|
||||
if(!incHisFrdCnt) { // 回滚
|
||||
await RoleModel.increaseFriendCnt(roleId, -1, dicFriend.frdCnt);
|
||||
return getResStr(STATUS.FRIEND_THEY_CNT_MAX);
|
||||
}
|
||||
originalFriendCnt = incMyFrdCnt.friendCnt;
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
export function getRecommendType(myFriendRelation: FriendRelationType, myRoleId: string, roleId: string) {
|
||||
if(myRoleId == roleId) {
|
||||
return FRIEND_RELATION_TYPE.MYSELF;
|
||||
}
|
||||
let friendList = myFriendRelation? myFriendRelation.friends: [];
|
||||
let blackList = myFriendRelation? myFriendRelation.blacklist: [];
|
||||
let hasFriend = friendList.find(cur => cur.roleId == roleId);
|
||||
if(hasFriend) {
|
||||
return FRIEND_RELATION_TYPE.HAS_FRIEND;
|
||||
}
|
||||
let hasBlcklist = blackList.find(cur => cur.roleId == roleId);
|
||||
if(hasBlcklist) {
|
||||
return FRIEND_RELATION_TYPE.HAS_BLOCKED;
|
||||
}
|
||||
return FRIEND_RELATION_TYPE.NORMAL;
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
export enum ROLE {
|
||||
// 玩家列表显示基础数据
|
||||
SHOW_SIMPLE = 'roleId roleName ce headHid sHid lv title job quitTime vLv guildName',
|
||||
SHOW_FRIEND_APPLY_LIST = 'roleId roleName ce headHid sHid lv title job quitTime vLv guildName friendCnt recFrdApplyCnt',
|
||||
HANDLE_APPLY = 'roleId friendCnt lv',
|
||||
|
||||
GET_LV = 'lv',
|
||||
|
||||
@@ -243,7 +243,8 @@ export const FUNCS_ID = {
|
||||
}
|
||||
|
||||
export const FRIEND_DROP_TYPE = {
|
||||
COM_BATTLE: 1
|
||||
COM_BATTLE: 1,
|
||||
SEND_GIFT: 2
|
||||
}
|
||||
|
||||
// 每日情谊点上限
|
||||
@@ -362,3 +363,10 @@ export const MAIL_TYPE = {
|
||||
};
|
||||
|
||||
export const CHAT_SERVER = 'chat-server-1';
|
||||
|
||||
export enum FRIEND_RELATION_TYPE {
|
||||
NORMAL = 1,
|
||||
HAS_FRIEND = 2,
|
||||
HAS_BLOCKED = 3,
|
||||
MYSELF = 4
|
||||
}
|
||||
@@ -231,7 +231,7 @@ export const STATUS = {
|
||||
EQUIP_NOT_EQUIPED_HERO: { code: 30509, simStr: '装备不能被该武将穿戴' },
|
||||
EQUIP_LEVEL_LIMIT: { code: 30510, simStr: '装备穿戴等级限制' },
|
||||
EQUIP_NOT_MATCH_JEWEL: { code: 30511, simStr: '装备不能镶嵌该宝石' },
|
||||
//全局养成30600-30799
|
||||
//全局养成30600-30699
|
||||
ROLE_REACH_MAX_TITLE_LEVEL: { code: 30600, simStr: '玩家已达到最高的爵位' },
|
||||
ROLE_TERAPH_NOT_STRENGTHEN: { code: 30601, simStr: '玩家神像不能强化' },
|
||||
ROLE_TERAPH_NOT_QUILITY: { code: 30602, simStr: '玩家神像不能进阶' },
|
||||
@@ -241,6 +241,14 @@ export const STATUS = {
|
||||
ROLE_SCHOOL_POSITION_UNLOCK_NOT_NEED: { code: 30605, simStr: '该位置已解锁' },
|
||||
ROLE_SCROLL_REACH_MAX: { code: 30606, simStr: '已经升到可以升的最高等级' },
|
||||
|
||||
// 好友30700-30799
|
||||
FRIEND_MY_CNT_MAX: { code: 30700, simStr: '好友数量已达上限' },
|
||||
FRIEND_THEY_CNT_MAX: { code: 30701, simStr: '玩家好友已满' },
|
||||
FRIEND_HAS_ADD: { code: 30702, simStr: '该玩家已是您的好友' },
|
||||
FRIEND_HAS_BLOCKED: { code: 30703, simStr: '该玩家在您的黑名单' },
|
||||
FRIEND_YOURSELF: { code: 30704, simStr: '不能添加自己为好友' },
|
||||
FRIEND_HIS_APPLY_MAX: { code: 30705, simStr: '该玩家申请达上限' },
|
||||
FRIEND_SHIP_CREATE_ERROR: { code: 30706, simStr: '创建失败' },
|
||||
|
||||
|
||||
// 社交相关状态 40000 - 49999
|
||||
|
||||
@@ -37,7 +37,7 @@ export default class FriendApply extends BaseModel {
|
||||
public static async getApplyList(roleId: string) {
|
||||
const list: FriendApplyType[] = await FriendApplyModel.find({ roleId }, { _id: 0 })
|
||||
// .select(select)
|
||||
.populate('friend', ROLE.SHOW_SIMPLE, 'Role')
|
||||
.populate('friend', ROLE.SHOW_FRIEND_APPLY_LIST, 'Role')
|
||||
.lean({ getters: true });
|
||||
return list;
|
||||
}
|
||||
@@ -46,7 +46,7 @@ export default class FriendApply extends BaseModel {
|
||||
public static async getApplyListByCode(applyCodeList: string[]) {
|
||||
const list: FriendApplyType[] = await FriendApplyModel.find({ applyCode: { $in: applyCodeList } }, { _id: 0 })
|
||||
// .select(select)
|
||||
.populate('friend', ROLE.SHOW_SIMPLE, 'Role')
|
||||
.populate('friend', ROLE.SHOW_FRIEND_APPLY_LIST, 'Role')
|
||||
.lean({ getters: true });
|
||||
return list;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ export default class FriendPoint extends BaseModel {
|
||||
@prop({ required: true, default: 0 })
|
||||
cnt: number; // 当天获取的点数
|
||||
@prop({ required: true, default: 0 })
|
||||
sendCnt: number; // 当天赠送的点数
|
||||
@prop({ required: true, default: 0 })
|
||||
type: number; // 情谊点统计的类型,不同功能都可能有每日获取上限
|
||||
|
||||
/**
|
||||
|
||||
@@ -41,12 +41,17 @@ export default class FriendRelation extends BaseModel {
|
||||
|
||||
|
||||
// 获取列表
|
||||
public static async findFriendByRole(roleId: string) {
|
||||
const result: FriendRelationType = await FriendRelationModel.findOne({ roleId })
|
||||
.populate('friends.role', ROLE.SHOW_SIMPLE, 'Role')
|
||||
.populate('friends.friendShip', null, 'FriendShip')
|
||||
public static async findFriendByRole(roleId: string, populate = true) {
|
||||
let document = FriendRelationModel.findOne({ roleId })
|
||||
.lean({ getters: true, virtuals: true });
|
||||
|
||||
if (populate) {
|
||||
document
|
||||
.populate('friends.role', ROLE.SHOW_SIMPLE, 'Role')
|
||||
.populate('friends.friendShip', null, 'FriendShip');
|
||||
}
|
||||
|
||||
let result: FriendRelationType = await document;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -79,6 +79,7 @@ export default class FriendShip extends BaseModel {
|
||||
return result;
|
||||
}
|
||||
|
||||
// 查询关系
|
||||
public static async deleteAccount(roleId: string) {
|
||||
let result = await FriendShipModel.deleteMany({ $or: [{ roleIdA: roleId }, { roleIdB: roleId }] });
|
||||
return result;
|
||||
|
||||
@@ -222,6 +222,8 @@ export default class Role extends BaseModel {
|
||||
friendCnt: number; // 好友人数
|
||||
@prop({ required: true, default: 0 })
|
||||
blockCnt: number; // 黑名单人数
|
||||
@prop({ required: true, default: 0 })
|
||||
recFrdApplyCnt: number; // 玩家收取好友申请数量
|
||||
|
||||
public static async findAllByUid(uid: number, lean = true) {
|
||||
const role: RoleType[] = await RoleModel.find({ 'userInfo.uid': uid }).select('roleId roleName serverId').lean(lean);
|
||||
@@ -445,11 +447,25 @@ export default class Role extends BaseModel {
|
||||
}
|
||||
|
||||
// 获取好友推荐列表
|
||||
public static async getRecommedList(roleId: string, minLv: number, maxLv: number, time: number) {
|
||||
const result = await RoleModel.find({ loginTime: { $gt: time }, lv: { $gte: minLv, $lte: maxLv }, roleId: { $ne: roleId } }, { _id: 0 })
|
||||
.select(ROLE.SHOW_SIMPLE)
|
||||
public static async getRecommedList(minLv: number, maxLv: number, time: number) {
|
||||
const result = await RoleModel.find({ loginTime: { $gt: time }, lv: { $gte: minLv, $lte: maxLv } }, { _id: 0 })
|
||||
.select(ROLE.SHOW_FRIEND_APPLY_LIST)
|
||||
.sort({quitTime: -1, lv: -1, ce: -1})
|
||||
.limit(100).lean({ getters: true });
|
||||
.limit(200).lean({ getters: true });
|
||||
return result;
|
||||
}
|
||||
|
||||
// 查询玩家
|
||||
public static async searchByNameOrId(value: string) {
|
||||
const result = await RoleModel.find({
|
||||
$or: [
|
||||
{ roleName: { $regex: new RegExp(value.toString(), 'i') } },
|
||||
{ roleId: value }
|
||||
]
|
||||
}, { _id: 0 })
|
||||
.select(ROLE.SHOW_FRIEND_APPLY_LIST)
|
||||
.sort({quitTime: -1, lv: -1, ce: -1})
|
||||
.limit(200).lean({ getters: true });
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -467,7 +483,13 @@ export default class Role extends BaseModel {
|
||||
|
||||
// 增加好友数量
|
||||
public static async increaseFriendCnt(roleId: string, inc: number, max: number) {
|
||||
const result = await RoleModel.findOneAndUpdate({ roleId, friendCnt: {$lt: max}}, {$inc: { friendCnt: inc }}, {new: true}).lean();
|
||||
const result = await RoleModel.findOneAndUpdate({ roleId, friendCnt: {$lte: max - inc}}, {$inc: { friendCnt: inc }}, {new: true}).lean();
|
||||
return result;
|
||||
}
|
||||
|
||||
// 增加好友申请数量
|
||||
public static async increaseFriendApplyCnt(roleId: string, inc: number, max: number) {
|
||||
const result = await RoleModel.findOneAndUpdate({ roleId, recFrdApplyCnt: {$lte: max - inc}}, {$inc: { recFrdApplyCnt: inc }}, {new: true}).lean();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,11 +21,30 @@ export class FriendParams {
|
||||
}
|
||||
}
|
||||
|
||||
export class FriendRecommendParams extends FriendParams {
|
||||
friendCnt: number = 0;
|
||||
recFrdApplyCnt: number = 0;
|
||||
type: number;
|
||||
|
||||
constructor(role: RoleType) {
|
||||
super(role);
|
||||
if(role.friendCnt) this.friendCnt = role.friendCnt;
|
||||
if(role.recFrdApplyCnt) this.recFrdApplyCnt = role.recFrdApplyCnt;
|
||||
}
|
||||
|
||||
setType(type: number) {
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
|
||||
export class FriendApplyParams extends FriendParams {
|
||||
applyCode: string;
|
||||
friendCnt: number = 0;
|
||||
|
||||
constructor(applyCode: string, role: RoleType) {
|
||||
super(role);
|
||||
this.applyCode = applyCode;
|
||||
if(role.friendCnt) this.friendCnt = role.friendCnt;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,8 +54,8 @@ export class FriendListParam extends FriendParams {
|
||||
quitTime: number = 0;
|
||||
friendValue: number = 0;
|
||||
friendLv: number = 1;
|
||||
canReceive: boolean = false;
|
||||
canSend: boolean = false;
|
||||
canReceive: boolean = false; // 初始没人送肯定不能领取
|
||||
canSend: boolean = true; // 初始可以赠送
|
||||
|
||||
constructor(role: RoleType, friendship: FriendShipType) {
|
||||
super(role);
|
||||
|
||||
@@ -324,6 +324,10 @@ export function resResult(status: { code: number, simStr: string }, data = null,
|
||||
return { code, msg: customMsg || simStr, data };
|
||||
}
|
||||
|
||||
export function getResStr(status: { code: number, simStr: string }) {
|
||||
return status.simStr;
|
||||
}
|
||||
|
||||
// 消除 js 浮点计算bug
|
||||
|
||||
export const cal = {
|
||||
|
||||
Reference in New Issue
Block a user