Browse Source

join leave kickout game

master
tangmingyou 4 years ago
parent
commit
2850120e4e
  1. 276
      src/api/proto.js
  2. 80
      src/api/websocket.js
  3. 2
      src/api/wsapi.js
  4. 1
      src/assets/icon/refresh-fill.svg
  5. 5
      src/components/title.jsx
  6. 46
      src/pages/lobby/lobby.jsx
  7. 15
      src/pages/lobby/lobby.scss
  8. 155
      src/pages/table/table.jsx
  9. 48
      src/pages/table/table.scss
  10. 9
      src/utils/collect.js

276
src/api/proto.js

@ -3585,7 +3585,7 @@ export const api = $root.api = (() => {
* Properties of a ReqKickOutTable.
* @memberof api
* @interface IReqKickOutTable
* @property {number|null} [playerId] ReqKickOutTable playerId
* @property {number|Long|null} [playerId] ReqKickOutTable playerId
*/
/**
@ -3605,11 +3605,11 @@ export const api = $root.api = (() => {
/**
* ReqKickOutTable playerId.
* @member {number} playerId
* @member {number|Long} playerId
* @memberof api.ReqKickOutTable
* @instance
*/
ReqKickOutTable.prototype.playerId = 0;
ReqKickOutTable.prototype.playerId = $util.Long ? $util.Long.fromBits(0,0,false) : 0;
/**
* Creates a new ReqKickOutTable instance using the specified properties.
@ -3636,7 +3636,7 @@ export const api = $root.api = (() => {
if (!writer)
writer = $Writer.create();
if (message.playerId != null && Object.hasOwnProperty.call(message, "playerId"))
writer.uint32(/* id 1, wireType 0 =*/8).int32(message.playerId);
writer.uint32(/* id 1, wireType 0 =*/8).int64(message.playerId);
return writer;
};
@ -3672,7 +3672,7 @@ export const api = $root.api = (() => {
let tag = reader.uint32();
switch (tag >>> 3) {
case 1: {
message.playerId = reader.int32();
message.playerId = reader.int64();
break;
}
default:
@ -3711,8 +3711,8 @@ export const api = $root.api = (() => {
if (typeof message !== "object" || message === null)
return "object expected";
if (message.playerId != null && message.hasOwnProperty("playerId"))
if (!$util.isInteger(message.playerId))
return "playerId: integer expected";
if (!$util.isInteger(message.playerId) && !(message.playerId && $util.isInteger(message.playerId.low) && $util.isInteger(message.playerId.high)))
return "playerId: integer|Long expected";
return null;
};
@ -3729,7 +3729,14 @@ export const api = $root.api = (() => {
return object;
let message = new $root.api.ReqKickOutTable();
if (object.playerId != null)
message.playerId = object.playerId | 0;
if ($util.Long)
(message.playerId = $util.Long.fromValue(object.playerId)).unsigned = false;
else if (typeof object.playerId === "string")
message.playerId = parseInt(object.playerId, 10);
else if (typeof object.playerId === "number")
message.playerId = object.playerId;
else if (typeof object.playerId === "object")
message.playerId = new $util.LongBits(object.playerId.low >>> 0, object.playerId.high >>> 0).toNumber();
return message;
};
@ -3747,9 +3754,16 @@ export const api = $root.api = (() => {
options = {};
let object = {};
if (options.defaults)
object.playerId = 0;
if ($util.Long) {
let long = new $util.Long(0, 0, false);
object.playerId = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long;
} else
object.playerId = options.longs === String ? "0" : 0;
if (message.playerId != null && message.hasOwnProperty("playerId"))
object.playerId = message.playerId;
if (typeof message.playerId === "number")
object.playerId = options.longs === String ? String(message.playerId) : message.playerId;
else
object.playerId = options.longs === String ? $util.Long.prototype.toString.call(message.playerId) : options.longs === Number ? new $util.LongBits(message.playerId.low >>> 0, message.playerId.high >>> 0).toNumber() : message.playerId;
return object;
};
@ -3782,6 +3796,181 @@ export const api = $root.api = (() => {
return ReqKickOutTable;
})();
api.ResKickOutTable = (function() {
/**
* Properties of a ResKickOutTable.
* @memberof api
* @interface IResKickOutTable
*/
/**
* Constructs a new ResKickOutTable.
* @memberof api
* @classdesc Represents a ResKickOutTable.
* @implements IResKickOutTable
* @constructor
* @param {api.IResKickOutTable=} [properties] Properties to set
*/
function ResKickOutTable(properties) {
if (properties)
for (let keys = Object.keys(properties), i = 0; i < keys.length; ++i)
if (properties[keys[i]] != null)
this[keys[i]] = properties[keys[i]];
}
/**
* Creates a new ResKickOutTable instance using the specified properties.
* @function create
* @memberof api.ResKickOutTable
* @static
* @param {api.IResKickOutTable=} [properties] Properties to set
* @returns {api.ResKickOutTable} ResKickOutTable instance
*/
ResKickOutTable.create = function create(properties) {
return new ResKickOutTable(properties);
};
/**
* Encodes the specified ResKickOutTable message. Does not implicitly {@link api.ResKickOutTable.verify|verify} messages.
* @function encode
* @memberof api.ResKickOutTable
* @static
* @param {api.IResKickOutTable} message ResKickOutTable message or plain object to encode
* @param {$protobuf.Writer} [writer] Writer to encode to
* @returns {$protobuf.Writer} Writer
*/
ResKickOutTable.encode = function encode(message, writer) {
if (!writer)
writer = $Writer.create();
return writer;
};
/**
* Encodes the specified ResKickOutTable message, length delimited. Does not implicitly {@link api.ResKickOutTable.verify|verify} messages.
* @function encodeDelimited
* @memberof api.ResKickOutTable
* @static
* @param {api.IResKickOutTable} message ResKickOutTable message or plain object to encode
* @param {$protobuf.Writer} [writer] Writer to encode to
* @returns {$protobuf.Writer} Writer
*/
ResKickOutTable.encodeDelimited = function encodeDelimited(message, writer) {
return this.encode(message, writer).ldelim();
};
/**
* Decodes a ResKickOutTable message from the specified reader or buffer.
* @function decode
* @memberof api.ResKickOutTable
* @static
* @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
* @param {number} [length] Message length if known beforehand
* @returns {api.ResKickOutTable} ResKickOutTable
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
ResKickOutTable.decode = function decode(reader, length) {
if (!(reader instanceof $Reader))
reader = $Reader.create(reader);
let end = length === undefined ? reader.len : reader.pos + length, message = new $root.api.ResKickOutTable();
while (reader.pos < end) {
let tag = reader.uint32();
switch (tag >>> 3) {
default:
reader.skipType(tag & 7);
break;
}
}
return message;
};
/**
* Decodes a ResKickOutTable message from the specified reader or buffer, length delimited.
* @function decodeDelimited
* @memberof api.ResKickOutTable
* @static
* @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
* @returns {api.ResKickOutTable} ResKickOutTable
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
ResKickOutTable.decodeDelimited = function decodeDelimited(reader) {
if (!(reader instanceof $Reader))
reader = new $Reader(reader);
return this.decode(reader, reader.uint32());
};
/**
* Verifies a ResKickOutTable message.
* @function verify
* @memberof api.ResKickOutTable
* @static
* @param {Object.<string,*>} message Plain object to verify
* @returns {string|null} `null` if valid, otherwise the reason why it is not
*/
ResKickOutTable.verify = function verify(message) {
if (typeof message !== "object" || message === null)
return "object expected";
return null;
};
/**
* Creates a ResKickOutTable message from a plain object. Also converts values to their respective internal types.
* @function fromObject
* @memberof api.ResKickOutTable
* @static
* @param {Object.<string,*>} object Plain object
* @returns {api.ResKickOutTable} ResKickOutTable
*/
ResKickOutTable.fromObject = function fromObject(object) {
if (object instanceof $root.api.ResKickOutTable)
return object;
return new $root.api.ResKickOutTable();
};
/**
* Creates a plain object from a ResKickOutTable message. Also converts values to other types if specified.
* @function toObject
* @memberof api.ResKickOutTable
* @static
* @param {api.ResKickOutTable} message ResKickOutTable
* @param {$protobuf.IConversionOptions} [options] Conversion options
* @returns {Object.<string,*>} Plain object
*/
ResKickOutTable.toObject = function toObject() {
return {};
};
/**
* Converts this ResKickOutTable to JSON.
* @function toJSON
* @memberof api.ResKickOutTable
* @instance
* @returns {Object.<string,*>} JSON object
*/
ResKickOutTable.prototype.toJSON = function toJSON() {
return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
};
/**
* Gets the default type url for ResKickOutTable
* @function getTypeUrl
* @memberof api.ResKickOutTable
* @static
* @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
* @returns {string} The default type url
*/
ResKickOutTable.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
if (typeUrlPrefix === undefined) {
typeUrlPrefix = "type.googleapis.com";
}
return typeUrlPrefix + "/api.ResKickOutTable";
};
return ResKickOutTable;
})();
api.ReqGameAction = (function() {
/**
@ -4369,7 +4558,8 @@ export const api = $root.api = (() => {
* @property {number|null} [tableNo] ResGameFullStatus tableNo
* @property {number|null} [gameStage] ResGameFullStatus gameStage
* @property {number|null} [chip] ResGameFullStatus chip
* @property {number|null} [RoundTimes] ResGameFullStatus RoundTimes
* @property {number|null} [roundTimes] ResGameFullStatus roundTimes
* @property {number|Long|null} [playerId] ResGameFullStatus playerId
* @property {Array.<api.ICard>|null} [publicCard] ResGameFullStatus publicCard
* @property {Array.<api.ITablePlayer>|null} [players] ResGameFullStatus players
*/
@ -4424,12 +4614,20 @@ export const api = $root.api = (() => {
ResGameFullStatus.prototype.chip = 0;
/**
* ResGameFullStatus RoundTimes.
* @member {number} RoundTimes
* ResGameFullStatus roundTimes.
* @member {number} roundTimes
* @memberof api.ResGameFullStatus
* @instance
*/
ResGameFullStatus.prototype.RoundTimes = 0;
ResGameFullStatus.prototype.roundTimes = 0;
/**
* ResGameFullStatus playerId.
* @member {number|Long} playerId
* @memberof api.ResGameFullStatus
* @instance
*/
ResGameFullStatus.prototype.playerId = $util.Long ? $util.Long.fromBits(0,0,false) : 0;
/**
* ResGameFullStatus publicCard.
@ -4479,8 +4677,10 @@ export const api = $root.api = (() => {
writer.uint32(/* id 3, wireType 0 =*/24).int32(message.gameStage);
if (message.chip != null && Object.hasOwnProperty.call(message, "chip"))
writer.uint32(/* id 4, wireType 0 =*/32).int32(message.chip);
if (message.RoundTimes != null && Object.hasOwnProperty.call(message, "RoundTimes"))
writer.uint32(/* id 5, wireType 0 =*/40).int32(message.RoundTimes);
if (message.roundTimes != null && Object.hasOwnProperty.call(message, "roundTimes"))
writer.uint32(/* id 5, wireType 0 =*/40).int32(message.roundTimes);
if (message.playerId != null && Object.hasOwnProperty.call(message, "playerId"))
writer.uint32(/* id 6, wireType 0 =*/48).int64(message.playerId);
if (message.publicCard != null && message.publicCard.length)
for (let i = 0; i < message.publicCard.length; ++i)
$root.api.Card.encode(message.publicCard[i], writer.uint32(/* id 9, wireType 2 =*/74).fork()).ldelim();
@ -4538,7 +4738,11 @@ export const api = $root.api = (() => {
break;
}
case 5: {
message.RoundTimes = reader.int32();
message.roundTimes = reader.int32();
break;
}
case 6: {
message.playerId = reader.int64();
break;
}
case 9: {
@ -4600,9 +4804,12 @@ export const api = $root.api = (() => {
if (message.chip != null && message.hasOwnProperty("chip"))
if (!$util.isInteger(message.chip))
return "chip: integer expected";
if (message.RoundTimes != null && message.hasOwnProperty("RoundTimes"))
if (!$util.isInteger(message.RoundTimes))
return "RoundTimes: integer expected";
if (message.roundTimes != null && message.hasOwnProperty("roundTimes"))
if (!$util.isInteger(message.roundTimes))
return "roundTimes: integer expected";
if (message.playerId != null && message.hasOwnProperty("playerId"))
if (!$util.isInteger(message.playerId) && !(message.playerId && $util.isInteger(message.playerId.low) && $util.isInteger(message.playerId.high)))
return "playerId: integer|Long expected";
if (message.publicCard != null && message.hasOwnProperty("publicCard")) {
if (!Array.isArray(message.publicCard))
return "publicCard: array expected";
@ -4644,8 +4851,17 @@ export const api = $root.api = (() => {
message.gameStage = object.gameStage | 0;
if (object.chip != null)
message.chip = object.chip | 0;
if (object.RoundTimes != null)
message.RoundTimes = object.RoundTimes | 0;
if (object.roundTimes != null)
message.roundTimes = object.roundTimes | 0;
if (object.playerId != null)
if ($util.Long)
(message.playerId = $util.Long.fromValue(object.playerId)).unsigned = false;
else if (typeof object.playerId === "string")
message.playerId = parseInt(object.playerId, 10);
else if (typeof object.playerId === "number")
message.playerId = object.playerId;
else if (typeof object.playerId === "object")
message.playerId = new $util.LongBits(object.playerId.low >>> 0, object.playerId.high >>> 0).toNumber();
if (object.publicCard) {
if (!Array.isArray(object.publicCard))
throw TypeError(".api.ResGameFullStatus.publicCard: array expected");
@ -4691,7 +4907,12 @@ export const api = $root.api = (() => {
object.tableNo = 0;
object.gameStage = 0;
object.chip = 0;
object.RoundTimes = 0;
object.roundTimes = 0;
if ($util.Long) {
let long = new $util.Long(0, 0, false);
object.playerId = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long;
} else
object.playerId = options.longs === String ? "0" : 0;
}
if (message.inGame != null && message.hasOwnProperty("inGame"))
object.inGame = message.inGame;
@ -4701,8 +4922,13 @@ export const api = $root.api = (() => {
object.gameStage = message.gameStage;
if (message.chip != null && message.hasOwnProperty("chip"))
object.chip = message.chip;
if (message.RoundTimes != null && message.hasOwnProperty("RoundTimes"))
object.RoundTimes = message.RoundTimes;
if (message.roundTimes != null && message.hasOwnProperty("roundTimes"))
object.roundTimes = message.roundTimes;
if (message.playerId != null && message.hasOwnProperty("playerId"))
if (typeof message.playerId === "number")
object.playerId = options.longs === String ? String(message.playerId) : message.playerId;
else
object.playerId = options.longs === String ? $util.Long.prototype.toString.call(message.playerId) : options.longs === Number ? new $util.LongBits(message.playerId.low >>> 0, message.playerId.high >>> 0).toNumber() : message.playerId;
if (message.publicCard && message.publicCard.length) {
object.publicCard = [];
for (let j = 0; j < message.publicCard.length; ++j)

80
src/api/websocket.js

@ -1,18 +1,24 @@
import proto from '@/api/proto';
import { fetchOpMap } from '@/api/api'
import { getStorage } from '@/utils/storage';
import { showToast } from '@/utils/application';
const { api } = proto
const websocket = {
conn: null,
state: 0, // 0未初始,1打开,2关闭 TODO 未连接,连接中 方法等待队列
status: 0, // 0未初始,1打开,2已认证,3关闭 TODO 未连接,连接中 方法等待队列
seq: 1, // 消息序号
offset: 0,
opFail: 0,
opSuccess: 0,
opPathMap: {},
nameOpMap: {},
// 消息监听列表
msgListener: {}, // {op: func}
waitInitCalls: [],
init(token, { offset, opFail, opSuccess, opPathMap, nameOpMap }) {
// TODO 连接状态判定
this.offset = offset || 0;
this.opFail = opFail;
@ -27,17 +33,28 @@ const websocket = {
console.log(this)
ws.binaryType = 'arraybuffer'
ws.onopen = (e) => {
this.status = 1;
// 连接后立即认证连接
const req = api.ReqIdentity.create({ token })
// const reqBuffer = api.ReqIdentity.encode(req).finish()
this.send(req, res => {
console.log('call1:', res)
this.status = 2;
console.log('identity success:', res)
// 依次发送等待连接的消息队列
for (let i = 0; i < this.waitInitCalls.length; i++) {
if (this.waitInitCalls[i]) {
this.waitInitCalls[i]();
this.waitInitCalls[i] = null;
}
}
}, err => {
console.log('call2:', err)
showToast({title: err})
console.error('连接认证失败:', err)
})
}
ws.onmessage = (e) => {
console.log('msg:', e.data)
// console.log('msg:', e.data)
const wrap = api.ProtoWrap.decode(new Uint8Array(e.data))
// 解码响应体
const opPath = this.opPathMap[wrap.op]
@ -65,19 +82,23 @@ const websocket = {
// 找消息类型的listen执行
const listener = this.msgListener[wrap.op];
if (listener) {
listener(res)
listener(res);
return;
}
console.log('no handler msg:', wrap.op, res)
}
ws.onerror = (a, b, c) => {
console.log('error:', a, b, c)
this.status = 3;
console.log('ws error:', a, b, c)
// var interval = setInterval(() => {
// this.reconnect();
// }, Math.random() * 3);
}
ws.onclose = e => {
console.log('close', e)
this.status = 3;
console.log('ws close', e)
}
},
reconnect() {
@ -85,6 +106,13 @@ const websocket = {
},
waitCall: {}, // 等待响应的 callback 列表
send(msg, resCall, errCall) {
window.msg = msg;
// 不是认证消息且连接未认证,将请求放到等待队列
if (msg.__proto__.constructor !== api.ReqIdentity && this.status !== 2) {
this.waitInitCalls.push(() => this.send(msg, resCall, errCall));
return;
}
// 序列化请求消息...
let typeUrl = msg.constructor.getTypeUrl();
const idx = typeUrl.lastIndexOf("/");
typeUrl = idx === -1 ? typeUrl : typeUrl.substring(idx + 1);
@ -103,15 +131,37 @@ const websocket = {
}
// 定时检查是否超时...
},
}
msgListener: {},
// 监听消息类型
listen(type, call) {
export default websocket
},
export const addMsgListen = (type, call) => {
if (websocket.status !== 2) {
websocket.waitInitCalls.push(() => addMsgListen(type, call));
return;
}
console.log('add listen...', type)
const op = websocket.nameOpMap[type];
if (op === undefined) {
console.error(`not found listen msg type [${type}] for all type:`, websocket.nameOpMap);
return;
}
websocket.msgListener[op] = call;
}
export default websocket
// 监听消息类型
export const removeMsgListener = type => {
if (websocket.status !== 2) {
websocket.waitInitCalls.push(() => removeMsgListener(type));
return;
}
const op = websocket.nameOpMap[type];
if (op === undefined) {
console.error(`when remove, not found listen msg type [${type}] for all type:`, websocket.nameOpMap);
return -1;
}
websocket.msgListener[op] = null;
}
export const sendPromise = function(msg) {
return new Promise((resolve, reject) => {
@ -120,8 +170,12 @@ export const sendPromise = function(msg) {
}
;(async function() {
const token = "15PohpTztq4YkMmErI4H71kJWX2pPqnvOZar9HKOfg1KEy0fd8fUNxnBIwuMDcKQEBPG7b9UC7ja_8FtwvYjnA=="
// const token = "15PohpTztq4YkMmErI4H71kJWX2pPqnvOZar9HKOfg1KEy0fd8fUNxnBIwuMDcKQEBPG7b9UC7ja_8FtwvYjnA=="
const token = getStorage('_t')
// console.log('token', token)
const opMap = await fetchOpMap()
websocket.init(token, opMap.data)
window.websocket = websocket;
})()

2
src/api/wsapi.js

@ -9,3 +9,5 @@ export const reqLobbyView = () => sendPromise(api.ReqLobbyView.create());
export const reqGameFullStatus = () => sendPromise(api.ReqGameFullStatus.create({}));
export const reqJoinTable = tableNo => sendPromise(api.ReqJoinTable.create({tableNo}));
export const reqKickOutTable = playerId => sendPromise(api.ReqKickOutTable.create({playerId}));

1
src/assets/icon/refresh-fill.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="38" height="38" viewBox="0 0 38 38"><defs><clipPath id="master_svg0_141_7063"><rect x="0" y="0" width="38" height="38" rx="0"/></clipPath></defs><g clip-path="url(#master_svg0_141_7063)"><g><path d="M18.999956494140626,34.833371752929686C10.255236494140625,34.833371752929686,3.166656494140625,27.744771752929687,3.166656494140625,18.99997175292969C3.166656494140625,10.255251752929688,10.255236494140625,3.1666717529296875,18.999956494140626,3.1666717529296875C27.744756494140624,3.1666717529296875,34.833356494140624,10.255251752929688,34.833356494140624,18.99997175292969C34.833356494140624,27.744771752929687,27.744756494140624,34.833371752929686,18.999956494140626,34.833371752929686ZM26.631656494140625,27.036971752929688C30.579556494140625,23.295071752929687,31.228456494140627,17.241271752929688,28.163456494140625,12.747591752929688C25.098356494140624,8.253901752929687,19.225356494140627,6.648631752929687,14.300656494140625,8.958501752929688L15.844456494140625,11.737251752929687C21.073656494140625,9.464521752929688,26.918256494140625,13.298171752929688,26.916656494140625,18.99997175292969L22.166656494140625,18.99997175292969L26.631656494140625,27.036971752929688ZM23.699356494140623,29.041471752929688L22.155556494140626,26.262771752929687C16.926356494140627,28.535471752929688,11.081756494140624,24.701771752929687,11.083326494140625,18.99997175292969L15.833356494140626,18.99997175292969L11.368326494140625,10.963001752929689C7.420436494140625,14.704971752929687,6.771486494140625,20.758771752929686,9.836546494140624,25.252471752929686C12.901606494140625,29.746071752929687,18.774656494140626,31.351371752929687,23.699356494140623,29.041471752929688Z" fill="#EE914E" fill-opacity="1"/></g></g></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

5
src/components/title.jsx

@ -8,14 +8,15 @@ import { useSelector } from 'react-redux'
function Title(props) {
const {username, nickname, avatar} = useSelector(state => state.user);
const { leftSolt, leftIcon, onLeftClick, rightSolt } = props;
return (
<View>
<View className={props.bgColor ? "page-top bgc" : "page-top"}>
{/* <View className='topHeight'></View> */}
<View className='page-title'>
<Image className="icon" src={left} onClick={() => navigateBack()} />
{leftSolt || <Image className="icon" src={leftIcon || left} onClick={onLeftClick || navigateBack} />}
<View className={props.colorStyle ? "title" : "title1"}><Text>{props.title}</Text></View>
<View className='blank'><Image className='avatar' src={avatar} /></View>
{rightSolt || <View className='blank'><Image className='avatar' src={avatar} /></View>}
</View>
</View>
{props.topNull ? '' : <View className='hidden'></View>}

46
src/pages/lobby/lobby.jsx

@ -14,7 +14,9 @@ import Title from '@/components/title'
import coin1 from '@/assets/coin-1.png'
import robotIcon from '@/assets/icon/robot-1.svg'
import plusIcon from '@/assets/icon/plus-2.svg';
import classNames from 'classnames';
import refreshIcon from '@/assets/icon/refresh-fill.svg';
import cnames from 'classnames';
const {ReqLobbyView} = proto.api;
@ -24,6 +26,7 @@ class Lobby extends Component {
this.state = {
tables: [],
defaultAvatar: "https://img0.baidu.com/it/u=2477829979,2171947490&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500",
lobbyLoading: false,
}
this.circleEle = [1,2,3,4,5,6,7];
this.circleElePos = [{x:16,y:8},{x:70,y:-3},{x:110,y:28},{x:115,y:70},{x:80,y:105},{x:20,y:100},{x:-2,y:60}];
@ -31,16 +34,8 @@ class Lobby extends Component {
componentDidMount() {
setTimeout(() => {
reqLobbyView()
.then(res => {
console.log('lobby res:', res)
this.setState({tables: res.tables})
})
.catch(err => {
console.log('lobby err:', err)
})
this.handleReqLobbyView();
}, 1500)
// fetchLobbyView()
// .then(res => {
// console.log('lobby', res)
@ -51,6 +46,28 @@ class Lobby extends Component {
// })
}
handleReqLobbyView = () => {
if (this.state.lobbyLoading) {
showToast({title: '加载中...'})
return
}
this.setState({lobbyLoading: true}, () => {
setTimeout(() => {
reqLobbyView()
.then(res => {
console.log('lobby res:', res)
this.setState({tables: res.tables})
})
.catch(err => {
console.log('lobby err:', err)
})
.finally(() => {
this.setState({lobbyLoading: false})
})
}, 1000)
})
}
async handleJoinTable(table) {
try {
const res = await reqJoinTable(table.tableNo)
@ -68,7 +85,12 @@ class Lobby extends Component {
// console.log('state', this.state)
return (
<View>
<Title title={"Lobby!!"} bgColor={true} />
<Title title={"Lobby!!"} bgColor={true} leftSolt={
<Image className={cnames("refresh-icon", {'refresh-icon-rotate': this.state.lobbyLoading})}
src={refreshIcon}
onClick={this.handleReqLobbyView}
/>
}/>
<View className="celling"></View>
<View className="tab">
{
@ -84,7 +106,7 @@ class Lobby extends Component {
top: Taro.pxTransform(this.circleElePos[j].y)
}}>
<Image
className={classNames("circle-avatar", {'circle-icon': player.robot || !player.id})}
className={cnames("circle-avatar", {'circle-icon': player.robot || !player.id})}
src={player.robot ? robotIcon : !player.id ? plusIcon : (player.avatar || this.state.defaultAvatar)}
/>
</View>

15
src/pages/lobby/lobby.scss

@ -1,4 +1,19 @@
.refresh-icon {
width: 38px;
height: 38px;
border-radius: 50%;
}
.refresh-icon-rotate {
animation: rotate360 1s infinite;
transform-origin: center center;
}
@keyframes rotate360 {
to {
transform: rotate(360deg);
}
}
.celling {
height: 43px;
}

155
src/pages/table/table.jsx

@ -3,7 +3,8 @@ import { View, Text, Image, Input, Button } from '@tarojs/components'
import { connect } from 'react-redux'
import cnames from 'classnames'
import { reqGameFullStatus } from '@/api/wsapi'
import { reqGameFullStatus, reqKickOutTable } from '@/api/wsapi'
import { addMsgListen, removeMsgListener } from '@/api/websocket'
import { ifEmpty } from '@/utils/validator'
import './table.scss'
@ -13,13 +14,16 @@ import coinIcon from '@/assets/icon/coin-1.svg'
import coin2Icon from '@/assets/icon/coin-2.svg'
import plus1Icon from '@/assets/icon/plus-1.svg'
import sub1Icon from '@/assets/icon/sub-1.svg'
import closeIcon from '@/assets/icon/close-1.svg'
import Taro from '@tarojs/taro'
import { showToast } from '@/utils/application'
import { showToast, redirectTo } from '@/utils/application'
import { isIn } from '@/utils/collect'
function PlayerStatus() {
return (
<View>
<Text>+20</Text>
<Text>Ready</Text>
</View>
)
}
@ -32,7 +36,12 @@ function cardDot(card, cardBackCode) {
}
function cardSuit(card) {
return card.suit || 'D';
return (card && card.suit) || 'D';
}
//
function existsCard(card) {
return !!card && !!card.suit;
}
class Table extends Component {
@ -43,56 +52,113 @@ class Table extends Component {
tableNo: 0,
stage: 0, // : 1;2;3;4;5,;6,,7
chip: 0,
RoundTimes: 0,
roundTimes: 0,
playerId: 0,
players: [],
publicCard: [],
}
}
componentWillUnmount() {
//
removeMsgListener('api.ResGameFullStatus')
removeMsgListener('api.ResKickOutTable')
}
componentDidMount() {
console.log('table mount')
setTimeout(() => {
// setTimeout(() => {
//
addMsgListen('api.ResGameFullStatus', res => this.handleResGameFullStatus(res));
addMsgListen('api.ResKickOutTable', res => {
console.log('listener level table', res);
redirectTo({url: '/pages/lobby/lobby', complete() {
showToast({title: '您被请出牌桌'})
}});
});
//
reqGameFullStatus()
.then(res => {
this.handleResGameFullStatus(res);
})
.catch(err => {
showToast({title: err});
if (err.code === 402) {
setTimeout(() => redirectTo({url: '/pages/lobby/lobby'}), 800);
}
})
// }, 2000)
}
handleResGameFullStatus = res => {
console.log('res game...++', this, res)
this.setState({
playerId: res.playerId,
inGame: !!res.inGame,
tableNo: res.tableNo,
stage: res.gameStage,
chip: res.chip || 0,
RoundTimes: res.RoundTimes || 0,
roundTimes: res.roundTimes || 0,
players: res.players,
publicCard: res.publicCard,
})
console.log('res game', res, res.publicCard[0].dot, ifEmpty(res.publicCard[0].dot, -3))
// console.log('res game', res, res.publicCard[0].dot, ifEmpty(res.publicCard[0].dot, -3))
window.publicCard = res.publicCard
}
//
handleKickoutPlayer(player) {
console.log('kickout', player)
Taro.showModal({
title: '提示',
content: `将玩家[${player.username}]移出牌桌?`,
success: res => {
if (!res.confirm) {
return;
}
reqKickOutTable(player.id)
.then(_ => {
showToast({title: `[${player.username}]已离开牌桌`})
})
.catch(err => {
showToast({title: err})
})
}, 2000)
}
})
}
render() {
const { username, nickname, avatar } = this.props.user; // useSelector(state => state.user);
// const players = [1, 2, 3, 4, 5, 6];
const playerRows = this.state.players.reduce((arr, player, idx) => {
const players = this.state.players.map((player, index) => ({player, index}));
const {playerId, tableNo, stage, chip, roundTimes} = this.state;
// TODO state, render
// console.log('props', this.props);
const otherPlayers = players.filter(({player}) => player.id !== playerId);
const self = players.find(({player}) => player.id === playerId);
const {index: selfIndex , player: selfPlayer} = self || {player: {handCard: []}};
// console.log(otherPlayers, self)
const playerRows = otherPlayers.reduce((arr, player, idx) => {
const row = parseInt(idx / 2);
let rowArr = arr[row] || [];
rowArr[idx % 2] = { index: idx, player };
rowArr[idx % 2] = player;
arr[row] = rowArr;
return arr;
}, []);
return (
<View className="tab">
<Title title="GAME" />
<Title title={`GAME #${tableNo}`} />
{
playerRows.map((row, i) => (
<View key={i} className="playerRow">
{
row.map((player, j) => (
<View key={j} className="player-wrap">
row.map(({index, player}, j) => (
<View key={j} className="player-wrap" onClick={(p => {console.log(p)}).bind(this, player)}>
{
j % 2 === 0 &&
<View className={cnames('player-state-wrap', {'state-left': j % 2 === 0})}>
@ -100,20 +166,29 @@ class Table extends Component {
</View>
}
<View className="player-bar">
<View className={cnames("player-no", { "player-no-running": player.index === 0 })}><Text>#{player.index}</Text></View>
<View className="card1"><Card w={38} h={48} dot={-1} suit={2} /></View>
<View className="card2"><Card w={38} h={48} dot={-1} suit={3} /></View>
<View className={cnames("player", {'player-wait': player.index !== 0})}>
<View className="avatar-wrap"><Image className="avatar" src={avatar} /></View>
<View className="player-name"><Text>Player{player.item}</Text></View>
<View className={cnames("player-no", { "player-no-running": player.index === 0 })}><Text>#{index}</Text></View>
{
stage === 1 && selfPlayer.master && player.id
? <View className="kickout" onClick={this.handleKickoutPlayer.bind(this, player)}><Image className="kickout-icon" src={closeIcon} /></View>
: null
}
{existsCard(player.handCard[0]) && <View className="card1"><Card w={38} h={48} dot={cardDot(player.handCard[0], player.status === 7 ? -2 : -1)} suit={cardSuit(player.handCard[0])} /></View>}
{existsCard(player.handCard[1]) && <View className="card2"><Card w={38} h={48} dot={cardDot(player.handCard[0], player.status === 7 ? -2 : -1)} suit={cardSuit(player.handCard[1])} /></View>}
<View className={cnames("player", {'player-wait': !player.id || isIn(player.status, 3, 7)})}>
<View className="avatar-wrap">{!player.id ? null : <Image className="avatar" src={player.avatar || avatar} />}</View>
<View className="player-name"><Text>{player.username}</Text></View>
</View>
{
!player.id ? null :
<View className="wallet-wrap">
<View className={cnames("wallet", {'wallet-wait': player.index !== 0})}>
<View className={cnames("wallet", {'wallet-wait': isIn(player.status, 3, 7)})}>
<View className="wallet-icon"><Image className="wallet-icon-img" src={coinIcon} /></View>
<View className="wallet-amount"><Text>3,000,000</Text></View>
<View className="wallet-amount"><Text>{player.chip}</Text></View>
</View>
<View className="pct"><Text>25%</Text></View>
<View className="pct"><Text>0%</Text></View>
</View>
}
</View>
</View>
))
@ -135,7 +210,7 @@ class Table extends Component {
<Image className="d-wallet-icon-img" src={coinIcon} />
<Text className="d-wallet-icon-text">POT</Text>
</View>
<View className="d-wallet-amount">22,088,000</View>
<View className="d-wallet-amount">{chip}</View>
</View>
</View>
{/* <View className="chatbox" style={{ display: 'none' }}>
@ -152,12 +227,12 @@ class Table extends Component {
<View className="self-box">
<View className="self-wrap">
<View className={cnames("player-no", { "player-no-running": true })}><Text>#7</Text></View>
<View className="hand-card1"><Card w={38} h={48} dot={12} suit={3} /></View>
<View className="hand-card2"><Card w={38} h={48} dot={12} suit={3} /></View>
<View className={cnames("player-no", { "player-no-running": true })}><Text>#{selfIndex}</Text></View>
{existsCard(selfPlayer.handCard[0]) && <View className="hand-card1"><Card w={38} h={48} dot={cardDot(selfPlayer.handCard[0], -1)} suit={cardSuit(selfPlayer.handCard[0])} /></View>}
{existsCard(selfPlayer.handCard[1]) && <View className="hand-card2"><Card w={38} h={48} dot={cardDot(selfPlayer.handCard[1], -1)} suit={cardSuit(selfPlayer.handCard[0])} /></View>}
<View className="hand-five">
{
[1, 2, 3, 4, 5].map((_, i) => (
existsCard(selfPlayer.handCard[0]) && [1, 2, 3, 4, 5].map((_, i) => (
<View key={i} className="hand-five-item"><Card w={28} h={36} dot={12} suit={2} /></View>
))
}
@ -165,13 +240,13 @@ class Table extends Component {
<View className='u-opt' style={{ display: 'flex' }}>
<View>
<View className="s-info-wrap">
<View className="s-avatar"><Image className="s-avatar-img" src={avatar} /></View>
<View className="s-username"><Text>Prometheus</Text></View>
<View className="s-avatar"><Image className="s-avatar-img" src={selfPlayer.avatar || avatar} /></View>
<View className="s-username"><Text>{selfPlayer.username}</Text></View>
</View>
<View className="s-wallet-wrap">
<View className="s-w-amount-wrap">
<View className="s-w-amount-icon"><Image className="s-w-amount-icon-img" src={coin2Icon} /></View>
<View className="s-w-amount"><Text>3,000,000</Text></View>
<View className="s-w-amount"><Text>{selfPlayer.chip}</Text></View>
</View>
<View className="s-w-pct"><Text>0%</Text></View>
</View>
@ -182,11 +257,25 @@ class Table extends Component {
<View className="amount-sub"><Image className="amount-sub-icon" src={sub1Icon} /></View>
<View className="amount-plus"><Image className="amount-plus-icon" src={plus1Icon} /></View>
</View>
<View className="ctl-opt-wrap" style={{ marginTop: Taro.pxTransform(10) }}>
{
stage === 1 ? (
// : ,
selfPlayer.master ? <View className="ctl-opt-wrap">
<View className="ctl-opt"><Button className={cnames("ctl-opt-btn-4", {'ctl-opt-btn-disable': selfPlayer.status === 2})}>关闭牌桌</Button></View>
<View className="ctl-opt"><Button className={cnames("ctl-opt-btn-6", {'ctl-opt-btn-disable': selfPlayer.status === 2})}>开始游戏</Button></View>
</View>
// 退,
: <View className="ctl-opt-wrap">
<View className="ctl-opt"><Button style={{display: selfPlayer.status === 2 ? 'none' : 'block'}} className={cnames("ctl-opt-btn-4", {'ctl-opt-btn-disable': selfPlayer.status === 2})}>退出</Button></View>
<View className="ctl-opt"><Button className={cnames("ctl-opt-btn-5", {'ctl-opt-btn-5-ready': selfPlayer.status === 2})}>{selfPlayer.status === 2 ? '已准备' : '准备'}</Button></View>
</View>
)
: <View className="ctl-opt-wrap">
<View className="ctl-opt"><Button className="ctl-opt-btn-1">让牌</Button></View>
<View className="ctl-opt"><Button className="ctl-opt-btn-2">弃牌</Button></View>
<View className="ctl-opt"><Button className="ctl-opt-btn-3">跟注</Button></View>
</View>
}
</View>
</View>
</View>

48
src/pages/table/table.scss

@ -52,6 +52,18 @@
background-color: #EE914E;
}
.kickout {
position: absolute;
z-index: 99;
width: 24px;
height: 24px;
border-radius: 50%;
}
.kickout-icon {
top: 5px;
left: 125px;
}
.card1,
.card2 {
position: absolute;
@ -85,6 +97,10 @@
.avatar-wrap {
margin: 10px 0 10px 4px;
height: 50px;
width: 50px;
border-radius: 5px;
background-color: #D8D8D8;
}
.avatar {
@ -352,6 +368,7 @@
display: flex;
width: 170px;
justify-content: space-between;
margin-top: 10px;
}
.amount-input {
@ -390,7 +407,10 @@
.ctl-opt-btn-1,
.ctl-opt-btn-2,
.ctl-opt-btn-3 {
.ctl-opt-btn-3,
.ctl-opt-btn-4,
.ctl-opt-btn-5,
.ctl-opt-btn-6 {
width: 53.25px;
height: 24px;
border-radius: 8px;
@ -415,4 +435,30 @@
background-color: #FF4400;
color: #F1D09F;
}
.ctl-opt-btn-4,
.ctl-opt-btn-5,
.ctl-opt-btn-6 {
width: 79.2px;
}
.ctl-opt-btn-4 {
background-color: #F1D09F;
color: #D05959;
}
.ctl-opt-btn-5 {
background-color: #48C25D;
color: #FFF;
}
.ctl-opt-btn-5-ready {
background-color: #6AAD76;
color: #FFF;
}
.ctl-opt-btn-6 {
background-color: #FF4400;
color: #F1D09F;
}
.ctl-opt-btn-disable {
background-color: #A8A29D;
color: #FFF;
}
}

9
src/utils/collect.js

@ -0,0 +1,9 @@
export const isIn = (value, ...values) => {
for (let i = 0; i < values.length; i++) {
if (values[i] === value) {
return true;
}
}
return false;
}
Loading…
Cancel
Save