Browse Source

ws logic

master
tangmingyou 4 years ago
parent
commit
c875973724
  1. 4
      config/dev.js
  2. 4
      src/api/api.js
  3. 2
      src/api/http.js
  4. 267
      src/api/proto.js
  5. 33
      src/api/websocket.js
  6. 3
      src/api/wsapi.js
  7. 1
      src/assets/icon/plus-1.svg
  8. 1
      src/assets/icon/robot-1.svg
  9. 1
      src/assets/icon/sub-1.svg
  10. 15
      src/pages/lobby/lobby.jsx
  11. 66
      src/pages/login/login.jsx
  12. 56
      src/pages/new_table/new_table.jsx
  13. 20
      src/pages/table/table.jsx
  14. 130
      src/pages/table/table.scss
  15. 11
      src/utils/application.js

4
config/dev.js

@ -9,8 +9,8 @@ module.exports = {
mini: {}, mini: {},
h5: { h5: {
devServer: { devServer: {
host: '0.0.0.0', //host: '0.0.0.0',
// host: '192.168.3.102', host: '192.168.0.102',
port: 10086, port: 10086,
// 设置代理来解决 H5 请求的跨域问题 // 设置代理来解决 H5 请求的跨域问题
proxy: { proxy: {

4
src/api/api.js

@ -1,5 +1,7 @@
import { get, post } from '@/api/http' import { get, post } from '@/api/http'
export const login = params => post('/api/auth/authorize', params) export const doLogin = params => post('/api/auth/authorize', params)
export const fetchOpMap = () => get('/api/conn/opMap') export const fetchOpMap = () => get('/api/conn/opMap')
export const fetchLobbyView = () => get('/api/game/lobby')

2
src/api/http.js

@ -22,7 +22,7 @@ function objUrlEncode(params) {
// Http GET 请求 // Http GET 请求
const fetch = function (method, url, params) { const fetch = function (method, url, params) {
const token = getStorage('user_token'); const token = getStorage('_t');
return new Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
try { try {
const data = objUrlEncode(params); const data = objUrlEncode(params);

267
src/api/proto.js

@ -671,6 +671,181 @@ export const api = $root.api = (() => {
return Pong; return Pong;
})(); })();
api.ResSuccess = (function() {
/**
* Properties of a ResSuccess.
* @memberof api
* @interface IResSuccess
*/
/**
* Constructs a new ResSuccess.
* @memberof api
* @classdesc Represents a ResSuccess.
* @implements IResSuccess
* @constructor
* @param {api.IResSuccess=} [properties] Properties to set
*/
function ResSuccess(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 ResSuccess instance using the specified properties.
* @function create
* @memberof api.ResSuccess
* @static
* @param {api.IResSuccess=} [properties] Properties to set
* @returns {api.ResSuccess} ResSuccess instance
*/
ResSuccess.create = function create(properties) {
return new ResSuccess(properties);
};
/**
* Encodes the specified ResSuccess message. Does not implicitly {@link api.ResSuccess.verify|verify} messages.
* @function encode
* @memberof api.ResSuccess
* @static
* @param {api.IResSuccess} message ResSuccess message or plain object to encode
* @param {$protobuf.Writer} [writer] Writer to encode to
* @returns {$protobuf.Writer} Writer
*/
ResSuccess.encode = function encode(message, writer) {
if (!writer)
writer = $Writer.create();
return writer;
};
/**
* Encodes the specified ResSuccess message, length delimited. Does not implicitly {@link api.ResSuccess.verify|verify} messages.
* @function encodeDelimited
* @memberof api.ResSuccess
* @static
* @param {api.IResSuccess} message ResSuccess message or plain object to encode
* @param {$protobuf.Writer} [writer] Writer to encode to
* @returns {$protobuf.Writer} Writer
*/
ResSuccess.encodeDelimited = function encodeDelimited(message, writer) {
return this.encode(message, writer).ldelim();
};
/**
* Decodes a ResSuccess message from the specified reader or buffer.
* @function decode
* @memberof api.ResSuccess
* @static
* @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
* @param {number} [length] Message length if known beforehand
* @returns {api.ResSuccess} ResSuccess
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
ResSuccess.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.ResSuccess();
while (reader.pos < end) {
let tag = reader.uint32();
switch (tag >>> 3) {
default:
reader.skipType(tag & 7);
break;
}
}
return message;
};
/**
* Decodes a ResSuccess message from the specified reader or buffer, length delimited.
* @function decodeDelimited
* @memberof api.ResSuccess
* @static
* @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
* @returns {api.ResSuccess} ResSuccess
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
ResSuccess.decodeDelimited = function decodeDelimited(reader) {
if (!(reader instanceof $Reader))
reader = new $Reader(reader);
return this.decode(reader, reader.uint32());
};
/**
* Verifies a ResSuccess message.
* @function verify
* @memberof api.ResSuccess
* @static
* @param {Object.<string,*>} message Plain object to verify
* @returns {string|null} `null` if valid, otherwise the reason why it is not
*/
ResSuccess.verify = function verify(message) {
if (typeof message !== "object" || message === null)
return "object expected";
return null;
};
/**
* Creates a ResSuccess message from a plain object. Also converts values to their respective internal types.
* @function fromObject
* @memberof api.ResSuccess
* @static
* @param {Object.<string,*>} object Plain object
* @returns {api.ResSuccess} ResSuccess
*/
ResSuccess.fromObject = function fromObject(object) {
if (object instanceof $root.api.ResSuccess)
return object;
return new $root.api.ResSuccess();
};
/**
* Creates a plain object from a ResSuccess message. Also converts values to other types if specified.
* @function toObject
* @memberof api.ResSuccess
* @static
* @param {api.ResSuccess} message ResSuccess
* @param {$protobuf.IConversionOptions} [options] Conversion options
* @returns {Object.<string,*>} Plain object
*/
ResSuccess.toObject = function toObject() {
return {};
};
/**
* Converts this ResSuccess to JSON.
* @function toJSON
* @memberof api.ResSuccess
* @instance
* @returns {Object.<string,*>} JSON object
*/
ResSuccess.prototype.toJSON = function toJSON() {
return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
};
/**
* Gets the default type url for ResSuccess
* @function getTypeUrl
* @memberof api.ResSuccess
* @static
* @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
* @returns {string} The default type url
*/
ResSuccess.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
if (typeUrlPrefix === undefined) {
typeUrlPrefix = "type.googleapis.com";
}
return typeUrlPrefix + "/api.ResSuccess";
};
return ResSuccess;
})();
api.ResFail = (function() { api.ResFail = (function() {
/** /**
@ -1660,6 +1835,8 @@ export const api = $root.api = (() => {
* Properties of a ReqCreateTable. * Properties of a ReqCreateTable.
* @memberof api * @memberof api
* @interface IReqCreateTable * @interface IReqCreateTable
* @property {number|null} [players] ReqCreateTable players
* @property {number|null} [robots] ReqCreateTable robots
*/ */
/** /**
@ -1677,6 +1854,22 @@ export const api = $root.api = (() => {
this[keys[i]] = properties[keys[i]]; this[keys[i]] = properties[keys[i]];
} }
/**
* ReqCreateTable players.
* @member {number} players
* @memberof api.ReqCreateTable
* @instance
*/
ReqCreateTable.prototype.players = 0;
/**
* ReqCreateTable robots.
* @member {number} robots
* @memberof api.ReqCreateTable
* @instance
*/
ReqCreateTable.prototype.robots = 0;
/** /**
* Creates a new ReqCreateTable instance using the specified properties. * Creates a new ReqCreateTable instance using the specified properties.
* @function create * @function create
@ -1701,6 +1894,10 @@ export const api = $root.api = (() => {
ReqCreateTable.encode = function encode(message, writer) { ReqCreateTable.encode = function encode(message, writer) {
if (!writer) if (!writer)
writer = $Writer.create(); writer = $Writer.create();
if (message.players != null && Object.hasOwnProperty.call(message, "players"))
writer.uint32(/* id 1, wireType 0 =*/8).int32(message.players);
if (message.robots != null && Object.hasOwnProperty.call(message, "robots"))
writer.uint32(/* id 2, wireType 0 =*/16).int32(message.robots);
return writer; return writer;
}; };
@ -1735,6 +1932,14 @@ export const api = $root.api = (() => {
while (reader.pos < end) { while (reader.pos < end) {
let tag = reader.uint32(); let tag = reader.uint32();
switch (tag >>> 3) { switch (tag >>> 3) {
case 1: {
message.players = reader.int32();
break;
}
case 2: {
message.robots = reader.int32();
break;
}
default: default:
reader.skipType(tag & 7); reader.skipType(tag & 7);
break; break;
@ -1770,6 +1975,12 @@ export const api = $root.api = (() => {
ReqCreateTable.verify = function verify(message) { ReqCreateTable.verify = function verify(message) {
if (typeof message !== "object" || message === null) if (typeof message !== "object" || message === null)
return "object expected"; return "object expected";
if (message.players != null && message.hasOwnProperty("players"))
if (!$util.isInteger(message.players))
return "players: integer expected";
if (message.robots != null && message.hasOwnProperty("robots"))
if (!$util.isInteger(message.robots))
return "robots: integer expected";
return null; return null;
}; };
@ -1784,7 +1995,12 @@ export const api = $root.api = (() => {
ReqCreateTable.fromObject = function fromObject(object) { ReqCreateTable.fromObject = function fromObject(object) {
if (object instanceof $root.api.ReqCreateTable) if (object instanceof $root.api.ReqCreateTable)
return object; return object;
return new $root.api.ReqCreateTable(); let message = new $root.api.ReqCreateTable();
if (object.players != null)
message.players = object.players | 0;
if (object.robots != null)
message.robots = object.robots | 0;
return message;
}; };
/** /**
@ -1796,8 +2012,19 @@ export const api = $root.api = (() => {
* @param {$protobuf.IConversionOptions} [options] Conversion options * @param {$protobuf.IConversionOptions} [options] Conversion options
* @returns {Object.<string,*>} Plain object * @returns {Object.<string,*>} Plain object
*/ */
ReqCreateTable.toObject = function toObject() { ReqCreateTable.toObject = function toObject(message, options) {
return {}; if (!options)
options = {};
let object = {};
if (options.defaults) {
object.players = 0;
object.robots = 0;
}
if (message.players != null && message.hasOwnProperty("players"))
object.players = message.players;
if (message.robots != null && message.hasOwnProperty("robots"))
object.robots = message.robots;
return object;
}; };
/** /**
@ -1835,6 +2062,7 @@ export const api = $root.api = (() => {
* Properties of a ResCreateTable. * Properties of a ResCreateTable.
* @memberof api * @memberof api
* @interface IResCreateTable * @interface IResCreateTable
* @property {number|null} [tableNo] ResCreateTable tableNo
*/ */
/** /**
@ -1852,6 +2080,14 @@ export const api = $root.api = (() => {
this[keys[i]] = properties[keys[i]]; this[keys[i]] = properties[keys[i]];
} }
/**
* ResCreateTable tableNo.
* @member {number} tableNo
* @memberof api.ResCreateTable
* @instance
*/
ResCreateTable.prototype.tableNo = 0;
/** /**
* Creates a new ResCreateTable instance using the specified properties. * Creates a new ResCreateTable instance using the specified properties.
* @function create * @function create
@ -1876,6 +2112,8 @@ export const api = $root.api = (() => {
ResCreateTable.encode = function encode(message, writer) { ResCreateTable.encode = function encode(message, writer) {
if (!writer) if (!writer)
writer = $Writer.create(); writer = $Writer.create();
if (message.tableNo != null && Object.hasOwnProperty.call(message, "tableNo"))
writer.uint32(/* id 1, wireType 0 =*/8).int32(message.tableNo);
return writer; return writer;
}; };
@ -1910,6 +2148,10 @@ export const api = $root.api = (() => {
while (reader.pos < end) { while (reader.pos < end) {
let tag = reader.uint32(); let tag = reader.uint32();
switch (tag >>> 3) { switch (tag >>> 3) {
case 1: {
message.tableNo = reader.int32();
break;
}
default: default:
reader.skipType(tag & 7); reader.skipType(tag & 7);
break; break;
@ -1945,6 +2187,9 @@ export const api = $root.api = (() => {
ResCreateTable.verify = function verify(message) { ResCreateTable.verify = function verify(message) {
if (typeof message !== "object" || message === null) if (typeof message !== "object" || message === null)
return "object expected"; return "object expected";
if (message.tableNo != null && message.hasOwnProperty("tableNo"))
if (!$util.isInteger(message.tableNo))
return "tableNo: integer expected";
return null; return null;
}; };
@ -1959,7 +2204,10 @@ export const api = $root.api = (() => {
ResCreateTable.fromObject = function fromObject(object) { ResCreateTable.fromObject = function fromObject(object) {
if (object instanceof $root.api.ResCreateTable) if (object instanceof $root.api.ResCreateTable)
return object; return object;
return new $root.api.ResCreateTable(); let message = new $root.api.ResCreateTable();
if (object.tableNo != null)
message.tableNo = object.tableNo | 0;
return message;
}; };
/** /**
@ -1971,8 +2219,15 @@ export const api = $root.api = (() => {
* @param {$protobuf.IConversionOptions} [options] Conversion options * @param {$protobuf.IConversionOptions} [options] Conversion options
* @returns {Object.<string,*>} Plain object * @returns {Object.<string,*>} Plain object
*/ */
ResCreateTable.toObject = function toObject() { ResCreateTable.toObject = function toObject(message, options) {
return {}; if (!options)
options = {};
let object = {};
if (options.defaults)
object.tableNo = 0;
if (message.tableNo != null && message.hasOwnProperty("tableNo"))
object.tableNo = message.tableNo;
return object;
}; };
/** /**

33
src/api/websocket.js

@ -1,4 +1,5 @@
import proto from '@/api/proto'; import proto from '@/api/proto';
import { fetchOpMap } from '@/api/api'
const { api } = proto const { api } = proto
@ -7,12 +8,15 @@ const websocket = {
state: 0, // 0未初始,1打开,2关闭 state: 0, // 0未初始,1打开,2关闭
seq: 1, // 消息序号 seq: 1, // 消息序号
offset: 0, offset: 0,
failOp: 0, opFail: 0,
opSuccess: 0,
opPathMap: {}, opPathMap: {},
nameOpMap: {}, nameOpMap: {},
init(token, { offset, failOp, opPathMap, nameOpMap }) { init(token, { offset, opFail, opSuccess, opPathMap, nameOpMap }) {
// TODO 连接状态判定
this.offset = offset || 0; this.offset = offset || 0;
this.failOp = failOp; this.opFail = opFail;
this.opSuccess = opSuccess;
this.opPathMap = opPathMap || {}; this.opPathMap = opPathMap || {};
this.nameOpMap = nameOpMap || {}; this.nameOpMap = nameOpMap || {};
// window.proto = proto; // window.proto = proto;
@ -38,19 +42,19 @@ const websocket = {
// 解码响应体 // 解码响应体
const opPath = this.opPathMap[wrap.op] const opPath = this.opPathMap[wrap.op]
if (!opPath) { if (!opPath) {
console.log('res op not exists!', wrap.op) console.error('res op not exists!', wrap.op)
return return
} }
const res = proto[opPath[0]][opPath[1]].decode(wrap.body) const res = proto[opPath[0]][opPath[1]].decode(wrap.body)
// const res = api.ResIdentity.decode(wrap.body) // const res = api.ResIdentity.decode(wrap.body)
console.log(wrap, res) console.log('res msg:', res)
if (wrap.seq !== 0) { if (wrap.seq !== 0) {
// 对应请求callback // 对应请求callback
const waitCall = this.waitCall[wrap.seq]; const waitCall = this.waitCall[wrap.seq];
delete this.waitCall[wrap.seq]; delete this.waitCall[wrap.seq];
console.log(waitCall, this.waitCall); // console.log(waitCall, this.waitCall);
if (waitCall) { if (waitCall) {
if (wrap.op === failOp) { if (wrap.op === opFail) {
waitCall.onFail(res, wrap); waitCall.onFail(res, wrap);
} else { } else {
waitCall.onRes(res, wrap); waitCall.onRes(res, wrap);
@ -85,7 +89,7 @@ const websocket = {
const idx = typeUrl.lastIndexOf("/"); const idx = typeUrl.lastIndexOf("/");
typeUrl = idx === -1 ? typeUrl : typeUrl.substring(idx + 1); typeUrl = idx === -1 ? typeUrl : typeUrl.substring(idx + 1);
const op = this.nameOpMap[typeUrl]; const op = this.nameOpMap[typeUrl];
console.log(typeUrl, op); console.log('req', typeUrl, op);
const msgBufer = msg.constructor.encode(msg).finish(); const msgBufer = msg.constructor.encode(msg).finish();
const wrap = api.ProtoWrap.create({ ver: 1, op: op, seq: this.seq++, body: msgBufer }); const wrap = api.ProtoWrap.create({ ver: 1, op: op, seq: this.seq++, body: msgBufer });
const wrapBuffer = api.ProtoWrap.encode(wrap).finish(); const wrapBuffer = api.ProtoWrap.encode(wrap).finish();
@ -108,3 +112,16 @@ const websocket = {
} }
export default websocket export default websocket
export const sendPromise = function(msg) {
return new Promise((resolve, reject) => {
websocket.send(msg, resolve, reject)
})
}
;(async function() {
const token = "15PohpTztq4YkMmErI4H71kJWX2pPqnvOZar9HKOfg1KEy0fd8fUNxnBIwuMDcKQEBPG7b9UC7ja_8FtwvYjnA=="
const opMap = await fetchOpMap()
websocket.init(token, opMap.data)
})()

3
src/api/wsapi.js

@ -0,0 +1,3 @@
import { sendPromise } from './websocket'
export const aa = msg => sendPromise(msg)

1
src/assets/icon/plus-1.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="13" height="13" viewBox="0 0 13 13"><g><path d="M5.57143,5.57143L5.57143,0L7.42857,0L7.42857,5.57143L13,5.57143L13,7.42857L7.42857,7.42857L7.42857,13L5.57143,13L5.57143,7.42857L0,7.42857L0,5.57143L5.57143,5.57143Z" fill="#D8D8D8" fill-opacity="1"/></g></svg>

After

Width:  |  Height:  |  Size: 374 B

1
src/assets/icon/robot-1.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="30" height="30" viewBox="0 0 30 30"><defs><clipPath id="master_svg0_84_00924"><rect x="0" y="0" width="30" height="30" rx="0"/></clipPath></defs><g clip-path="url(#master_svg0_84_00924)"><g><path d="M16.25,5.06875C21.875,5.69,26.25,10.45875,26.25,16.25L26.25,27.5L3.75,27.5L3.75,16.25C3.75,10.45875,8.125,5.69,13.75,5.06875L13.75,1.25L16.25,1.25L16.25,5.06875ZM15,22.5C18.4518,22.5,21.25,19.7018,21.25,16.25C21.25,12.7982,18.4518,10,15,10C11.54822,10,8.75,12.7982,8.75,16.25C8.75,19.7018,11.54822,22.5,15,22.5ZM15,20C12.92893,20,11.25,18.3211,11.25,16.25C11.25,14.1789,12.92893,12.5,15,12.5C17.0711,12.5,18.75,14.1789,18.75,16.25C18.75,18.3211,17.0711,20,15,20ZM15,17.5C15.6904,17.5,16.25,16.9404,16.25,16.25C16.25,15.5596,15.6904,15,15,15C14.3096,15,13.75,15.5596,13.75,16.25C13.75,16.9404,14.3096,17.5,15,17.5Z" fill="#FFFFFF" fill-opacity="1"/></g></g></svg>

After

Width:  |  Height:  |  Size: 977 B

1
src/assets/icon/sub-1.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="16" height="2" viewBox="0 0 16 2"><g><path d="M0,0L16,0L16,2L0,2L0,0Z" fill="#D8D8D8" fill-opacity="1"/></g></svg>

After

Width:  |  Height:  |  Size: 230 B

15
src/pages/lobby/lobby.jsx

@ -5,8 +5,9 @@ import Taro from '@tarojs/taro'
import { useSelector, useDispatch } from 'react-redux' import { useSelector, useDispatch } from 'react-redux'
import './lobby.scss' import './lobby.scss'
import { navigateTo } from '@/utils/application'
import { increment } from '@/store/index' import { increment } from '@/store/index'
import { fetchOpMap } from '@/api/api' import { fetchOpMap, fetchLobbyView } from '@/api/api'
import Title from '@/components/title' import Title from '@/components/title'
import coin1 from '@/assets/coin-1.png' import coin1 from '@/assets/coin-1.png'
import tabQuestion from '@/assets/tab-question.svg' import tabQuestion from '@/assets/tab-question.svg'
@ -17,9 +18,13 @@ function Lobby() {
const user = useSelector((state) => state.user) const user = useSelector((state) => state.user)
console.log(user) console.log(user)
const dispatch = useDispatch() const dispatch = useDispatch()
fetchOpMap() fetchLobbyView()
.then(res => { console.log(res) }) .then(res => {
.catch(err => console.log(err)) console.log('lobby', res)
})
.catch(err => {
console.error(err)
})
const avatar = "https://img0.baidu.com/it/u=2477829979,2171947490&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500"; const avatar = "https://img0.baidu.com/it/u=2477829979,2171947490&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500";
@ -97,7 +102,7 @@ function Lobby() {
<View className="tab-wrap"></View> <View className="tab-wrap"></View>
</View> </View>
<View className="bottom-btn-wrap"> <View className="bottom-btn-wrap">
<Button className="bottom-btn" onClick={() => dispatch(increment())}>Create New Table</Button> <Button className="bottom-btn" onClick={() => navigateTo({url: '/pages/new_table/new_table'})}>Create New Table</Button>
</View> </View>
</View> </View>
) )

66
src/pages/login/login.jsx

@ -5,54 +5,48 @@ import Taro from '@tarojs/taro';
//import { Form, Input, TextArea, Cell, Button, Row, Col, Image } from '@nutui/nutui-react-taro'; //import { Form, Input, TextArea, Cell, Button, Row, Col, Image } from '@nutui/nutui-react-taro';
import ws from '@/api/websocket' import ws from '@/api/websocket'
import './login.scss' import './login.scss'
import { fetchOpMap } from '@/api/api' import { doLogin, fetchOpMap } from '@/api/api'
import { redirectTo, showToast } from '@/utils/application'
import iconUser from '@/assets/icon/user-3-fill.svg' import iconUser from '@/assets/icon/user-3-fill.svg'
import iconLock from '@/assets/icon/lock-2-fill.svg' import iconLock from '@/assets/icon/lock-2-fill.svg'
import abIcon from '@/assets/icon/a-b.svg' import abIcon from '@/assets/icon/a-b.svg'
import { setStorage } from '@/utils/storage';
/* /*
登录 -> 大厅 -> 新桌面 -> 进桌面 -> profile(弹窗) 登录 -> 大厅 -> 新桌面 -> 进桌面 -> profile(弹窗)
*/ */
function Login(props, ref) { function Login() {
// protobuf
// let msg = message.Proto.create({ver:1, seq:1, op: 1});
// let buffer = message.Proto.encode(msg).finish();
// console.log(buffer)
// let decoded = message.Proto.decode(buffer);
// console.log(decoded)
const [state, setState] = useState({ const [state, setState] = useState({
username: '', username: '',
password: '', password: '',
captcha: '', captcha: '',
}); });
const [captcha, setCaptcha] = useState({ const [captcha, setCaptcha] = useState({
origin: "/api/auth/captcha", // http://localhost:9999 origin: "/api/auth/captcha",
src: "/api/auth/captcha", src: "/api/auth/captcha",
}) });
const usernameChange = (username, e) => { const [submitLoding, setSubmitLoding] = useState(false)
if (!e) return;
state.username = username; const handleSubmit = async () => {
console.log(state.username) if (submitLoding) { return; }
} setSubmitLoding(true);
const passwordChange = (password, e) => {
if (!e) return;
state.password = password;
console.log(state.password)
}
const handleSubmit = () => {
console.log('submit', state)
const token = "AgOjcdf3goeYDX3lwWWwkXtVpcrL-l2rX8csrRKgs3_-BC3JOx0l6nZU0MV25eIn"
fetchOpMap()
.then(res => {
console.log('opMap', res)
ws.init(token, res.data)
})
.catch(err => {
console.log('err', err)
})
//const token = "AgOjcdf3goeYDX3lwWWwkXtVpcrL-l2rX8csrRKgs3_-BC3JOx0l6nZU0MV25eIn"
try {
const [tokenRes, opMapRes] = await Promise.all([doLogin(state), fetchOpMap()]);
setStorage('_t', tokenRes.data.token)
// websocket
ws.init(tokenRes.data.token, opMapRes.data);
showToast({title: '登录成功', duration: 800});
//
setTimeout(() => redirectTo({url: '/pages/lobby/lobby'}), 800);
}catch(err) {
showToast({icon: 'error', title: err.msg})
} finally {
setSubmitLoding(false);
}
} }
console.log(submitLoding)
return ( return (
<View className='login'> <View className='login'>
<View className='ceiling'></View> <View className='ceiling'></View>
@ -63,22 +57,22 @@ function Login(props, ref) {
<View className='input-wrap'> <View className='input-wrap'>
<Label for="username"><Image className='input-icon' src={iconUser} /></Label> <Label for="username"><Image className='input-icon' src={iconUser} /></Label>
<Input className="input-1" id="username" name="username" type="text" defaultValue={state.username} placeholder="account" leftIcon="dongdong" <Input className="input-1" id="username" name="username" type="text" defaultValue={state.username} placeholder="account" leftIcon="dongdong"
onChange={usernameChange}/> onChange={e => setState({...state, username: e.target.value})}/>
</View> </View>
<View className='input-wrap'> <View className='input-wrap'>
<Image className='input-icon' src={iconLock} /> <Image className='input-icon' src={iconLock} />
<Input className='input-1' name="password" type="password" password={true} defaultValue={state.password} placeholder="password" <Input className='input-1' name="password" type="password" password={true} defaultValue={state.password} placeholder="password"
onChange={passwordChange}/> onChange={e => setState({...state, password: e.target.value})}/>
</View> </View>
<View className='input-wrap'> <View className='input-wrap'>
<Image className='input-icon' src={abIcon} /> <Image className='input-icon' src={abIcon} />
<Input className='input-2' name="captcha" type="text" defaultValue={state.password} placeholder="captcha" <Input className='input-2' name="captcha" type="text" defaultValue={state.password} placeholder="captcha"
onChange={() => {}}/> onChange={e => setState({...state, captcha: e.target.value})}/>
<Image className='captcha' src={captcha.src} width="107" height="36" <Image className='captcha' src={captcha.src} width="107" height="36"
onClick={() => setCaptcha({...captcha, src: captcha.origin + '?t=' + Math.random()})} /> onClick={() => setCaptcha({...captcha, src: captcha.origin + '?t=' + Math.random()})} />
</View> </View>
<View> <View>
<Button className='submit-btn'>START</Button> <Button className='submit-btn' loading={submitLoding} onClick={handleSubmit}>START</Button>
</View> </View>
<View style={{display: 'none'}}> <View style={{display: 'none'}}>
<Button type="primary" style={{width: '160px'}} onClick={handleSubmit}>提交</Button> <Button type="primary" style={{width: '160px'}} onClick={handleSubmit}>提交</Button>

56
src/pages/new_table/new_table.jsx

@ -1,26 +1,52 @@
import React, { Component, useState } from 'react' import React, { Component, useState } from 'react'
import { View, Text, Image, Button } from '@tarojs/components' import { View, Text, Image, Button } from '@tarojs/components'
import { Popup, Picker } from '@nutui/nutui-react-taro';
import { useSelector } from 'react-redux' import { useSelector } from 'react-redux'
import './new_table.scss' import './new_table.scss'
import Title from '@/components/title' import Title from '@/components/title'
import { sendPromise } from '@/api/websocket'
import proto from '@/api/proto';
import { showToast } from '@/utils/application'
import userIcon from '@/assets/icon/user-2.svg' import userIcon from '@/assets/icon/user-2.svg'
import robotIcon from '@/assets/icon/robot-1.svg'
import closeIcon from '@/assets/icon/close-1.svg' import closeIcon from '@/assets/icon/close-1.svg'
import addIcon from '@/assets/icon/add-2.svg' import addIcon from '@/assets/icon/add-2.svg'
const { ReqCreateTable } = proto.api
function NewTable() { function NewTable() {
const {username, nickname, avatar} = useSelector(state => state.user); const {username, nickname, avatar} = useSelector(state => state.user);
const [submitLoading, setSubmitLoading] = useState(false);
const [choosingPlace, setChoosingPlace] = useState(-1);
const players = [1,2,3,4,5,6]; const [players, setPlayers] = useState([0,0,0,0,0,0]); // 0,1,2
const playerRows = players.reduce((arr, item, idx) => { const playerRows = players.reduce((arr, item, idx) => {
const row = parseInt(idx / 2); const row = parseInt(idx / 2);
let rowArr = arr[row] || []; let rowArr = arr[row] || [];
rowArr[idx % 2] = {index: idx, item}; rowArr[idx % 2] = {index: idx, item};
arr[row] = rowArr; arr[row] = rowArr;
parseInt()
return arr; return arr;
}, []); }, []);
const createTable = async () => {
if (submitLoading) { return }
setSubmitLoading(true)
const req = ReqCreateTable.create({
players: players.filter(type => type === 1).length,
robots: players.filter(type => type === 2).length
})
try {
const res = await sendPromise(req)
console.log('finish', res)
}catch(err) {
showToast({title: err})
} finally {
setSubmitLoading(false)
}
}
return ( return (
<View className="nt"> <View className="nt">
<Title title={"Create New Table"} /> <Title title={"Create New Table"} />
@ -30,13 +56,16 @@ function NewTable() {
<View key={i} className="playerRow"> <View key={i} className="playerRow">
{ {
row.map((player, j) => ( row.map((player, j) => (
player.index === 5 player.item === 0
? <View key={j} className='player empty-player'><Image className="empty-icon" src={addIcon} /></View> ? <View key={j} onClick={() => setChoosingPlace(player.index)} className='player empty-player'><Image className="empty-icon" src={addIcon} /></View>
: <View key={j} className="player-wrap"> : <View key={j} className="player-wrap">
<View className="player-icon"><Image className="player-icon-img" src={userIcon} /></View> <View className="player-icon"><Image className="player-icon-img" src={player.item === 1 ? userIcon : robotIcon} /></View>
<View className="close-icon"><Image className="close-icon-img" src={closeIcon} /></View> <View className="close-icon" onClick={() => {
players[player.index] = 0;
setPlayers([...players]);
}}><Image className="close-icon-img" src={closeIcon} /></View>
<View className="player"> <View className="player">
<Text className="player-name">Player{player.item}</Text> <Text className="player-name">{player.item === 1 ? 'Player' : 'Robot'}#{player.index + 1}</Text>
</View> </View>
</View> </View>
)) ))
@ -52,9 +81,20 @@ function NewTable() {
</View> </View>
</View> </View>
<View className='submit-btn-wrap'> <View className='submit-btn-wrap'>
<Button className='submit-btn'>CREATE</Button> <Button className='submit-btn' loading={submitLoading} onClick={createTable}>CREATE</Button>
</View> </View>
</View> </View>
<Picker
title='Player OR Robot'
isVisible={choosingPlace > -1}
listData={[{value: 1, text: 'Player'}, {value: 2, text: 'Robot'}]}
onConfirm={(values) => {
players[choosingPlace] = values[0];
setPlayers([...players]);
}}
onClose={() => setChoosingPlace(-1)}
/>
</View> </View>
) )
} }

20
src/pages/table/table.jsx

@ -8,6 +8,10 @@ import Title from '@/components/title'
import Card from '@/components/card' import Card from '@/components/card'
import coinIcon from '@/assets/icon/coin-1.svg' import coinIcon from '@/assets/icon/coin-1.svg'
import coin2Icon from '@/assets/icon/coin-2.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 Taro from '@tarojs/taro'
function Table() { function Table() {
@ -92,6 +96,8 @@ function Table() {
)) ))
} }
</View> </View>
<View className='u-opt' style={{ display: 'flex' }}>
<View>
<View className="s-info-wrap"> <View className="s-info-wrap">
<View className="s-avatar"><Image className="s-avatar-img" src={avatar} /></View> <View className="s-avatar"><Image className="s-avatar-img" src={avatar} /></View>
<View className="s-username"><Text>Prometheus</Text></View> <View className="s-username"><Text>Prometheus</Text></View>
@ -104,6 +110,20 @@ function Table() {
<View className="s-w-pct"><Text>0%</Text></View> <View className="s-w-pct"><Text>0%</Text></View>
</View> </View>
</View> </View>
<View className="control">
<View className="ctl-opt-wrap">
<View className="amount-input"><Input placeholder='stake' defaultValue={0} /></View>
<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) }}>
<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>
</View> </View>
</View> </View>
) )

130
src/pages/table/table.scss

@ -7,10 +7,12 @@
// width: 405px; // width: 405px;
margin: 46px 26px 0 26px; margin: 46px 26px 0 26px;
} }
.player-wrap { .player-wrap {
// flex: 0 0 50%; // flex: 0 0 50%;
position: relative; position: relative;
} }
.player-no { .player-no {
position: absolute; position: absolute;
top: -25px; top: -25px;
@ -23,23 +25,28 @@
border-radius: 50%; border-radius: 50%;
text-align: center; text-align: center;
} }
.player-no-running { .player-no-running {
font-weight: bold; font-weight: bold;
color: #fff; color: #fff;
background-color: #EE914E; background-color: #EE914E;
} }
.card1, .card2 { .card1,
.card2 {
position: absolute; position: absolute;
z-index: 999; z-index: 999;
top: -27px; top: -27px;
} }
.card1 { .card1 {
left: 60px; left: 60px;
} }
.card2 { .card2 {
left: 104px; left: 104px;
} }
.player { .player {
width: 153px; width: 153px;
height: 69px; height: 69px;
@ -51,14 +58,17 @@
border: 1px solid #000; border: 1px solid #000;
border-radius: 5px; border-radius: 5px;
} }
.avatar-wrap { .avatar-wrap {
margin: 10px 0 10px 4px; margin: 10px 0 10px 4px;
} }
.avatar { .avatar {
border-radius: 5px; border-radius: 5px;
height: 50px; height: 50px;
width: 50px; width: 50px;
} }
.player-name { .player-name {
font-size: 12px; font-size: 12px;
line-height: 20px; line-height: 20px;
@ -75,6 +85,7 @@
display: flex; display: flex;
margin-top: 3px; margin-top: 3px;
} }
.wallet { .wallet {
display: flex; display: flex;
background-color: #EE914E; background-color: #EE914E;
@ -85,19 +96,23 @@
box-sizing: border-box; box-sizing: border-box;
padding: 0 4px; padding: 0 4px;
} }
.wallet-icon { .wallet-icon {
//margin: 2px 0 2px 4px; //margin: 2px 0 2px 4px;
line-height: 22px; line-height: 22px;
} }
.wallet-icon-img { .wallet-icon-img {
width: 14px; width: 14px;
height: 14px; height: 14px;
} }
.wallet-amount { .wallet-amount {
font-size: 12px; font-size: 12px;
color: #fff; color: #fff;
line-height: 18px; line-height: 18px;
} }
.pct { .pct {
background-color: #807878; background-color: #807878;
font-size: 12px; font-size: 12px;
@ -115,9 +130,9 @@
flex-wrap: nowrap; flex-wrap: nowrap;
margin: 33px 26px 0 26px; margin: 33px 26px 0 26px;
} }
.desktop-wrap {
} .desktop-wrap {}
.desktop-cards { .desktop-cards {
width: 250px; width: 250px;
height: 95px; height: 95px;
@ -128,6 +143,7 @@
align-items: center; align-items: center;
flex-wrap: nowrap; flex-wrap: nowrap;
} }
.desktop-wallet { .desktop-wallet {
margin-top: 4px; margin-top: 4px;
width: 250px; width: 250px;
@ -139,6 +155,7 @@
box-sizing: border-box; box-sizing: border-box;
padding: 0 5px; padding: 0 5px;
} }
.d-wallet-icon { .d-wallet-icon {
font-size: 18px; font-size: 18px;
color: #fff; color: #fff;
@ -147,19 +164,23 @@
display: flex; display: flex;
align-items: center; align-items: center;
} }
.d-wallet-icon-img { .d-wallet-icon-img {
height: 28px; height: 28px;
width: 28px; width: 28px;
} }
.d-wallet-icon-text { .d-wallet-icon-text {
margin-left: 7px; margin-left: 7px;
} }
.d-wallet-amount { .d-wallet-amount {
font-size: 18px; font-size: 18px;
color: #fff; color: #fff;
font-weight: bold; font-weight: bold;
line-height: 36px; line-height: 36px;
} }
.chatbox { .chatbox {
width: 159px; width: 159px;
height: 134px; height: 134px;
@ -167,6 +188,7 @@
border-radius: 5px; border-radius: 5px;
padding: 5px; padding: 5px;
} }
.chat-window { .chat-window {
.line { .line {
@ -174,32 +196,37 @@
line-height: 12px; line-height: 12px;
} }
} }
.chat-panel {
} .chat-panel {}
.self-box { .self-box {
// width: 100%; // width: 100%;
height: 109px; height: 109px;
background-color: #EE914E; background-color: #EE914E;
margin: 30px 26px 0 26px; margin: 30px 26px 0 26px;
border-radius: 5px;; border-radius: 5px;
;
} }
.self-wrap { .self-wrap {
position: relative; position: relative;
} }
.s-info-wrap { .s-info-wrap {
display: flex; display: flex;
height: 89px; height: 89px;
} }
.s-avatar { .s-avatar {
align-self: center; align-self: center;
margin-left: 6px; margin-left: 6px;
} }
.s-avatar-img { .s-avatar-img {
width: 65px; width: 65px;
height: 65px; height: 65px;
} }
.s-username { .s-username {
font-size: 12px; font-size: 12px;
font-weight: bold; font-weight: bold;
@ -210,10 +237,12 @@
margin-bottom: 16px; margin-bottom: 16px;
margin-left: 10px; margin-left: 10px;
} }
.s-wallet-wrap { .s-wallet-wrap {
display: flex; display: flex;
width: 156px; width: 156px;
} }
.s-w-amount-wrap { .s-w-amount-wrap {
width: 97px; width: 97px;
height: 18px; height: 18px;
@ -226,20 +255,24 @@
box-sizing: border-box; box-sizing: border-box;
padding: 0 5px 0 3px; padding: 0 5px 0 3px;
} }
.s-w-amount-icon { .s-w-amount-icon {
width: 14px; width: 14px;
height: 14px; height: 14px;
margin-top: -2px; margin-top: -2px;
} }
.s-w-amount-icon-img { .s-w-amount-icon-img {
width: 15px; width: 15px;
height: 15px; height: 15px;
} }
.s-w-amount { .s-w-amount {
color: #3D3D3D; color: #3D3D3D;
font-size: 12px; font-size: 12px;
line-height: 18px; line-height: 18px;
} }
.s-w-pct { .s-w-pct {
width: 50px; width: 50px;
height: 18px; height: 18px;
@ -251,14 +284,18 @@
background-color: #fff; background-color: #fff;
margin-left: 8px; margin-left: 8px;
} }
.hand-card1,.hand-card2 {
.hand-card1,
.hand-card2 {
position: absolute; position: absolute;
top: -20px; top: -20px;
left: 80px; left: 80px;
} }
.hand-card2 { .hand-card2 {
left: 126px; left: 126px;
} }
.hand-five { .hand-five {
position: absolute; position: absolute;
left: 188px; left: 188px;
@ -271,7 +308,84 @@
justify-content: space-evenly; justify-content: space-evenly;
// background-color: #807878; // background-color: #807878;
} }
.hand-five-item {
.hand-five-item {}
.u-opt {
display: flex;
justify-content: flex-start;
}
.control {
align-self: flex-end;
margin-left: 30px;
}
.ctl-opt-wrap {
display: flex;
width: 170px;
justify-content: space-between;
}
.amount-input {
width: 80px;
height: 24px;
box-sizing: border-box;
text-align: center;
background-color: #F1D09F;
border-radius: 8px;
font-size: 12px;
padding: 4px 0;
color: 3D3D3D;
}
.amount-sub,
.amount-plus {
width: 36px;
height: 24px;
background-color: #fff;
border-radius: 8px;
text-align: center;
}
.amount-sub-icon,
.amount-plus-icon {
width: 16px;
height: 13px;
}
.amount-plus-icon {
width: 16px;
height: 13px;
}
.ctl-opt {}
.ctl-opt-btn-1,
.ctl-opt-btn-2,
.ctl-opt-btn-3 {
width: 53.25px;
height: 24px;
border-radius: 8px;
font-size: 12px;
font-weight: bold;
padding: 0;
line-height: 24px;
border: 0;
}
.ctl-opt-btn-1 {
background-color: #F1D09F;
color: #EA8C28;
}
.ctl-opt-btn-2 {
background-color: #F1D09F;
color: #D05959;
}
.ctl-opt-btn-3 {
background-color: #FF4400;
color: #F1D09F;
} }
} }

11
src/utils/application.js

@ -53,3 +53,14 @@ export const navigateBack = function(option = {delta: 1}) {
} }
return Taro.navigateBack(option); return Taro.navigateBack(option);
} }
export const showToast = function(option = {icon: 'success'}) {
let {title} = option
if (!title) { return }
title = typeof(title) === 'string' ? title : title.msg || title.message;
if (!title) {
console.log('no title toast:', option.title)
return
}
Taro.showToast(option)
}

Loading…
Cancel
Save