From 67d6f7b20628a93c77cf288fd15447efc3785ae6 Mon Sep 17 00:00:00 2001 From: zhl Date: Wed, 27 Jan 2021 20:13:46 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=AD=BE=E5=88=B0=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/controllers/DaySignController.ts | 163 +++++++++++++++++++++++++++ src/models/SignRecord.ts | 49 ++++++++ src/service/SvrConfig.ts | 34 ++++++ src/service/jcfw.ts | 14 ++- src/utils/string.util.ts | 20 ++++ src/utils/time.util.ts | 7 ++ 6 files changed, 281 insertions(+), 6 deletions(-) create mode 100644 src/controllers/DaySignController.ts create mode 100644 src/models/SignRecord.ts create mode 100644 src/service/SvrConfig.ts diff --git a/src/controllers/DaySignController.ts b/src/controllers/DaySignController.ts new file mode 100644 index 0000000..555b870 --- /dev/null +++ b/src/controllers/DaySignController.ts @@ -0,0 +1,163 @@ +import BaseController from '../common/base.controller' +import { router } from '../decorators/router' +import { SvrConfig } from '../service/SvrConfig' +import { SignRecord } from '../models/SignRecord' +import { ZError } from '../common/ZError' +import { parseGameAccountId } from '../utils/string.util' +import { calcBetweenDays } from '../utils/time.util' +import ItemCtrl from '../logic/ItemCtrl' +import { ItemInfo } from '../logic/ItemDef' +import { BagItem } from '../models/BagItem' + +export default class DaySignController extends BaseController { + /** + * 获取签到列表 + */ + @router('post /api/:accountid/sign/list') + async signList(req: any) { + let { accountid, retroactive } = req.params + retroactive = retroactive || 1 + let { gameid, channel } = parseGameAccountId(accountid) + if (!gameid || !channel) { + throw new ZError(11, '无法从accountid获取gameid和channel') + } + const cfgs = await new SvrConfig().getSignCfg(gameid, channel) + let record = (await SignRecord.findOrCreate({ accountid })).doc + if (!cfgs || !Array.isArray(cfgs)) { + throw new ZError(10, 'error get svr sign cfg') + } + let userData: any = {} + for (let cfg of cfgs) { + cfg.status = record.data.get(cfg.id + '') || 0 + if (record.data.has(cfg.id + '')) { + userData[cfg.id] = 3 + } + } + let betweenDays = 0 + if (record.last == 0) { + betweenDays = 0 + } else { + betweenDays = calcBetweenDays(Date.now(), record.last) + } + let doubleReward = betweenDays == 0 ? record.double : 0 + let needNext = true + if (betweenDays === 0) { + needNext = false + } + if (needNext) { + if (betweenDays == 2 && !!retroactive) { + for (let i = 0; i < cfgs.length - 1; i++) { + if (cfgs[i].status == 3 && cfgs[i + 1].status == 0) { + cfgs[i + 1].status = 1 //可补签 + if (i + 2 < cfgs.length) { + cfgs[i + 2].status = 2 //可领取 + } else { + cfgs[0].status = 2 + } + needNext = false + break + } + } + } + } + if (needNext) { + //正常或者超过两天的 + let count = 0 + for (let obj of cfgs) { + obj.status == 3 && count++ + } + if (count == 7 || betweenDays > 1) { + //一轮领完 或者过期了, 2上面处理过了 + // this.refreshData(); + for (let obj of cfgs) { + obj.status = 0 + } + record.data.clear() + record.last = 0 + betweenDays = 0 + doubleReward = 0 + userData = {} + await record.save() + } + for (let obj of cfgs) { + if (obj.status == 0) { + obj.status = 2 + break + } + } + } + + return { + cfgs, + last: record.last / 1000 | 0, + betweenDays, + doubleReward, + userData + } + } + + /** + * 签到 + */ + @router('post /api/:accountid/sign/get') + async receiveReward(req: any) { + // type: 1: 普通领取, 2: 双倍领取, 3: 补签 + let { accountid, type, id } = req.params + type = parseInt(type) + let { gameid, channel } = parseGameAccountId(accountid) + if (!gameid || !channel) { + throw new ZError(11, '无法从accountid获取gameid和channel') + } + const cfgs: any[] = await new SvrConfig().getSignCfg(gameid, channel) + let record = (await SignRecord.findOrCreate({ accountid })).doc + let rate = 1 + let cfg = cfgs.find(o => o.id === id) + if (!cfg) { + throw new ZError(13, '无法获取对应的配置') + } + switch (type) { + case 1: + if (record.data.has(id + '')) { + throw new ZError(12, '不满足领取条件') + } + record.double = 0 + record.last = Date.now() + break + case 2: + if (!record.data.has(id + '')) { + rate = 2 + } + record.double = 1 + record.last = Date.now() + break + case 3: + if (record.data.has(id + '')) { + throw new ZError(12, '不满足补签条件') + } + record.double = 0 + record.last = Date.now() - 3600 * 24 * 1000 + break + default: + if (record.data.has(id + '')) { + throw new ZError(12, '不满足领取条件') + } + record.double = 0 + record.last = Date.now() + break + } + record.data.set(id + '', 3) + let itemStr = '' + if (cfg.reward_list && Array.isArray(cfg.reward_list)) { + for (let sub of cfg.reward_list) { + if (itemStr.length > 0) itemStr += '|' + itemStr += `${sub.reward_type}:${sub.reward_count}` + } + } else { + itemStr += `${cfg.reward_type}:${cfg.reward_count}` + } + const itemInfos: ItemInfo[] = ItemCtrl.getItemsByInfo(itemStr) + await BagItem.addItems(accountid, itemInfos) + await record.save() + return itemInfos + } +} diff --git a/src/models/SignRecord.ts b/src/models/SignRecord.ts new file mode 100644 index 0000000..7168d43 --- /dev/null +++ b/src/models/SignRecord.ts @@ -0,0 +1,49 @@ +import { dbconn } from '../decorators/dbconn' +import { + getModelForClass, + index, + modelOptions, plugin, + prop +} from '@typegoose/typegoose' +import { + Base, + FindOrCreate, + TimeStamps +} from '@typegoose/typegoose/lib/defaultClasses' +// @ts-ignore +import findOrCreate from 'mongoose-findorcreate' +import { Card } from './subdoc/Card' + +interface SignRecordClass extends Base, TimeStamps { +} + +@dbconn() +@plugin(findOrCreate) +@index({ accountid: 1 }, { unique: false }) +@modelOptions({ + schemaOptions: + { collection: 'sign_record', timestamps: true } +}) +class SignRecordClass extends FindOrCreate{ + @prop({ required: true }) + public accountid!: string + @prop({default: 0}) + public last: number + // 0 未完成,3 已完成 + @prop({ type: Number, default: new Map() }) + public data: Map + + @prop({default: 0}) + public double: number + public toJson() { + return { + accoundid: this.accountid, + last: this.last, + data: this.data + } + } +} + +export const SignRecord = getModelForClass(SignRecordClass, +// @ts-ignore + { existingConnection: SignRecordClass['db'] }) diff --git a/src/service/SvrConfig.ts b/src/service/SvrConfig.ts new file mode 100644 index 0000000..a68a751 --- /dev/null +++ b/src/service/SvrConfig.ts @@ -0,0 +1,34 @@ +import { singleton } from '../decorators/singleton.decorator' +import { getGameConfig } from './jcfw' + +@singleton +export class SvrConfig { + public cfgMap: Map = new Map() + + public async loadData(gameid: string, channel: string) { + const cfgs = await getGameConfig(gameid, channel) + let map: Map = new Map() + for (let cfg of cfgs) { + try { + let obj = JSON.parse(cfg.value) + map.set(cfg.key, obj) + } catch(e) { + map.set(cfg.key, cfg.value) + } + } + this.cfgMap.set(SvrConfig.generateKey(gameid, channel), map) + } + public static generateKey(gameid: string, channel: string) { + return `${gameid}_${channel}` + } + + public async getSignCfg(gameid: string, channel: string) { + let key = SvrConfig.generateKey(gameid, channel) + if (!this.cfgMap.has(key)) { + await this.loadData(gameid, channel) + } + return this.cfgMap.get(key).get('sign_list') + } + + +} diff --git a/src/service/jcfw.ts b/src/service/jcfw.ts index 381f745..74b1936 100644 --- a/src/service/jcfw.ts +++ b/src/service/jcfw.ts @@ -1,17 +1,19 @@ import { generateKeyValStr } from '../utils/string.util' import axios from 'axios' -const CONFIG_URL = 'https://cloud.kingsome.cn/webapp/index.php?c=Config&a=read' +const CONFIG_URL = 'https://center.kingsome.cn/api/cfg_list' /** * 获取jcfw中该游戏的配置 * @param {string} gameid * @param {string} channel - * @return {Promise>} */ export function getGameConfig(gameid: string, channel: string) { - let data = { gameid, channel } - let paramStr = generateKeyValStr(data) - let url = `${ CONFIG_URL }&${ paramStr }` - return axios.get(url) + let url = `${ CONFIG_URL }?game_id=${gameid}&channel_id=${channel}` + return axios.get(url).then((res: any) => { + if (res.data.errorcode && res.data.result) { + throw new Error(`error get game cfg, code: ${res.errorcode}, msg: ${res.errmsg}`) + } + return JSON.parse(res.data.result) + }) } diff --git a/src/utils/string.util.ts b/src/utils/string.util.ts index eaed80a..f45c9ab 100644 --- a/src/utils/string.util.ts +++ b/src/utils/string.util.ts @@ -43,3 +43,23 @@ export function keyValToObject(str: string, } return result } + +export function isJsonString(str: string) { + try { + if (typeof JSON.parse(str) == "object") { + return true; + } + } catch(e) { + } + return false; +} + +export function checkAccountId(accountId: string) { + return /^\d{4}_\d{4}_.+$/.test(accountId); +} +export function parseGameAccountId(accountId: string) { + const arr = accountId.split('_'); + const gameid = arr[1]; + const channel = arr[0]; + return {gameid, channel}; +} diff --git a/src/utils/time.util.ts b/src/utils/time.util.ts index e763e85..5f44fe7 100644 --- a/src/utils/time.util.ts +++ b/src/utils/time.util.ts @@ -7,3 +7,10 @@ export function timeBeforeDay(day: number): number { let time = Date.now(); return time - day * 1000 * 24 * 24; } + +//间隔天数 +export function calcBetweenDays(time1: number, time2: number) { + let v1 = Math.floor(time1/3600/24/1000); + let v2 = Math.floor(time2/3600/24/1000); + return Math.abs(v1 - v2); +}