Skip to content

Commit

Permalink
feat: 好友对战实现房间数据创建
Browse files Browse the repository at this point in the history
  • Loading branch information
arleyGuoLei committed Dec 26, 2021
1 parent 791f2ba commit 047c9f5
Show file tree
Hide file tree
Showing 23 changed files with 1,407 additions and 24 deletions.
5 changes: 4 additions & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
typings/types/wx/
typings/types/wx/
cloudfunctions/server/
node_modules/
miniprogram_npm/
3 changes: 2 additions & 1 deletion miniprogram/app.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"pages": [
"pages/home/home"
"pages/home/home",
"pages/combat/combat"
],
"window": {
"backgroundColor": "#FFFFFF",
Expand Down
2 changes: 1 addition & 1 deletion miniprogram/components/header/header.wxml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<view class="header" style="height:{{CustomBarHeight}}px;padding-top:{{StatusBarHeight}}px;">
<view class="content" style="top:{{StatusBarHeight}}px;">
<view class="content">
<slot name="content"></slot>
</view>
</view>
11 changes: 9 additions & 2 deletions miniprogram/models/base.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { IAppOption } from 'miniprogram/app'
import type { DB as serverDB } from 'typings/types/wx/wx-server-sdk'

export default class {
collection: string
Expand All @@ -10,9 +11,15 @@ export default class {
this.collection = Model.$collection
}

get model (): DB.CollectionReference {
get model (): serverDB.CollectionReference {
// NOTE: miniprogram-api-typings 中的云函数操作类型定义不全,使用 wx-server-sdk 中的方法来替代
const db = wx.cloud.database({ env: getApp<IAppOption>().store.$state.cloudEnv })
return db.collection(this.collection)
return db.collection(this.collection) as unknown as serverDB.CollectionReference
}

get db (): DB.Database {
const db = wx.cloud.database({ env: getApp<IAppOption>().store.$state.cloudEnv })
return db
}

async server <R, T>(url: string, data?: T): Promise<R> {
Expand Down
9 changes: 5 additions & 4 deletions miniprogram/models/book.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Base from './base'
import { Book } from './../../typings/model'
import type { Book } from './../../typings/model'
import type { DB } from 'typings/types/wx/wx-server-sdk'

class BookModel extends Base {
static $collection = 'book'
Expand All @@ -9,18 +10,18 @@ class BookModel extends Base {
}

async getTotal (): Promise<number> {
const { total } = await this.model.count()
const { total } = (await this.model.count()) as DB.ICountResult
return total
}

async getList (page: number): Promise<Book[]> {
const size = 5 // 每页包含多少条

const { data: books } = await this.model
const { data: books } = (await this.model
.orderBy('sort', 'asc')
.skip((page - 1) * size)
.limit(size)
.get()
.get()) as DB.IQueryResult

return books as Book[]
}
Expand Down
37 changes: 37 additions & 0 deletions miniprogram/models/combat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import Base from './base'
import type { Combat } from './../../typings/model'

/**
* 所有用户可读写:{ "read": true, "write": true }
*/
class CombatModel extends Base {
static $collection = 'combat'

constructor () {
super(CombatModel)
}

/**
* 创建房间并返回房间信息
* @param combatInfo 房间信息
*/
async create (combatInfo: Pick<Combat, 'users' | 'book' | 'wordList' | 'type'>): Promise<Combat> {
const { users, book, wordList, type } = combatInfo
const combatData: Omit<Combat, '_id'> = {
users,
book,
wordList,
type,
state: 'create',
next: '',
_createTime: this.db.serverDate()
}
const { _id } = (await this.model.add({
data: combatData
})) as DB.IAddResult

return { ...combatData, _id }
}
}

export default new CombatModel()
9 changes: 9 additions & 0 deletions miniprogram/models/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ class UserModel extends Base {
super(UserModel)
}

/**
* 更新用户头像、昵称信息
* @param userinfo 用户信息
*/
async updateUserInfo (userinfo: User): Promise<void> {
const { avatar, nickname } = userinfo
await this.model.where({ _openid: '{openid}' }).update({ data: { avatar, nickname } })
}

async login (): Promise<LoginUserInfo> {
const userinfo = await this.server<{state: 0, data: LoginUserInfo}, undefined>('user/login')

Expand Down
29 changes: 29 additions & 0 deletions miniprogram/models/word.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,40 @@
import Base from './base'
import type { Word } from './../../typings/model'

/**
* 所有用户可读
*/
class WordModel extends Base {
static $collection = 'word'

constructor () {
super(WordModel)
}

/**
* 从指定单词书获取 size 数目的随机单词
* @param bookId 所需要获取的单词书 id
* @param size 需要获取的单词数目
*/
async getRandomWords (bookId: string, size: number): Promise<Word[]> {
const where = bookId === 'random' ? {} : { bookId }
try {
// NOTE: 可以通过 .sample({ size }) 获取随机数据
const res = await this.model.aggregate()
.match(where)
.limit(999999)
.sample({ size })
.end()
if (res) {
return res.list
}

throw new Error('get getRandomWords list error')
} catch (error) {
console.log(error)
throw error
}
}
}

export default new WordModel()
3 changes: 3 additions & 0 deletions miniprogram/pages/combat/combat.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"usingComponents": {}
}
1 change: 1 addition & 0 deletions miniprogram/pages/combat/combat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
App.Page({})
Empty file.
Empty file.
8 changes: 7 additions & 1 deletion miniprogram/pages/home/components/bookSelect/bookSelect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,13 @@ App.Component({
})
})

store.setState({ book: newBook })
store.setState({
book: newBook,
user: {
...store.getState().user,
bookId: newBook._id
}
})
}
}
})
40 changes: 35 additions & 5 deletions miniprogram/pages/home/components/main/main.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,53 @@
import { COMBAT_TYPE } from './../../../../../typings/model'
import { formatWordList, getUserInfo, formatCombatInfo } from './../../../../utils/helper'
import { throttle, loading } from './../../../../utils/util'
import config from './../../../../utils/config'
import wordModel from './../../../../models/word'
import CombatModel from './../../../../models/combat'
import { store } from './../../../../app'

App.Component({
options: {
/** 页面 wxss 样式将影响到自定义组件,但自定义组件 wxss 中指定的样式不会影响页面 */
/** 为了使用 app.wxss 中定义的一些全局样式,比如:.shadow-lg 和 动画库 */
addGlobalClass: true
},
methods: {
async createCombat (combatType: COMBAT_TYPE) {
const userinfo = await getUserInfo()

loading.show('生成题目中...')

// NOTE: 1. 获取随机单词,获取的长度为「每道题目选项数」 * 「用户每局对战题目的数目」,因为每道题目只有一个选项是正确的,所以需要获取「选项数倍数」的单词
const words = await wordModel.getRandomWords(userinfo.bookId, config.combatOptionNumber * userinfo.config.combatQuestionNumber)

// NOTE: 2. 格式化单词数据
const wordList = formatWordList(words, config.combatOptionNumber)

loading.show('正在创建房间...')

// NOTE: 3. 数据库中新增房间数据
const book = store.getState().book
const combatInfo = formatCombatInfo(userinfo, book, combatType, wordList)
const combat = await CombatModel.create(combatInfo)

store.setState({ combat })
loading.hide()
},

/**
* 随机匹配
*/
onRandomMatch () {
onRandomMatch: throttle(async function (this: {createCombat: (combatType: COMBAT_TYPE) => Promise<void>}) {

},
}, 500),

/**
* 好友对战
*/
onChallengeFriend () {

},
onChallengeFriend: throttle(function (this: {createCombat: (combatType: COMBAT_TYPE) => Promise<void>}) {
void this.createCombat('friend')
}, 500),

/**
* 词汇挑战
Expand Down
4 changes: 3 additions & 1 deletion miniprogram/utils/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@ export default {
cloudEnv: {
develop: 'cloud1-2gxt3f0qb7420723',
release: 'release-5g3qji4cea00e725'
}
},
/** 对战模式每道题目的选项数目 */
combatOptionNumber: 4
}
117 changes: 117 additions & 0 deletions miniprogram/utils/helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import { sleep, chunk } from './util'
import type { UserInfoState, BookState } from './state'
import { store } from './../app'
import userModel from './../models/user'
import { Word, CombatWord, COMBAT_TYPE, Combat } from './../../typings/model'

export const DEFAULT_USER_INFO = {
avatarUrl: 'https://7072-prod-words-pk-1255907426.tcb.qcloud.la/word-pk-logo.jpeg',
city: '',
country: 'China',
gender: 1,
language: 'zh_CN',
nickName: '神秘学霸',
province: ''
}

/**
* 获取当前用户的用户信息,如果从 getUserProfile 获取,将会更新数据库数据
* @param getUserProfile 是否强制使用 getUserProfile 从微信获取最新的用户信息
*/
export const getUserInfo = async (getUserProfile = false): Promise<UserInfoState> => {
const user = store.getState().user
// 1. 使用数据库存储的数据,即 state 中的 user 数据
let baseUserInfo = { avatar: user.avatar, nickname: user.nickname }

if (!baseUserInfo.avatar ||
!baseUserInfo.nickname ||
baseUserInfo.avatar === DEFAULT_USER_INFO.avatarUrl ||
baseUserInfo.nickname === DEFAULT_USER_INFO.nickName ||
getUserProfile) {
try {
// 2. 调用 wx.getUserProfile 获取数据
const { userInfo } = await wx.getUserProfile({ desc: '将用于对战信息显示' })
const { avatarUrl, nickName } = userInfo
baseUserInfo = { avatar: avatarUrl, nickname: nickName }
} catch (error) {
// 3. 获取失败则使用匿名默认数据,注意:匿名数据同时也会存入数据库
baseUserInfo = { avatar: DEFAULT_USER_INFO.avatarUrl, nickname: DEFAULT_USER_INFO.nickName }
const duration = 1200
void wx.showToast({
title: '获取用户信息失败, 将使用匿名信息',
icon: 'none',
duration
})
await sleep(duration)
}

const newUser = { ...user, ...baseUserInfo }
void userModel.updateUserInfo(newUser)
store.setState({ user: newUser })
}

return {
...user,
...baseUserInfo
}
}

/**
* 随机单词列表转成符合对战选词的列表
* @param {array} list 随机单词列表
* @param {number} len 每一个题目有多少个选项
*/
export const formatWordList = (list: Word[], len: number): CombatWord[] => {
const lists = chunk(list, len)
return lists.map(words => {
const question: CombatWord = {
options: [],
correctIndex: -1,
word: '',
wordId: '',
usphone: ''
}

// 随机生成一个 correctIndex 作为 options 中的答案索引
const correctIndex = Math.floor(Math.random() * len)

words.forEach((word, index) => {
if (index === correctIndex) {
question.correctIndex = correctIndex
question.word = word.word
question.wordId = word._id
question.usphone = word.usphone
}

// 对于有多个释义的单词,随机取一个释义
const { pos, tranCn } = word.trans.sort(() => Math.random() - 0.5)[0]
let trans = tranCn
if (pos) {
trans = `${pos}.${tranCn}` // 如果有词性,则拼接词性
}

question.options.push(trans)
})
return question
})
}

export const formatCombatInfo = (user: UserInfoState, book: BookState, type: COMBAT_TYPE, wordList: CombatWord[]): Pick<Combat, 'users' | 'book' | 'wordList' | 'type'> => {
const combatInfo = {
users: [{
gradeTotal: 0,
records: [],
avatar: user.avatar,
nickname: user.nickname,
_openid: user._openid
}],
book: {
_id: book._id,
name: book.name
},
wordList,
type
}

return combatInfo
}
Loading

0 comments on commit 047c9f5

Please sign in to comment.