From ceba41fb08356dfaed18bf958b3c15a3dce1e344 Mon Sep 17 00:00:00 2001
From: wsy182 <2392948297@qq.com>
Date: Tue, 24 Mar 2026 16:26:13 +0800
Subject: [PATCH] ``` style(global): update background gradients and visual
styling
- Replace radial gradient with combined radial and linear gradients
- Update color schemes with warmer tones and improved transparency
- Adjust border colors and add subtle glow effects
- Increase blur intensity for better glassmorphism effect
style(game): enhance seat player card design
- Add avatar panel container for better layout structure
- Implement dealer mark positioning with absolute placement
- Add missing suit icons with computed property mapping
- Replace text-based missing marks with image icons when available
- Improve visual hierarchy and spacing between elements
refactor(game): add computed property for dynamic suit icon selection
- Import suit icon assets (wan, tong, tiao)
- Create computed property to map suit labels to corresponding icons
- Handle fallback to text display when no icon is available
```
---
src/assets/styles/global.css | 101 ++-
src/components/game/SeatPlayerCard.vue | 32 +-
src/views/ChengduGamePage.vue | 1101 +++++++++++++++++++-----
3 files changed, 966 insertions(+), 268 deletions(-)
diff --git a/src/assets/styles/global.css b/src/assets/styles/global.css
index 81e0ee8..95cadbd 100644
--- a/src/assets/styles/global.css
+++ b/src/assets/styles/global.css
@@ -23,7 +23,9 @@ body,
body {
margin: 0;
min-width: 320px;
- background: radial-gradient(circle at 12% 12%, #254935 0%, #11251c 45%, #0a1411 100%);
+ background:
+ radial-gradient(circle at top, rgba(219, 171, 91, 0.16), transparent 22%),
+ linear-gradient(180deg, #442621 0%, #24110e 100%);
}
#app {
@@ -54,10 +56,12 @@ p {
width: min(440px, 100%);
padding: 28px 24px;
border-radius: 16px;
- border: 1px solid rgba(255, 255, 255, 0.16);
- background: rgba(8, 27, 20, 0.82);
- backdrop-filter: blur(8px);
- box-shadow: 0 18px 40px rgba(0, 0, 0, 0.35);
+ border: 1px solid rgba(246, 212, 139, 0.18);
+ background:
+ linear-gradient(180deg, rgba(62, 33, 26, 0.96), rgba(26, 14, 11, 0.96)),
+ radial-gradient(circle at top, rgba(255, 214, 134, 0.08), transparent 40%);
+ backdrop-filter: blur(10px);
+ box-shadow: 0 18px 40px rgba(0, 0, 0, 0.42);
}
.auth-card h1 {
@@ -204,8 +208,10 @@ button:disabled {
gap: 12px;
padding: 18px;
border-radius: 14px;
- border: 1px solid rgba(255, 255, 255, 0.15);
- background: linear-gradient(130deg, rgba(22, 57, 43, 0.9), rgba(10, 30, 22, 0.92));
+ border: 1px solid rgba(244, 210, 140, 0.14);
+ background:
+ linear-gradient(180deg, rgba(62, 33, 26, 0.94), rgba(30, 15, 12, 0.92)),
+ radial-gradient(circle at top, rgba(255, 214, 134, 0.08), transparent 42%);
}
.hall-topbar {
@@ -289,8 +295,8 @@ button:disabled {
.panel {
padding: 18px;
border-radius: 14px;
- border: 1px solid rgba(255, 255, 255, 0.12);
- background: rgba(10, 30, 22, 0.85);
+ border: 1px solid rgba(244, 210, 140, 0.12);
+ background: rgba(40, 21, 17, 0.8);
}
.panel h2 {
@@ -762,16 +768,25 @@ button:disabled {
display: flex;
align-items: center;
gap: 10px;
- min-width: 148px;
- padding: 8px 12px;
- border-radius: 14px;
- border: 1px solid rgba(244, 222, 163, 0.24);
- background: rgba(8, 27, 20, 0.72);
- box-shadow: 0 12px 28px rgba(0, 0, 0, 0.2);
+ min-width: 154px;
+ padding: 9px 12px;
+ border-radius: 16px;
+ border: 1px solid rgba(248, 226, 173, 0.24);
+ background:
+ linear-gradient(180deg, rgba(43, 52, 73, 0.84), rgba(17, 22, 34, 0.82)),
+ radial-gradient(circle at top, rgba(255, 255, 255, 0.08), transparent 40%);
+ box-shadow:
+ inset 0 1px 0 rgba(255, 255, 255, 0.08),
+ 0 12px 28px rgba(0, 0, 0, 0.24);
+}
+
+.avatar-panel {
+ position: relative;
+ flex: 0 0 auto;
}
.player-badge.seat-top {
- top: 76px;
+ top: 28px;
left: 50%;
transform: translateX(-50%);
}
@@ -783,7 +798,7 @@ button:disabled {
}
.player-badge.seat-bottom {
- bottom: 90px;
+ bottom: 136px;
left: 50%;
transform: translateX(-50%);
}
@@ -805,22 +820,29 @@ button:disabled {
.avatar-card {
display: grid;
place-items: center;
- width: 42px;
- height: 42px;
- border-radius: 12px;
- background: linear-gradient(145deg, #ecd995, #d3b767);
- color: #1c2d23;
+ width: 48px;
+ height: 48px;
+ border-radius: 10px;
+ border: 1px solid rgba(255, 248, 215, 0.32);
+ background:
+ linear-gradient(145deg, #b3e79c, #4eaf4a 46%, #2f7e28 100%);
+ color: #f7fff7;
font-weight: 800;
+ box-shadow:
+ inset 0 2px 4px rgba(255, 255, 255, 0.18),
+ 0 6px 14px rgba(0, 0, 0, 0.22);
}
.player-meta p {
font-size: 14px;
font-weight: 700;
+ color: #eef5ff;
}
.player-meta strong {
- font-size: 13px;
- color: #f7e4b0;
+ font-size: 15px;
+ color: #ffd85c;
+ text-shadow: 0 0 10px rgba(255, 216, 92, 0.2);
}
.dealer-mark,
@@ -828,22 +850,39 @@ button:disabled {
display: inline-flex;
align-items: center;
justify-content: center;
- min-width: 24px;
- height: 24px;
- padding: 0 6px;
+ min-width: 28px;
+ height: 28px;
border-radius: 999px;
font-size: 12px;
}
.dealer-mark {
- background: rgba(236, 188, 84, 0.88);
- color: #1c2d23;
+ position: absolute;
+ right: -8px;
+ bottom: -6px;
+ background: linear-gradient(180deg, #ffe38a 0%, #f1b92e 100%);
+ color: #5f3200;
+ box-shadow: 0 6px 12px rgba(0, 0, 0, 0.18);
}
.missing-mark {
margin-left: auto;
- background: rgba(255, 255, 255, 0.08);
- color: #d6eadf;
+ width: 34px;
+ height: 34px;
+ padding: 0;
+ overflow: hidden;
+ background: linear-gradient(180deg, rgba(114, 219, 149, 0.2) 0%, rgba(21, 148, 88, 0.34) 100%);
+ box-shadow: 0 6px 12px rgba(0, 0, 0, 0.16);
+}
+
+.missing-mark img {
+ width: 22px;
+ height: 22px;
+ object-fit: contain;
+}
+
+.missing-mark span {
+ color: #effff5;
}
.wall {
diff --git a/src/components/game/SeatPlayerCard.vue b/src/components/game/SeatPlayerCard.vue
index 8544e36..003b993 100644
--- a/src/components/game/SeatPlayerCard.vue
+++ b/src/components/game/SeatPlayerCard.vue
@@ -1,10 +1,27 @@
@@ -12,12 +29,19 @@ defineProps<{
class="player-badge"
:class="[seatClass, { 'is-turn': player.isTurn, offline: !player.isOnline }]"
>
- {{ player.avatar }}
+
+
{{ player.avatar }}
+
庄
+
+
- 庄
- {{ player.missingSuitLabel }}
+
+
+
![]()
+
{{ player.missingSuitLabel }}
+
diff --git a/src/views/ChengduGamePage.vue b/src/views/ChengduGamePage.vue
index de7ff56..cf8dd84 100644
--- a/src/views/ChengduGamePage.vue
+++ b/src/views/ChengduGamePage.vue
@@ -2,6 +2,9 @@
import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import deskImage from '../assets/images/desk/desk_01.png'
+import wanIcon from '../assets/images/flowerClolor/wan.png'
+import tongIcon from '../assets/images/flowerClolor/tong.png'
+import tiaoIcon from '../assets/images/flowerClolor/tiao.png'
import topBackImage from '../assets/images/tiles/top/tbgs_2.png'
import rightBackImage from '../assets/images/tiles/right/tbgs_1.png'
import bottomBackImage from '../assets/images/tiles/bottom/tdbgs_4.png'
@@ -86,10 +89,6 @@ const formattedClock = computed(() => {
})
})
-const statusRibbon = computed(() => {
- return roomState.value.game?.rule?.name || currentPhaseText.value
-})
-
const wallBacks = computed>(() => {
const wallSize = roomState.value.game?.state?.wall.length ?? 0
const perSide = Math.max(6, Math.ceil((wallSize || 48) / 4 / 2))
@@ -138,42 +137,24 @@ const seatDecor = computed>(() => {
dealer: seat.player.index === dealerIndex,
isTurn: seat.isTurn,
isOnline: true,
- missingSuitLabel: defaultMissingSuitLabel,
+ missingSuitLabel: missingSuitLabel(seat.player.missingSuit),
}
}
return result
})
-const seatMarkers = computed(() => {
- const seatTitleMap: Record = {
- top: '上家',
- right: '右家',
- bottom: '本家',
- left: '左家',
- }
-
- return seatViews.value.map((seat) => ({
- key: seat.key,
- occupied: Boolean(seat.player),
- isSelf: seat.isSelf,
- isTurn: seat.isTurn,
- label: seat.player ? seatTitleMap[seat.key] : '空位',
- subLabel: seat.player ? `座位 ${seat.player.index}` : '',
- }))
-})
-
const centerTimer = computed(() => {
const wallLeft = roomState.value.game?.state?.wall.length
if (typeof wallLeft === 'number' && Number.isFinite(wallLeft)) {
- return `余牌 ${wallLeft}`
+ return String(wallLeft).padStart(2, '0')
}
- return roomState.value.playerCount > 0
- ? `${roomState.value.playerCount}/${roomState.value.maxPlayers} 人`
- : '等待中'
+ return String(roomState.value.playerCount).padStart(2, '0')
})
+const selectedTileText = computed(() => selectedTile.value ?? '未选择')
+
const pendingClaimText = computed(() => {
const claim = roomState.value.game?.state?.pendingClaim
if (!claim) {
@@ -183,12 +164,24 @@ const pendingClaimText = computed(() => {
try {
return JSON.stringify(claim)
} catch {
- return '存在响应窗口'
+ return '有待响应动作'
}
})
-const selectedTileText = computed(() => {
- return selectedTile.value ?? '未选择'
+const rightMessages = computed(() => wsMessages.value.slice(-16).reverse())
+
+const floatingMissingSuit = computed(() => {
+ const suitMap: Record = {
+ 万: wanIcon,
+ 筒: tongIcon,
+ 条: tiaoIcon,
+ }
+
+ return {
+ top: suitMap[seatDecor.value.top.missingSuitLabel] ?? '',
+ left: suitMap[seatDecor.value.left.missingSuitLabel] ?? '',
+ right: suitMap[seatDecor.value.right.missingSuitLabel] ?? '',
+ }
})
function missingSuitLabel(value: string | null | undefined): string {
@@ -216,6 +209,16 @@ function getBackImage(seat: SeatKey): string {
return imageMap[seat]
}
+function actionTheme(type: string): 'gold' | 'jade' | 'blue' {
+ if (type === 'hu' || type === 'gang') {
+ return 'gold'
+ }
+ if (type === 'pass') {
+ return 'jade'
+ }
+ return 'blue'
+}
+
onMounted(() => {
clockTimer = window.setInterval(() => {
now.value = Date.now()
@@ -231,249 +234,881 @@ onBeforeUnmount(() => {
-