client ui

This commit is contained in:
wzdwc
2020-05-21 01:02:33 +08:00
parent 62dc627e23
commit 1f2de944dc
20 changed files with 1026 additions and 584 deletions
+4 -1
View File
@@ -4,15 +4,18 @@
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"dev": "vue-cli-service serve",
"dev": "cross-env NODE_ENV=develop vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"@types/fastclick": "^1.0.29",
"@types/js-cookie": "^2.2.6",
"@types/socket.io-client": "^1.4.32",
"axios": "^0.19.2",
"core-js": "^3.6.4",
"cross-env": "^7.0.2",
"fastclick": "^1.0.6",
"js-cookie": "^2.2.1",
"socket.io-client": "^2.3.0",
"vconsole": "^3.3.4",
+74 -71
View File
@@ -1,71 +1,74 @@
<template>
<div id="app">
<router-view/>
</div>
</template>
<script lang="ts">
import { Vue } from 'vue-property-decorator';
export default class App extends Vue {}
</script>
<style lang="less">
@import "assets/less/base";
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
max-width: 640rem;
overflow: hidden;
margin: auto;
}
*{
padding: 0;
margin: 0;
}
body{
box-sizing: border-box;
}
.container{
.input-bd{
line-height: 30px;
margin: 10px;
.input-name{
display: inline-block;
width: 150px;
text-align: center;
}
.input-text{
display: inline-block;
padding-left: 10px;
input{
height: 30px;
width: 180px;
padding:0 5px;
}
}
}
.btn {
margin-top: 15px;
span{
color: #fff;
background-color: #6796ff;
border-radius: 8px;
padding: 5px 20px;
display: inline-block;
margin: 10px;
}
b{
display: inline-block;
border: aliceblue;
border-radius: 8px;
padding: 5px 20px;
margin-left: 10px;
}
}
}
</style>
<template>
<div id="app">
<router-view/>
</div>
</template>
<script lang="ts">
import { Vue } from 'vue-property-decorator';
export default class App extends Vue {}
</script>
<style lang="less">
@import "assets/less/base";
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
max-width: 640rem;
overflow: hidden;
margin: auto;
}
*{
padding: 0;
margin: 0;
}
body{
box-sizing: border-box;
}
.container{
.input-bd{
line-height: 30px;
margin: 10px;
font-size: 0;
.input-name{
display: inline-block;
min-width: 10vw;
font-size: 14px;
vertical-align: middle;
}
.input-text{
display: inline-block;
font-size: 14px;
vertical-align: middle;
input{
min-height: 30px;
min-width: 40vw;
}
}
}
.btn {
margin-top: 15px;
span{
color: #fff;
background-color: #00976e;
border-radius: 8px;
padding: 5px 20px;
display: block;
margin: 10px;
}
b{
display: inline-block;
border: aliceblue;
font-size: 12px;
border-radius: 8px;
padding: 5px 20px;
margin-left: 10px;
}
}
}
</style>
+52 -42
View File
@@ -1,42 +1,52 @@
@font-face {
font-family: 'iconfont'; /* project id 1801313 */
src: url('//at.alicdn.com/t/font_1801313_gon9izdrhub.eot');
src: url('//at.alicdn.com/t/font_1801313_gon9izdrhub.eot?#iefix') format('embedded-opentype'),
url('//at.alicdn.com/t/font_1801313_gon9izdrhub.woff2') format('woff2'),
url('//at.alicdn.com/t/font_1801313_gon9izdrhub.woff') format('woff'),
url('//at.alicdn.com/t/font_1801313_gon9izdrhub.ttf') format('truetype'),
url('//at.alicdn.com/t/font_1801313_gon9izdrhub.svg#iconfont') format('svg');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-account:before {
content: "\e60a";
}
.icon-password:before {
content: "\e777";
}
.icon-user-avatar:before {
content: "\e636";
}
.icon-pot:before {
content: "\e60c";
}
.icon-gold:before {
content: "\e609";
}
.icon-setting:before {
content: "\e611";
}
@font-face {
font-family: 'iconfont'; /* project id 1801313 */
src: url('//at.alicdn.com/t/font_1801313_ys37cfwp48.eot');
src: url('//at.alicdn.com/t/font_1801313_ys37cfwp48.eot?#iefix') format('embedded-opentype'),
url('//at.alicdn.com/t/font_1801313_ys37cfwp48.woff2') format('woff2'),
url('//at.alicdn.com/t/font_1801313_ys37cfwp48.woff') format('woff'),
url('//at.alicdn.com/t/font_1801313_ys37cfwp48.ttf') format('truetype'),
url('//at.alicdn.com/t/font_1801313_ys37cfwp48.svg#iconfont') format('svg');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-account:before {
content: "\e60a";
}
.icon-user-avatar:before {
content: "\e636";
}
.icon-pot:before {
content: "\e60c";
}
.icon-gold:before {
content: "\e609";
}
.icon-setting:before {
content: "\e611";
}
.icon-password:before {
content: "\e603";
}
.icon-close:before {
content: "\e615";
}
body, p,h1,h2,ul,li,input{
padding: 0;
margin: 0;
}
input{
border: 0;
outline: none;
}
+95 -89
View File
@@ -1,89 +1,95 @@
<template>
<div class="buy-in"
v-show="showBuyIn">
<div class="shadow"
@click="closeBuyIn"></div>
<div class="buy-in-body">
<div class="input-bd">
<div class="input-name">buy in: {{buyInSize}}</div>
<range :max="max"
:min="min"
@change="getBuyInSize"></range>
</div>
<div class="btn"><span @click="buyIn">buy in</span></div>
</div>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
import range from '../components/range.vue';
@Component({
components: {
range,
},
})
export default class BuyIn extends Vue {
@Prop() private showBuyIn!: boolean;
@Prop() private min!: number;
@Prop() private max!: number;
private buyInSize: number = 0;
private getBuyInSize(val: string) {
this.buyInSize = Number(val);
}
private closeBuyIn() {
this.$emit('update:showBuyIn', false);
}
private async buyIn() {
this.closeBuyIn();
this.$emit('buyIn', this.buyInSize);
}
private mounted() {
this.buyInSize = this.min;
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped
lang="less">
.buy-in {
position: fixed;
z-index: 99;
.shadow {
position: fixed;
z-index: 9;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.2);
}
.buy-in-body {
z-index: 99;
position: fixed;
left: 50%;
top: 50%;
margin: -100px -150px;
width: 300px;
height: 150px;
border-radius: 12px;
box-sizing: border-box;
background: #fff;
padding: 20px;
}
.input-text {
input {
width: 100px;
}
}
}
</style>
<template>
<div class="buy-in"
v-show="showBuyIn">
<div class="shadow"
@click="closeBuyIn"></div>
<div class="buy-in-body">
<div class="input-bd">
<div class="input-name">buy in: {{buyInSize}}</div>
<range :max="max"
:min="min"
@change="getBuyInSize"></range>
</div>
<div class="btn"><span @click="buyIn">buy in</span></div>
</div>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
import range from '../components/range.vue';
@Component({
components: {
range,
},
})
export default class BuyIn extends Vue {
@Prop() private showBuyIn!: boolean;
@Prop() private min!: number;
@Prop() private max!: number;
private buyInSize: number = 0;
private getBuyInSize(val: string) {
this.buyInSize = Number(val);
}
private closeBuyIn() {
this.$emit('update:showBuyIn', false);
}
private async buyIn() {
this.closeBuyIn();
this.$emit('buyIn', this.buyInSize);
}
private mounted() {
this.buyInSize = this.min;
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped
lang="less">
.buy-in {
position: fixed;
z-index: 99;
.shadow {
position: fixed;
z-index: 9;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.2);
}
.buy-in-body {
z-index: 99;
position: fixed;
left: 50%;
top: 50%;
margin: -100px -150px;
width: 300px;
border-radius: 12px;
box-sizing: border-box;
background: #fff;
padding: 20px;
}
.input-text {
input {
width: 100px;
}
}
.input-name{
margin-bottom: 15px;
font-size: 20px;
}
.btn{
margin-top: 20px;
}
}
</style>
+1 -1
View File
@@ -165,7 +165,7 @@
if (sitNode) {
const next = sitNode.next;
if (sitNode.node.player?.nickName === this.currPlayer?.nickName) {
sitNode.node.player = null;
delete sitNode.node.player;
}
sitNode = next as ILinkNode<ISit>;
}
+96
View File
@@ -0,0 +1,96 @@
<template>
<div class="record-container"
v-show="show">
<div class="shadow" @click="show = false"></div>
<div class="body">
<div class="title">record</div>
<ul>
<li>
<i>nickName</i>
<i>buy in</i>
<i>counter</i>
<i>income</i>
</li>
<li v-for="player in players">
<i>{{player.nickName}}</i>
<i>{{player.buyIn}}</i>
<i>{{player.counter}}</i>
<i>{{player.counter - player.buyIn}}</i>
</li>
</ul>
</div>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
import { IPlayer } from '@/interface/IPlayer';
@Component({
components: {
},
})
export default class Record extends Vue {
@Prop() private value!: boolean;
@Prop() private players!: IPlayer[];
get show() {
return this.value;
};
set show(val) {
this.$emit('input', val)
}
private mounted() {
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped
lang="less">
.record-container {
width: 80vw;
height: 100vh;
color: #fff;
background: #2a2a2a;
position: absolute;
left: 0;
top: 0;
.shadow{
background: rgba(0,0,0,0.3);
left: 0;
top: 0;
right: 0;
bottom: 0;
position: fixed;
z-index: 1;
}
.body{
position: relative;
z-index: 9;
}
.title{
color: #fff;
text-align: left;
line-height: 30px;
padding: 5px 10px;
border-bottom: 1px solid #fff;
}
ul{
li{
display: flex;
i{
flex: 1;
padding: 5px 10px;
font-size: 16px;
line-height: 20px;
display: inline-block;
font-style: normal;
font-size: 12px;
}
}
}
}
</style>
+60 -61
View File
@@ -1,61 +1,60 @@
<template>
<div class="toast-container">
<div class="toast-body" v-show="showValue">
{{text}}
</div>
</div>
</template>
<script lang="ts">
import {Component, Prop, Watch, Vue} from 'vue-property-decorator';
@Component
export default class Toast extends Vue {
@Prop() private text!: string;
@Prop({default: false, type: Boolean}) private show!: boolean;
@Prop({default: 1500, type: Number}) private timeOut!: number;
private showValue = false;
private Time: any;
@Watch('show')
private showChange(val: boolean) {
this.showValue = val;
if (val) {
this.close();
}
}
private close() {
clearTimeout(this.Time);
this.Time = setTimeout(() => {
this.showValue = false;
this.$emit('close');
}, this.timeOut);
}
private created() {
this.showValue = this.show;
this.close();
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped
lang="less">
.toast-container {
.toast-body {
padding: 2px 6px;
background: rgba(0, 0, 0, 0.3);
text-align: center;
color: #fff;
font-size: 12px;
position: fixed;
top: 50%;
left: 50%;
transform: translate3d(-50%, -50%, 0);
border-radius: 4px;
}
}
</style>
<template>
<div class="toast-container">
<div class="toast-body" v-show="showValue">
{{text}}
</div>
</div>
</template>
<script lang="ts">
import {Component, Prop, Watch, Vue} from 'vue-property-decorator';
@Component
export default class Toast extends Vue {
@Prop() private text!: string;
@Prop({default: false, type: Boolean}) private show!: boolean;
@Prop({default: 1000, type: Number}) private timeOut!: number;
private Time: any;
get showValue() {
console.log('come in')
if (this.show) {
this.close();
}
return this.show;
}
set showValue(val) {
this.$emit('update:show', val);
}
private close() {
console.log('come in')
clearTimeout(this.Time);
this.Time = setTimeout(() => {
this.showValue = false;
this.$emit('close');
}, this.timeOut || 0);
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped
lang="less">
.toast-container {
.toast-body {
padding: 2px 6px;
background: rgba(0, 0, 0, 0.3);
text-align: center;
color: #fff;
font-size: 12px;
position: fixed;
top: 50%;
left: 50%;
transform: translate3d(-50%, -50%, 0);
border-radius: 4px;
}
}
</style>
+119
View File
@@ -0,0 +1,119 @@
<template>
<div class="input-container">
<div class="user-name input-bd"
:class="{ move: focus || value !== '', focus: focus, error: error }">
<div class="input-name">{{text}}</div>
<div class="input-text">
<input :type="type"
@focus="onFocus"
@blur="focus = false"
v-model="changeValue"/>
<i class="iconfont icon-close close" v-show="value !== ''" @click="clear"></i>
</div>
</div>
</div>
</template>
<script lang="ts">
import {Component, Prop, Vue} from 'vue-property-decorator';
@Component
export default class XInput extends Vue {
@Prop({ default: '', type: String }) private value!: string;
@Prop({ default: '', type: String }) private text!: string;
@Prop({ default: 'text', type: String }) private type!: string;
@Prop({ default: false, type: Boolean }) private error!: boolean;
private focus = false;
get changeValue() {
return this.value;
}
set changeValue(val: string) {
this.$emit('input', val);
this.$emit('change', val);
}
private clear() {
this.$emit('input', '');
}
private onFocus() {
this.focus = true;
this.$emit('focus')
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped
lang="less">
.input-container {
.input-name{
top: 12px;
left: 10px;
text-align: left;
padding-left: 2px;
position: absolute;
height: 20px;
line-height: 20px;
transition: 300ms transform;
z-index: 0;
background-color: #fff;
}
.input-text{
position: relative;
display: block;
padding: 2px;
box-sizing: border-box;
z-index: 1;
input{
width: 80vw;
height: 20px;
padding: 5px 10px;
display: inline-block;
vertical-align: top;
line-height: 20px;
background: transparent;
}
}
.input-bd{
margin: 4vw 0;
border: 1px solid #bababa;
border-radius: 4px;
text-align: left;
line-height: 40px;
box-sizing: border-box;
position: relative;
}
.move{
.input-name{
transform: translate3d(-10px, -22px, 0px) scale(0.8);
}
}
.focus{
border: 1px solid #00976e;
.input-name{
color: #00976e;
}
}
.error{
border: 1px solid #e8050a;
.input-name{
color: #e8050a;
}
}
.close{
position: absolute;
display: inline-block;
width: 30px;
height: 30px;
line-height: 30px;
text-align: center;
z-index: 9;
right: 0;
top: 8px;
}
}
</style>
+23 -17
View File
@@ -1,17 +1,23 @@
import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';
import VConsole from 'vconsole';
import './utils/init';
Vue.config.productionTip = false;
// tslint:disable-next-line:no-unused-expression
new VConsole();
new Vue({
router,
store,
render: (h) => h(App),
}).$mount('#app');
import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';
import VConsole from 'vconsole';
import './utils/init';
// 快速点击bug
// import fastClick from 'fastclick';
Vue.config.productionTip = false;
// tslint:disable-next-line:no-unused-expression
if (process.env.NODE_ENV !== 'production') {
new VConsole();
}
// @ts-ignore
// fastClick.attach(document.body);
new Vue({
router,
store,
render: (h) => h(App),
}).$mount('#app');
+20 -20
View File
@@ -1,20 +1,20 @@
import request from '../utils/request';
export default {
register: (userAccount: string, password: string, nickName: string) => request({
url: '/user/register',
body: { userAccount, password, nickName },
}),
login: (userAccount: string, password: string ) => request({
url: '/user/login',
body: { userAccount, password },
}),
createRoom: () => request({
url: '/game/room',
body: { },
}),
buyIn: (buyInSize: number) => request({
url: '/game/buyIn',
body: { buyInSize },
}),
};
import request from '../utils/request';
export default {
register: ({ userAccount = '', password = '', nickName = '' }) => request({
url: '/user/register',
body: { userAccount, password, nickName },
}),
login: (userAccount: string, password: string ) => request({
url: '/user/login',
body: { userAccount, password },
}),
createRoom: () => request({
url: '/game/room',
body: { },
}),
buyIn: (buyInSize: number) => request({
url: '/game/buyIn',
body: { buyInSize },
}),
};
+18 -18
View File
@@ -1,18 +1,18 @@
export default (cards: string []) => {
const cardNumber = [2, 3, 4, 5, 6, 7, 8, 9, 10, 'J', 'Q', 'K', 'A'];
const color = ['♦', '♣', '♥', '♠'];
return cards?.map((c: string) => {
const cNumber = c.charCodeAt(0) - 97;
const cColor = Number(c[1]) - 1;
return [`${cardNumber[cNumber]}`, `${color[cColor]}`];
});
};
const mapCard = (card: string) => {
const cardNumber = [2, 3, 4, 5, 6, 7, 8, 9, 10, 'J', 'Q', 'K', 'A'];
const color = ['♦', '♣', '♥', '♠'];
const cNumber = card.charCodeAt(0) - 97;
const cColor = Number(card[1]) - 1;
return [`${cardNumber[cNumber]}`, `${color[cColor]}`];
}
export { mapCard }
export default (cards: string []) => {
const cardNumber = [2, 3, 4, 5, 6, 7, 8, 9, 10, 'J', 'Q', 'K', 'A'];
const color = ['♦', '♣', '♥', '♠'];
return cards?.map((c: string) => {
const cNumber = c.charCodeAt(0) - 97;
const cColor = Number(c[1]) - 1;
return [`${cardNumber[cNumber]}`, `${color[cColor]}`];
});
};
const mapCard = (card: string) => {
const cardNumber = [2, 3, 4, 5, 6, 7, 8, 9, 10, 'J', 'Q', 'K', 'A'];
const color = ['♦', '♣', '♥', '♠'];
const cNumber = card.charCodeAt(0) - 97;
const cColor = Number(card[1]) - 1;
return [`${cardNumber[cNumber]}`, `${color[cColor]}`];
}
export { mapCard }
+5 -5
View File
@@ -1,5 +1,5 @@
export default {
url: process.env.NODE_ENV !== 'production' ?
process.env.NODE_ENV === 'develop' ? 'http://172.22.72.70:7001'
: 'http://192.168.0.110:7001' : 'http://www.jojgame.com:7001',
}
export default {
url: process.env.NODE_ENV !== 'production' ?
process.env.NODE_ENV === 'develop' ? 'http://172.22.72.70:7001'
: 'http://192.168.0.110:7001' : 'http://www.jojgame.com:7001',
}
+34 -34
View File
@@ -1,34 +1,34 @@
import axios, {AxiosRequestConfig, Method} from 'axios';
import cookie from 'js-cookie';
import origin from '@/utils/origin';
const request = async ({method = 'post' as Method, url = '', body = {}, timeout = 8000}) => {
if (!url) {
return Promise.reject('Request url is null!');
}
const token = cookie.get('token');
const headers = {
Authorization: `Bearer ${token}`,
};
console.log('url', origin.url);
url = `${origin.url}/node${url}`;
const option: AxiosRequestConfig = {
url,
method,
timeout,
data: body,
withCredentials: true,
headers,
};
try {
const result = await axios(option);
if (result.data.code === '000000') {
return result.data;
} else {
throw result.data;
}
} catch (e) {
throw e;
}
};
export default request;
import axios, {AxiosRequestConfig, Method} from 'axios';
import cookie from 'js-cookie';
import origin from '@/utils/origin';
const request = async ({method = 'post' as Method, url = '', body = {}, timeout = 8000}) => {
if (!url) {
return Promise.reject('Request url is null!');
}
const token = cookie.get('token');
const headers = {
Authorization: `Bearer ${token}`,
};
console.log('url', origin.url);
url = `${origin.url}/node${url}`;
const option: AxiosRequestConfig = {
url,
method,
timeout,
data: body,
withCredentials: true,
headers,
};
try {
const result = await axios(option);
if (result.data.code === '000000') {
return result.data;
} else {
throw result.data;
}
} catch (e) {
throw e;
}
};
export default request;
+55 -10
View File
@@ -8,15 +8,17 @@
@click="joinRoom"> <span>join room</span>
</div>
</div>
<div class="room number" v-show="isJoin">
<div class="input-bd">
<div class="input-name">room number:</div>
<div class="input-text">
<input type="tel" maxlength="6"
v-model="roomNumber"/>
<div class="room-number" v-show="isJoin">
<div class="room-input inline">
<div class="input-bd">
<div class="input-name iconfont icon-password"></div>
<div class="input-text">
<input type="tel" maxlength="6"
v-model="roomNumber"/>
</div>
</div>
</div>
<div class="btn">
<div class="room-btn inline">
<span @click="go">go</span>
</div>
</div>
@@ -50,12 +52,55 @@
}
private go() {
this.$router.replace({ name: 'game', params: { roomNumber: this.roomNumber } });
if (/^\d+$/.test(this.roomNumber)) {
this.$router.replace({ name: 'game', params: { roomNumber: this.roomNumber } });
}
}
}
</script>
<style lang="less">
<style lang="less" scoped>
.home-container {
height: 100vh;
display: flex;
flex-direction: row;
align-items: center;
.room-btn{
flex: 1;
.btn{
width: 50vw;
margin:30px auto;
}
}
.room-number{
line-height: 40px;
text-align: center;
width: 100%;
.input-bd{
border: 1px solid #bababa;
border-radius: 4px;
input{
border-radius: 8px;
}
}
.room-btn{
height: 30px;
margin-top: 0;
span{
margin: 0;
line-height: 30px;
height: 30px;
font-size: 12px;
color: #fff;
background-color: #00976e;
border-radius: 8px;
padding: 0 20px;
display: block;
}
}
.inline{
display: inline-block;
vertical-align: middle;
}
}
}
</style>
+29 -6
View File
@@ -21,6 +21,7 @@
</div>
<div class="game-body">
<div class="pot">pot: {{pot}}</div>
<div class="roomId">No.:{{roomId}}</div>
<div class="btn play"
v-show="isOwner && !isPlay"><span @click="play">play game</span></div>
</div>
@@ -80,15 +81,16 @@
<div class="setting-body"
:class="{show: showSetting}">
<i @click="showBuyInDialog()">buy in</i>
<i></i>
<i @click="showCounterRecord">counter record</i>
</div>
</div>
<BuyIn :showBuyIn.sync='showBuyIn'
:min='200'
:max='1000'
@buyIn='buyIn'></BuyIn>
<toast :show="showMsg"
<toast :show.sync="showMsg"
:text="msg"></toast>
<record :players="players" v-model="showRecord"></record>
</div>
</template>
@@ -105,6 +107,7 @@
import BuyIn from '../components/BuyIn.vue';
import range from '../components/range.vue';
import toast from '../components/toast.vue';
import record from '../components/record.vue';
import map from '../utils/map';
import {PokerStyle} from '@/utils/PokerStyle';
import origin from '../utils/origin'
@@ -133,6 +136,7 @@
BuyIn,
range,
toast,
record
},
})
export default class Game extends Vue {
@@ -160,6 +164,7 @@
private msg = '';
private time = 30;
private timeSt = 0;
private showRecord = false;
private raiseSizeMap = {
firsAction: {
two: 2,
@@ -177,7 +182,7 @@
private playerChange(players: IPlayer[]) {
console.log('player change-------');
this.sitList = this.sitList.map((sit: ISit) => {
const player = players.find((p) => p.userId === sit.player?.userId);
const player = players.find((p) => sit.player && p.userId === sit.player.userId && sit.player.counter > 0);
return Object.assign({}, {}, {player, position: sit.position}) as ISit;
});
this.initSitLink();
@@ -268,6 +273,12 @@
this.isRaise = false;
this.winner = [];
this.showBuyIn = false;
this.initSitLink();
}
private showCounterRecord() {
this.showRecord = true;
this.showSetting = false;
}
private doCountDown() {
@@ -488,6 +499,12 @@
if (msg.action === 'newGame') {
this.init();
}
if (msg.action === 'pause') {
this.players = msg.data.players;
this.gaming = false;
this.init();
}
});
// 系统事件
@@ -509,11 +526,12 @@
if (this.currPlayer && (!this.isPlay || !this.hasSit)) {
this.currPlayer.counter += size;
}
console.log('come in buyIn ==================', size)
this.showMsg = true;
this.msg = this.hasSit && this.isPlay ? `已补充买入 ${ size }, 下局生效` : `已补充买入 ${ size }`;
this.emit('buyIn', {
buyInSize: size,
});
this.showMsg = true;
this.msg = this.hasSit ? `已补充买入 ${ size }, 下局生效` : `已补充买入 ${ size }`;
} catch (e) {
console.log(e);
}
@@ -577,7 +595,7 @@
<style lang="less"
scoped>
.game-container {
background: url("../assets/bg.png");
background: radial-gradient(#00bf86, #006a55);
background-size: 100% 100%;
.winner-poke-style {
@@ -596,6 +614,10 @@
left: 50%;
transform: translate3d(-50%, -50%, 0);
z-index: 0;
.roomId{
margin-top: 10px;
font-size: 14px;
}
}
@@ -728,6 +750,7 @@
font-size: 12px;
color: #fff;
background: rgba(0, 0, 0, 0.6);
margin: 1px 0;
}
&.show {
+88 -52
View File
@@ -1,52 +1,88 @@
<template>
<div class="login container">
<div class="user-name input-bd">
<div class="input-name">userName:</div>
<div class="input-text">
<input type="text"
v-model="userAccount"/>
</div>
</div>
<div class="password input-bd">
<div class="input-name">password:</div>
<div class="input-text">
<input type="password"
v-model="password"/>
</div>
</div>
<div class="login-btn btn">
<span @click="login">sign in</span>
<b @click="signUp">sign up</b>
</div>
</div>
</template>
<script lang="ts">
import {Vue} from 'vue-property-decorator';
import service from '../service';
import Component from 'vue-class-component';
import cookie from 'js-cookie';
@Component
export default class Login extends Vue {
public userAccount: string = '';
public password: string = '';
private signUp() {
this.$router.replace({name: 'register'});
return;
}
private async login() {
try {
const result = await service.login(this.userAccount, this.password);
const { token } = result.data;
cookie.set('token', token, {expires: 1});
this.$router.replace({name: 'home'});
} catch (e) {
console.log(e);
}
}
}
</script>
<style lang="less">
</style>
<template>
<div class="login-container container">
<div class="login-body">
<div class="name">J-POKER</div>
<div class="user-name input-bd">
<div class="input-name iconfont icon-account"></div>
<div class="input-text">
<input type="text"
v-model="userAccount"/>
</div>
</div>
<div class="password input-bd">
<div class="input-name iconfont icon-password"></div>
<div class="input-text">
<input type="password"
v-model="password"/>
</div>
</div>
<div class="login-btn btn">
<span @click="login">sign in</span>
<b @click="signUp">sign up</b>
</div>
</div>
</div>
</template>
<script lang="ts">
import {Vue} from 'vue-property-decorator';
import service from '../service';
import Component from 'vue-class-component';
import cookie from 'js-cookie';
@Component
export default class Login extends Vue {
public userAccount: string = '';
public password: string = '';
private signUp() {
this.$router.replace({name: 'register'});
return;
}
private async login() {
try {
const result = await service.login(this.userAccount, this.password);
const { token } = result.data;
cookie.set('token', token, {expires: 1});
this.$router.replace({name: 'home'});
} catch (e) {
console.log(e);
}
}
}
</script>
<style lang="less" scoped>
.login-container{
background: radial-gradient(#00bf86, #006a55);
background-size: 100% 100%;
width: 100vw;
height: 100vh;
padding: 50vw 0;
box-sizing: border-box;
.login-body{
width: 85vw;
margin: auto;
border-radius: 4px;
box-sizing: border-box;
box-shadow: 2px 3px 9px rgba(0, 0, 0, 0.3);
background-color: #fff;
padding: 30px;
.input-bd{
border: 1px solid #bababa;
border-radius: 20px;
width: 60vw;
margin: 30px auto;
text-align: left;
.input-name{
text-align: center;
font-size: 18px;
color: #bababa;
}
input{
height: 40px;
background-color: transparent;
}
}
}
}
</style>
+124 -81
View File
@@ -1,81 +1,124 @@
<template>
<div class="register-container container">
<div class="user-name input-bd">
<div class="input-name">userName:</div>
<div class="input-text">
<input type="text"
v-model="userName"/>
</div>
</div>
<div class="user-name input-bd">
<div class="input-name">nickName:</div>
<div class="input-text">
<input type="text"
v-model="nickName"/>
</div>
</div>
<div class="password input-bd">
<div class="input-name">password:</div>
<div class="input-text">
<input type="password"
v-model="password"/>
</div>
</div>
<div class="re-password input-bd">
<div class="input-name">re-password:</div>
<div class="input-text">
<input type="password"
v-model="rePassword"/>
</div>
</div>
<div class="s-btn btn"><span @click="register">submit</span></div>
<toast :show="showMsg"
:text="msg"></toast>
</div>
</template>
<script lang="ts">
import {Vue} from 'vue-property-decorator';
import service from '../service';
import Component from 'vue-class-component';
import toast from '../components/toast.vue';
@Component({
components: {
toast,
},
})
export default class Register extends Vue {
public userName: string = '';
public password: string = '';
private nickName: string = '';
public rePassword: string = '';
private showMsg = false;
private msg = '';
get valid() {
return this.password === this.rePassword;
}
private async register() {
try {
if (!this.valid) {
console.log('Those password didn\'t match.')
return
}
const result = await service.register(this.userName, this.password, this.nickName);
this.msg = 'sign successful';
this.showMsg = true;
setTimeout(() => {
this.$router.replace({name: 'login'});
}, 2000);
} catch (e) {
this.msg = JSON.stringify(e);
this.showMsg = true;
console.log(e);
}
}
}
</script>
<style lang="less">
</style>
<template>
<div class="register-container container">
<div class="register-body">
<div class="logo">J-POKER</div>
<div class="title">Create Account</div>
<div class="user-name">
<XInput v-model='form.userAccount'
text="account"
@focus="removeValid('userAccount')"
:error="errorData.indexOf('userAccount') > -1"></XInput>
</div>
<div class="user-name">
<XInput v-model='form.nickName'
text="nickName"
@focus="removeValid('nickName')"
:error="errorData.indexOf('nickName') > -1"></XInput>
</div>
<div class="password">
<XInput v-model='form.password'
text="password"
type="password"
@focus="removeValid('password')"
:error="errorData.indexOf('password') > -1"></XInput>
</div>
<div class="confirm">
<XInput v-model='form.confirm'
text="confirm"
type="password"
@focus="removeValid('confirm')"
:error="errorData.indexOf('confirm') > -1"></XInput>
</div>
<div class="register-btn">
<div class="s-btn btn"><span @click="register">submit</span></div>
</div>
</div>
<toast :show="showMsg"
:text="msg"></toast>
</div>
</template>
<script lang="ts">
import {Vue} from 'vue-property-decorator';
import service from '../service';
import Component from 'vue-class-component';
import toast from '../components/toast.vue';
import XInput from '../components/x-input.vue';
@Component({
components: {
toast,
XInput,
},
})
export default class Register extends Vue {
private form: any = {
userAccount: '',
nickName: '',
password: '',
confirm: '',
}
private errorData: string [] = [];
private showMsg = false;
private msg = '';
private valid() {
const errorArr: string[] = [];
for (let formKey in this.form) {
if (this.form[formKey] === '') {
errorArr.push(formKey);
}
}
// confirm password
if (this.form.password !== this.form.confirm) {
errorArr.push('confirm');
errorArr.push('password');
}
this.errorData = errorArr;
}
private removeValid(validName: string) {
this.errorData = this.errorData.join(',').replace(validName, '').split(',');
}
private async register() {
try {
this.valid();
if (this.errorData.join('') === '') {
const result = await service.register(this.form);
this.msg = 'sign successful';
this.showMsg = true;
setTimeout(() => {
this.$router.replace({name: 'login'});
}, 2000);
}
} catch (e) {
this.msg = JSON.stringify(e);
this.showMsg = true;
console.log(e);
}
}
}
</script>
<style lang="less">
.register-container{
padding: 20px;
margin: auto;
.logo{
text-align: left;
margin-bottom: 10px;
font-size: 16px;
font-weight: 700;
}
.title{
text-align: left;
margin-bottom: 5vh;
}
.register-btn{
width: 50vw;
float: right;
margin: auto;
}
}
</style>
+13 -1
View File
@@ -926,6 +926,11 @@
resolved "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7"
integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==
"@types/fastclick@^1.0.29":
version "1.0.29"
resolved "https://registry.npmjs.org/@types/fastclick/-/fastclick-1.0.29.tgz#90f43082848187b42250620f13ec93e32393169b"
integrity sha512-umkMhdAk3dNAenNuhoKPzZUYN9uBHrK8UAvUKWMLst80Gj4BWC1syLuiNzdBzPpM2b2Xg036vvl6X1wiu1Piuw==
"@types/glob@^7.1.1":
version "7.1.1"
resolved "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575"
@@ -2618,6 +2623,13 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
safe-buffer "^5.0.1"
sha.js "^2.4.8"
cross-env@^7.0.2:
version "7.0.2"
resolved "https://registry.npm.taobao.org/cross-env/download/cross-env-7.0.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcross-env%2Fdownload%2Fcross-env-7.0.2.tgz#bd5ed31339a93a3418ac4f3ca9ca3403082ae5f9"
integrity sha1-vV7TEzmpOjQYrE88qco0Awgq5fk=
dependencies:
cross-spawn "^7.0.1"
cross-spawn@^5.0.1:
version "5.1.0"
resolved "https://registry.npm.taobao.org/cross-spawn/download/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
@@ -2638,7 +2650,7 @@ cross-spawn@^6.0.0:
shebang-command "^1.2.0"
which "^1.2.9"
cross-spawn@^7.0.0:
cross-spawn@^7.0.0, cross-spawn@^7.0.1:
version "7.0.2"
resolved "https://registry.npm.taobao.org/cross-spawn/download/cross-spawn-7.0.2.tgz#d0d7dcfa74e89115c7619f4f721a94e1fdb716d6"
integrity sha1-0Nfc+nTokRXHYZ9PchqU4f23FtY=