edit readme,fix some bug,edit client ui

This commit is contained in:
wzdwc
2020-09-12 20:52:18 +08:00
parent 3105f88f97
commit 70ecee7d87
157 changed files with 6409 additions and 7263 deletions
+2
View File
@@ -0,0 +1,2 @@
# Default ignored files
/workspace.xml
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
+67
View File
@@ -0,0 +1,67 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<JSCodeStyleSettings version="0">
<option name="USE_SEMICOLON_AFTER_STATEMENT" value="false" />
<option name="FORCE_SEMICOLON_STYLE" value="true" />
<option name="ALIGN_OBJECT_PROPERTIES" value="2" />
<option name="USE_DOUBLE_QUOTES" value="false" />
<option name="FORCE_QUOTE_STYlE" value="true" />
<option name="ENFORCE_TRAILING_COMMA" value="WhenMultiline" />
<option name="OBJECT_LITERAL_WRAP" value="2" />
<option name="IMPORTS_WRAP" value="0" />
<option name="SPACES_WITHIN_IMPORTS" value="true" />
<option name="CHAINED_CALL_DOT_ON_NEW_LINE" value="false" />
</JSCodeStyleSettings>
<TypeScriptCodeStyleSettings version="0">
<option name="FORCE_SEMICOLON_STYLE" value="true" />
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
<option name="USE_DOUBLE_QUOTES" value="false" />
<option name="FORCE_QUOTE_STYlE" value="true" />
<option name="SPACE_WITHIN_TYPE_ASSERTION" value="true" />
</TypeScriptCodeStyleSettings>
<codeStyleSettings language="JavaScript">
<option name="RIGHT_MARGIN" value="80" />
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
<option name="CALL_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE" value="true" />
<option name="METHOD_CALL_CHAIN_WRAP" value="5" />
<option name="BINARY_OPERATION_WRAP" value="1" />
<option name="TERNARY_OPERATION_WRAP" value="5" />
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
<option name="KEEP_SIMPLE_BLOCKS_IN_ONE_LINE" value="true" />
<option name="KEEP_SIMPLE_METHODS_IN_ONE_LINE" value="true" />
<option name="ARRAY_INITIALIZER_WRAP" value="5" />
<option name="ARRAY_INITIALIZER_LBRACE_ON_NEXT_LINE" value="true" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="TypeScript">
<option name="RIGHT_MARGIN" value="120" />
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
<option name="CALL_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE" value="true" />
<option name="METHOD_CALL_CHAIN_WRAP" value="5" />
<option name="BINARY_OPERATION_WRAP" value="1" />
<option name="TERNARY_OPERATION_WRAP" value="5" />
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
<option name="KEEP_SIMPLE_BLOCKS_IN_ONE_LINE" value="true" />
<option name="KEEP_SIMPLE_METHODS_IN_ONE_LINE" value="true" />
<option name="ARRAY_INITIALIZER_WRAP" value="5" />
<option name="ARRAY_INITIALIZER_LBRACE_ON_NEXT_LINE" value="true" />
<option name="IF_BRACE_FORCE" value="3" />
<option name="DOWHILE_BRACE_FORCE" value="3" />
<option name="WHILE_BRACE_FORCE" value="3" />
<option name="FOR_BRACE_FORCE" value="3" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
</code_scheme>
</component>
+5
View File
@@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>
+6
View File
@@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="TsLint" enabled="true" level="WARNING" enabled_by_default="true" />
</profile>
</component>
+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="TsLintConfiguration" use-custom-config-file="true" custom-config-file-path="$PROJECT_DIR$/tslint.json" />
</project>
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
</project>
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/client.iml" filepath="$PROJECT_DIR$/.idea/client.iml" />
</modules>
</component>
</project>
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>
+22 -18
View File
@@ -1,17 +1,11 @@
# poke-game-front-ts
## Project setup
poke-game-front-ts
=====================
## Setup
```
yarn install
yarn
yarn serve
```
### Compiles and hot-reloads for development
```
yarn run serve
```
### Compiles and minifies for production
```
@@ -24,12 +18,22 @@ yarn run build
yarn run test
```
### Lints and fixes files
## Project structure
```
├─public // html
└─src
├─assets
│ ├─less
│ └─mp3
├─components
├─interface
├─plugins
├─router
├─service // api
├─store
├─utils
└─views
```
yarn run lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).
## License
The MIT License (MIT)
+7 -1
View File
@@ -4,14 +4,18 @@
"private": true,
"scripts": {
"serve": "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",
@@ -19,7 +23,8 @@
"vue-class-component": "^7.2.3",
"vue-property-decorator": "^8.4.1",
"vue-router": "^3.1.6",
"vuex": "^3.1.3"
"vuex": "^3.1.3",
"vux": "^2.9.4"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^4.3.0",
@@ -27,6 +32,7 @@
"@vue/cli-service": "^4.3.0",
"less": "^3.0.4",
"less-loader": "^5.0.0",
"postcss-px-to-viewport": "^1.1.1",
"typescript": "~3.8.3",
"vue-template-compiler": "^2.6.11"
}
+74 -67
View File
@@ -1,67 +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">
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
*{
padding: 0;
margin: 0;
}
body{
box-sizing: border-box;
}
.container{
.input-bd{
line-height: 30px;
margin: 10px;
.input-name{
display: inline-block;
width: 100px;
text-align: right;
}
.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>
+1
View File
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1588773343791" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4283" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M124.2 512c0 214.2 173.6 387.8 387.8 387.8S899.8 726.1 899.8 512 726.2 124.2 512 124.2 124.2 297.8 124.2 512z" fill="#FFD96B" p-id="4284"></path><path d="M786.3 237.9L237.9 786.4c151.5 151.3 396.9 151.3 548.3-0.1 151.4-151.5 151.5-396.9 0.1-548.4z" fill="#FDC223" p-id="4285"></path><path d="M230.1 512c0 155.7 126.2 281.9 281.9 282 155.7 0 281.9-126.2 282-281.9v-0.1c0-155.7-126.2-281.9-281.9-282s-282 126.2-282 282c0-0.1 0-0.1 0 0z" fill="#F9AB10" p-id="4286"></path><path d="M705.3 307.2c-110.4-104.3-284.4-102.7-392.6 5.5-108.1 108.2-109.8 282.2-5.5 392.6 0-0.1 398.1-398.1 398.1-398.1z" fill="#F9B721" p-id="4287"></path><path d="M487.8 591.7h-69.4v-41.4h69.4v-22.4h-69.4v-41.4h48.8L409 368.4h57.6l37.4 79.7c4.8 10 8.1 18.8 10.1 26.4 2.3-8.2 5.7-17.1 10.1-26.4l38.2-79.7H620l-58.9 118.1h49.6v41.4h-70.4v22.4h70.4v41.4h-70.4v87.6h-52.5v-87.6z" fill="#D3830D" p-id="4288"></path><path d="M564.5 479.7l-112 112h35.2v87.6h52.6v-87.6h70.4v-41.4h-70.4v-22.4h70.4v-41.4h-49.6l3.4-6.8z" fill="#BF790A" p-id="4289"></path></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

+64
View File
@@ -0,0 +1,64 @@
@font-face {
font-family: 'iconfont'; /* project id 1801313 */
src: url('//at.alicdn.com/t/font_1801313_4rcv94i1hxw.eot');
src: url('//at.alicdn.com/t/font_1801313_4rcv94i1hxw.eot?#iefix') format('embedded-opentype'),
url('//at.alicdn.com/t/font_1801313_4rcv94i1hxw.woff2') format('woff2'),
url('//at.alicdn.com/t/font_1801313_4rcv94i1hxw.woff') format('woff'),
url('//at.alicdn.com/t/font_1801313_4rcv94i1hxw.ttf') format('truetype'),
url('//at.alicdn.com/t/font_1801313_4rcv94i1hxw.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";
}
.icon-msg:before{
content: "\e781";
}
.icon-record:before{
content: "\e657";
}
.icon-arrow:before{
content: "\e623";
}
body, p,h1,h2,ul,li,input{
padding: 0;
margin: 0;
}
input{
border: 0;
outline: none;
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+300
View File
@@ -0,0 +1,300 @@
<template>
<div class="action-container">
<div class="action"
v-show="isAction">
<div class="action-type action-btn">
<span @click="action('fold')">fold</span>
<span @click="action('check')"
v-show="showActionBtn('check')">check</span>
<span @click="action('call')"
v-show="showActionBtn('call')">call</span>
<span @click="otherSizeHandle()"
v-show="showActionBtn('raise')">more</span>
<span @click="action('allin')"
v-show="!showActionBtn('raise')">allin</span>
</div>
<div class="raise-size">
<div class="not-allin"
v-show="showActionBtn('raise')">
<i v-for="size in raiseSizeMap.firsAction"
@click="raise(size)"
v-show="isPreFlop && pot === 3">
{{Math.floor(size * prevSize)}}
</i>
<i v-for="size in raiseSizeMap.other"
@click="raise(size)"
v-show="showActionSize(size)"
> {{Math.floor(size * pot)}}</i>
<!-- <i @click="raise(pot)">{{pot}}</i>-->
<!-- <i @click="raise(pot * 2)">{{2*pot}}</i>-->
</div>
</div>
<div class="action-other-size"
v-if="isRaise">
<div class="action-other-size-body">
<div class="size"
v-show="currPlayer && raiseSize < currPlayer.counter">
<input type="number" v-model="raiseSize">
</div>
<div class="size"
v-show="currPlayer && raiseSize === currPlayer.counter">Allin
</div>
<range :max="currPlayer && currPlayer.counter"
:min="minActionSize"
:is-horizontal="true"
v-model="raiseSize"
@change="getActionSize"></range>
<div class="btn"
@click="addSize">ok
</div>
</div>
<div class="shadow"
@click="isRaise = false"></div>
</div>
<iAudio :play="playClick" type="click"></iAudio>
<iAudio :play="playFold" type="fold"></iAudio>
<iAudio :play="playRaise" type="raise"></iAudio>
</div>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
import range from './Range.vue';
import iAudio from './Audio.vue';
import { IPlayer } from '@/interface/IPlayer';
@Component({
components: {
range,
iAudio,
},
})export default class Action extends Vue {
@Prop() private isAction: boolean = false;
@Prop() private minActionSize!: number;
@Prop() private pot!: number;
@Prop() private prevSize!: number;
@Prop() private baseSize!: number;
@Prop() private isPreFlop!: boolean;
@Prop() private isTwoPlayer!: boolean;
@Prop() private currPlayer!: IPlayer;
private isRaise = false;
private raiseSize: number = 0;
private actioned = false;
private playClick = false;
private playRaise = false;
private playFold = false;
private raiseSizeMap = {
firsAction: {
two: 2,
three: 3,
four: 4,
},
other: {
oneThirdPot: 0.5,
halfPot: 0.75,
pot: 1,
},
};
@Watch('isAction')
private wAction(val: boolean) {
this.actioned = !val;
this.playClick = false;
this.playRaise = false;
this.playFold = false;
}
@Watch('raiseSize')
private wRaiseSize(val: number) {
this.raiseSize = val > this.currPlayer.counter ? this.currPlayer.counter : val < this.minActionSize
? this.minActionSize
: val;
}
get canActionSize() {
return Number(this.currPlayer && this.currPlayer.counter + this.currPlayer.actionSize);
}
private raise(size: number) {
const realSize = size === 0 ? this.prevSize * 3 : size * this.pot;
this.action(`raise:${Math.floor(realSize)}`);
}
private action(command: string) {
if (command.indexOf('raise') > -1 || command === 'allin' || command === 'call' ) {
this.playRaise = true;
}
if (command === 'fold' || command === 'check') {
this.playFold = true;
}
if (!this.actioned) {
this.actioned = true;
this.$emit('action', command);
// this.isAction = false;
this.isRaise = false;
this.actioned = false;
}
}
private showActionSize(multiple: number) {
// big then double pre-size and small then counter
return this.currPlayer
&& this.currPlayer.counter > Math.floor(multiple * this.pot)
&& this.prevSize * 2 <= Math.floor(multiple * this.pot)
&& this.baseSize * 2 <= Math.floor(multiple * this.pot);
}
private otherSizeHandle() {
this.isRaise = true;
this.raiseSize = this.minActionSize;
}
private getActionSize(size: number) {
this.raiseSize = size;
}
private addSize() {
if (this.raiseSize === this.currPlayer?.counter) {
this.action('allin');
} else {
this.action(`raise:${this.raiseSize}`);
}
}
private showActionBtn(type: string) {
// check
if ('check' === type) {
return this.prevSize <= 0
|| (this.isPreFlop
&& this.isTwoPlayer
&& this.currPlayer?.type === 'd'
&& this.prevSize === 2)
|| (this.currPlayer?.type === 'bb' && this.prevSize === 2 &&
this.isPreFlop);
}
// raise
if ('raise' === type) {
return this.canActionSize > this.prevSize * 2;
}
// call
if ('call' === type) {
return this.canActionSize > this.prevSize
&& this.prevSize > 0
&& !((this.isPreFlop
&& this.isTwoPlayer
&& this.currPlayer?.type === 'd'
&& this.prevSize === 2 * this.baseSize)
|| (this.currPlayer?.type === 'bb' && this.prevSize === 2 * this.baseSize &&
this.isPreFlop));
}
return true;
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="less">
.action-container {
.action {
position: absolute;
color: #fff;
width: 80vw;
top: 65vh;
left: 50%;
transform: translateX(-50%);
.raise-size {
position: absolute;
top: -7vh;
left: 50%;
width: 53vw;
margin-left: -26.4vw;
text-align: center;
i {
padding: 2px;
width: 24px;
height: 24px;
display: inline-block;
font-style: normal;
font-size: 10px;
line-height: 24px;
border-radius: 50%;
color: #fff;
border: 1px solid #fff;
background: rgba(0, 0, 0, .2);
margin: 10px;
vertical-align: middle;
}
}
.action-btn {
span {
border-radius: 50%;
width: 40px;
height: 40px;
padding: 2px;
text-align: center;
margin: 0 10px;
line-height: 40px;
border: 1px solid #fff;
font-size: 14px;
display: inline-block;
}
}
.action-other-size {
background-color: rgba(0, 0, 0, 0);
position: fixed;
width: 50vw;
height: 30vh;
right: -16px;
top: -35vh;
z-index: 90;
.shadow {
position: absolute;
top: -30vh;
width: 99vw;
height: 100vh;
right: -5vw;
z-index: 8;
overflow: hidden;
background: linear-gradient(-70deg, black, transparent);
}
.action-other-size-body {
z-index: 9;
position: absolute;
width: 50vw;
height: 30vh;
.size{
input{
background: transparent;
font-size: 20px;
width: 50px;
text-align: center;
color: #fff;
}
}
.btn {
position: absolute;
top: 34vh;
left: 20vw;
border: 1px solid #fff;
border-radius: 50%;
background-color: rgba(0, 0, 0, 0.4);
padding: 5px;
font-size: 12px;
width: 20px;
height: 20px;
line-height: 20px;
}
}
}
}
}
</style>
+106
View File
@@ -0,0 +1,106 @@
<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"><span>buy in: </span><input type="number" v-model="buyInSize"></div>
<range :max="max"
:min="min"
v-model="buyInSize"
@change="getBuyInSize"></range>
</div>
<div class="btn"><span @click="buyIn">buy in</span></div>
</div>
</div>
</template>
<script lang="ts">
import { Component, Prop, Watch, Vue } from 'vue-property-decorator';
import range from './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;
@Watch('buyInSize')
private wBuyInSize(val: number) {
this.buyInSize = val > this.max ? this.max : val < this.min ? this.min : val;
}
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;
text-align: center;
input{
width: 50px;
font-size: 20px;
}
}
.btn{
margin-top: 20px;
}
}
</style>
+144 -34
View File
@@ -1,53 +1,163 @@
<template>
<div class="common-card-container">
<i></i>
<i></i>
<i></i>
<i></i>
<i></i>
<div class="container">
<div class="common-card-container">
<cardList :card-list="commonCardMap"
:value-cards="valueCards"></cardList>
</div>
</div>
</template>
<script lang="ts">
import {Component, Prop, Vue} from 'vue-property-decorator';
import { Component, Prop, Vue } from 'vue-property-decorator';
import cardList from './CardList.vue';
@Component
export default class SitList extends Vue {
@Prop() private msg!: string;
@Prop() private currPlayer: any;
private sitList: ISit[] = [];
@Component({
components: {
cardList,
},
})
export default class CommonCard extends Vue {
@Prop() private commonCard: any;
@Prop() private valueCards!: string[];
private sitDown(sit: ISit) {
if (!sit.player) {
sit.player = this.currPlayer;
}
}
private mounted() {
for (let i = 0; i < 9; i++) {
const sit = {
position: i + 1,
};
this.sitList.push(sit);
get commonCardMap() {
const arr = [];
if (this.commonCard.length !== 0) {
for (let i = 0; i < 5; i++) {
if (this.commonCard[i]) {
arr.push(this.commonCard[i]);
} else {
arr.push('');
}
}
}
return arr;
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="less">
.common-card-container{
<style scoped
lang="less">
.common-card-container {
position: absolute;
top: 50vh;
left: 50%;
margin: -35px -122px;
i{
background: url("../assets/poke.png");
height: 237/3.5px;
width: 155/3.5px;
background-size: 100% 100%;
display: inline-block;
margin:0 2px;
margin: -38px -114px;
.card {
height: 60px;
width: 40px;
position: absolute;
top: 0;
left: 0;
transform-style: preserve-3d;
opacity: 0;
border-radius: 5px;
i {
background: url("../assets/poke.png");
height: 60px;
width: 40px;
background-size: 100% 100%;
transform: rotateY(0deg) translate3d(0px, 0px, 0px);
backface-visibility: hidden;
position: absolute;
border-radius: 5px;
top: 0;
left: 0;
z-index: 1;
}
.card-bg {
/*background: url("../assets/poke-icon.png");*/
background-size: 100% 100%;
height: 60px;
width: 40px;
border-radius: 5px;
background-color: #fff;
transform: rotateY(180deg) translate3d(0px, 0px, 0px);
backface-visibility: hidden;
position: absolute;
left: 0;
z-index: 0;
display: flex;
flex-direction: column;
transform-style: preserve-3d;
box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3);
&.red {
color: #e8050a;
}
&.black {
color: #000;
}
.number {
text-align: left;
position: absolute;
z-index: -2;
left: 5px;
font-size: 16px;
}
.color {
flex: 1;
font-size: 28px;
line-height: 60px;
}
}
&.show {
display: block;
opacity: 1;
transition: left 1s;
}
&.turn {
animation: turnA 2s forwards;
animation-delay: 2s;
}
&:nth-child(1) {
&.show {
left: 0;
}
}
&:nth-child(2) {
&.show {
left: 44px;
}
}
&:nth-child(3) {
&.show {
left: 44 * 2px;
}
}
&:nth-child(4) {
&.show {
left: 44 * 3px;
}
}
&:nth-child(5) {
&.show {
left: 44 * 4px;
}
}
}
@-webkit-keyframes turnA /* Safari 与 Chrome */ {
from {
transform: rotateY(0deg);
}
to {
transform: rotateY(-180deg);
}
}
}
</style>
+24
View File
@@ -0,0 +1,24 @@
<template>
<div class="audio-container">
</div>
</template>
<script lang="ts">
import {Component, Prop, Vue} from 'vue-property-decorator';
@Component
export default class Emoji extends Vue {
@Prop() private type!: string;
@Prop() private show!: boolean;
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped
lang="less">
.audio-container {
position: absolute;
z-index: -99;
display: none;
}
</style>
+408 -101
View File
@@ -1,100 +1,314 @@
<template>
<div class="sit-list-container">
<div class="sit-list">
<div class="item" v-for="(sit,key) in sitList" :key="key" @click="sitDown(key)">
<div class="default"></div>
<div class="player">
<div class="user-name">test</div>
<div class="icon"></div>
<div class="counter">100</div>
<div class="action-size">200</div>
<div class="action-command">call</div>
<div class="type">bb</div>
<div class="hand-card"></div>
<div
class="sit"
v-for="(sit, key) in sitList"
:key="key"
@click="sitDown(sit)"
>
<div class="default"
v-show="!sit.player">
<i>sit</i>
</div>
<div class="cards">
<div class="hand-card"></div>
<div class="card-style"></div>
<div class="sit-player"
v-if="sit.player">
<div class="player"
:class="{fold: sit.player.status === -1}">
<div class="count-down"
v-show="actionUserId === sit.player.userId">{{time}}
</div>
<div class="user-name"
v-show="sit.player.nickName">
{{ sit.player.nickName }}
</div>
<div class="icon iconfont icon-user-avatar"></div>
<div class="counter"
:class="{isAction: actionUserId === sit.player.userId,
'close-time-out': time > 0 && time < 10 && actionUserId === sit.player.userId }"
v-show="sit.player.counter || sit.player.actionCommand === 'allin'">
{{ sit.player.counter }}
</div>
<div class="action-size"
v-show="sit.player.actionSize > 0">
{{ sit.player.actionSize }}
</div>
<div class="action-command"
v-show="sit.player.actionCommand">
{{ sit.player.actionCommand }}
</div>
<div class="type"
v-show="sit.player.type">
{{ sit.player.type }}
</div>
<div class="hand-card"
v-show="!!!currPlayer || (sit.player.userId !== currPlayer.userId
&& sit.player.handCard
&& sit.player.handCard.length !== 0)">
<cardList :cardList="sit.player.handCard"
:valueCards="valueCards"></cardList>
</div>
<div class="card-style"
v-show="!!!currPlayer || (sit.player.userId !== currPlayer.userId
&& sit.player.handCard
&& sit.player.handCard.length !== 0)">
{{PokeStyle(sit.player.handCard)}}
</div>
</div>
<div class="cards"
v-show="showHandCard(sit)">
<div class="hand-card">
<cardList :cardList="handCard"
:valueCards="valueCards"></cardList>
</div>
<div class="ready"
v-show="handCard && handCard.length === 0">ready
</div>
<div class="card-style"
v-if="commonCard && commonCard.length > 0">{{PokeStyle()}}
</div>
</div>
<div class="win"
v-show="sit.player.income">
<!-- <span>win!</span>-->
<span>{{`+${sit.player.income}`}}</span>
</div>
</div>
</div>
</div>
<BuyIn :showBuyIn.sync="showBuyIn"
:min="0"
:max="1000"
@buyIn='buyIn'></BuyIn>
</div>
</template>
<script lang="ts">
import {Component, Prop, Vue} from 'vue-property-decorator';
import {IUser} from '../../../server/src/interface/IUser';
import { Component, Prop, Watch, Vue } from 'vue-property-decorator';
import { IPlayer } from '@/interface/IPlayer';
import { ILinkNode } from '@/utils/Link';
import ISit from '@/interface/ISit';
import cardList from './CardList.vue';
import BuyIn from '@/components/BuyIn.vue';
import { PokerStyle } from '@/utils/PokerStyle';
import map from '../utils/map';
import {IRoom} from '@/interface/IRoom';
interface ISit {
player?: IUser;
position: number;
}
@Component
@Component({
components: {
cardList,
BuyIn,
},
})
export default class SitList extends Vue {
@Prop() private msg!: string;
@Prop() private currPlayer: any;
private sitList: ISit[] = [];
@Prop() private currPlayer!: IPlayer;
@Prop() private commonCard!: string[];
@Prop() private sitLink!: ILinkNode<ISit>;
@Prop() private handCard!: string[];
@Prop() private winner!: IPlayer[][];
@Prop() private isPlay!: boolean;
@Prop() private roomConfig!: IRoom;
@Prop() private actionUserId!: string;
@Prop() private valueCards!: string;
@Prop({ default: 30, type: Number }) private time!: number;
private sitLinkNode: any = '';
private showBuyIn = false;
private currSit!: ISit;
@Watch('sitLink')
private getSit(val: ILinkNode<ISit>) {
this.sitLinkNode = val;
}
private buyIn(size: number) {
console.log('ccc');
this.showBuyIn = false;
this.currPlayer.counter += size;
this.$emit('buyIn', Number(size));
this.sitDown(this.currSit);
}
private showHandCard(sit: ISit) {
return sit.player?.userId === this.currPlayer?.userId;
}
private PokeStyle(cards: string[]) {
if (this.commonCard.length === 0) {
return '';
}
const commonCard = this.commonCard || [];
let handCard = this.handCard || [];
if (cards) {
handCard = cards;
}
const card = [...handCard, ...commonCard];
const style = new PokerStyle(card, this.roomConfig.isShort);
return style.getPokerStyleName();
}
get handCardString() {
return this.mapCard(this.handCard);
}
get hasSit() {
return !!this.sitList.find((s) => s.player && s.player.userId === this.currPlayer?.userId);
}
private mapCard(cards: string[]) {
return map(cards);
}
private sitDown(sit: ISit) {
if (!sit.player) {
sit.player = this.currPlayer;
if (!sit.player && (!this.isPlay || !this.hasSit)) {
if (this.currPlayer.counter <= 0) {
this.showBuyIn = true;
this.currSit = sit;
return;
}
let sitNode = this.sitLinkNode;
for (let i = 0; i < 9; i++) {
if (sitNode) {
const next = sitNode.next;
if (sitNode.node.player?.nickName === this.currPlayer?.nickName) {
delete sitNode.node.player;
}
sitNode = next as ILinkNode<ISit>;
}
}
for (let i = 0; i < 9; i++) {
if (sitNode) {
const next = sitNode.next;
if (sit.position === sitNode.node.position) {
sitNode.node.player = this.currPlayer as IPlayer;
this.$emit('update:sitLink', sitNode);
this.$emit('sit', sitNode);
break;
}
sitNode = next as ILinkNode<ISit>;
}
}
}
}
private mounted() {
for (let i = 0; i < 9; i++) {
const sit = {
position: i + 1,
};
this.sitList.push(sit);
get sitList() {
const sitMap: ISit[] = [];
if (this.sitLinkNode) {
let link = this.sitLinkNode;
for (let i = 0; i < 9; i++) {
if (
link.node.player &&
link.node.player.userId === this.currPlayer?.userId
) {
this.sitLinkNode = link;
break;
}
const next = link.next;
link = next as ILinkNode<ISit>;
}
let sitNode = this.sitLinkNode;
for (let i = 0; i < 9; i++) {
const next = sitNode.next;
sitMap.push(sitNode.node);
sitNode = next as ILinkNode<ISit>;
}
console.log('sit', sitMap);
return sitMap;
}
return [];
}
private mounted() {
this.sitLinkNode = this.sitLink;
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="less">
<style scoped
lang="less">
.sit-list-container {
display: flex;
flex-direction: row-reverse;
align-items: center;
height: 100vh;
width: 100vw;
.sit-list {
position: relative;
width: 100vw;
height: 620px;
height: 620 / 6.67vh;
padding: 10px;
margin:0 15px;
margin: 0 15px;
box-sizing: border-box;
.item {
.sit {
position: absolute;
font-size: 12px;
.player{
position: relative;
.icon{
width: 45px;
height: 45px;
background: url("../assets/poke-icon.png") #fff;
background-size: 100% 100%;
border-radius: 2px;
.default {
i {
width: 45 / 3.75vw;
height: 45 / 3.75vw;
border-radius: 50%;
border: 1px solid #bababa;
margin-bottom: 2px;
}
.user-name{
display: block;
font-style: normal;
font-size: 20px;
line-height: 45 / 3.75vw;
color: #fff;
}
.counter{
background-color: rgba(0,0,0,0.8);
}
.player {
position: relative;
.icon {
width: 45 / 3.75vw;
height: 45 / 3.75vw;
font-size: 45px;
line-height: 45 / 3.75vw;
border-radius: 50%;
margin-bottom: 2px;
}
.user-name {
color: #fff;
}
.count-down {
height: 7vh;
line-height: 9vh;
width: 12vw;
position: absolute;
left: 0;
top: 14px;
color: #fff;
font-weight: 700;
font-size: 20px;
background-image: linear-gradient(0deg, rgba(0, 0, 0, 0.3), transparent);
}
.counter {
background-color: rgba(0, 0, 0, 0.6);
color: #fff;
font-weight: 600;
font-size: 12px;
border-radius: 2px;
&.isAction {
box-shadow: 0px 0px 6px 4px;
}
&.close-time-out {
animation: 300ms timeOut infinite;
}
}
.action-command{
top: 15px;
left: 45px;
.action-command {
top: 15 / 6.67vh;
left: 45 / 3.75vw;
padding: 1px 8px;
border-radius: 9px;
color: #ffffff;
@@ -102,102 +316,195 @@
text-shadow: 1px 2px 3px rgba(0, 0, 0, 0.3);
position: absolute;
}
.type{
.card-style {
color: #fff;
}
.type {
background-color: #fff;
color: #2b2b2b;
border-radius: 50%;
padding: 2px;
width: 18px;
height: 18px;
line-height: 18px;
width: 15 / 3.75vw;
height: 15px;
line-height: 16px;
position: absolute;
top: 53px;
left: 38px;
top: 53 / 6.67vh;
left: 38 / 3.75vw;
font-size: 12px;
transform: scale(0.8);
}
.action-size{
background-color: rgba(0, 0, 0, 0.3);
.action-size {
background: rgba(0, 0, 0, 0.3) url("../assets/gold.svg") center left no-repeat;
background-size: contain;
border-radius: 2px;
padding:1px 4px;
padding: 1px 4px 1px 12px;
text-align: center;
min-width: 35px;
min-width: 35 / 3.75vw;
color: #fff;
font-weight: 600;
position: absolute;
top: 35px;
left: 40px;
top: 35 / 6.67vh;
left: 40 / 3.75vw;
}
&.fold {
opacity: 0.4;
}
}
.hand-card {
position: absolute;
top: 1vh;
}
&:nth-child(1) {
left: 75px;
top: 0;
left: 100 / 3.75vw;
top: 460 / 6.67vh;
.action-command {
left: -22 / 3.75vw;
}
.type {
left: -16 / 3.75vw;
}
.action-size {
top: -5 / 6.67vh;
left: 57 / 3.75vw;
padding-right: 15px;
text-align: right;
}
}
&:nth-child(2) {
left: 240px;
top: 0;
left: 0;
top: 330 / 6.67vh;
}
&:nth-child(3) {
left: 296px;
top: 100px;
left: 0;
top: 210 / 6.67vh;
}
&:nth-child(4) {
left: 296px;
top: 200px;
left: 0;
top: 100 / 6.67vh;
}
&:nth-child(5) {
left: 296px;
top: 330px;
left: 75 / 3.75vw;
top: 0;
}
&:nth-child(6) {
left: 100px;
top: 460px;
.action-command{
left: -22px;
}
.type{
left: -16px;
}
.action-size{
top: -5px;
left: 57px;
padding-right: 15px;
text-align: right;
}
left: 240 / 3.75vw;
top: 0;
}
&:nth-child(7) {
left: 0;
top: 330px;
left: 296 / 3.75vw;
top: 100 / 6.67vh;
}
&:nth-child(8) {
left: 0;
top: 200px;
left: 296 / 3.75vw;
top: 210 / 6.67vh;
}
&:nth-child(9) {
left: 0;
top: 100px;
left: 296 / 3.75vw;
top: 330 / 6.67vh;
}
&:nth-child(2),&:nth-child(3),&:nth-child(4),&:nth-child(5){
.action-command{
left: -22px;
&:nth-child(6),
&:nth-child(7),
&:nth-child(8),
&:nth-child(9) {
.action-command {
left: -22 / 3.75vw;
}
.type{
left: -16px;
.type {
left: -16 / 3.75vw;
}
.action-size{
left: -40px;
padding-right: 15px;
.action-size {
background-position: right;
left: -40 / 3.75vw;
padding-left: 1px;
padding-right: 17px;
text-align: right;
}
.hand-card {
left: -3vh;
top: 0;
}
}
.cards {
position: absolute;
left: 52 / 3.75vw;
top: 20 / 6.67vh;
min-width: 60 / 3.75vw;
min-height: 60 / 6.67vh;
line-height: 60 / 6.67vh;
.ready {
font-size: 14px;
display: inline-block;
vertical-align: middle;
}
.card-style {
position: absolute;
color: #fff;
font-size: 14px;
bottom: -48px;
width: 60 / 3.75vw;
text-align: center;
font-weight: 700;
}
}
.win {
position: absolute;
z-index: 8;
left: 0;
top: 4vh;
font-size: 20px;
color: rgba(255, 209, 0, 0.99);
font-weight: 600;
animation: fadeOut 4s forwards;
background-image: linear-gradient(to top, rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0));
}
}
}
@-webkit-keyframes fadeOut /* Safari Chrome */ {
0% {
transform: translate3d(2px, 0, 0);
opacity: 1;
}
30% {
transform: translate3d(2px, 0, 0);
opacity: 1;
}
to {
transform: translate3d(2px, -15px, 0);
opacity: 0;
}
}
@-webkit-keyframes timeOut /* Safari Chrome */ {
0% {
box-shadow: none;
}
100% {
box-shadow: 0px 0px 6px 4px;
}
}
}
+130
View File
@@ -0,0 +1,130 @@
<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>
+46
View File
@@ -0,0 +1,46 @@
<template>
<div class="audio-container">
<audio ref="click" controls>
<source src="../assets/mp3/click.mp3" type="audio/mpeg">
Your browser does not support the audio element.
</audio>
<audio ref="raise" controls>
<source src="../assets/mp3/raise.mp3" type="audio/mpeg">
Your browser does not support the audio element.
</audio>
<audio ref="fold" controls>
<source src="../assets/mp3/fold.mp3" type="audio/mpeg">
Your browser does not support the audio element.
</audio>
<audio ref="income" controls>
<source src="../assets/mp3/income.mp3" type="audio/mpeg">
Your browser does not support the audio element.
</audio>
</div>
</template>
<script lang="ts">
import {Component, Prop, Vue, Watch} from 'vue-property-decorator';
@Component
export default class Audio extends Vue {
@Prop() private type!: string;
@Prop() private play!: boolean;
@Watch('play')
private wPlay(val: boolean) {
if (val) {
(this.$refs[this.type] as HTMLAudioElement).play();
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped
lang="less">
.audio-container {
position: absolute;
z-index: -99;
display: none;
}
</style>
+191
View File
@@ -0,0 +1,191 @@
<template>
<div class="card-container">
<div
class="card"
v-for="(card, key) in cardList"
v-bind:class="{ show: show, turn: show && card !== '' }"
>
<i></i>
<span class="card-bg red"
:class="{ black : isBlack(map(card)[1])}">
<div class="shadow"
v-show="shadow(card)"></div>
<b class="number">{{ map(card)[0] }}</b>
<b class="color">{{ map(card)[1] }}</b>
<b class="color big">{{ map(card)[1] }}</b>
</span>
</div>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
import { mapCard } from '@/utils/map';
@Component
export default class Card extends Vue {
@Prop() private cardList: any;
@Prop({ default: () => [], type: Array }) private valueCards!: string[];
get show() {
return this.cardList.length !== 0;
}
private isBlack(type: string) {
return type === '♠' || type === '♣';
}
private map(card: string) {
return mapCard(card);
}
private shadow(card: string) {
if (this.valueCards.length === 0 || card === '') {
return false;
}
return this.valueCards.indexOf(card) < 0;
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped
lang="less">
.card-container {
.card {
height: 60px;
width: 40px;
position: absolute;
top: 0;
left: 0;
transform-style: preserve-3d;
opacity: 0;
border-radius: 5px;
z-index: 0;
i {
background: url("../assets/poke.png");
height: 60px;
width: 40px;
background-size: 100% 100%;
transform: rotateY(0deg) translate3d(0px, 0px, 0px);
backface-visibility: hidden;
position: absolute;
border-radius: 5px;
top: 0;
left: 0;
z-index: 1;
}
.card-bg {
/*background: url("../assets/poke-icon.png");*/
background-size: 100% 100%;
height: 60px;
width: 40px;
border-radius: 5px;
background-color: #fff;
transform: rotateY(180deg) translate3d(0px, 0px, 0px);
backface-visibility: hidden;
position: absolute;
left: 0;
z-index: 0;
display: flex;
flex-direction: column;
transform-style: preserve-3d;
box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3);
.shadow {
width: 40px;
height: 60px;
left: 0;
top: 0;
border-radius: 5px;
position: absolute;
z-index: 1;
background: rgba(0, 0, 0, 0.4);
}
&.red {
color: #e8050a;
}
&.black {
color: #000;
}
.number {
text-align: left;
position: absolute;
left: 5px;
font-size: 16px;
line-height: 25px;
font-family: initial;
}
.color {
position: absolute;
left: 5px;
top: -2px;
font-size: 20px;
line-height: 60px;
font-family: Arial;
&.big {
left: 15px;
font-size: 35px;
top: 12px;
}
}
}
&.show {
display: block;
opacity: 1;
transition: left 1s;
}
&.turn {
animation: turnA 1s forwards;
animation-delay: 1s;
}
&:nth-child(1) {
&.show {
left: 0;
}
}
&:nth-child(2) {
&.show {
left: 44px;
}
}
&:nth-child(3) {
&.show {
left: 44 * 2px;
}
}
&:nth-child(4) {
&.show {
left: 44 * 3px;
}
}
&:nth-child(5) {
&.show {
left: 44 * 4px;
}
}
}
@-webkit-keyframes turnA /* Safari 与 Chrome */ {
from {
transform: rotateY(0deg);
}
to {
transform: rotateY(-180deg);
}
}
}
</style>
+236
View File
@@ -0,0 +1,236 @@
<template>
<div class="record-container" :class="{show:show}">
<div class="shadow"
@click="show = false"></div>
<div class="body">
<div class="title">record</div>
<div class="record-context">
<ul class = 'td'>
<div class="lo">
<span class="player">player</span>
<i>commonCard</i>
<span class="pot">pot</span>
</div>
</ul>
<ul class="record-box">
<li v-for="player in commandList">
<div class="player">
<Player :player="player" :is-small="true"></Player>
</div>
<div class="commandCard">
<cardList :card-list="commonCardMap(player.commonCard)"
:value-cards="valueCard"
></cardList>
</div>
<div class="pot">
<span>{{player.pot}}</span>
</div>
</li>
</ul>
<div class="record-btn">
<i class="iconfont icon-arrow" :class="{ disable: currGameIndex === 1 }" @click="getRecord(-1)"></i>
<span>{{currGameIndex}}</span>
<i class="iconfont icon-arrow right" :class="{ disable: currGameIndex === maxIndex }" @click="getRecord(1)"></i>
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
import { IPlayer } from '@/interface/IPlayer';
import Player from './Player.vue';
import CardList from '@/components/CardList.vue';
import { IGameRecord } from '@/interface/IGameRecord';
@Component({
components: {
CardList,
Player,
},
})
export default class Record extends Vue {
@Prop() private value!: boolean;
@Prop() private gameList!: IGameRecord [];
@Prop() private commandList!: IPlayer[];
@Prop() private currGameIndex!: number;
private valueCard = [];
get show() {
return this.value;
}
set show(val) {
this.$emit('input', val);
}
get maxIndex() {
return this.gameList.length;
}
private getRecord(type: number) {
const index = this.currGameIndex + type;
if (index > this.maxIndex || index <= 0) {
return;
}
this.$emit('getRecord', index);
}
private commonCardMap(commonCard: string) {
const commonCardArr = commonCard.split(',');
const arr = [];
for (let i = 0; i < 5; i++) {
if (commonCardArr[i]) {
arr.push(commonCardArr[i]);
} else {
arr.push('');
}
}
return arr;
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped
lang="less">
.record-container {
position: absolute;
right: 0;
top: 0;
width: 100vw;
height: 100vh;
overflow: hidden;
display: none;
&.show{
display: block;
.body{
animation: 0.3s move forwards;
}
}
.shadow {
background: rgba(0, 0, 0, 0.3);
left: 0;
top: 0;
right: 0;
bottom: 0;
position: fixed;
z-index: 1;
}
.body {
width: 90vw;
height: 100vh;
color: #fff;
background: #006a55;
position: absolute;
right: 0;
top: 0;
z-index: 9999;
overflow: hidden;
transform: translate3d(100vw, 0, 0);
display: flex;
flex-direction: column;
.record-context{
display: flex;
flex-direction: column;
overflow: hidden;
flex: 1;
.record-box{
flex: 1;
overflow: auto;
}
}
}
.title {
color: #fff;
text-align: left;
line-height: 30px;
height: 30px;
padding: 5px 10px;
border-bottom: 1px solid #fff;
}
.td{
height:30px;
}
ul {
.pot{
width: 10vw;
font-size: 11px;
line-height: 58px;
span{
display: inline-block;
vertical-align: middle;
}
}
.player{
width: 16vw;
}
.lo {
display: flex;
i {
flex: 1;
padding: 5px 10px;
line-height: 20px;
display: inline-block;
font-style: normal;
font-size: 14px;
}
span {
padding: 5px 10px;
line-height: 20px;
display: inline-block;
font-style: normal;
font-size: 14px;
}
.pot{
line-height: 18px;
font-size: 14px;
}
}
li{
padding: 0 6px;
display: flex;
height: 90px;
.commandCard{
flex: 1;
position: relative;
transform: scale(0.7);
}
}
}
.record-btn{
height: 50px;
width: 100%;
line-height: 50px;
i{
transform: rotate(90deg);
display: inline-block;
vertical-align: middle;
font-size: 40px;
&.right{
transform: rotate(270deg);
}
&.disable{
opacity: .4;
}
}
span{
display: inline-block;
vertical-align: middle;
}
}
@-webkit-keyframes move /* Safari 与 Chrome */ {
0% {
transform: translate3d(100vw,0,0);
}
100% {
transform: translate3d(0, 0px, 0px);
}
}
}
</style>
+59
View File
@@ -0,0 +1,59 @@
<template>
<div class="notice-container">
<div class="notice-body">
<i v-for="message in messageList"
v-if="message !== ''"
:style="{top: `${message.top}vh`}"
>{{message.message}}</i>
</div>
</div>
</template>
<script lang="ts">
import {Component, Prop, Watch, Vue} from 'vue-property-decorator';
@Component
export default class Notice extends Vue {
@Prop() private messageList!: any[];
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped
lang="less">
.notice-container {
.notice-body{
position: fixed;
top: 0;
left: 0;
width: 100vw;
i{
position: absolute;
top: 20px;
left: 0;
transform: translate3d(100vw,0,0);
z-index: 10;
animation: 4s move linear forwards;
color: #fff;
padding: 4px;
font-size: 12px;
font-style: normal;
border-radius: 2px;
background-color: rgba(0,0,0,0.4);
}
}
@-webkit-keyframes move /* Safari 与 Chrome */ {
0% {
transform: translate3d(100vw,0,0);
}
99%{
transform: translate3d(-198px, 0px, 0px);
opacity: 1;
}
100% {
transform: translate3d(-200px, 0px, 0px);
opacity: 0;
}
}
}
</style>
+176
View File
@@ -0,0 +1,176 @@
<template>
<div class="sit-container">
<div class="sit-player"
v-if="player" :class="{ small: isSmall }">
<div class="player"
:class="{fold: player.status === -1}">
<div class="user-name"
v-show="player.nickName">
{{ player.nickName }}
</div>
<div class="icon iconfont icon-user-avatar"></div>
<div class="counter"
v-show="player.counter || player.command === 'allin'">
{{ player.counter }}
</div>
<div class="action-size"
v-show="player.actionSize > 0">
{{ player.actionSize }}
</div>
<div class="action-command"
v-show="player.command">
{{ player.command }}
</div>
<div class="type"
v-show="player.type">
{{ player.type }}
</div>
<div class="hand-card"
v-show="player.handCard !== ''">
<cardList :cardList="player.handCard.split(',')"></cardList>
</div>
<div class="card-style"
v-show="player.handCard !== '' && player.commonCard !== ''">
{{PokeStyle(player.handCard, player.commonCard)}}
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
import cardList from './CardList.vue';
import { PokerStyle } from '@/utils/PokerStyle';
@Component({
components: {
cardList,
},
})
export default class Player extends Vue {
@Prop() private player!: any;
@Prop() private isSmall!: boolean;
private PokeStyle(cards: string, commonCard: string) {
if (commonCard === '' || cards === '') {
return '';
}
const commonCardArr = commonCard.split(',');
const cardsArr = cards.split(',');
const card = [...cardsArr, ...commonCardArr];
const style = new PokerStyle(card);
return style.getPokerStyleName();
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="less">
.sit-container {
.small{
transform: scale(0.9);
}
.player {
position: relative;
font-size: 14px;
width: 50 / 3.75vw;
.icon {
width: 45 / 3.75vw;
height: 45 / 3.75vw;
font-size: 45px;
line-height: 45 / 3.75vw;
border-radius: 50%;
margin-bottom: 2px;
}
.user-name {
color: #fff;
}
.count-down {
height: 7vh;
line-height: 9vh;
width: 12vw;
position: absolute;
left: 0;
top: 14px;
color: #fff;
font-weight: 700;
font-size: 20px;
background-image: linear-gradient(0deg, rgba(0, 0, 0, 0.3), transparent);
}
.counter {
background-color: rgba(0, 0, 0, 0.6);
color: #fff;
font-weight: 600;
font-size: 12px;
border-radius: 2px;
&.isAction {
box-shadow: 0px 0px 6px 4px;
}
&.close-time-out {
animation: 300ms timeOut infinite;
}
}
.action-command {
top: 15 / 6.67vh;
left: 45 / 3.75vw;
padding: 1px 8px;
border-radius: 9px;
color: #ffffff;
background-color: #2c3e50;
text-shadow: 1px 2px 3px rgba(0, 0, 0, 0.3);
position: absolute;
}
.card-style {
color: #fff;
}
.type {
background-color: #fff;
color: #2b2b2b;
border-radius: 50%;
padding: 2px;
width: 15 / 3.75vw;
height: 15px;
line-height: 16px;
position: absolute;
top: 53 / 6.67vh;
left: 38 / 3.75vw;
font-size: 12px;
transform: scale(0.8);
}
.action-size {
background: rgba(0, 0, 0, 0.3) url("../assets/gold.svg") center left no-repeat;
background-size: contain;
border-radius: 2px;
padding: 1px 4px 1px 12px;
text-align: center;
min-width: 35 / 3.75vw;
color: #fff;
font-weight: 600;
position: absolute;
top: 35 / 6.67vh;
left: 40 / 3.75vw;
}
&.fold {
opacity: 0.4;
}
.hand-card{
position: absolute;
left: 0;
top: 2vh;
transform: scale(0.7);
}
}
}
</style>
+98
View File
@@ -0,0 +1,98 @@
<template>
<div class="slide-bar-container">
<!-- <div class="value">{{raiseSize}}</div>-->
<div class="range-body">
<input type="range"
v-model="rangeSize"
:class="{horizontal: !!isHorizontal}">
</div>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
@Component
export default class Range extends Vue {
@Prop({ type: Number, default: 1000 }) private max!: number;
@Prop({ type: Number, default: 100 }) private min!: number;
@Prop() private value!: any;
@Prop({ type: Boolean, default: false }) private isHorizontal!: boolean;
private rangeRound = (this.max - this.min) / 100;
get rangeSize() {
const valNum = Number(this.value);
const size = valNum >= this.max ? this.max / this.rangeRound :
valNum < this.min ? 0 : (valNum - this.min) / this.rangeRound;
return size;
}
set rangeSize(val) {
const valNum = Number(val);
const size = Number(val) === 0 ? this.min : Math.floor(valNum / 100 * (this.max - this.min)) +
this.min;
console.log('size', size);
this.$emit('change', size);
this.$emit('input', size);
}
// @Watch('range')
// private raiseSize(val: string) {
// const valNum = Number(val);
// const size = Number(val) === 0 ? this.min : Math.floor(valNum / 100 * (this.max - this.min)) +
// this.min;
// console.log('size', size);
// this.$emit('change', size);
// }
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped
lang="less">
.slide-bar-container {
.range-body {
line-height: 10px;
}
.value {
margin-bottom: 10px;
}
input[type=range] {
-webkit-appearance: none;
width: 200px;
border-radius: 10px; /*这个属性设置使填充进度条时的图形为圆角*/
vertical-align: middle;
display: inline-block;
&.horizontal {
transform: rotateZ(-90deg) translate3d(-50%, 0, 0);
transform-origin: center;
margin-left: -8px;
}
}
input[type=range]:focus {
outline: none;
}
input[type=range]::-webkit-slider-thumb {
-webkit-appearance: none;
height: 30px;
width: 30px;
margin-top: -12px; /*使滑块超出轨道部分的偏移量相等*/
background: #ffffff;
border-radius: 50%; /*外观设置为圆形*/
border: solid 0.125em rgba(205, 224, 230, 0.5); /*设置边框*/
box-shadow: 0 .125em .125em #3b4547; /*添加底部阴影*/
}
input[type=range]::-webkit-slider-runnable-track {
height: 6px;
border-radius: 10px; /*将轨道设为圆角的*/
box-shadow: 0 1px 1px #def3f8, inset 0 .125em .125em #0d1112; /*轨道内置阴影效果*/
}
}
</style>
+101
View File
@@ -0,0 +1,101 @@
<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);
}
}
</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;
z-index: 9999;
.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>
+80
View File
@@ -0,0 +1,80 @@
<template>
<div class="send-msg-container">
<div class="send-msg-body">
<div class="msg-name iconfont icon-msg"></div>
<div class="msg-input">
<input type="text"
v-model='msg'>
</div>
<div class="msg-btn btn"
@click="send"><span>send</span></div>
</div>
</div>
</template>
<script lang="ts">
import { Component, Prop, Watch, Vue } from 'vue-property-decorator';
@Component
export default class SendMsg extends Vue {
private msg: string = '';
private send() {
if (this.msg !== '') {
this.$emit('send', this.msg);
this.msg = '';
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped
lang="less">
.send-msg-container {
position: fixed;
.send-msg-body {
position: fixed;
width: 100vw;
height: 25px;
padding: 10px 0;
left: 0;
bottom: 0;
background-color: #fff;
font-size: 12px;
display: flex;
align-items: center;
.msg-name {
width: 40px;
font-size: 30px;
color: #009870;
text-align: center;
}
.msg-input {
flex: 1;
border: 1px solid #bababa;
text-align: left;
input {
height: 20px;
width: 90%;
padding: 0 5px;
font-size: 12px;
}
}
.msg-btn {
width: 80px;
margin-top: 0;
margin-left: 0;
text-align: center;
span {
padding: 5px 10px;
}
}
}
}
</style>
+62
View File
@@ -0,0 +1,62 @@
<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: 3000, type: Number }) private timeOut!: number;
private Time: any;
get showValue() {
console.log('come in1111', this.show);
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: 4px 10px;
background: rgba(0, 0, 0, 0.6);
text-align: center;
color: #fff;
font-size: 12px;
position: fixed;
top: 50%;
left: 50%;
transform: translate3d(-50%, -50%, 0);
border-radius: 4px;
line-height: 16px;
}
}
</style>
+3
View File
@@ -0,0 +1,3 @@
export interface IGameRecord {
gameId: number;
}
+19
View File
@@ -0,0 +1,19 @@
enum PlayerType {
READY,
SIT_DOWN,
GAMING,
}
export interface IPlayer {
counter: number;
nickName: string;
actionSize: number;
actionCommand: string;
type: string;
userId?: number;
handCard?: string[];
buyIn: number;
status: number;
income?: number;
isSit: boolean;
}
+6
View File
@@ -0,0 +1,6 @@
export interface IRoom {
roomNumber?: string;
isShort: boolean;
time?: number;
smallBlind: number;
}
+6
View File
@@ -0,0 +1,6 @@
import { IPlayer } from '@/interface/IPlayer';
export default interface ISit {
player: IPlayer | null;
position: number;
}
+7
View File
@@ -0,0 +1,7 @@
export interface IUser {
nickName: string;
counter: number;
userId?: number;
buyIn: number;
account: string;
}
-10
View File
@@ -1,10 +0,0 @@
export interface IUser {
counter: number;
nick_name: string;
actionSize: number;
actionCommand: string;
type: string;
userId?: number;
handCard?: string[];
buyIn: number;
}
+12 -2
View File
@@ -3,11 +3,21 @@ import App from './App.vue';
import router from './router';
import store from './store';
import VConsole from 'vconsole';
import './utils/init';
import toastPlugin from './plugins/toast';
// 快速点击bug
// import fastClick from 'fastclick';
Vue.use(toastPlugin);
Vue.config.productionTip = false;
// tslint:disable-next-line:no-unused-expression
new VConsole();
if (process.env.NODE_ENV !== 'production') {
// tslint:disable-next-line:no-unused-expression
new VConsole();
}
// @ts-ignore
// fastClick.attach(document.body);
new Vue({
router,
+12
View File
@@ -0,0 +1,12 @@
import Vue from 'vue';
import { ToastExtendConstructor, IOptions } from '../src/plugins/toast';
interface IPlugin {
toast(options: string | IOptions): ToastExtendConstructor;
}
declare module 'vue/types/vue' {
interface Vue {
$plugin: IPlugin;
}
}
+69
View File
@@ -0,0 +1,69 @@
import Vue, { PluginObject } from 'vue';
import Toast from '../components/Toast.vue';
export interface IOptions {
text?: string;
timeOut?: number;
}
const ToastConstructor = Vue.extend(Toast);
export class ToastExtendConstructor extends ToastConstructor {
public close() {
this.$props.show = false;
this.$off('update:show');
}
}
let instance: ToastExtendConstructor;
let defaultOptions: IOptions;
const getInstance = () => {
if (instance) { return instance; }
instance = new ToastExtendConstructor({
el: document.createElement('div'),
});
return instance;
};
const toast = (options: string | IOptions) => {
const vm = getInstance();
if (!defaultOptions) {
defaultOptions = { ...vm.$props };
}
let opts: IOptions;
if (typeof options === 'string') {
opts = { ...defaultOptions, text: options };
} else {
opts = { ...defaultOptions, ...options };
}
Object.keys(opts).forEach((key) => {
vm.$props[key] = opts[key as keyof IOptions];
});
console.log(vm.$props);
vm.$props.show = true;
vm.$off('update:show');
vm.$on('update:show', (val: boolean) => {
vm.$props.show = val;
});
document.body.appendChild(vm.$el);
return vm;
};
const plugin: PluginObject<Vue> = {
// tslint:disable-next-line:no-shadowed-variable
install(Vue) {
if (!Vue.prototype.$plugin) {
Vue.prototype.$plugin = {};
}
Vue.prototype.$plugin.toast = toast;
},
};
export default plugin;
+70 -37
View File
@@ -1,37 +1,70 @@
import Vue from 'vue';
import VueRouter, { RouteConfig } from 'vue-router';
import Home from '../views/Home.vue';
import Login from '../views/login.vue';
import Register from '../views/register.vue';
import Game from '../views/game.vue';
Vue.use(VueRouter);
const routes: RouteConfig[] = [
{
path: '/',
name: 'home',
component: Home,
},
{
path: '/login',
name: 'login',
component: Login,
},
{
path: '/register',
name: 'register',
component: Register,
},
{
path: '/game/:roomNumber/:isOwner?',
name: 'game',
component: Game,
},
];
const router = new VueRouter({
routes,
});
export default router;
import Vue from 'vue';
import VueRouter, { RouteConfig } from 'vue-router';
import Home from '../views/home.vue';
import Login from '../views/login.vue';
import Register from '../views/register.vue';
import Game from '../views/game.vue';
import service from '../service';
import origin from '../utils/origin';
Vue.use(VueRouter);
const routes: RouteConfig[] = [
{
path: '/',
name: 'home',
component: Home,
meta: {
title: 'home',
needLogin: true,
},
},
{
path: '/login',
name: 'login',
component: Login,
meta: {
title: 'login',
},
},
{
path: '/register',
name: 'register',
component: Register,
meta: {
title: 'create account',
},
},
{
path: '/game/:roomNumber/:isOwner?',
name: 'game',
component: Game,
meta: {
title: 'game',
needLogin: true,
},
},
];
const router = new VueRouter({
routes,
});
router.beforeEach(async (to, from, next) => {
if (to.meta.title) {
document.title = to.meta.title;
}
if (to.meta.needLogin) {
try {
const result = await service.checkLogin();
console.log(result);
next();
} catch (e) {
await router.replace({ name: 'login' });
}
} else {
next();
}
});
export default router;
+21 -5
View File
@@ -1,20 +1,36 @@
import request from '../utils/request';
export default {
register: (userName: string, password: string) => request({
register: ({ userAccount = '', password = '', nickName = '' }) => request({
url: '/user/register',
body: { userName, password },
body: { userAccount, password, nickName },
}),
login: (userAccount: string, password: string) => request({
login: (userAccount: string, password: string ) => request({
url: '/user/login',
body: { userAccount, password },
}),
createRoom: () => request({
checkLogin: () => request({
url: '/user',
body: {},
}),
createRoom: (isShort: boolean, smallBlind: number, time: number) => request({
url: '/game/room',
body: { },
body: { isShort, smallBlind, time },
}),
findRoom: (roomNumber: string) => request({
url: '/game/room/find',
body: { roomNumber },
}),
buyIn: (buyInSize: number) => request({
url: '/game/buyIn',
body: { buyInSize },
}),
commandRecordList: (roomNumber: string, gameId: number) => request({
url: '/game/record/find/commandRecord',
body: { roomNumber, gameId },
}),
gameRecordList: (roomNumber: string) => request({
url: '/game/record/find/gameRecord',
body: { roomNumber },
}),
};
+73
View File
@@ -0,0 +1,73 @@
export interface ILinkNode<T> {
node: T;
next: ILinkNode<T> | null;
}
// interface ILink<T> {
// getNode(position: number): T;
// setNode(position: number): void;
// removeNode(position: number): void;
export class Link<T> {
public link: ILinkNode<T> = {
node: {} as T,
next: null,
};
constructor(nodes: T[], isCircular: boolean = true) {
let prevNode: ILinkNode<T> = {
node: {} as T,
next: null,
};
nodes.forEach((node, key) => {
const currNode: ILinkNode<T> = {
node,
next: null,
};
// head
if (key === 0) {
this.link = currNode;
} else {
// circular, last node next is first
if (key === nodes.length - 1 && isCircular) {
currNode.next = this.link;
}
prevNode.next = currNode;
}
prevNode = currNode;
});
}
public getNode(position: number) {
let linkNode = this.link;
let i = 0;
while (linkNode.next) {
if (i === position) {
return linkNode;
}
linkNode = linkNode.next;
i++;
}
return linkNode;
}
public setNode(node: T, position: number) {
let linkNode = this.link;
let i = 0;
const currNode: ILinkNode<T> = {
node,
next: null,
};
while (linkNode.next) {
if (i === position) {
currNode.next = linkNode.next;
linkNode.next = currNode;
return;
}
linkNode = linkNode.next;
i++;
}
currNode.next = linkNode.next;
linkNode.next = currNode;
}
}
+324
View File
@@ -0,0 +1,324 @@
const POKER_STR = 'abcdefghijklm';
function sort(cards: string []): string[] {
let temp = '';
// 排序
for (let i = 0; i < cards.length; i++) {
for (let j = i + 1; j < cards.length; j++) {
if (cards[i] > cards[j]) {
temp = cards[i];
cards[i] = cards[j];
cards[j] = temp;
}
}
}
return cards;
}
interface IPokerStyle {
init(): void;
isStraight(str?: string []): string;
}
enum PokerStyleEnum {
'ROYAL_FlUSH',
'STRAIGHT_FLUSH',
'FOUR_KIND',
'FULL_HOUSE',
'FLUSH',
'STRAIGHT',
'THREE_KIND',
'TWO_PAIR',
'PAIR',
'HIGH_CARD',
}
enum ShortPokerStyleEnum {
'ROYAL_FlUSH',
'STRAIGHT_FLUSH',
'FOUR_KIND',
'FLUSH',
'FULL_HOUSE',
'THREE_KIND',
'STRAIGHT',
'TWO_PAIR',
'PAIR',
'HIGH_CARD',
}
export class PokerStyle implements IPokerStyle {
private readonly cards: string[] = [];
private readonly isShort: boolean;
private flushObj: { [key: string]: any } = {
1: [],
2: [],
3: [],
4: [],
};
private flushColor: string = '';
private straightArr: string[] = [];
private styleName = [
'ROYAL_FlUSH',
'STRAIGHT_FLUSH',
'FOUR_KIND',
'FULL_HOUSE',
'FLUSH',
'STRAIGHT',
'THREE_KIND',
'TWO_PAIR',
'PAIR',
'HIGH_CARD'];
private pokerStyle: string[] = [
'0',
'0',
'0',
'0',
'0',
'0',
'0',
'0',
'0',
'0'];
private numObj: Map<string, number> = new Map(
POKER_STR.split('').map((m) => [m, 0]));
constructor(cards: string[], isShort= false) {
this.cards = sort(cards);
this.isShort = isShort;
if (this.isShort) {
this.styleName = [
'ROYAL_FlUSH',
'STRAIGHT_FLUSH',
'FOUR_KIND',
'FLUSH',
'FULL_HOUSE',
'THREE_KIND',
'STRAIGHT',
'TWO_PAIR',
'PAIR',
'HIGH_CARD',
];
}
this.init();
}
public isStraight(str?: string []): string {
const straightStr = str && str.join('') || [ ...new Set(this.straightArr) ].join('');
let first = -1;
let second = -1;
let three = -1;
function indexOf(pokeString: string): number {
return POKER_STR.indexOf(pokeString);
}
if (straightStr.length === 5 && indexOf(straightStr) > -1) {
return POKER_STR.slice(indexOf(straightStr), indexOf(straightStr) + 5);
}
if (straightStr.length === 6) {
first = indexOf(straightStr.slice(0, 5));
second = indexOf(straightStr.slice(1, 6));
if (Math.max(first, second) > -1) {
const max = Math.max(first, second);
return POKER_STR.slice(max, max + 5);
}
}
if (straightStr.length === 7) {
first = indexOf(straightStr.slice(0, 5));
second = indexOf(straightStr.slice(1, 6));
three = indexOf(straightStr.slice(2, 7));
if (Math.max(first, second, three) > -1) {
const max = Math.max(first, second, three);
return POKER_STR.slice(max, max + 5);
}
}
// special straight "A2345",'m' -> A
if (!this.isShort && straightStr.indexOf('m') > -1 && straightStr.indexOf('abcd') > -1) {
return 'abcdm';
}
// special straight "A2345",'m' -> A
if (this.isShort && straightStr.indexOf('m') > -1 && straightStr.indexOf('efgh') > -1) {
return 'efghm';
}
return '0';
}
public getPokerWeight() {
return this.pokerStyle.join('');
}
public getPokerStyleName() {
for (let i = 0; i < this.pokerStyle.length; i++) {
if (this.pokerStyle[i] !== '0') {
return this.styleName[i];
}
}
}
public init() {
let i = 0;
const isTwo = [];
const isThree = [];
let isFour = '0';
let isFullHouse = '0';
// const isStraightFlush = '0';
let isFlush: string[] = [];
let isRoyalFlush = '0';
let isThreeKind = '';
let isTowPair = '';
let isPair = '';
const highCard = [];
while (i < this.cards.length) {
const color = this.cards[i][1];
const num = this.cards[i][0];
this.straightArr.push(this.cards[i][0]);
this.flushObj[color].push(num);
let value = this.numObj.get(num) || 0;
value++;
this.numObj.set(num, value);
i++;
}
// find flush
for (const f in this.flushObj) {
if (this.flushObj[f].length >= 5) {
// flush is order,so flush[length - 1] is max flush card
isFlush = this.flushObj[f];
this.flushColor = f;
}
}
// find two,three,four
for (const [key, value] of this.numObj) {
// high card
if (value === 1) {
highCard.unshift(key);
}
// pairs max count 3, source is small to large
if (value >= 2) {
isTwo.unshift(key);
}
// three of kind max count 2
if (value === 3) {
isThree.unshift(key);
}
// four of kind only one
if (value === 4) {
isFour = key;
}
}
// straight flush
if (isFlush.length !== 0 && this.isStraight(isFlush) !== '0') {
if (this.isStraight(isFlush) === 'ijklm') {
isRoyalFlush = 'ijklm';
this.pokerStyle[0] = isRoyalFlush;
return;
}
this.pokerStyle[1] = this.isStraight(isFlush).split('').reverse().join('');
return;
}
// four of kind
if (isFour !== '0') {
isFour += highCard[0];
this.pokerStyle[2] = isFour;
return;
}
// full house
if (isThree.length > 0 && isTwo.length > isThree.length ||
isThree.length === 2) {
const maxTwoCard = isThree.length === 2 ? isThree[1] : isThree[0] ===
isTwo[0] ? isTwo[1] : isTwo[0];
const maxThree = isThree[0];
isFullHouse = maxThree + maxTwoCard;
if (this.isShort) {
this.pokerStyle[4] = isFullHouse;
} else {
this.pokerStyle[3] = isFullHouse;
}
return;
}
// flush
if (isFlush.length !== 0) {
isFlush.reverse().length = 5;
if (this.isShort) {
this.pokerStyle[3] = isFlush.join('');
} else {
this.pokerStyle[4] = isFlush.join('');
}
return;
}
if (this.isShort) {
// three of kind
if (isThree.length > 0) {
isThreeKind = isThree.join('');
isThreeKind += highCard[0] + highCard[1];
this.pokerStyle[5] = isThreeKind;
return;
}
// straight
if (this.isStraight() !== '0') {
this.pokerStyle[6] = `${this.isStraight()}`;
return;
}
} else {
// straight
if (this.isStraight() !== '0') {
this.pokerStyle[5] = `${this.isStraight()}`;
return;
}
// three of kind
if (isThree.length > 0) {
isThreeKind = isThree.join('');
isThreeKind += highCard[0] + highCard[1];
this.pokerStyle[6] = isThreeKind;
return;
}
}
// tow pair
if (isTwo.length >= 2) {
const towPair = isTwo;
towPair.length = 2;
isTowPair = towPair.join('');
// third tow pair card big then high card
const highCardForTowPair = isTwo[3] && isTwo[3] > highCard[0] ? isTwo[3] : highCard[0];
isTowPair += highCardForTowPair;
this.pokerStyle[7] = isTowPair;
return;
}
// pair
if (isTwo.length === 1) {
isPair = isTwo.join('');
isPair += highCard[0] + highCard[1] + highCard[2];
this.pokerStyle[8] = isPair;
return;
}
// High card
highCard.length = 5;
this.pokerStyle[9] = highCard.join('');
}
public getPokerValueCard() {
let valueStyle = '';
let isFlush = false;
this.pokerStyle.forEach((style, key) => {
if (style !== '0') {
isFlush = key === 1 || this.isShort ? key === 3 : key === 4;
valueStyle = style;
}
});
const cards = this.cards.filter((card) => {
if (isFlush) {
return valueStyle.indexOf(card[0]) > -1 && card[1] === this.flushColor;
}
return valueStyle.indexOf(card[0]) > -1;
});
cards.reverse().length = 5;
return cards;
}
}
+13
View File
@@ -0,0 +1,13 @@
let setRem = () => {
let curWidth = document.documentElement.clientWidth || window.screen.width;
const basicWidth = 375;
const basicFontSize = 20;
let calcFontSize = 0;
curWidth = curWidth > 640 ? 640 : curWidth < 320 ? 320 : curWidth;
calcFontSize = (curWidth / basicWidth) * basicFontSize;
document.documentElement.style.fontSize = calcFontSize + 'px';
};
setRem();
window.addEventListener('resize', () => {
setRem();
});
+18
View File
@@ -0,0 +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 };
+6
View File
@@ -0,0 +1,6 @@
export default {
url: process.env.NODE_ENV !== 'production' ?
process.env.NODE_ENV === 'develop' ? 'http://172.22.72.70:7001'
: 'http://127.0.0.1:7001' : 'http://www.jojgame.com:7001',
res: location.href.split('#')[0] + '#',
};
+34 -34
View File
@@ -1,34 +1,34 @@
import axios, {AxiosRequestConfig, Method} from 'axios';
import cookie from 'js-cookie';
const request = async ({method = 'post' as Method, url = '', body = {}, timeout = 8000}) => {
const origin = 'http://192.168.0.101:7001/node';
// const origin = 'http://172.22.72.70:7001/node';
if (!url) {
return Promise.reject('Request url is null!');
}
const token = cookie.get('token');
const headers = {
Authorization: `Bearer ${token}`,
};
url = `${origin}${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;
-62
View File
@@ -1,62 +0,0 @@
<template>
<div class="home-container container">
<div class="room-btn" v-show="showBtn">
<div class="create-room btn"
@click="createRoom"><span>create room</span>
</div>
<div class="btn"
@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>
</div>
<div class="btn">
<span @click="go">go</span>
</div>
</div>
</div>
</template>
<script lang="ts">
import { Vue } from 'vue-property-decorator';
import Component from 'vue-class-component';
import service from '../service';
@Component
export default class Home extends Vue {
public roomNumber: string = '';
private isJoin = false;
private showBtn = true;
private async createRoom() {
try {
const result = await service.createRoom();
const { roomNumber } = result.data;
console.log(result);
this.$router.replace({ name: 'game', params: { roomNumber, isOwner: '1' } });
} catch (e) {
console.log(e);
}
}
private joinRoom() {
this.isJoin = true;
this.showBtn = false;
}
private go() {
this.$router.replace({ name: 'game', params: { roomNumber: this.roomNumber } });
}
}
</script>
<style lang="less">
.home-container {
}
</style>
+448 -162
View File
@@ -1,115 +1,191 @@
<template>
<div class="game-container container">
<sitList></sitList>
<common-card></common-card>
<div class="game-body" v-show="hasBuyIn">
<div class="game-player-info">
<div class="users"
v-for="user in users">
<span> {{user.nickName}}: {{user.counter}}</span>
<span>buyIn: {{user.buyIn}}</span>
<span v-show="user.actionSize > 0"> actionSize:{{user.actionSize}} </span>
<span v-show="user.type"> type:{{user.type}} </span>
<span v-show="gameOver && user.handCard">handCard: {{mapCard(user.handCard)}}</span>
</div>
<div class="join">
{{joinMsg}}
</div>
</div>
<sitList :sitLink.sync='sitLink'
:currPlayer="currPlayer"
:commonCard="commonCard"
@sit="sitDown"
@buyIn="buyIn"
:isPlay='isPlay'
:valueCards='valueCards'
:roomConfig = 'roomConfig'
:time='time'
:winner="winner"
:actionUserId='actionUserId'
:hand-card="handCard"></sitList>
<common-card
:commonCard="commonCard"
:valueCards='valueCards'
></common-card>
<notice :message-list="messageList"></notice>
<div class="winner-poke-style"
v-show="gameOver && winner[0][0].handCard.length > 0">
{{PokeStyle(winner[0] && winner[0][0] && winner[0][0].handCard)}} WIN!!
</div>
<div class="game-body">
<div class="pot">pot: {{pot}}</div>
<div class="common-card">commonCard:{{commonCardString}}</div>
<div class="hand-card">handCard:{{handCardString}}</div>
<div class="action">
<div class="action-type btn"
v-show="isAction">
<span @click="action('check')"
v-show="showActionBtn('check')">check</span>
<span @click="action('fold')">fold</span>
<span @click="action('call')"
v-show="showActionBtn('call')">call</span>
<span @click="isRaise = true">raise</span>
</div>
<div class="raise-size"
v-show="isRaise">
<div class="not-allin"
v-show="showActionBtn('raise')">
<i @click="raise(pot / 3)">1/3 pot</i>
<i @click="raise(pot / 2)">1/2 pot</i>
<i @click="raise(pot / 4)">3/4 pot</i>
<i @click="raise(pot)">1 pot</i>
<i @click="raise(pot * 2)">2 pot</i>
<i @click="raise(pot * 3)">3 pot</i>
</div>
<i @click="action('allin')">allin</i>
</div>
</div>
<div class="roomId">No.:{{roomId}}</div>
<div class="btn play"
v-show="isOwner && !isPlay"><span @click="play">play game</span></div>
</div>
<div class="buy-in">
<div class="input-bd">
<div class="input-name">buy in:</div>
<div class="input-text">
<input type="text"
v-model="buyInSize"/>
</div>
<div class="game-record iconfont icon-record" @click="getRecord(0)"></div>
<actionDialog :base-size="baseSize"
:curr-player="currPlayer"
:is-action="isAction"
:is-pre-flop="commonCard.length === 0"
:min-action-size="minActionSize"
:is-two-player="gamePlayers.length === 2"
:pot="pot"
:prev-size="prevSize"
@action = 'action'
></actionDialog>
<div class="setting">
<div class="iconfont icon-setting setting-btn"
@click="showSetting = true"></div>
<div class="setting-body"
:class="{show: showSetting}">
<i @click="showBuyInDialog()">buy in</i>
<i @click="showCounterRecord">counter record</i>
</div>
<div class="btn"><span @click="buyIn">buy in</span></div>
</div>
<BuyIn :showBuyIn.sync='showBuyIn'
:min='0'
:max='1000'
@buyIn='buyIn'></BuyIn>
<toast :show.sync="showMsg"
:text="msg"></toast>
<record :players="players"
v-model="showRecord"></record>
<sendMsg @send = 'sendMsgHandle'></sendMsg>
<iAudio :play="playIncome" type="income"></iAudio>
<gameRecord v-model="showCommandRecord"
:game-list="gameList"
@getRecord = "getRecord"
:curr-game-index="currGameIndex"
:command-list="commandRecordList"></gameRecord>
</div>
</template>
<script lang="ts">
import {Vue} from 'vue-property-decorator';
import { Vue, Watch } from 'vue-property-decorator';
import Component from 'vue-class-component';
import io from 'socket.io-client';
import cookie from 'js-cookie';
import sitList from '../components/SitList.vue';
import commonCard from '../components/CommonCard.vue';
import {IUser} from '@/interface/user';
import { IPlayer } from '@/interface/IPlayer';
import { ILinkNode, Link } from '@/utils/Link';
import ISit from '../interface/ISit';
import BuyIn from '../components/BuyIn.vue';
import toast from '../components/Toast.vue';
import record from '../components/Record.vue';
import notice from '../components/Notice.vue';
import iAudio from '../components/Audio.vue';
import sendMsg from '../components/SendMsg.vue';
import actionDialog from '../components/Action.vue';
import { PokerStyle } from '@/utils/PokerStyle';
import origin from '../utils/origin';
import { IRoom } from '@/interface/IRoom';
import service from '../service';
import gameRecord from '@/components/GameRecord.vue';
import {IGameRecord} from '@/interface/IGameRecord';
export enum ECommand {
CALL = 'call',
CALL = 'call',
ALL_IN = 'allin',
RAISE = 'raise',
CHECK = 'check',
FOLD = 'fold',
RAISE = 'raise',
CHECK = 'check',
FOLD = 'fold',
}
interface IMsg {
action: string;
clients: string[];
target: string;
message?: any;
data: any;
}
const GAME_BASE_SIZE = 1;
@Component({
components: {
sitList,
commonCard,
BuyIn,
toast,
record,
gameRecord,
notice,
iAudio,
actionDialog,
sendMsg,
},
})
export default class Game extends Vue {
public socket: any = null;
private users: IUser[] = [];
// in the room user
// have a sit user
private players: IPlayer[] = [];
private userInfo: any = {};
private joinMsg = '';
private handCard = [];
private commonCard = [];
private buyInSize = 0;
private pot = 0;
private slidePots = [];
private prevSize = 0;
private isAction = false;
private isRaise = false;
private winner = [];
private showBuyIn = true;
private winner: IPlayer [][] = [];
private showBuyIn = false;
private showSetting = false;
private sitLink: any = '';
private gaming = false;
private sitList: ISit[] = [];
private actionUserId = '';
private showAllin = false;
private showMsg = false;
private baseSize = GAME_BASE_SIZE;
private playIncome = false;
private msg = '';
private time = 30;
private timeSt = 0;
private commandRecordList = [];
private showCommandRecord = false;
private gameList: IGameRecord [] = [];
private currGameIndex = 0;
private roomConfig: IRoom = {
isShort: false,
smallBlind: 1,
};
private messageList: any[] = [];
private showRecord = false;
get isPlay() {
return this.pot !== 0 && this.currPlayer?.buyIn !== 0;
@Watch('players')
private playerChange(players: IPlayer[]) {
console.log('player change-------');
this.sitList = this.sitList.map((sit: ISit) => {
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();
}
get hasBuyIn() {
return this.currPlayer?.buyIn !== 0;
@Watch('isPlay')
private isPlayChange(val: boolean) {
if (val) {
clearTimeout(this.timeSt);
this.doCountDown();
}
}
@Watch('actionUserId')
private actionUserIdChange() {
this.time = 30;
clearTimeout(this.timeSt);
this.doCountDown();
}
get isPlay() {
return this.gaming || this.pot !== 0;
}
get roomId() {
@@ -124,92 +200,129 @@
return this.winner.length !== 0;
}
get isAction() {
return this.userInfo && this.userInfo.userId === this.actionUserId;
}
get valueCards() {
if (this.gameOver && this.winner[0] && this.winner[0][0].handCard) {
const handCards = this.winner[0][0].handCard;
const style = new PokerStyle([...handCards, ...this.commonCard], this.roomConfig.isShort);
return style.getPokerValueCard();
} else {
return [];
}
}
get gamePlayers() {
if (!this.isPlay) {
return [];
}
return this.sitList.filter((s) => s.player && s.player.status === 1);
}
get hasSit() {
return !!this.sitList.find((s) => s.player && s.player.userId === this.currPlayer?.userId);
}
get currPlayer() {
return this.users.find((u: IUser) => this.userInfo.userId === u.userId);
return this.players.find((u: IPlayer) => this.userInfo.userId === u.userId);
}
get canActionSize() {
return Number(this.currPlayer && this.currPlayer.counter + this.currPlayer.actionSize);
}
get commonCardString() {
return this.mapCard(this.commonCard);
}
get handCardString() {
return this.mapCard(this.handCard);
get minActionSize() {
return this.prevSize <= 0 ? GAME_BASE_SIZE * 2 : this.prevSize * 2;
}
private init() {
this.users = [];
this.userInfo = {};
this.joinMsg = '';
this.handCard = [];
this.commonCard = [];
this.buyInSize = 0;
this.pot = 0;
this.prevSize = 0;
this.isAction = false;
this.isRaise = false;
this.time = 30;
this.winner = [];
this.showBuyIn = false;
this.initSitLink();
}
private sendMsgHandle(msgInfo: string) {
const msg = `${this.userInfo.nickName}:${msgInfo}`;
this.emit('broadcast', { msg });
}
private showCounterRecord() {
this.showRecord = true;
this.showSetting = false;
}
private doCountDown() {
if (this.time <= 0) {
clearTimeout(this.timeSt);
return;
}
this.timeSt = setTimeout(() => {
this.time--;
this.doCountDown();
}, 1000);
}
private PokeStyle(cards: string[]) {
if (this.commonCard.length === 0 || !cards) {
return '';
}
const commonCards = this.commonCard || [];
const card = [...cards, ...commonCards];
const style = new PokerStyle(card, this.roomConfig.isShort);
return style.getPokerStyleName();
}
private showBuyInDialog() {
this.showBuyIn = true;
this.showSetting = false;
}
private mapCard(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]}`;
});
private sitListMap() {
let node = this.sitLink;
const sit = [];
for (let i = 0; i < 9; i++) {
sit.push(node.node);
const next = node.next;
node = next;
}
return sit;
}
private showActionBtn(type: string) {
// check
if ('check' === type) {
return this.prevSize <= 0
|| (this.commonCard.length === 0
&& this.users.length === 2
&& this.currPlayer?.type === 'dealer'
&& this.prevSize === 2)
|| (this.currPlayer?.type === 'big_blind' && this.prevSize === 2 &&
this.commonCard.length === 0);
}
// raise
if ('raise' === type) {
return this.canActionSize > this.prevSize * 2;
}
// call
if ('call' === type) {
return this.canActionSize > this.prevSize
&& this.prevSize > 0
&& !(this.currPlayer?.type === 'big_blind' && this.prevSize === 2 &&
this.commonCard.length === 0);
}
return true;
}
private raise(size: number) {
this.action(`raise:${size}`);
private sitDown() {
this.emit('sitDown', { sitList: this.sitListMap() });
}
private action(command: string) {
this.emit('action', {command});
this.isAction = false;
this.isRaise = false;
if (command === 'fold') {
clearTimeout(this.timeSt);
}
if (command === 'allin') {
this.showAllin = true;
setTimeout(() => {
this.showAllin = false;
}, 3000);
}
this.emit('action', { command });
// this.isAction = false;
// this.isRaise = false;
}
private socketInit() {
const token = cookie.get('token');
const roomConfig = cookie.get('roomConfig') || '';
const log = console.log;
// const origin = 'http://172.22.72.70:7001';
const origin = 'http://192.168.0.101:7001';
this.socket = io(`${origin}/socket`, {
this.roomConfig = JSON.parse(roomConfig);
console.log(JSON.parse(roomConfig), 'roomConfig');
this.socket = io(`${origin.url}/socket`, {
// 实际使用中可以在这里传递参数
query: {
room: this.roomId,
token,
roomConfig,
},
transports: ['websocket'],
});
@@ -223,19 +336,35 @@
log('#receive,', msg);
const data = msg.data;
if (data.action === 'handCard') {
console.log('come in handCard =========', data);
this.handCard = data.payload.handCard;
console.log('come in handCard =========', this.handCard);
}
if (data.action === 'userInfo') {
this.userInfo = data.payload;
this.userInfo = data.payload.userInfo;
}
if (data.action === 'sitList') {
this.sitList = data.payload.sitList;
this.initSitLink();
}
if (data.action === 'gameInfo') {
const payload = data.payload;
this.users = payload.data.players;
this.pot = payload.data.pot;
this.players = payload.data.players;
this.pot = payload.data.pot || 0;
this.prevSize = payload.data.prevSize;
this.commonCard = payload.data.commonCard;
console.log('msg.data.currPlayer.userId', msg.data);
this.isAction = !!(this.userInfo && this.userInfo.userId ===
payload.data.currPlayer.userId);
this.actionUserId = payload.data.currPlayer.userId;
// this.isAction = !!(this.userInfo
// && this.userInfo.userId === payload.data.currPlayer.userId);
}
// room time out
if (data.action === 'deny') {
this.$plugin.toast('room is close');
setTimeout(() => {
this.$router.replace({ name: 'home' });
}, 1000);
}
});
});
@@ -243,40 +372,74 @@
// 接收在线用户信息
this.socket.on('online', (msg: IMsg) => {
log('#online,', msg);
if (msg.action === 'sitList') {
console.log(msg.data, 'sit');
this.sitList = msg.data.sitList;
this.initSitLink();
}
if (msg.action === 'join') {
this.joinMsg = msg.data;
}
if (msg.action === 'players') {
this.users = msg.data.players;
this.players = msg.data.players;
}
if (msg.action === 'commonCard') {
if (msg.action === 'actionComplete') {
this.commonCard = msg.data.commonCard;
console.log('users', msg.data);
this.slidePots = msg.data.slidePots;
console.log('players', msg.data);
}
if (msg.action === 'gameInfo') {
this.users = msg.data.players;
this.pot = msg.data.pot;
this.players = msg.data.players;
this.pot = msg.data.pot || 0;
this.prevSize = msg.data.prevSize;
this.isAction = !!(this.userInfo && this.userInfo.userId === msg.data.currPlayer.userId);
this.actionUserId = msg.data.currPlayer.userId;
// this.isAction = !!(this.userInfo && this.userInfo.userId === msg.data.currPlayer.userId);
this.sitList = msg.data.sitList;
console.log('gameInfo', msg.data);
console.log('handCard', this.handCard);
}
if (msg.action === 'gameOver') {
console.log('gameOver', msg.data);
clearTimeout(this.timeSt);
this.actionUserId = '0';
this.winner = msg.data.winner;
this.commonCard = msg.data.commonCard;
const allPlayers = msg.data.allPlayers;
allPlayers.forEach((w: IUser) => {
this.users.forEach((p) => {
if (w.userId === p.userId) {
p.handCard = w.handCard;
allPlayers.forEach((winner: IPlayer) => {
this.players.forEach((p) => {
if (winner.userId === p.userId) {
p.handCard = winner.handCard;
p.counter = winner.counter;
p.income = winner.income;
}
});
});
// income music
this.playIncome = true;
setTimeout(() => {
this.playIncome = false;
}, 1000);
}
if (msg.action === 'newGame') {
this.init();
}
if (msg.action === 'pause') {
this.players = msg.data.players;
this.sitList = msg.data.sitList;
console.log('players', this.players);
this.gaming = false;
this.init();
}
if (msg.action === 'broadcast') {
this.messageList.push({
message: msg.message.msg || '',
top: Math.random() * 50 + 10,
});
}
});
// 系统事件
@@ -293,20 +456,32 @@
});
}
private async buyIn() {
private async buyIn(size: number) {
if (size <= 0) {
this.$plugin.toast('buy in size too small');
return;
}
try {
console.log('come in buyIn ==================', size);
this.showMsg = true;
this.msg = this.hasSit && this.isPlay
? `已补充买入 ${size},下局生效` : `已补充买入 ${size}`;
this.emit('buyIn', {
buyInSize: this.buyInSize,
buyInSize: size,
});
this.showBuyIn = false;
} catch (e) {
console.log(e);
}
}
private play() {
console.log('play');
this.emit('playGame');
if (this.players.length >= 2) {
this.gaming = true;
this.emit('playGame');
} else {
console.log('no enough player');
}
}
private emit(eventType: string, data: any = {}) {
@@ -318,8 +493,63 @@
});
}
private mounted() {
this.socketInit();
private initSitLink() {
const sitListMap = this.sitList || [];
if (sitListMap.length === 0) {
for (let i = 0; i < 9; i++) {
const sit = {
player: null,
position: i + 1,
};
sitListMap.push(sit);
}
}
let link = new Link<ISit>(sitListMap).link;
for (let i = 0; i < 9; i++) {
if (link.node.player
&& link.node.player.userId === this.currPlayer?.userId) {
this.sitLink = link;
return;
}
const next = link.next;
link = next as ILinkNode<ISit>;
}
this.sitLink = link;
}
private async getRecord(index: number) {
try {
let gameId = 0;
if (!index) {
const result = await service.gameRecordList(this.roomId);
this.gameList = Object.values(result.data);
gameId = this.gameList[this.gameList.length - 1].gameId;
this.currGameIndex = this.gameList.length;
console.log('ccc len', this.gameList.length);
} else {
this.currGameIndex = index;
gameId = this.gameList[index - 1].gameId;
}
console.log(gameId, 'ccc11');
const { data } = await service.commandRecordList(this.roomId, gameId);
this.commandRecordList = data.commandList;
this.showCommandRecord = true;
console.log(data);
} catch (e) {
console.log(e);
this.$plugin.toast('can\'t find the room');
}
}
private created() {
try {
this.socketInit();
if (!this.sitLink) {
this.initSitLink();
}
} catch (e) {
console.log(e);
}
}
}
</script>
@@ -327,30 +557,86 @@
<style lang="less"
scoped>
.game-container {
background: url("../assets/bg.png");
background: radial-gradient(#00bf86, #006a55);
background-size: 100% 100%;
.raise-size {
i {
padding: 5px;
width: 30px;
height: 30px;
display: inline-block;
font-style: normal;
font-size: 12px;
line-height: 30px;
border-radius: 50%;
border: 1px solid #bababa;
margin: 10px;
vertical-align: middle;
height: 100vh;
width: 100vw;
overflow: hidden;
.winner-poke-style {
position: absolute;
top: 55vh;
left: 50%;
transform: translate3d(-50%, 0, 0);
z-index: 0;
font-size: 14px;
color: #fff;
}
.game-body {
position: absolute;
top: 38vh;
left: 50%;
transform: translate3d(-50%, -50%, 0);
z-index: 0;
.roomId {
margin-top: 10px;
font-size: 14px;
}
}
.sit-list {
.sit {
i {
.setting {
left: 0;
top: 0;
position: absolute;
.setting-btn {
width: 30px;
height: 30px;
line-height: 30px;
text-align: center;
background: #fff;
top: 10px;
left: 0;
position: absolute;
font-size: 20px;
color: #898888;
border-radius: 0 10px 10px 0;
}
.setting-body {
position: absolute;
left: 0;
top: 0;
transform: translate3d(-150px, 0px, 0px);
z-index: 1;
transition: transform .5s;
i {
display: block;
width: 100px;
height: 20px;
padding: 4px;
font-style: normal;
text-align: left;
line-height: 20px;
font-size: 12px;
color: #fff;
background: rgba(0, 0, 0, 0.6);
margin: 1px 0;
}
&.show {
transform: translate3d(0, 0, 0);
}
}
}
.game-record{
position: absolute;
right: 10px;
top: 7px;
font-size: 36px;
color: #fff;
}
}
</style>
+267
View File
@@ -0,0 +1,267 @@
<template>
<div class="home-container container">
<div class="room-btn"
v-show="showBtn">
<div class="room-config" v-show="showRoomConfig">
<div class="room-config-shadow" @click="showRoomConfig = false"></div>
<div class="room-config-body">
<h1> room config</h1>
<div class="input-bd">
<div class="input-name">smallBlind:</div>
<div class="input-text">
<input type="tel"
v-model="smallBlind"/>
</div>
</div>
<div class="input-bd">
<div class="input-name">isShort:</div>
<div class="input-text">
<input type="checkbox"
v-model="isShort"/>
</div>
</div>
<div class="btn" @click="createRoom"><span>create</span></div>
</div>
</div>
<div class="create-room btn"
@click="showRoomConfig = true" ><span>create room</span>
</div>
<div class="btn"
@click="joinRoom"><span>join room</span>
</div>
<div class="btn"
@click="getRecord(0)"><span>test record</span>
</div>
</div>
<div class="room-number"
v-show="isJoin">
<div class="room-input inline">
<div class="input-bd"
:class="{error: isError}">
<div class="input-name iconfont icon-password"></div>
<div class="input-text">
<input type="tel"
maxlength="6"
@focus="isError = false"
v-model="roomNumber"/>
</div>
</div>
</div>
<div class="room-btn inline">
<span @click="go">go</span>
</div>
</div>
<gameRecord v-model="showRecord"
:game-list="gameList"
:curr-game-index="currGameIndex"
@getRecord = "getRecord"
:command-list="commandList"></gameRecord>
</div>
</template>
<script lang="ts">
import { Vue } from 'vue-property-decorator';
import Component from 'vue-class-component';
import gameRecord from '@/components/GameRecord.vue';
import service from '../service';
import cookie from 'js-cookie';
import {IGameRecord} from '@/interface/IGameRecord';
@Component({
components: {
gameRecord,
},
})
export default class Home extends Vue {
public roomNumber: string = '';
private isJoin = false;
private showBtn = true;
private isError = false;
private isShort = false;
private smallBlind = 1;
private showRoomConfig = false;
private showRecord = false;
private commandList = [];
private currGameIndex = 0;
private gameList: IGameRecord [] = [];
private async createRoom() {
try {
const result = await service.createRoom(this.isShort, this.smallBlind, 0);
const { roomNumber } = result.data;
const roomConfig = {
isShort: this.isShort,
smallBlind: this.smallBlind,
};
cookie.set('roomConfig', roomConfig, {expires: 1});
this.$router.push({ name: 'game', params: { roomNumber, isOwner: '1' } });
} catch (e) {
console.log(e);
}
}
private joinRoom() {
this.isJoin = true;
this.showBtn = false;
}
private async go() {
if (!/^\d+$/.test(this.roomNumber)) {
this.isError = true;
return;
}
try {
const { data } = await service.findRoom(this.roomNumber);
if (data) {
const roomConfig = {
...data,
};
cookie.set('roomConfig', roomConfig, {expires: 1});
this.$router.push({ name: 'game', params: { roomNumber: this.roomNumber } });
} else {
this.$plugin.toast('can\'t find the room');
console.log('can\'t find the room');
}
} catch (e) {
this.$plugin.toast('can\'t find the room');
}
}
private async getRecord(index: number) {
try {
console.log('ccc');
let gameId = 0;
if (!index) {
const result = await service.gameRecordList('889008');
this.gameList = Object.values(result.data);
gameId = this.gameList[this.gameList.length - 1].gameId;
this.currGameIndex = this.gameList.length;
console.log('ccc len', this.gameList.length);
} else {
this.currGameIndex = index;
}
console.log(gameId, 'ccc11');
gameId = this.gameList[index].gameId;
const { data } = await service.commandRecordList('889008', gameId);
this.commandList = data.commandList;
this.showRecord = true;
console.log(data);
} catch (e) {
console.log(e);
this.$plugin.toast('can\'t find the room');
}
}
}
</script>
<style lang="less"
scoped>
.home-container {
height: 100vh;
display: flex;
flex-direction: row;
align-items: center;
.room-config{
position: absolute;
width: 100vw;
height: 100vh;
top: 0;
left: 0;
.room-config-shadow{
position: fixed;
left: 0;
right: 0;
bottom: 0;
top: 0;
z-index: 9;
background-color: rgba(0,0,0,.3);
}
.room-config-body{
position: absolute;
background-color: #fff;
border-radius: 8px;
left: 50%;
top: 50%;
z-index: 99;
width: 230px;
min-height: 200px;
transform: translate3d(-50%, -50%, 0);
h1{
font-size: 16px;
text-align: center;
line-height: 40px;
}
.input-bd{
display: flex;
.input-name{
width: 20vw;
text-align: right;
}
.input-text{
margin-left: 8px;
line-height: 30px;
input{
width: 10vw;
min-width: 10vw;
display: inline-block;
text-align: center;
vertical-align: middle;
border-bottom: 1px solid #bababa;
&[type=checkbox]{
width: 4vw;
height: 4vw;
min-width: auto;
min-height: auto;
}
}
}
}
}
}
.room-btn {
flex: 1;
.btn {
width: 50vw;
margin: 30px auto;
}
}
.room-number {
line-height: 40px;
text-align: center;
width: 100%;
.error {
border: 1px solid #e8050a;
}
.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>
+52 -16
View File
@@ -1,23 +1,26 @@
<template>
<div class="login container">
<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">userName:</div>
<div class="input-text">
<input type="text"
v-model="userAccount"/>
</div>
<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">password:</div>
<div class="input-text">
<input type="password"
v-model="password"/>
</div>
<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>
<span @click="login">sign in</span>
<b @click="signUp">sign up</b>
</div>
</div>
</div>
</template>
<script lang="ts">
@@ -41,12 +44,45 @@
const result = await service.login(this.userAccount, this.password);
const { token } = result.data;
cookie.set('token', token, {expires: 1});
this.$router.replace({name: 'home'});
await this.$router.push({name: 'home'});
} catch (e) {
console.log(e);
this.$plugin.toast('Wrong password or account.');
}
}
}
</script>
<style lang="less">
<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>
+118 -53
View File
@@ -1,53 +1,118 @@
<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="password input-bd">
<div class="input-name">password:</div>
<div class="input-text">
<input type="text"
v-model="password"/>
</div>
</div>
<div class="re-password input-bd">
<div class="input-name">re-password:</div>
<div class="input-text">
<input type="text"
v-model="rePassword"/>
</div>
</div>
<div class="s-btn btn"><span @click="register">submit</span></div>
</div>
</template>
<script lang="ts">
import {Vue} from 'vue-property-decorator';
import service from '../service';
import Component from 'vue-class-component';
@Component
export default class Register extends Vue {
public userName: string = '';
public password: string = '';
public rePassword: string = '';
get vaild() {
return this.password === this.rePassword;
}
private async register() {
try {
const result = await service.register(this.userName, this.password);
} catch (e) {
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>
</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/XInput.vue';
@Component({
components: {
toast,
XInput,
},
})
export default class Register extends Vue {
private form: any = {
userAccount: '',
nickName: '',
password: '',
confirm: '',
};
private errorData: string [] = [];
private valid() {
const errorArr: string[] = [];
for (const 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('') === '') {
await service.register(this.form);
this.$plugin.toast('sign successful');
setTimeout(() => {
this.$router.replace({ name: 'login' });
}, 2000);
}
} catch (e) {
this.$plugin.toast(JSON.stringify(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>
+219 -2
View File
@@ -2,6 +2,51 @@
# yarn lockfile v1
"@antv/adjust@~0.1.1":
version "0.1.1"
resolved "https://registry.npmjs.org/@antv/adjust/-/adjust-0.1.1.tgz#e263ab0e1a1941a648842fc086cf65a7e3b75e98"
integrity sha512-9FaMOyBlM4AgoRL0b5o0VhEKAYkexBNUrxV8XmpHU/9NBPJONBOB/NZUlQDqxtLItrt91tCfbAuMQmF529UX2Q==
dependencies:
"@antv/util" "~1.3.1"
"@antv/f2@^3.1.4-beta.2":
version "3.6.3"
resolved "https://registry.npmjs.org/@antv/f2/-/f2-3.6.3.tgz#0c80132494977730fe69a9d760082e06540b6475"
integrity sha512-Q6tT4/c0qU0KhJk2j5ywcgvq6MlByayGEYN9gN0WxttgeZeuOoGCN5wHk0jv/DVP5PVMN2tfbERthitwtJZ2lg==
dependencies:
"@antv/adjust" "~0.1.1"
"@antv/scale" "0.1.3"
"@antv/util" "~2.0.6"
"@babel/runtime" "^7.7.7"
hammerjs "^2.0.8"
"@antv/gl-matrix@^2.7.1":
version "2.7.1"
resolved "https://registry.npmjs.org/@antv/gl-matrix/-/gl-matrix-2.7.1.tgz#acb8e37f7ab3df01345aba4372d7942be42eba14"
integrity sha512-oOWcVNlpELIKi9x+Mm1Vwbz8pXfkbJKykoCIOJ/dNK79hSIANbpXJ5d3Rra9/wZqK6MC961B7sybFhPlLraT3Q==
"@antv/scale@0.1.3":
version "0.1.3"
resolved "https://registry.npmjs.org/@antv/scale/-/scale-0.1.3.tgz#4876e6140cb7dcda190e7fe2e780882dcac6b09d"
integrity sha512-oknlOg4OUqIh8LygrfQttx+OAnNJm2fQ81si4g8aby1WJJwj/TU1gCr+J3loIpKBtBK4VpP/OzTTqg1Ym67SOQ==
dependencies:
"@antv/util" "~1.3.1"
fecha "~2.3.3"
"@antv/util@~1.3.1":
version "1.3.1"
resolved "https://registry.npmjs.org/@antv/util/-/util-1.3.1.tgz#30a34b201ff9126ec0d58c72c8166a9c3e644ccd"
integrity sha512-cbUta0hIJrKEaW3eKoGarz3Ita+9qUPF2YzTj8A6wds/nNiy20G26ztIWHU+5ThLc13B1n5Ik52LbaCaeg9enA==
dependencies:
"@antv/gl-matrix" "^2.7.1"
"@antv/util@~2.0.6":
version "2.0.9"
resolved "https://registry.npmjs.org/@antv/util/-/util-2.0.9.tgz#bd3e296a392e11fbe2781fde39d8e70ba1c53ed0"
integrity sha512-JblWzne7msAPDdxkUhEk8zAz0Wd6igKwqymGbvIeyOydGrhBhGjA3nEayFj4IlG+XixCvGFKsCB4yuFS4glRIA==
dependencies:
tslib "^1.10.0"
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.8.3":
version "7.8.3"
resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e"
@@ -756,6 +801,13 @@
"@babel/types" "^7.4.4"
esutils "^2.0.2"
"@babel/runtime@^7.7.7":
version "7.9.6"
resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.9.6.tgz#a9102eb5cadedf3f31d08a9ecf294af7827ea29f"
integrity sha512-64AF1xY3OAkFHqOb9s4jpgk1Mm5vDZ4L3acHvAml+53nO1XbXLuDodsVpO4OIUsmemlUHMxNdYMNJmsvOwLrvQ==
dependencies:
regenerator-runtime "^0.13.4"
"@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
version "7.9.2"
resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.9.2.tgz#d90df0583a3a252f09aaa619665367bae518db06"
@@ -874,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"
@@ -1475,6 +1532,16 @@ arr-union@^3.1.0:
resolved "https://registry.npm.taobao.org/arr-union/download/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4"
integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=
array-filter@^1.0.0:
version "1.0.0"
resolved "https://registry.npm.taobao.org/array-filter/download/array-filter-1.0.0.tgz#baf79e62e6ef4c2a4c0b831232daffec251f9d83"
integrity sha1-uveeYubvTCpMC4MSMtr/7CUfnYM=
array-find@^1.0.0:
version "1.0.0"
resolved "https://registry.npm.taobao.org/array-find/download/array-find-1.0.0.tgz#6c8e286d11ed768327f8e62ecee87353ca3e78b8"
integrity sha1-bI4obRHtdoMn+OYuzuhzU8o+eLg=
array-flatten@1.1.1:
version "1.1.1"
resolved "https://registry.npm.taobao.org/array-flatten/download/array-flatten-1.1.1.tgz?cache=0&sync_timestamp=1574313384951&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Farray-flatten%2Fdownload%2Farray-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
@@ -1485,6 +1552,16 @@ array-flatten@^2.1.0:
resolved "https://registry.npm.taobao.org/array-flatten/download/array-flatten-2.1.2.tgz?cache=0&sync_timestamp=1574313384951&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Farray-flatten%2Fdownload%2Farray-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099"
integrity sha1-JO+AoowaiTYX4hSbDG0NeIKTsJk=
array-map@^0.0.0:
version "0.0.0"
resolved "https://registry.npm.taobao.org/array-map/download/array-map-0.0.0.tgz#88a2bab73d1cf7bcd5c1b118a003f66f665fa662"
integrity sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=
array-shuffle@^1.0.1:
version "1.0.1"
resolved "https://registry.npm.taobao.org/array-shuffle/download/array-shuffle-1.0.1.tgz#7ea4882a356b4bca5f545e0b6e52eaf6d971557a"
integrity sha1-fqSIKjVrS8pfVF4LblLq9tlxVXo=
array-union@^1.0.1, array-union@^1.0.2:
version "1.0.2"
resolved "https://registry.npm.taobao.org/array-union/download/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39"
@@ -1586,6 +1663,11 @@ autoprefixer@^9.7.5:
postcss "^7.0.27"
postcss-value-parser "^4.0.3"
autosize@^3.0.20:
version "3.0.21"
resolved "https://registry.npm.taobao.org/autosize/download/autosize-3.0.21.tgz#f182f40d17757d978a139a4c9ca40c4c0e448603"
integrity sha1-8YL0DRd1fZeKE5pMnKQMTA5EhgM=
aws-sign2@~0.7.0:
version "0.7.0"
resolved "https://registry.npm.taobao.org/aws-sign2/download/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
@@ -1596,6 +1678,13 @@ aws4@^1.8.0:
resolved "https://registry.npm.taobao.org/aws4/download/aws4-1.9.1.tgz#7e33d8f7d449b3f673cd72deb9abdc552dbe528e"
integrity sha1-fjPY99RJs/ZzzXLeuavcVS2+Uo4=
axios@^0.15.3:
version "0.15.3"
resolved "https://registry.npm.taobao.org/axios/download/axios-0.15.3.tgz#2c9d638b2e191a08ea1d6cc988eadd6ba5bdc053"
integrity sha1-LJ1jiy4ZGgjqHWzJiOrda6W9wFM=
dependencies:
follow-redirects "1.0.0"
axios@^0.19.2:
version "0.19.2"
resolved "https://registry.npm.taobao.org/axios/download/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27"
@@ -1729,6 +1818,11 @@ bluebird@^3.1.1, bluebird@^3.5.5:
resolved "https://registry.npm.taobao.org/bluebird/download/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
integrity sha1-nyKcFb4nJFT/qXOs4NvueaGww28=
blueimp-md5@^2.6.0:
version "2.15.0"
resolved "https://registry.npm.taobao.org/blueimp-md5/download/blueimp-md5-2.15.0.tgz?cache=0&sync_timestamp=1588940550383&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fblueimp-md5%2Fdownload%2Fblueimp-md5-2.15.0.tgz#ae945f87ca6c2c11e2562983e11450b0545f9bb3"
integrity sha1-rpRfh8psLBHiVimD4RRQsFRfm7M=
bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0:
version "4.11.8"
resolved "https://registry.npm.taobao.org/bn.js/download/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f"
@@ -2493,6 +2587,11 @@ cosmiconfig@^5.0.0:
js-yaml "^3.13.1"
parse-json "^4.0.0"
countup.js@^1.8.1:
version "1.9.3"
resolved "https://registry.npm.taobao.org/countup.js/download/countup.js-1.9.3.tgz#ce3e50cd7160441e478f07da31895edcc0f1c9dd"
integrity sha1-zj5QzXFgRB5HjwfaMYle3MDxyd0=
create-ecdh@^4.0.0:
version "4.0.3"
resolved "https://registry.npm.taobao.org/create-ecdh/download/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff"
@@ -2524,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"
@@ -2544,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=
@@ -3417,6 +3523,11 @@ fast-json-stable-stringify@^2.0.0:
resolved "https://registry.npm.taobao.org/fast-json-stable-stringify/download/fast-json-stable-stringify-2.1.0.tgz?cache=0&sync_timestamp=1576340291001&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffast-json-stable-stringify%2Fdownload%2Ffast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
integrity sha1-h0v2nG9ATCtdmcSBNBOZ/VWJJjM=
fastclick@^1.0.6:
version "1.0.6"
resolved "https://registry.npm.taobao.org/fastclick/download/fastclick-1.0.6.tgz#161625b27b1a5806405936bda9a2c1926d06be6a"
integrity sha1-FhYlsnsaWAZAWTa9qaLBkm0Gvmo=
faye-websocket@^0.10.0:
version "0.10.0"
resolved "https://registry.npm.taobao.org/faye-websocket/download/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4"
@@ -3431,6 +3542,11 @@ faye-websocket@~0.11.1:
dependencies:
websocket-driver ">=0.5.1"
fecha@~2.3.3:
version "2.3.3"
resolved "https://registry.npm.taobao.org/fecha/download/fecha-2.3.3.tgz#948e74157df1a32fd1b12c3a3c3cdcb6ec9d96cd"
integrity sha1-lI50FX3xoy/RsSw6PDzctuydls0=
figgy-pudding@^3.5.1:
version "3.5.2"
resolved "https://registry.npm.taobao.org/figgy-pudding/download/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e"
@@ -3532,6 +3648,13 @@ flush-write-stream@^1.0.0:
inherits "^2.0.3"
readable-stream "^2.3.6"
follow-redirects@1.0.0:
version "1.0.0"
resolved "https://registry.npm.taobao.org/follow-redirects/download/follow-redirects-1.0.0.tgz?cache=0&sync_timestamp=1585479417937&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffollow-redirects%2Fdownload%2Ffollow-redirects-1.0.0.tgz#8e34298cbd2e176f254effec75a1c78cc849fd37"
integrity sha1-jjQpjL0uF28lTv/sdaHHjMhJ/Tc=
dependencies:
debug "^2.2.0"
follow-redirects@1.5.10:
version "1.5.10"
resolved "https://registry.npm.taobao.org/follow-redirects/download/follow-redirects-1.5.10.tgz?cache=0&sync_timestamp=1585479417937&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffollow-redirects%2Fdownload%2Ffollow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a"
@@ -3786,6 +3909,11 @@ gzip-size@^5.0.0:
duplexer "^0.1.1"
pify "^4.0.1"
hammerjs@^2.0.8:
version "2.0.8"
resolved "https://registry.npm.taobao.org/hammerjs/download/hammerjs-2.0.8.tgz#04ef77862cff2bb79d30f7692095930222bf60f1"
integrity sha1-BO93hiz/K7edMPdpIJWTAiK/YPE=
handle-thing@^2.0.0:
version "2.0.1"
resolved "https://registry.npm.taobao.org/handle-thing/download/handle-thing-2.0.1.tgz#857f79ce359580c340d43081cc648970d0bb234e"
@@ -4814,6 +4942,11 @@ locate-path@^5.0.0:
dependencies:
p-locate "^4.1.0"
lodash.debounce@^4.0.8:
version "4.0.8"
resolved "https://registry.npm.taobao.org/lodash.debounce/download/lodash.debounce-4.0.8.tgz?cache=0&sync_timestamp=1571657605147&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash.debounce%2Fdownload%2Flodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168=
lodash.defaultsdeep@^4.6.1:
version "4.6.1"
resolved "https://registry.npm.taobao.org/lodash.defaultsdeep/download/lodash.defaultsdeep-4.6.1.tgz#512e9bd721d272d94e3d3a63653fa17516741ca6"
@@ -4834,6 +4967,11 @@ lodash.memoize@^4.1.2:
resolved "https://registry.npm.taobao.org/lodash.memoize/download/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=
lodash.throttle@^4.1.1:
version "4.1.1"
resolved "https://registry.npm.taobao.org/lodash.throttle/download/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4"
integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=
lodash.transform@^4.6.0:
version "4.6.0"
resolved "https://registry.npm.taobao.org/lodash.transform/download/lodash.transform-4.6.0.tgz#12306422f63324aed8483d3f38332b5f670547a0"
@@ -5385,7 +5523,7 @@ oauth-sign@~0.9.0:
resolved "https://registry.npm.taobao.org/oauth-sign/download/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
integrity sha1-R6ewFrqmi1+g7PPe4IqFxnmsZFU=
object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
object-assign@>=4.0.1, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.npm.taobao.org/object-assign/download/object-assign-4.1.1.tgz?cache=0&sync_timestamp=1571657171505&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fobject-assign%2Fdownload%2Fobject-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
@@ -6128,6 +6266,14 @@ postcss-ordered-values@^4.1.2:
postcss "^7.0.0"
postcss-value-parser "^3.0.0"
postcss-px-to-viewport@^1.1.1:
version "1.1.1"
resolved "https://registry.npm.taobao.org/postcss-px-to-viewport/download/postcss-px-to-viewport-1.1.1.tgz#a25ca410b553c9892cc8b525cc710da47bf1aa55"
integrity sha1-olykELVTyYksyLUlzHENpHvxqlU=
dependencies:
object-assign ">=4.0.1"
postcss ">=5.0.2"
postcss-reduce-initial@^4.0.3:
version "4.0.3"
resolved "https://registry.npm.taobao.org/postcss-reduce-initial/download/postcss-reduce-initial-4.0.3.tgz#7fd42ebea5e9c814609639e2c2e84ae270ba48df"
@@ -6195,6 +6341,15 @@ postcss-value-parser@^4.0.0, postcss-value-parser@^4.0.2, postcss-value-parser@^
resolved "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-4.0.3.tgz?cache=0&sync_timestamp=1582065311556&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-value-parser%2Fdownload%2Fpostcss-value-parser-4.0.3.tgz#651ff4593aa9eda8d5d0d66593a2417aeaeb325d"
integrity sha1-ZR/0WTqp7ajV0NZlk6JBeurrMl0=
postcss@>=5.0.2:
version "7.0.29"
resolved "https://registry.npm.taobao.org/postcss/download/postcss-7.0.29.tgz#d3a903872bd52280b83bce38cdc83ce55c06129e"
integrity sha1-06kDhyvVIoC4O844zcg85VwGEp4=
dependencies:
chalk "^2.4.2"
source-map "^0.6.1"
supports-color "^6.1.0"
postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.27, postcss@^7.0.5, postcss@^7.0.6:
version "7.0.27"
resolved "https://registry.npm.taobao.org/postcss/download/postcss-7.0.27.tgz?cache=0&sync_timestamp=1581994853208&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss%2Fdownload%2Fpostcss-7.0.27.tgz#cc67cdc6b0daa375105b7c424a85567345fc54d9"
@@ -6329,6 +6484,11 @@ q@^1.1.2:
resolved "https://registry.npm.taobao.org/q/download/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=
qr.js@0.0.0:
version "0.0.0"
resolved "https://registry.npm.taobao.org/qr.js/download/qr.js-0.0.0.tgz#cace86386f59a0db8050fa90d9b6b0e88a1e364f"
integrity sha1-ys6GOG9ZoNuAUPqQ2baw6IoeNk8=
qs@6.7.0:
version "6.7.0"
resolved "https://registry.npm.taobao.org/qs/download/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
@@ -6828,6 +6988,11 @@ sha.js@^2.4.0, sha.js@^2.4.8:
inherits "^2.0.1"
safe-buffer "^5.0.1"
shake.js@^1.2.2:
version "1.2.2"
resolved "https://registry.npm.taobao.org/shake.js/download/shake.js-1.2.2.tgz#b2ac560a82abe68d78a029623a7088e1b30bacff"
integrity sha1-sqxWCoKr5o14oCliOnCI4bMLrP8=
shebang-command@^1.2.0:
version "1.2.0"
resolved "https://registry.npm.taobao.org/shebang-command/download/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
@@ -7785,6 +7950,16 @@ validate-npm-package-license@^3.0.1:
spdx-correct "^3.0.0"
spdx-expression-parse "^3.0.0"
validator@^9.3.0:
version "9.4.1"
resolved "https://registry.npm.taobao.org/validator/download/validator-9.4.1.tgz#abf466d398b561cd243050112c6ff1de6cc12663"
integrity sha1-q/Rm05i1Yc0kMFARLG/x3mzBJmM=
vanilla-masker@^1.2.0:
version "1.2.0"
resolved "https://registry.npm.taobao.org/vanilla-masker/download/vanilla-masker-1.2.0.tgz#c2830e9d994a5fecd2261506477c2707fe589756"
integrity sha1-woMOnZlKX+zSJhUGR3wnB/5Yl1Y=
vary@~1.1.2:
version "1.1.2"
resolved "https://registry.npm.taobao.org/vary/download/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
@@ -7878,6 +8053,43 @@ vuex@^3.1.3:
resolved "https://registry.npm.taobao.org/vuex/download/vuex-3.1.3.tgz#f2ad73e3fb73691698b38c93f66e58e267947180"
integrity sha1-8q1z4/tzaRaYs4yT9m5Y4meUcYA=
vux-blazy@^1.6.4:
version "1.6.4"
resolved "https://registry.npm.taobao.org/vux-blazy/download/vux-blazy-1.6.4.tgz#e33073d902e0a3844ef1a463cce3ca2e0aab47bf"
integrity sha1-4zBz2QLgo4RO8aRjzOPKLgqrR78=
vux-xscroll@^3.1.10:
version "3.1.12"
resolved "https://registry.npm.taobao.org/vux-xscroll/download/vux-xscroll-3.1.12.tgz#e352e7f9dc5f9fee9253db331c967dd56b3bc950"
integrity sha1-41Ln+dxfn+6SU9szHJZ91Ws7yVA=
vux@^2.9.4:
version "2.9.4"
resolved "https://registry.npm.taobao.org/vux/download/vux-2.9.4.tgz#3964df4f0ac54b3fbf6cc9beb072e44dce00afaa"
integrity sha1-OWTfTwrFSz+/bMm+sHLkTc4Ar6o=
dependencies:
"@antv/f2" "^3.1.4-beta.2"
array-filter "^1.0.0"
array-find "^1.0.0"
array-map "^0.0.0"
array-shuffle "^1.0.1"
autosize "^3.0.20"
axios "^0.15.3"
big.js "^3.1.3"
blueimp-md5 "^2.6.0"
countup.js "^1.8.1"
fastclick "^1.0.6"
lodash.debounce "^4.0.8"
lodash.throttle "^4.1.1"
object-assign "^4.1.0"
qr.js "0.0.0"
shake.js "^1.2.2"
validator "^9.3.0"
vanilla-masker "^1.2.0"
vux-blazy "^1.6.4"
vux-xscroll "^3.1.10"
x-photoswipe "^4.1.3-rc.1"
watchpack@^1.6.0:
version "1.6.1"
resolved "https://registry.npm.taobao.org/watchpack/download/watchpack-1.6.1.tgz#280da0a8718592174010c078c7585a74cd8cd0e2"
@@ -8113,6 +8325,11 @@ ws@~6.1.0:
dependencies:
async-limiter "~1.0.0"
x-photoswipe@^4.1.3-rc.1:
version "4.1.3-rc.1"
resolved "https://registry.npm.taobao.org/x-photoswipe/download/x-photoswipe-4.1.3-rc.1.tgz#e761901752dd3dd1f718e538514b609b5df5f7db"
integrity sha1-52GQF1LdPdH3GOU4UUtgm13199s=
xmlhttprequest-ssl@~1.5.4:
version "1.5.5"
resolved "https://registry.npm.taobao.org/xmlhttprequest-ssl/download/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e"