增加店铺物品, 配置等,及相关方法
This commit is contained in:
parent
fc125cf624
commit
8428f78731
12
doc/api.md
12
doc/api.md
@ -5,6 +5,7 @@
|
|||||||
### 20200604
|
### 20200604
|
||||||
1. [增加用户信息](#212), [抽奖转盘信息](#213), [抽奖](#214), [邀请奖励信息](#215), [挑战详情](#216) 接口
|
1. [增加用户信息](#212), [抽奖转盘信息](#213), [抽奖](#214), [邀请奖励信息](#215), [挑战详情](#216) 接口
|
||||||
2. 所有接口增加post字段 version(当前版本固定取1.0.1)和sessionid(取自jcfw)
|
2. 所有接口增加post字段 version(当前版本固定取1.0.1)和sessionid(取自jcfw)
|
||||||
|
3. 获取店铺信息 增加返回店铺的数字编号
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -332,6 +333,7 @@
|
|||||||
```js
|
```js
|
||||||
{
|
{
|
||||||
"id": "607ff59d4a4e16687a3b7079", // 店铺id
|
"id": "607ff59d4a4e16687a3b7079", // 店铺id
|
||||||
|
"numid": 1002, // 店铺的数字编号
|
||||||
"name": "一品漫城", // 店铺名
|
"name": "一品漫城", // 店铺名
|
||||||
"area": "上海市-上海市-闵行区", // 区域
|
"area": "上海市-上海市-闵行区", // 区域
|
||||||
"logo": "https://resource.kingsome.cn/game607fd53cb40504740fdccb13.png", // 店铺logo
|
"logo": "https://resource.kingsome.cn/game607fd53cb40504740fdccb13.png", // 店铺logo
|
||||||
@ -493,15 +495,17 @@
|
|||||||
|
|
||||||
| 字段 | 说明 |
|
| 字段 | 说明 |
|
||||||
| -------- | -------------------------------------- |
|
| -------- | -------------------------------------- |
|
||||||
| sid | 店铺id, 不传的话获取所有 |
|
| sid | 店铺id |
|
||||||
|
|
||||||
3. Response: JSON
|
3. Response: JSON
|
||||||
|
|
||||||
```js
|
```js
|
||||||
[{
|
{
|
||||||
shop: '店铺id',
|
|
||||||
tocket_lottery: 10, //用户在当前店铺拥有的抽奖券数量
|
tocket_lottery: 10, //用户在当前店铺拥有的抽奖券数量
|
||||||
}]
|
share_rewards: [{
|
||||||
|
|
||||||
|
}],
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 13. 抽奖转盘信息
|
### 13. 抽奖转盘信息
|
||||||
|
@ -6,6 +6,9 @@ import { mongoose } from '@typegoose/typegoose'
|
|||||||
import logger from 'logger/logger'
|
import logger from 'logger/logger'
|
||||||
import config from 'config/config'
|
import config from 'config/config'
|
||||||
import { AdminRole } from 'models/admin/AdminRole'
|
import { AdminRole } from 'models/admin/AdminRole'
|
||||||
|
import { Shop } from './models/shop/Shop'
|
||||||
|
import { MongoTool } from './services/MongoTool'
|
||||||
|
import { GameItem } from './models/content/GameItem'
|
||||||
|
|
||||||
const rbacPlugin = require('plugins/zrbac')
|
const rbacPlugin = require('plugins/zrbac')
|
||||||
const zAuthPlugin = require('plugins/zauth')
|
const zAuthPlugin = require('plugins/zauth')
|
||||||
@ -137,11 +140,20 @@ export class AdminServer {
|
|||||||
return payload
|
return payload
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async initUniqueKeyCache() {
|
||||||
|
let id = await Shop.maxNumKey()
|
||||||
|
new MongoTool().init('shop', id)
|
||||||
|
id = await GameItem.maxNumKey()
|
||||||
|
new MongoTool().init('gameitem', id)
|
||||||
|
}
|
||||||
|
|
||||||
public async start() {
|
public async start() {
|
||||||
let self = this
|
let self = this
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
await self.connectDB()
|
await self.connectDB()
|
||||||
await self.registerRbac()
|
await self.registerRbac()
|
||||||
|
await self.initUniqueKeyCache()
|
||||||
self.initControllers()
|
self.initControllers()
|
||||||
self.registerRouter()
|
self.registerRouter()
|
||||||
self.setErrHandler()
|
self.setErrHandler()
|
||||||
|
@ -3,16 +3,22 @@ import { permission, role, router } from '../../decorators/router'
|
|||||||
import { ZError } from '../../common/ZError'
|
import { ZError } from '../../common/ZError'
|
||||||
import { Game } from '../../models/content/Game'
|
import { Game } from '../../models/content/Game'
|
||||||
import { generateQrFile } from '../../services/File'
|
import { generateQrFile } from '../../services/File'
|
||||||
|
import { getInviteeNum } from '../../services/JCFW'
|
||||||
|
import { UserItem } from '../../models/user/UserItem'
|
||||||
|
|
||||||
class GameController extends BaseController {
|
class GameController extends BaseController {
|
||||||
@role('anon')
|
@role('anon')
|
||||||
@router('get /api/test')
|
@router('get /api/test')
|
||||||
async test(req) {
|
async test(req) {
|
||||||
let gameId = '60810dd156af0e8550832a44'
|
// let gameId = '60810dd156af0e8550832a44'
|
||||||
let version = '608117912ff0238a3e607d33'
|
// let version = '608117912ff0238a3e607d33'
|
||||||
let shop = 'sa6xtgbmj7'
|
// let shop = 'sa6xtgbmj7'
|
||||||
const { file, url } = await generateQrFile({ gameId, version, shop })
|
// const { file, url } = await generateQrFile({ gameId, version, shop })
|
||||||
return { file, url }
|
// return { file, url }
|
||||||
|
let accountId = '7101_8004_opBlx1vRs-UIGF6rZDkkSrSTJYAs'
|
||||||
|
let sessionId = '1622783517_1556611531_60838f020d9c51716f144bf7a71b2af5_e5818d3fc90f8491aa285246cb6d85ce'
|
||||||
|
let result = await getInviteeNum(accountId, sessionId, [1001])
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
@permission(['game:read', 'shop:game_setting'])
|
@permission(['game:read', 'shop:game_setting'])
|
||||||
@router('post /api/games')
|
@router('post /api/games')
|
||||||
|
70
src/admin/controllers/gameitem.controller.ts
Normal file
70
src/admin/controllers/gameitem.controller.ts
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import BaseController from '../../common/base.controller'
|
||||||
|
import { permission, router } from '../../decorators/router'
|
||||||
|
import { ZError } from '../../common/ZError'
|
||||||
|
import { Game } from '../../models/content/Game'
|
||||||
|
|
||||||
|
class GameItemController extends BaseController {
|
||||||
|
@permission(['gameitem:read'])
|
||||||
|
@router('post /api/game_items')
|
||||||
|
async list(req, res) {
|
||||||
|
let { start, limit, page } = req.params
|
||||||
|
limit = +limit || 10
|
||||||
|
start = +start || (+page - 1) * limit || 0
|
||||||
|
let { opt, sort } = Game.parseQueryParam(req.params)
|
||||||
|
let articles = await Game.find(opt).sort(sort).skip(start).limit(limit)
|
||||||
|
let count = await Game.countDocuments(opt)
|
||||||
|
let records = []
|
||||||
|
for (let record of articles) {
|
||||||
|
records.push(record.toJson())
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
total: count,
|
||||||
|
start,
|
||||||
|
limit,
|
||||||
|
records,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@permission('gameitem:read')
|
||||||
|
@router('get /api/game_item/:id')
|
||||||
|
async detail(req, res) {
|
||||||
|
let { id } = req.params
|
||||||
|
const record = await Game.findById(id)
|
||||||
|
if (!record) {
|
||||||
|
throw new ZError(11, 'record not found')
|
||||||
|
}
|
||||||
|
return record.toJson()
|
||||||
|
}
|
||||||
|
|
||||||
|
@permission('gameitem:read')
|
||||||
|
@router('post /api/game_item/save')
|
||||||
|
async save(req: any) {
|
||||||
|
let { _id } = req.params
|
||||||
|
let user = req.user
|
||||||
|
let record
|
||||||
|
if (!_id) {
|
||||||
|
record = new Game(req.params)
|
||||||
|
record.createdBy = user.id
|
||||||
|
} else {
|
||||||
|
record = await Game.findById(_id)
|
||||||
|
record.updateFromReq(req.params)
|
||||||
|
}
|
||||||
|
await record.save()
|
||||||
|
return record.toJson()
|
||||||
|
}
|
||||||
|
@permission('gameitem:read')
|
||||||
|
@router('post /api/game_item/:id/delete')
|
||||||
|
async delete(req: any) {
|
||||||
|
let { id } = req.params
|
||||||
|
if (!id) {
|
||||||
|
throw new ZError(11, 'params mismatch')
|
||||||
|
}
|
||||||
|
await Game.findByIdAndUpdate(id, {
|
||||||
|
$set: {
|
||||||
|
deleted: true,
|
||||||
|
deleteTime: new Date(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,8 @@
|
|||||||
import { router, role } from 'decorators/router'
|
import { role, router } from 'decorators/router'
|
||||||
import BaseController from 'common/base.controller'
|
import BaseController from 'common/base.controller'
|
||||||
import { Account } from 'models/Account'
|
import { Account } from 'models/Account'
|
||||||
import { AccountTmp } from 'models/AccountTmp'
|
|
||||||
import { AppInfo, PlatInfo } from 'models/AppInfo'
|
import { AppInfo, PlatInfo } from 'models/AppInfo'
|
||||||
import { IPlat, IPlatUser } from 'plats/IPlat'
|
import { IPlat, IPlatUser } from 'plats/IPlat'
|
||||||
import { PlatAliPayPage } from 'plats/PlatAliPayPage'
|
|
||||||
|
|
||||||
class AccountController extends BaseController {
|
class AccountController extends BaseController {
|
||||||
plat: IPlat
|
plat: IPlat
|
||||||
|
@ -6,7 +6,7 @@ import { Puzzle } from '../../models/content/Puzzle'
|
|||||||
import { PuzzleSession, PuzzleStatusClass } from '../../models/match/PuzzleSession'
|
import { PuzzleSession, PuzzleStatusClass } from '../../models/match/PuzzleSession'
|
||||||
import { calcExamScore, getRank, transformRecord, updateExamRank } from '../../services/GameLogic'
|
import { calcExamScore, getRank, transformRecord, updateExamRank } from '../../services/GameLogic'
|
||||||
import { Shop, validShopId } from '../../models/shop/Shop'
|
import { Shop, validShopId } from '../../models/shop/Shop'
|
||||||
import { UserReward } from '../../models/UserReward'
|
import { UserReward } from '../../models/user/UserReward'
|
||||||
import { ShopPuzzle } from '../../models/shop/ShopPuzzle'
|
import { ShopPuzzle } from '../../models/shop/ShopPuzzle'
|
||||||
|
|
||||||
class ExamController extends BaseController {
|
class ExamController extends BaseController {
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import BaseController from '../../common/base.controller'
|
import BaseController from '../../common/base.controller'
|
||||||
import { role, router } from '../../decorators/router'
|
import { role, router } from '../../decorators/router'
|
||||||
import { GameUser } from '../../models/GameUser'
|
import { GameUser } from '../../models/user/GameUser'
|
||||||
import { ZError } from '../../common/ZError'
|
import { ZError } from '../../common/ZError'
|
||||||
import { getRandom } from '../../utils/number.util'
|
import { getRandom } from '../../utils/number.util'
|
||||||
import { UserReward } from '../../models/UserReward'
|
import { UserReward } from '../../models/user/UserReward'
|
||||||
|
import { UserItem } from '../../models/user/UserItem'
|
||||||
|
import { LOTTERY_TICKET } from '../../constants/BaseConst'
|
||||||
|
|
||||||
class GameUserController extends BaseController {
|
class GameUserController extends BaseController {
|
||||||
// TODO:: 增加返回未使用的券
|
// TODO:: 增加返回未使用的券
|
||||||
@ -52,4 +54,14 @@ class GameUserController extends BaseController {
|
|||||||
const result = await UserReward.ticketList(accountid, sid)
|
const result = await UserReward.ticketList(accountid, sid)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@role('anon')
|
||||||
|
@router('post /api/:accountId/info')
|
||||||
|
async userInfo(req: any) {
|
||||||
|
const { accountId, sid } = req.params
|
||||||
|
let result: any = {}
|
||||||
|
result.tocket_lottery = await UserItem.fetchCount({ accountId, shop: sid, item: LOTTERY_TICKET })
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ import {
|
|||||||
} from '../../services/GameLogic'
|
} from '../../services/GameLogic'
|
||||||
import { Shop, validShopId } from '../../models/shop/Shop'
|
import { Shop, validShopId } from '../../models/shop/Shop'
|
||||||
import { ShopActivity } from '../../models/shop/ShopActivity'
|
import { ShopActivity } from '../../models/shop/ShopActivity'
|
||||||
import { GameUser } from '../../models/GameUser'
|
import { GameUser } from '../../models/user/GameUser'
|
||||||
import { isObjectId } from '../../utils/string.util'
|
import { isObjectId } from '../../utils/string.util'
|
||||||
|
|
||||||
class PuzzleController extends BaseController {
|
class PuzzleController extends BaseController {
|
||||||
|
@ -99,6 +99,7 @@ class ShopController extends BaseController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
rspData.id = shop.sid
|
rspData.id = shop.sid
|
||||||
|
rspData.numid = shop.numid
|
||||||
rspData.name = shop.showName
|
rspData.name = shop.showName
|
||||||
rspData.area = shop.areaStr
|
rspData.area = shop.areaStr
|
||||||
rspData.logo = shop.logo
|
rspData.logo = shop.logo
|
||||||
|
@ -934,7 +934,7 @@ interface Map<K, V> {
|
|||||||
* @param key
|
* @param key
|
||||||
* @param value
|
* @param value
|
||||||
*/
|
*/
|
||||||
inc?(key: K, value: V): this
|
inc?(key: K, value: V): number
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.defineProperties(Map.prototype, {
|
Object.defineProperties(Map.prototype, {
|
||||||
@ -945,6 +945,7 @@ Object.defineProperties(Map.prototype, {
|
|||||||
} else {
|
} else {
|
||||||
this.set(key, value)
|
this.set(key, value)
|
||||||
}
|
}
|
||||||
|
return this.get(key)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -9,3 +9,6 @@ export class BaseConst {
|
|||||||
// 第一题延后发送时间
|
// 第一题延后发送时间
|
||||||
public static readonly FIST_QUESTION_DELAY = 2000
|
public static readonly FIST_QUESTION_DELAY = 2000
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 抽奖券的物品id
|
||||||
|
export const LOTTERY_TICKET = 'lottery_ticket'
|
||||||
|
39
src/models/content/GameItem.ts
Normal file
39
src/models/content/GameItem.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { dbconn } from '../../decorators/dbconn'
|
||||||
|
import { getModelForClass, modelOptions, pre, prop } from '@typegoose/typegoose'
|
||||||
|
import { BaseModule } from '../Base'
|
||||||
|
import { INIT_KEY_NUM, MongoTool } from '../../services/MongoTool'
|
||||||
|
|
||||||
|
@dbconn()
|
||||||
|
@modelOptions({ schemaOptions: { collection: 'game_items', timestamps: true, _id: false } })
|
||||||
|
@pre<GameItemClass>('save', async function () {
|
||||||
|
if (!this._id) {
|
||||||
|
let sid = 0
|
||||||
|
while (!sid) {
|
||||||
|
sid = new MongoTool().getUniqueKey('gameitem')
|
||||||
|
}
|
||||||
|
this._id = sid + ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
class GameItemClass extends BaseModule {
|
||||||
|
@prop()
|
||||||
|
public _id: string
|
||||||
|
@prop()
|
||||||
|
public shop: string
|
||||||
|
|
||||||
|
@prop()
|
||||||
|
public name: string
|
||||||
|
|
||||||
|
@prop({ default: 0 })
|
||||||
|
public type: number
|
||||||
|
|
||||||
|
public static async maxNumKey() {
|
||||||
|
const records = await GameItem.find().sort({ _id: -1 }).limit(1)
|
||||||
|
let result = INIT_KEY_NUM
|
||||||
|
if (records && records.length > 0) {
|
||||||
|
result = Number(records[0]._id) || result
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const GameItem = getModelForClass(GameItemClass, { existingConnection: GameItemClass.db })
|
@ -5,6 +5,7 @@ import { BaseModule } from '../Base'
|
|||||||
import { customAlphabet } from 'nanoid'
|
import { customAlphabet } from 'nanoid'
|
||||||
import { isObjectId } from '../../utils/string.util'
|
import { isObjectId } from '../../utils/string.util'
|
||||||
import { ZError } from '../../common/ZError'
|
import { ZError } from '../../common/ZError'
|
||||||
|
import { INIT_KEY_NUM, MongoTool } from '../../services/MongoTool'
|
||||||
|
|
||||||
const nanoid = customAlphabet('2345678abcdefghjkmnpqrstwxy', 10)
|
const nanoid = customAlphabet('2345678abcdefghjkmnpqrstwxy', 10)
|
||||||
|
|
||||||
@ -30,11 +31,21 @@ class GameInfo {
|
|||||||
}
|
}
|
||||||
this.sid = sid
|
this.sid = sid
|
||||||
}
|
}
|
||||||
|
if (!this.numid) {
|
||||||
|
let sid = 0
|
||||||
|
while (!sid) {
|
||||||
|
sid = new MongoTool().getUniqueKey('shop')
|
||||||
|
}
|
||||||
|
this.numid = sid
|
||||||
|
}
|
||||||
})
|
})
|
||||||
class ShopClass extends BaseModule {
|
class ShopClass extends BaseModule {
|
||||||
@prop()
|
@prop()
|
||||||
public sid: string
|
public sid: string
|
||||||
|
|
||||||
|
@prop()
|
||||||
|
public numid: number
|
||||||
|
|
||||||
@prop({ required: true })
|
@prop({ required: true })
|
||||||
public name!: string
|
public name!: string
|
||||||
/**
|
/**
|
||||||
@ -180,6 +191,15 @@ class ShopClass extends BaseModule {
|
|||||||
}
|
}
|
||||||
return records[0]?._id
|
return records[0]?._id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async maxNumKey() {
|
||||||
|
const records = await Shop.find().sort({ numid: -1 }).limit(1)
|
||||||
|
let result = INIT_KEY_NUM
|
||||||
|
if (records && records.length > 0) {
|
||||||
|
result = records[0].numid || result
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isShopSid(id: string) {
|
export function isShopSid(id: string) {
|
||||||
|
72
src/models/shop/ShopCfg.ts
Normal file
72
src/models/shop/ShopCfg.ts
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import { dbconn } from '../../decorators/dbconn'
|
||||||
|
import { getModelForClass, index, modelOptions, prop } from '@typegoose/typegoose'
|
||||||
|
import { BaseModule } from '../Base'
|
||||||
|
import { Severity } from '@typegoose/typegoose/lib/internal/constants'
|
||||||
|
import { Base } from '@typegoose/typegoose/lib/defaultClasses'
|
||||||
|
|
||||||
|
export class ShareCfgClass extends Base {
|
||||||
|
/**
|
||||||
|
* 所需人数
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
@prop()
|
||||||
|
public need_count: number
|
||||||
|
|
||||||
|
@prop()
|
||||||
|
public name: string
|
||||||
|
|
||||||
|
@prop()
|
||||||
|
public reward_type: string
|
||||||
|
|
||||||
|
@prop()
|
||||||
|
public reward_count: number
|
||||||
|
|
||||||
|
@prop()
|
||||||
|
public icon: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export class LotteryCfgClass extends Base {
|
||||||
|
@prop()
|
||||||
|
public name: string
|
||||||
|
|
||||||
|
@prop()
|
||||||
|
public reward_type: string
|
||||||
|
|
||||||
|
@prop()
|
||||||
|
public reward_count: number
|
||||||
|
|
||||||
|
@prop()
|
||||||
|
public icon: string
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 店铺的一些额外配置
|
||||||
|
*/
|
||||||
|
@dbconn()
|
||||||
|
@index({ shop: 1 }, { unique: false })
|
||||||
|
@modelOptions({
|
||||||
|
schemaOptions: { collection: 'shop_cfg_ext', timestamps: true },
|
||||||
|
options: { allowMixed: Severity.ALLOW },
|
||||||
|
})
|
||||||
|
export class ShopCfgClass extends BaseModule {
|
||||||
|
/**
|
||||||
|
* 所属店铺
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
@prop()
|
||||||
|
public shop: string
|
||||||
|
/**
|
||||||
|
* 抽奖转盘奖励配置
|
||||||
|
* @type {LotteryCfgClass[]}
|
||||||
|
*/
|
||||||
|
@prop({ type: [LotteryCfgClass] })
|
||||||
|
public lottery_cfgs: LotteryCfgClass[]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 邀请好友奖励配置
|
||||||
|
* @type {ShareCfgClass[]}
|
||||||
|
*/
|
||||||
|
@prop({ type: [ShareCfgClass] })
|
||||||
|
public share_cfgs: ShareCfgClass[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ShopCfg = getModelForClass(ShopCfgClass, { existingConnection: ShopCfgClass.db })
|
@ -2,7 +2,6 @@ import { dbconn } from '../../decorators/dbconn'
|
|||||||
import { getModelForClass, index, modelOptions, mongoose, prop } from '@typegoose/typegoose'
|
import { getModelForClass, index, modelOptions, mongoose, prop } from '@typegoose/typegoose'
|
||||||
import { BaseModule } from '../Base'
|
import { BaseModule } from '../Base'
|
||||||
import { Severity } from '@typegoose/typegoose/lib/internal/constants'
|
import { Severity } from '@typegoose/typegoose/lib/internal/constants'
|
||||||
import { ShopExamClass } from './ShopExam'
|
|
||||||
|
|
||||||
@dbconn()
|
@dbconn()
|
||||||
@index({ shop: 1, game: 1 }, { unique: false })
|
@index({ shop: 1, game: 1 }, { unique: false })
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { dbconn } from '../decorators/dbconn'
|
|
||||||
import { getModelForClass, index, modelOptions, prop, ReturnModelType } from '@typegoose/typegoose'
|
import { getModelForClass, index, modelOptions, prop, ReturnModelType } from '@typegoose/typegoose'
|
||||||
import { BaseModule } from './Base'
|
import { BaseModule } from '../Base'
|
||||||
|
import { dbconn } from '../../decorators/dbconn'
|
||||||
|
|
||||||
@dbconn()
|
@dbconn()
|
||||||
@index({ accountId: 1 }, { unique: true })
|
@index({ accountId: 1 }, { unique: true })
|
49
src/models/user/ItemRecord.ts
Normal file
49
src/models/user/ItemRecord.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import { getModelForClass, index, modelOptions, mongoose, prop, Severity } from '@typegoose/typegoose'
|
||||||
|
import { dbconn } from '../../decorators/dbconn'
|
||||||
|
import { BaseModule } from '../Base'
|
||||||
|
|
||||||
|
@dbconn()
|
||||||
|
@index({ accountId: 1, item: 1 }, { unique: false })
|
||||||
|
@index({ accountId: 1 }, { unique: false })
|
||||||
|
@modelOptions({
|
||||||
|
schemaOptions: { collection: 'item_record', timestamps: true },
|
||||||
|
options: { allowMixed: Severity.ALLOW },
|
||||||
|
})
|
||||||
|
class ItemRecordClass extends BaseModule {
|
||||||
|
@prop()
|
||||||
|
public item: number
|
||||||
|
@prop()
|
||||||
|
public accountId: string
|
||||||
|
@prop()
|
||||||
|
public shop: string
|
||||||
|
/**
|
||||||
|
* 增加为正
|
||||||
|
* 使用为负
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
@prop()
|
||||||
|
public count: number
|
||||||
|
@prop()
|
||||||
|
public reason: string
|
||||||
|
@prop({ type: mongoose.Schema.Types.Mixed })
|
||||||
|
public data: {}
|
||||||
|
|
||||||
|
public static async log(
|
||||||
|
accountId: string,
|
||||||
|
shop: string,
|
||||||
|
itemId: number,
|
||||||
|
count: number,
|
||||||
|
reason?: string,
|
||||||
|
moreparam?: any,
|
||||||
|
) {
|
||||||
|
let record = new ItemRecord()
|
||||||
|
record.accountId = accountId
|
||||||
|
record.item = itemId
|
||||||
|
record.count = count
|
||||||
|
record.reason = reason
|
||||||
|
record.data = moreparam
|
||||||
|
await record.save()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ItemRecord = getModelForClass(ItemRecordClass, { existingConnection: ItemRecordClass['db'] })
|
54
src/models/user/UserItem.ts
Normal file
54
src/models/user/UserItem.ts
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import { dbconn } from '../../decorators/dbconn'
|
||||||
|
import { getModelForClass, index, modelOptions, prop } from '@typegoose/typegoose'
|
||||||
|
import { BaseModule } from '../Base'
|
||||||
|
|
||||||
|
@dbconn()
|
||||||
|
@index({ accountId: 1, shop: 1 }, { unique: false })
|
||||||
|
@index({ accountId: 1, shop: 1, item: 1 }, { unique: true })
|
||||||
|
@modelOptions({ schemaOptions: { collection: 'user_items', timestamps: true } })
|
||||||
|
class UserItemClass extends BaseModule {
|
||||||
|
@prop()
|
||||||
|
public accountId: string
|
||||||
|
|
||||||
|
@prop()
|
||||||
|
public shop: string
|
||||||
|
|
||||||
|
@prop()
|
||||||
|
public item: string
|
||||||
|
|
||||||
|
@prop({ default: 0 })
|
||||||
|
public count: number
|
||||||
|
|
||||||
|
public static async fetchCount({ accountId, shop, item }: { accountId: string; shop: string; item: string }) {
|
||||||
|
let record = await UserItem.findOne({ accountId, shop, item })
|
||||||
|
return record?.count || 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加一件物品
|
||||||
|
* @param {string} accountId
|
||||||
|
* @param {string} shop
|
||||||
|
* @param {string} item
|
||||||
|
* @param {number} count
|
||||||
|
*/
|
||||||
|
public static async addItem({
|
||||||
|
accountId,
|
||||||
|
shop,
|
||||||
|
item,
|
||||||
|
count,
|
||||||
|
}: {
|
||||||
|
accountId: string
|
||||||
|
shop: string
|
||||||
|
item: string
|
||||||
|
count: number
|
||||||
|
}) {
|
||||||
|
let record = await UserItem.findOneAndUpdate(
|
||||||
|
{ accountId, shop, item },
|
||||||
|
{ $inc: { count: count } },
|
||||||
|
{ upsert: true, new: true },
|
||||||
|
)
|
||||||
|
return record
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const UserItem = getModelForClass(UserItemClass, { existingConnection: UserItemClass.db })
|
@ -1,12 +1,12 @@
|
|||||||
import { dbconn } from '../decorators/dbconn'
|
|
||||||
import { getModelForClass, index, modelOptions, pre, prop } from '@typegoose/typegoose'
|
import { getModelForClass, index, modelOptions, pre, prop } from '@typegoose/typegoose'
|
||||||
import { BaseModule } from './Base'
|
|
||||||
import { customAlphabet } from 'nanoid'
|
import { customAlphabet } from 'nanoid'
|
||||||
import { Shop } from './shop/Shop'
|
import { dbconn } from '../../decorators/dbconn'
|
||||||
import { Coupon } from './shop/Coupon'
|
import { BaseModule } from '../Base'
|
||||||
import { getCouponUrl } from '../services/File'
|
import { isObjectId } from '../../utils/string.util'
|
||||||
import { PuzzleSessionClass } from './match/PuzzleSession'
|
import { Shop } from '../shop/Shop'
|
||||||
import { isObjectId } from '../utils/string.util'
|
import { Coupon } from '../shop/Coupon'
|
||||||
|
import { getCouponUrl } from '../../services/File'
|
||||||
|
import { PuzzleSessionClass } from '../match/PuzzleSession'
|
||||||
|
|
||||||
const nanoid = customAlphabet('2345678abcdefghjkmnpqrstwxy', 10)
|
const nanoid = customAlphabet('2345678abcdefghjkmnpqrstwxy', 10)
|
||||||
|
|
@ -9,8 +9,8 @@ import { mission_vo } from '../config/parsers/mission_vo'
|
|||||||
import { ShopActivity } from '../models/shop/ShopActivity'
|
import { ShopActivity } from '../models/shop/ShopActivity'
|
||||||
import { getAccountRank, getRankCount, getRankList, updateRank, updateTotalRank } from './Rank'
|
import { getAccountRank, getRankCount, getRankList, updateRank, updateTotalRank } from './Rank'
|
||||||
import { PuzzleRank } from '../models/match/PuzzleRank'
|
import { PuzzleRank } from '../models/match/PuzzleRank'
|
||||||
import { UserReward } from '../models/UserReward'
|
import { UserReward } from '../models/user/UserReward'
|
||||||
import { GameUser } from '../models/GameUser'
|
import { GameUser } from '../models/user/GameUser'
|
||||||
|
|
||||||
export function transformRecord(records: any[]) {
|
export function transformRecord(records: any[]) {
|
||||||
return records.map(o => {
|
return records.map(o => {
|
||||||
|
23
src/services/MongoTool.ts
Normal file
23
src/services/MongoTool.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { singleton } from '../decorators/singleton'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自增id的初始值
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
export const INIT_KEY_NUM = 10000
|
||||||
|
/**
|
||||||
|
* 用于生成自增id
|
||||||
|
* 需要在服务启动时, 调用init方法, 将现有表的数据放入keyMap中
|
||||||
|
*/
|
||||||
|
@singleton
|
||||||
|
export class MongoTool {
|
||||||
|
private keyMap: Map<string, number> = new Map()
|
||||||
|
|
||||||
|
public init(name: string, current: number) {
|
||||||
|
this.keyMap.set(name, current)
|
||||||
|
}
|
||||||
|
|
||||||
|
public getUniqueKey(name: string): number {
|
||||||
|
return this.keyMap.inc(name, 1)
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user