Compare commits

..
19 Commits
Author SHA1 Message Date
fengshao1227 cc3ea27b1d feat(gameRecords): 会员游戏记录增加洗码量显示 2026-05-29 11:58:31 +08:00
黎小北 b36f75599e 手机端项目整体UI调整修改 2026-05-14 16:45:12 +08:00
testadmin 31996b716f fix: 退出登录清空浏览器历史栈,防止返回键回到游戏页面 2026-05-13 13:49:47 +08:00
testadmin e8f0e2efbe feat: AlinPay 充值改为 iframe 内嵌弹窗,不再跳转外链 2026-04-26 20:37:50 +08:00
testadmin fcda0e1f0d feat: 充值页新增 CCpay 银行QR 第三通道
- recharge.vue: 新增 Ngân hàng QR tab + 银行QR弹窗 + 轮询到账
- api.js: 新增 ccpayDeposit / ccpayOrderStatus 接口
2026-04-20 11:15:47 +08:00
testadmin a81b39aef0 feat(recharge): USDT 提示语明确输入货币为 VND + 新汇率 27100 2026-04-16 23:33:46 +08:00
testadmin 301af6d91c feat(recharge): USDT 通道改为内嵌二维码弹窗,替代跳转 pay.g7g7.top
- 复用 qr-image 库生成 TRC20 地址二维码(YBF 分支已在用,无需新依赖)
- u-popup 内嵌展示:地址/精确金额/QR/倒计时,可一键复制
- 每 3s 轮询 /epay_order_status,成功后刷新用户信息并自动关闭
- 新增 api.epayOrderStatus
- 后端未返回 qrcode 时回退跳转式(向后兼容)
2026-04-16 23:31:52 +08:00
li 99e4265e01 fix(portal): 越南双 tab 按 area_id=3 判断,与 PC 统一
之前只认 pay_channel=='ALIN_VN'(只有 2 个账号),
现在所有 area_id=3 的越南用户都能看到 银行卡/USDT 双 tab。
BC/YBF 分支加 area_id != 3 条件避免重复。
2026-04-15 23:52:37 +08:00
li 91fa85f4ef feat: 越南充值页加 USDT (TRC20) 通道切换
- recharge.vue: 银行卡 / USDT 两个 tab,共用 amount 输入
- api.js: 新增 epayDeposit 调 /epay_online_order

USDT 请求体多传 pay_type='usdt',下单响应同 AlinPay 走 Data.url 跳转
2026-04-15 23:19:16 +08:00
b67b11c181 chore: 杂项更新(gitignore/登录/注册/首页微调)
Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-03-22 12:56:08 +08:00
18a4d03c3a feat: 对接越南AlinPay支付(充值+提现)
- recharge.vue: 新增ALIN_VN充值模板,最低1,000,000 VND
- withdraw.vue: 新增银行卡提现模板,银行列表API加载,最低1,000,000 VND
- api.js: 新增alinDeposit/applyWithdrawBank/getBankListVn接口

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-03-22 12:55:52 +08:00
li be597042c8 fix: 大厅余额K格式化 + 货币符号改为越南盾₫
- 左上角余额用 $fk() 包裹,≥1000显示为K格式
- 货币符号从 ¥ 改为 ₫(越南盾)
2026-02-11 16:41:43 +08:00
li 27cdc9a568 fix: 大厅限红动态显示+K格式化,在线人数动态计算
- 限红从 item.limit_money 动态拆分显示(上限/下限),不再硬编码
- 上限值≥1000自动显示为K格式(如50000→50K)
- 在线人数改为动态计算(基础800+时段浮动+随机数)
- 注入全局 $fk 方法用于金额K格式化
2026-02-11 16:29:34 +08:00
li 124cbf36ce fix: 牛牛路单改白底+限制最多显示7列,对齐游戏内UI风格 2026-02-11 01:54:05 +08:00
li 87c12ed6c2 style: 优化牛牛路单表格样式,对齐百家乐UI风格 2026-02-11 01:47:55 +08:00
li d0ff375ba7 feat: 牛牛/三卡大厅路单改为表格样式,显示牛型文字和WIN标记 2026-02-11 01:43:15 +08:00
li 88b9e49108 fix: 修复牛牛/三卡路单在大厅不显示的问题,适配nn_waybill数据结构 2026-02-11 01:37:02 +08:00
li 322cc24208 feat: integrate customer service chat functionality and add socket.io-client dependency
- Implemented a customer service chat interface in the application.
- Added socket.io-client for real-time communication.
- Updated language files to include customer service related translations.
- Modified navigation to direct users to the customer service page.
- Enhanced UI elements for better user experience in chat interactions.
2026-01-29 03:04:52 +08:00
li 14c8cbffcc add 2026-01-26 23:21:30 +08:00
39 changed files with 4829 additions and 787 deletions
+1
View File
@@ -32,3 +32,4 @@ pnpm-debug.log*
*.log
*.tmp
*.temp
.ace-tool/
+100 -9
View File
@@ -5,6 +5,7 @@
['Recharge', 'Withdraw', 'Index', 'User', 'Transfer'].includes(routeName)
"
>
<view class="tab-bar__shell">
<view
class="item"
:class="{ active: routeName == item.name }"
@@ -12,14 +13,20 @@
:key="index"
@click="goTab(item)"
>
<view class="item-inner">
<view class="item-indicator"></view>
<view class="icon-box">
<image
class="icon"
:src="routeName == item.name ? item.selectedIconPath : item.iconPath"
alt=""
></image>
</view>
<view class="text">{{ item.text }}</view>
</view>
</view>
</view>
</view>
</template>
<script>
@@ -122,27 +129,111 @@ export default {
left: 0;
right: 0;
bottom: 0;
z-index: 99;
padding: 0 8px 4px;
background: linear-gradient(
180deg,
rgba(0, 0, 0, 0) 0%,
rgba(0, 0, 0, 0.12) 26%,
rgba(0, 0, 0, 0.32) 100%
);
.tab-bar__shell {
display: flex;
background: #000;
justify-content: space-between;
height: 50px;
align-items: stretch;
min-height: 56px;
padding: 4px 5px calc(4px + env(safe-area-inset-bottom));
background: linear-gradient(
180deg,
rgba(9, 8, 7, 0.98) 0%,
rgba(2, 2, 2, 0.99) 100%
);
border: 1px solid rgba(226, 193, 117, 0.22);
border-bottom: none;
border-radius: 16px 16px 0 0;
box-shadow: 0 -8px 22px rgba(0, 0, 0, 0.18),
inset 0 1px 0 rgba(255, 243, 212, 0.04);
}
.item {
flex: 1;
min-width: 0;
color: rgba(255, 255, 255, 0.84);
.item-inner {
position: relative;
display: flex;
align-items: center;
flex-direction: column;
justify-content: center;
color: #fff;
&.active {
color: #deb366;
min-height: 46px;
margin: 0 1px;
padding: 5px 5px 2px;
border-radius: 14px;
transition: all 0.2s ease;
}
.item-indicator {
position: absolute;
top: -1px;
left: 50%;
width: 20px;
height: 2px;
border-radius: 999px;
background: transparent;
transform: translateX(-50%);
}
.icon-box {
width: 28px;
height: 28px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 10px;
transition: all 0.2s ease;
}
.icon {
width: 25px;
height: 25px;
width: 22px;
height: 22px;
}
.text {
font-size: 12px;
padding-top: 2px;
margin-top: 2px;
font-size: 11px;
line-height: 1.2;
letter-spacing: 0.2px;
white-space: nowrap;
transition: all 0.2s ease;
}
&.active {
color: #e8c26f;
.item-inner {
background: linear-gradient(
180deg,
rgba(63, 46, 20, 0.24) 0%,
rgba(30, 22, 13, 0.08) 100%
);
box-shadow: inset 0 1px 0 rgba(255, 236, 192, 0.08);
}
.item-indicator {
background: linear-gradient(90deg, #f4ddb0 0%, #d9ae55 100%);
}
.icon-box {
background: rgba(225, 191, 116, 0.08);
box-shadow: inset 0 1px 0 rgba(255, 244, 219, 0.06);
}
.text {
font-weight: 600;
text-shadow: 0 0 10px rgba(217, 174, 85, 0.1);
}
}
}
}
+23
View File
@@ -72,6 +72,12 @@ var cn = {
commission: "手续费",
amountCannotBe0: "金额不能为0",
submittingApplication: "提交申请中...",
bankName: "银行名称",
accountName: "账户姓名",
accountNumber: "银行卡号",
enterAccountName: "请输入账户姓名",
enterAccountNumber: "请输入银行卡号",
insufficientBalance: "余额不足",
transfer: "划转",
accountBalance: "账户余额",
@@ -86,6 +92,7 @@ var cn = {
user: "我的",
userBalance: "余额",
customerService: "在线客服",
logout: "退出登录",
tip: "提示",
logoutTip: "确认退出登录?",
@@ -150,6 +157,7 @@ var cn = {
tableNumber: "桌台号",
playingMethod: "玩法",
maliang: "码粮",
ximaliang: "洗码量",
result: "结果",
totalBetting: "总投注",
totalWin: "总输赢",
@@ -174,6 +182,21 @@ var cn = {
chooseCoin: "请选择币种",
flagshipHall: "旗舰厅",
liveHall: "现场厅",
// 在线客服
csConnected: "已连接",
csConnecting: "连接中...",
csWelcome: "欢迎使用在线客服",
csBusy: "客服繁忙,请稍候...",
csInputTip: "请输入您的问题",
csInputPlaceholder: "输入消息,点击发送...",
csSend: "发送",
csMe: "我",
csAgent: "客服",
csSessionEnded: "会话已结束",
csAgentServing: "客服为您服务",
csAgentJoined: "已接入",
csConnectFailed: "连接失败",
};
export { cn };
+24 -1
View File
@@ -29,7 +29,7 @@ var en = {
baccarat: "Baccarat",
niuniu: "Bull Bull",
longhu: "D-Tiger",
longhu: "Dragon-Tiger",
lunpan: "Roulette",
threecard: "3-Card",
zhajinghua: "Sedie",
@@ -72,6 +72,12 @@ var en = {
commission: "Commission",
amountCannotBe0: "Amount cannot be 0",
submittingApplication: "Submitting Application...",
bankName: "Bank Name",
accountName: "Account Name",
accountNumber: "Bank Account Number",
enterAccountName: "Please enter account name",
enterAccountNumber: "Please enter bank account number",
insufficientBalance: "Insufficient balance",
transfer: "Transfer",
accountBalance: "Account Balance",
@@ -86,6 +92,7 @@ var en = {
user: "User",
userBalance: "Balance",
customerService: "Customer Service",
logout: "Logout",
tip: "Tip",
logoutTip: "Are you sure to logout?",
@@ -154,6 +161,7 @@ var en = {
tableNumber: "Table Number",
playingMethod: "Playing Method",
maliang: "Rebate",
ximaliang: "Turnover",
result: "Result",
totalBetting: "Total Betting",
totalWin: "Total Win or Lose",
@@ -178,6 +186,21 @@ var en = {
chooseCoin: "Currency",
flagshipHall: "Flagship Hall",
liveHall: "Live hall",
// Customer Service
csConnected: "Connected",
csConnecting: "Connecting...",
csWelcome: "Welcome to Customer Service",
csBusy: "Agents are busy, please wait...",
csInputTip: "Please enter your question",
csInputPlaceholder: "Type a message and send...",
csSend: "Send",
csMe: "Me",
csAgent: "Agent",
csSessionEnded: "Session ended",
csAgentServing: "is serving you",
csAgentJoined: "has joined",
csConnectFailed: "Connection failed",
};
export { en };
+25 -2
View File
@@ -27,10 +27,10 @@ var In = {
goLogin: "Sudah memiliki akun? Login",
submit: "Kirim",
baccarat: "Baccarat",
baccarat: "Bakarat",
niuniu: "Sapi Sapi",
longhu: "Naga Harimau",
lunpan: "Roulette",
lunpan: "Rolet",
threecard: "3 Kartu",
zhajinghua: "Three Card Poker Nyata",
sedie: "Color Plate Nyata",
@@ -72,6 +72,12 @@ var In = {
commission: "Biaya Administrasi",
amountCannotBe0: "Jumlah tidak boleh 0",
submittingApplication: "Mengirimkan permintaan...",
bankName: "Nama Bank",
accountName: "Nama Rekening",
accountNumber: "Nomor Rekening Bank",
enterAccountName: "Masukkan nama rekening",
enterAccountNumber: "Masukkan nomor rekening bank",
insufficientBalance: "Saldo tidak cukup",
transfer: "Transfer",
accountBalance: "Saldo",
@@ -86,6 +92,7 @@ var In = {
user: "Saya",
userBalance: "Saldo",
customerService: "Layanan Pelanggan",
logout: "Keluar",
tip: "Tips",
logoutTip: "Konfirmasi keluar?",
@@ -150,6 +157,7 @@ var In = {
tableNumber: "Nomor Meja",
playingMethod: "Gameplay",
maliang: "Rabat Komisi",
ximaliang: "Turnover",
result: "Hasil",
totalBetting: "Total Taruhan",
totalWin: "Total Menang/Kalah",
@@ -173,6 +181,21 @@ var In = {
chooseCoin: "Currency",
flagshipHall: "Flagship Hall",
liveHall: "Live hall",
// Layanan Pelanggan
csConnected: "Terhubung",
csConnecting: "Menghubungkan...",
csWelcome: "Selamat datang di Layanan Pelanggan",
csBusy: "Agen sedang sibuk, harap tunggu...",
csInputTip: "Silakan masukkan pertanyaan Anda",
csInputPlaceholder: "Ketik pesan dan kirim...",
csSend: "Kirim",
csMe: "Saya",
csAgent: "Agen",
csSessionEnded: "Sesi berakhir",
csAgentServing: "melayani Anda",
csAgentJoined: "telah bergabung",
csConnectFailed: "Koneksi gagal",
};
export { In };
+23
View File
@@ -72,6 +72,12 @@ var kr = {
commission: "수수료",
amountCannotBe0: "금액은 0일 수 없습니다.",
submittingApplication: "신청 제출 중...",
bankName: "은행명",
accountName: "예금주명",
accountNumber: "은행 계좌번호",
enterAccountName: "예금주명을 입력해 주세요",
enterAccountNumber: "은행 계좌번호를 입력해 주세요",
insufficientBalance: "잔액이 부족합니다",
transfer: "전송",
accountBalance: "계정 잔액",
@@ -86,6 +92,7 @@ var kr = {
user: "나의 계정",
userBalance: "잔액",
customerService: "고객 서비스",
logout: "로그아웃",
tip: "알림",
logoutTip: "로그아웃하시겠습니까?",
@@ -150,6 +157,7 @@ var kr = {
tableNumber: "테이블 번호",
playingMethod: "플레이 방법",
maliang: "커미션 반환",
ximaliang: "롤링",
result: "결과",
totalBetting: "총 베팅",
totalWin: "총 승패",
@@ -174,6 +182,21 @@ var kr = {
chooseCoin: "통화를 선택하세요",
flagshipHall: "플래그십 홀",
liveHall: "라이브홀",
// 고객 서비스
csConnected: "연결됨",
csConnecting: "연결 중...",
csWelcome: "고객 서비스에 오신 것을 환영합니다",
csBusy: "상담원이 바빠요. 잠시만 기다려 주세요...",
csInputTip: "질문을 입력해 주세요",
csInputPlaceholder: "메시지를 입력하고 보내세요...",
csSend: "보내기",
csMe: "나",
csAgent: "상담원",
csSessionEnded: "세션 종료",
csAgentServing: "님이 도와드립니다",
csAgentJoined: "님이 참여했습니다",
csConnectFailed: "연결 실패",
};
export { kr };
+24 -1
View File
@@ -30,7 +30,7 @@ var tl = {
baccarat: "บาคาร่า",
niuniu: "วัวกระทิง",
longhu: "มังกรเสือ",
lunpan: "รูเล็ต",
lunpan: "วงล้อ",
threecard: "3 ใบ",
zhajinghua: "ไฮโลออนไลน์ Live",
sedie: "Sedie Live",
@@ -71,6 +71,12 @@ var tl = {
commission: "คอมมิชชัน",
amountCannotBe0: "ยอดไม่สามารถเป็น 0",
submittingApplication: "ยื่นถอนเงิน",
bankName: "ชื่อธนาคาร",
accountName: "ชื่อบัญชี",
accountNumber: "เลขที่บัญชีธนาคาร",
enterAccountName: "กรุณากรอกชื่อบัญชี",
enterAccountNumber: "กรุณากรอกเลขที่บัญชีธนาคาร",
insufficientBalance: "ยอดเงินคงเหลือไม่เพียงพอ",
transfer: "โอน",
accountBalance: "ยอดเงินในบัญชี",
@@ -85,6 +91,7 @@ var tl = {
user: "ผู้ใช้",
userBalance: "ยอด",
customerService: "บริการลูกค้า",
logout: "ออกจากระบบ",
tip: "คำแนะนำ",
logoutTip: "คุณต้องการออกจากระบบหรือไม่",
@@ -149,6 +156,7 @@ var tl = {
tableNumber: "หมายเลขโต๊ะ",
playingMethod: "วิธีเล่น",
maliang: "รับเงินคืน",
ximaliang: "ยอดเทิร์นโอเวอร์",
result: "ผล",
totalBetting: "ยอดเดิมพัน",
totalWin: "ยอดชนะหรือแพ้",
@@ -173,6 +181,21 @@ var tl = {
chooseCoin: "โปรดเลือกสกุลเงิน",
flagshipHall: "แฟล็กชิปฮอลล์",
liveHall: "ฮอลล์สด",
// บริการลูกค้า
csConnected: "เชื่อมต่อแล้ว",
csConnecting: "กำลังเชื่อมต่อ...",
csWelcome: "ยินดีต้อนรับสู่บริการลูกค้า",
csBusy: "เจ้าหน้าที่กำลังยุ่ง กรุณารอสักครู่...",
csInputTip: "กรุณาใส่คำถามของคุณ",
csInputPlaceholder: "พิมพ์ข้อความและส่ง...",
csSend: "ส่ง",
csMe: "ฉัน",
csAgent: "เจ้าหน้าที่",
csSessionEnded: "เซสชันสิ้นสุด",
csAgentServing: "กำลังให้บริการคุณ",
csAgentJoined: "ได้เข้าร่วม",
csConnectFailed: "เชื่อมต่อไม่สำเร็จ",
};
export { tl };
+23
View File
@@ -72,6 +72,12 @@ var tw = {
commission: "手續費",
amountCannotBe0: "金額不能為0",
submittingApplication: "提交申請中...",
bankName: "銀行名稱",
accountName: "賬戶姓名",
accountNumber: "銀行卡號",
enterAccountName: "請輸入賬戶姓名",
enterAccountNumber: "請輸入銀行卡號",
insufficientBalance: "餘額不足",
transfer: "劃轉",
accountBalance: "賬戶餘額",
@@ -86,6 +92,7 @@ var tw = {
user: "我的",
userBalance: "餘額",
customerService: "在線客服",
logout: "退出登錄",
tip: "提示",
logoutTip: "確認退出登錄?",
@@ -150,6 +157,7 @@ var tw = {
tableNumber: "桌台號",
playingMethod: "玩法",
maliang: "碼糧",
ximaliang: "洗碼量",
result: "結果",
totalBetting: "總投注",
totalWin: "總輸贏",
@@ -174,6 +182,21 @@ var tw = {
chooseCoin: "請選擇幣種",
flagshipHall: "旗艦廳",
liveHall: "現場廳",
// 在線客服
csConnected: "已連接",
csConnecting: "連接中...",
csWelcome: "歡迎使用在線客服",
csBusy: "客服繁忙,請稍候...",
csInputTip: "請輸入您的問題",
csInputPlaceholder: "輸入消息,點擊發送...",
csSend: "發送",
csMe: "我",
csAgent: "客服",
csSessionEnded: "會話已結束",
csAgentServing: "客服為您服務",
csAgentJoined: "已接入",
csConnectFailed: "連接失敗",
};
export { tw };
+24 -1
View File
@@ -27,7 +27,7 @@ var yn = {
goLogin: "Đã có tài khoản? Đến đăng nhập",
submit: "Gửi",
baccarat: "Baccarat",
baccarat: "Bài Bạc",
niuniu: "Bò Bò",
longhu: "Rồng Hổ",
lunpan: "Roulette",
@@ -72,6 +72,12 @@ var yn = {
commission: "Phí thủ tục",
amountCannotBe0: "Số tiền không thể bằng 0",
submittingApplication: "Đang gửi yêu cầu...",
bankName: "Tên ngân hàng",
accountName: "Tên tài khoản",
accountNumber: "Số tài khoản ngân hàng",
enterAccountName: "Vui lòng nhập tên tài khoản",
enterAccountNumber: "Vui lòng nhập số tài khoản ngân hàng",
insufficientBalance: "Số dư không đủ",
transfer: "Chuyển khoản",
accountBalance: "Số dư tài khoản",
@@ -86,6 +92,7 @@ var yn = {
user: "Của tôi",
userBalance: "Số dư",
customerService: "Hỗ trợ trực tuyến",
logout: "Đăng xuất",
tip: "Gợi ý",
logoutTip: "Xác nhận đăng xuất?",
@@ -154,6 +161,7 @@ var yn = {
tableNumber: "ID bàn",
playingMethod: "Lối chơi",
maliang: "Phỉnh boa",
ximaliang: "Doanh số cược",
result: "Kết quả",
totalBetting: "Tổng cược",
totalWin: "Tổng thắng thua",
@@ -178,6 +186,21 @@ var yn = {
chooseCoin: "Vui lòng chọn loại tiền tệ",
flagshipHall: "Hội trường hàng đầu",
liveHall: "Hội trường trực tiếp",
// Hỗ trợ trực tuyến
csConnected: "Đã kết nối",
csConnecting: "Đang kết nối...",
csWelcome: "Chào mừng đến với hỗ trợ trực tuyến",
csBusy: "Nhân viên đang bận, vui lòng chờ...",
csInputTip: "Hãy nhập câu hỏi của bạn",
csInputPlaceholder: "Nhập tin nhắn và gửi...",
csSend: "Gửi",
csMe: "Tôi",
csAgent: "CSKH",
csSessionEnded: "Phiên đã kết thúc",
csAgentServing: "đang phục vụ bạn",
csAgentJoined: "đã tham gia",
csConnectFailed: "Kết nối thất bại",
};
export { yn };
+14
View File
@@ -12,6 +12,20 @@ import {
Vue.config.productionTip = false;
Vue.prototype.$api = api;
const formatK = (val) => {
if (val === null || val === undefined || val === '') return val
if (typeof val === 'string' && val.includes('-')) {
return val.split('-').map(s => formatK(isNaN(s) ? s : Number(s))).join('-')
}
const n = Number(val)
if (isNaN(n)) return val
if (n >= 1000 || n <= -1000) {
const k = n / 1000
return (k % 1 === 0 ? k.toFixed(0) : k) + 'K'
}
return val
}
Vue.prototype.$fk = formatK
Vue.use(uView);
Vue.use(router);
App.mpType = "app";
+519
View File
@@ -3,12 +3,210 @@
"lockfileVersion": 3,
"requires": true,
"packages": {
"node_modules/@babel/helper-string-parser": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
"integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-identifier": {
"version": "7.28.5",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
"integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/parser": {
"version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.6.tgz",
"integrity": "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/types": "^7.28.6"
},
"bin": {
"parser": "bin/babel-parser.js"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@babel/types": {
"version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.6.tgz",
"integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-string-parser": "^7.27.1",
"@babel/helper-validator-identifier": "^7.28.5"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
"dev": true,
"license": "MIT",
"peer": true
},
"node_modules/@vue/compiler-core": {
"version": "3.5.26",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.26.tgz",
"integrity": "sha512-vXyI5GMfuoBCnv5ucIT7jhHKl55Y477yxP6fc4eUswjP8FG3FFVFd41eNDArR+Uk3QKn2Z85NavjaxLxOC19/w==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/parser": "^7.28.5",
"@vue/shared": "3.5.26",
"entities": "^7.0.0",
"estree-walker": "^2.0.2",
"source-map-js": "^1.2.1"
}
},
"node_modules/@vue/compiler-dom": {
"version": "3.5.26",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.26.tgz",
"integrity": "sha512-y1Tcd3eXs834QjswshSilCBnKGeQjQXB6PqFn/1nxcQw4pmG42G8lwz+FZPAZAby6gZeHSt/8LMPfZ4Rb+Bd/A==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@vue/compiler-core": "3.5.26",
"@vue/shared": "3.5.26"
}
},
"node_modules/@vue/compiler-sfc": {
"version": "3.5.26",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.26.tgz",
"integrity": "sha512-egp69qDTSEZcf4bGOSsprUr4xI73wfrY5oRs6GSgXFTiHrWj4Y3X5Ydtip9QMqiCMCPVwLglB9GBxXtTadJ3mA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/parser": "^7.28.5",
"@vue/compiler-core": "3.5.26",
"@vue/compiler-dom": "3.5.26",
"@vue/compiler-ssr": "3.5.26",
"@vue/shared": "3.5.26",
"estree-walker": "^2.0.2",
"magic-string": "^0.30.21",
"postcss": "^8.5.6",
"source-map-js": "^1.2.1"
}
},
"node_modules/@vue/compiler-ssr": {
"version": "3.5.26",
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.26.tgz",
"integrity": "sha512-lZT9/Y0nSIRUPVvapFJEVDbEXruZh2IYHMk2zTtEgJSlP5gVOqeWXH54xDKAaFS4rTnDeDBQUYDtxKyoW9FwDw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@vue/compiler-dom": "3.5.26",
"@vue/shared": "3.5.26"
}
},
"node_modules/@vue/devtools-api": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.5.0.tgz",
"integrity": "sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q==",
"dev": true
},
"node_modules/@vue/reactivity": {
"version": "3.5.26",
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.26.tgz",
"integrity": "sha512-9EnYB1/DIiUYYnzlnUBgwU32NNvLp/nhxLXeWRhHUEeWNTn1ECxX8aGO7RTXeX6PPcxe3LLuNBFoJbV4QZ+CFQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@vue/shared": "3.5.26"
}
},
"node_modules/@vue/runtime-core": {
"version": "3.5.26",
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.26.tgz",
"integrity": "sha512-xJWM9KH1kd201w5DvMDOwDHYhrdPTrAatn56oB/LRG4plEQeZRQLw0Bpwih9KYoqmzaxF0OKSn6swzYi84e1/Q==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@vue/reactivity": "3.5.26",
"@vue/shared": "3.5.26"
}
},
"node_modules/@vue/runtime-dom": {
"version": "3.5.26",
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.26.tgz",
"integrity": "sha512-XLLd/+4sPC2ZkN/6+V4O4gjJu6kSDbHAChvsyWgm1oGbdSO3efvGYnm25yCjtFm/K7rrSDvSfPDgN1pHgS4VNQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@vue/reactivity": "3.5.26",
"@vue/runtime-core": "3.5.26",
"@vue/shared": "3.5.26",
"csstype": "^3.2.3"
}
},
"node_modules/@vue/server-renderer": {
"version": "3.5.26",
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.26.tgz",
"integrity": "sha512-TYKLXmrwWKSodyVuO1WAubucd+1XlLg4set0YoV+Hu8Lo79mp/YMwWV5mC5FgtsDxX3qo1ONrxFaTP1OQgy1uA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@vue/compiler-ssr": "3.5.26",
"@vue/shared": "3.5.26"
},
"peerDependencies": {
"vue": "3.5.26"
}
},
"node_modules/@vue/shared": {
"version": "3.5.26",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.26.tgz",
"integrity": "sha512-7Z6/y3uFI5PRoKeorTOSXKcDj0MSasfNNltcslbFrPpcw6aXRUALq4IfJlaTRspiWIUOEZbrpM+iQGmCOiWe4A==",
"dev": true,
"license": "MIT",
"peer": true
},
"node_modules/after": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz",
"integrity": "sha512-QbJ0NTQ/I9DI3uSJA4cbexiwQeRAfjPScqIbSjUDd9TOrcg6pTkdgziesOqxBMBzit8vFCTwrP27t13vFOORRA==",
"license": "MIT"
},
"node_modules/arraybuffer.slice": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz",
"integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==",
"license": "MIT"
},
"node_modules/backo2": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
"integrity": "sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA==",
"license": "MIT"
},
"node_modules/base64-arraybuffer": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
@@ -18,6 +216,31 @@
"node": ">= 0.6.0"
}
},
"node_modules/blob": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz",
"integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==",
"license": "MIT"
},
"node_modules/component-bind": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz",
"integrity": "sha512-WZveuKPeKAG9qY+FkYDeADzdHyTYdIboXS59ixDeRJL5ZhxpqUnxSOwop4FQjMsiYm3/Or8cegVbpAHNA7pHxw=="
},
"node_modules/component-emitter": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz",
"integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/component-inherit": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz",
"integrity": "sha512-w+LhYREhatpVqTESyGFg3NlP6Iu0kEKUHETY9GoZP/pQyW4mHFZuFWRUCIqVPZ36ueVLtoOEZaAqbCF2RDndaA=="
},
"node_modules/css-line-break": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
@@ -27,12 +250,106 @@
"utrie": "^1.0.2"
}
},
"node_modules/csstype": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
"dev": true,
"license": "MIT",
"peer": true
},
"node_modules/dayjs": {
"version": "1.11.7",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz",
"integrity": "sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==",
"dev": true
},
"node_modules/debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"license": "MIT",
"dependencies": {
"ms": "2.0.0"
}
},
"node_modules/engine.io-client": {
"version": "3.5.6",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.5.6.tgz",
"integrity": "sha512-2fDMKiXSU7bGRDCWEw9cHEdRNfoU8cpP6lt+nwJhv72tSJpO7YBsqMqYZ63eVvwX3l9prPl2k/mxhfVhY+SDWg==",
"license": "MIT",
"dependencies": {
"component-emitter": "~1.3.0",
"component-inherit": "0.0.3",
"debug": "~3.1.0",
"engine.io-parser": "~2.2.0",
"has-cors": "1.1.0",
"indexof": "0.0.1",
"parseqs": "0.0.6",
"parseuri": "0.0.6",
"ws": "~7.5.10",
"xmlhttprequest-ssl": "~1.6.2",
"yeast": "0.1.2"
}
},
"node_modules/engine.io-parser": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.1.tgz",
"integrity": "sha512-x+dN/fBH8Ro8TFwJ+rkB2AmuVw9Yu2mockR/p3W8f8YtExwFgDvBDi0GWyb4ZLkpahtDGZgtr3zLovanJghPqg==",
"license": "MIT",
"dependencies": {
"after": "0.8.2",
"arraybuffer.slice": "~0.0.7",
"base64-arraybuffer": "0.1.4",
"blob": "0.0.5",
"has-binary2": "~1.0.2"
}
},
"node_modules/engine.io-parser/node_modules/base64-arraybuffer": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz",
"integrity": "sha512-a1eIFi4R9ySrbiMuyTGx5e92uRH5tQY6kArNcFaKBUleIoLjdjBg7Zxm3Mqm3Kmkf27HLR/1fnxX9q8GQ7Iavg==",
"engines": {
"node": ">= 0.6.0"
}
},
"node_modules/entities": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-7.0.0.tgz",
"integrity": "sha512-FDWG5cmEYf2Z00IkYRhbFrwIwvdFKH07uV8dvNy0omp/Qb1xcyCWp2UDtcwJF4QZZvk0sLudP6/hAu42TaqVhQ==",
"dev": true,
"license": "BSD-2-Clause",
"peer": true,
"engines": {
"node": ">=0.12"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/estree-walker": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
"dev": true,
"license": "MIT",
"peer": true
},
"node_modules/has-binary2": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz",
"integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==",
"license": "MIT",
"dependencies": {
"isarray": "2.0.1"
}
},
"node_modules/has-cors": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz",
"integrity": "sha512-g5VNKdkFuUuVCP9gYfDJHjK2nqdQJ7aDLTnycnc2+RvsOQbuLdF5pm7vuE5J76SEBIQjs4kQY/BWq74JUmjbXA==",
"license": "MIT"
},
"node_modules/html2canvas": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
@@ -46,18 +363,157 @@
"node": ">=8.0.0"
}
},
"node_modules/indexof": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
"integrity": "sha512-i0G7hLJ1z0DE8dsqJa2rycj9dBmNKgXBvotXtZYXakU9oivfB9Uj2ZBC27qqef2U58/ZLwalxa1X/RDCdkHtVg=="
},
"node_modules/isarray": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
"integrity": "sha512-c2cu3UxbI+b6kR3fy0nRnAhodsvR9dx7U5+znCOzdj6IfP3upFURTr0Xl5BlQZNKZjEtxrmVyfSdeE3O57smoQ==",
"license": "MIT"
},
"node_modules/js-md5": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/js-md5/-/js-md5-0.7.3.tgz",
"integrity": "sha512-ZC41vPSTLKGwIRjqDh8DfXoCrdQIyBgspJVPXHBGu4nZlAEvG3nf+jO9avM9RmLiGakg7vz974ms99nEV0tmTQ==",
"dev": true
},
"node_modules/magic-string": {
"version": "0.30.21",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
"integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.5"
}
},
"node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"license": "MIT"
},
"node_modules/nanoid": {
"version": "3.3.11",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"peer": true,
"bin": {
"nanoid": "bin/nanoid.cjs"
},
"engines": {
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/parseqs": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz",
"integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==",
"license": "MIT"
},
"node_modules/parseuri": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz",
"integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==",
"license": "MIT"
},
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
"dev": true,
"license": "ISC",
"peer": true
},
"node_modules/postcss": {
"version": "8.5.6",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
"integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
"dev": true,
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/postcss"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"nanoid": "^3.3.11",
"picocolors": "^1.1.1",
"source-map-js": "^1.2.1"
},
"engines": {
"node": "^10 || ^12 || >=14"
}
},
"node_modules/qr-image": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/qr-image/-/qr-image-3.2.0.tgz",
"integrity": "sha512-rXKDS5Sx3YipVsqmlMJsJsk6jXylEpiHRC2+nJy66fxA5ExYyGa4PqwteW69SaVmAb2OQ18HbYriT7cGQMbduw==",
"dev": true
},
"node_modules/socket.io-client": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.5.0.tgz",
"integrity": "sha512-lOO9clmdgssDykiOmVQQitwBAF3I6mYcQAo7hQ7AM6Ny5X7fp8hIJ3HcQs3Rjz4SoggoxA1OgrQyY8EgTbcPYw==",
"license": "MIT",
"dependencies": {
"backo2": "1.0.2",
"component-bind": "1.0.0",
"component-emitter": "~1.3.0",
"debug": "~3.1.0",
"engine.io-client": "~3.5.0",
"has-binary2": "~1.0.2",
"indexof": "0.0.1",
"parseqs": "0.0.6",
"parseuri": "0.0.6",
"socket.io-parser": "~3.3.0",
"to-array": "0.1.4"
}
},
"node_modules/socket.io-parser": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.4.tgz",
"integrity": "sha512-z/pFQB3x+EZldRRzORYW1vwVO8m/3ILkswtnpoeU6Ve3cbMWkmHEWDAVJn4QJtchiiFTo5j7UG2QvwxvaA9vow==",
"license": "MIT",
"dependencies": {
"component-emitter": "~1.3.0",
"debug": "~3.1.0",
"isarray": "2.0.1"
}
},
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
"dev": true,
"license": "BSD-3-Clause",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/text-segmentation": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
@@ -67,6 +523,11 @@
"utrie": "^1.0.2"
}
},
"node_modules/to-array": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz",
"integrity": "sha512-LhVdShQD/4Mk4zXNroIQZJC+Ap3zgLcDuwEdcmLv9CCO73NWockQDwyUnW/m8VX/EElfL6FcYx7EeutN4HJA6A=="
},
"node_modules/uni-read-pages": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/uni-read-pages/-/uni-read-pages-1.0.5.tgz",
@@ -97,6 +558,29 @@
"HBuilderX": "^3.1.0"
}
},
"node_modules/vue": {
"version": "3.5.26",
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.26.tgz",
"integrity": "sha512-SJ/NTccVyAoNUJmkM9KUqPcYlY+u8OVL1X5EW9RIs3ch5H2uERxyyIUI4MRxVCSOiEcupX9xNGde1tL9ZKpimA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@vue/compiler-dom": "3.5.26",
"@vue/compiler-sfc": "3.5.26",
"@vue/runtime-dom": "3.5.26",
"@vue/server-renderer": "3.5.26",
"@vue/shared": "3.5.26"
},
"peerDependencies": {
"typescript": "*"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/vuex": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/vuex/-/vuex-4.1.0.tgz",
@@ -108,6 +592,41 @@
"peerDependencies": {
"vue": "^3.2.0"
}
},
"node_modules/ws": {
"version": "7.5.10",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",
"integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==",
"license": "MIT",
"engines": {
"node": ">=8.3.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": "^5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/xmlhttprequest-ssl": {
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.6.3.tgz",
"integrity": "sha512-3XfeQE/wNkvrIktn2Kf0869fC0BN6UpydVasGIeSm2B1Llihf7/0UfZM+eCkOw3P7bP4+qPgqhm7ZoxuJtFU0Q==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/yeast": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz",
"integrity": "sha512-8HFIh676uyGYP6wP13R/j6OJ/1HwJ46snpvzE7aHAN3Ryqh2yX6Xox2B4CUmTwwOIzlG3Bs7ocsP5dZH/R1Qbg==",
"license": "MIT"
}
}
}
+520
View File
@@ -5,6 +5,7 @@
"packages": {
"": {
"dependencies": {
"socket.io-client": "^2.5.0",
"uview-ui": "^2.0.36"
},
"devDependencies": {
@@ -17,12 +18,210 @@
"vuex": "^4.1.0"
}
},
"node_modules/@babel/helper-string-parser": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
"integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-identifier": {
"version": "7.28.5",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
"integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/parser": {
"version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.6.tgz",
"integrity": "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/types": "^7.28.6"
},
"bin": {
"parser": "bin/babel-parser.js"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@babel/types": {
"version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.6.tgz",
"integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-string-parser": "^7.27.1",
"@babel/helper-validator-identifier": "^7.28.5"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
"dev": true,
"license": "MIT",
"peer": true
},
"node_modules/@vue/compiler-core": {
"version": "3.5.26",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.26.tgz",
"integrity": "sha512-vXyI5GMfuoBCnv5ucIT7jhHKl55Y477yxP6fc4eUswjP8FG3FFVFd41eNDArR+Uk3QKn2Z85NavjaxLxOC19/w==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/parser": "^7.28.5",
"@vue/shared": "3.5.26",
"entities": "^7.0.0",
"estree-walker": "^2.0.2",
"source-map-js": "^1.2.1"
}
},
"node_modules/@vue/compiler-dom": {
"version": "3.5.26",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.26.tgz",
"integrity": "sha512-y1Tcd3eXs834QjswshSilCBnKGeQjQXB6PqFn/1nxcQw4pmG42G8lwz+FZPAZAby6gZeHSt/8LMPfZ4Rb+Bd/A==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@vue/compiler-core": "3.5.26",
"@vue/shared": "3.5.26"
}
},
"node_modules/@vue/compiler-sfc": {
"version": "3.5.26",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.26.tgz",
"integrity": "sha512-egp69qDTSEZcf4bGOSsprUr4xI73wfrY5oRs6GSgXFTiHrWj4Y3X5Ydtip9QMqiCMCPVwLglB9GBxXtTadJ3mA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/parser": "^7.28.5",
"@vue/compiler-core": "3.5.26",
"@vue/compiler-dom": "3.5.26",
"@vue/compiler-ssr": "3.5.26",
"@vue/shared": "3.5.26",
"estree-walker": "^2.0.2",
"magic-string": "^0.30.21",
"postcss": "^8.5.6",
"source-map-js": "^1.2.1"
}
},
"node_modules/@vue/compiler-ssr": {
"version": "3.5.26",
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.26.tgz",
"integrity": "sha512-lZT9/Y0nSIRUPVvapFJEVDbEXruZh2IYHMk2zTtEgJSlP5gVOqeWXH54xDKAaFS4rTnDeDBQUYDtxKyoW9FwDw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@vue/compiler-dom": "3.5.26",
"@vue/shared": "3.5.26"
}
},
"node_modules/@vue/devtools-api": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.5.0.tgz",
"integrity": "sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q==",
"dev": true
},
"node_modules/@vue/reactivity": {
"version": "3.5.26",
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.26.tgz",
"integrity": "sha512-9EnYB1/DIiUYYnzlnUBgwU32NNvLp/nhxLXeWRhHUEeWNTn1ECxX8aGO7RTXeX6PPcxe3LLuNBFoJbV4QZ+CFQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@vue/shared": "3.5.26"
}
},
"node_modules/@vue/runtime-core": {
"version": "3.5.26",
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.26.tgz",
"integrity": "sha512-xJWM9KH1kd201w5DvMDOwDHYhrdPTrAatn56oB/LRG4plEQeZRQLw0Bpwih9KYoqmzaxF0OKSn6swzYi84e1/Q==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@vue/reactivity": "3.5.26",
"@vue/shared": "3.5.26"
}
},
"node_modules/@vue/runtime-dom": {
"version": "3.5.26",
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.26.tgz",
"integrity": "sha512-XLLd/+4sPC2ZkN/6+V4O4gjJu6kSDbHAChvsyWgm1oGbdSO3efvGYnm25yCjtFm/K7rrSDvSfPDgN1pHgS4VNQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@vue/reactivity": "3.5.26",
"@vue/runtime-core": "3.5.26",
"@vue/shared": "3.5.26",
"csstype": "^3.2.3"
}
},
"node_modules/@vue/server-renderer": {
"version": "3.5.26",
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.26.tgz",
"integrity": "sha512-TYKLXmrwWKSodyVuO1WAubucd+1XlLg4set0YoV+Hu8Lo79mp/YMwWV5mC5FgtsDxX3qo1ONrxFaTP1OQgy1uA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@vue/compiler-ssr": "3.5.26",
"@vue/shared": "3.5.26"
},
"peerDependencies": {
"vue": "3.5.26"
}
},
"node_modules/@vue/shared": {
"version": "3.5.26",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.26.tgz",
"integrity": "sha512-7Z6/y3uFI5PRoKeorTOSXKcDj0MSasfNNltcslbFrPpcw6aXRUALq4IfJlaTRspiWIUOEZbrpM+iQGmCOiWe4A==",
"dev": true,
"license": "MIT",
"peer": true
},
"node_modules/after": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz",
"integrity": "sha512-QbJ0NTQ/I9DI3uSJA4cbexiwQeRAfjPScqIbSjUDd9TOrcg6pTkdgziesOqxBMBzit8vFCTwrP27t13vFOORRA==",
"license": "MIT"
},
"node_modules/arraybuffer.slice": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz",
"integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==",
"license": "MIT"
},
"node_modules/backo2": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
"integrity": "sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA==",
"license": "MIT"
},
"node_modules/base64-arraybuffer": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
@@ -32,6 +231,31 @@
"node": ">= 0.6.0"
}
},
"node_modules/blob": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz",
"integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==",
"license": "MIT"
},
"node_modules/component-bind": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz",
"integrity": "sha512-WZveuKPeKAG9qY+FkYDeADzdHyTYdIboXS59ixDeRJL5ZhxpqUnxSOwop4FQjMsiYm3/Or8cegVbpAHNA7pHxw=="
},
"node_modules/component-emitter": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz",
"integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/component-inherit": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz",
"integrity": "sha512-w+LhYREhatpVqTESyGFg3NlP6Iu0kEKUHETY9GoZP/pQyW4mHFZuFWRUCIqVPZ36ueVLtoOEZaAqbCF2RDndaA=="
},
"node_modules/css-line-break": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
@@ -41,12 +265,106 @@
"utrie": "^1.0.2"
}
},
"node_modules/csstype": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
"dev": true,
"license": "MIT",
"peer": true
},
"node_modules/dayjs": {
"version": "1.11.7",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz",
"integrity": "sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==",
"dev": true
},
"node_modules/debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"license": "MIT",
"dependencies": {
"ms": "2.0.0"
}
},
"node_modules/engine.io-client": {
"version": "3.5.6",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.5.6.tgz",
"integrity": "sha512-2fDMKiXSU7bGRDCWEw9cHEdRNfoU8cpP6lt+nwJhv72tSJpO7YBsqMqYZ63eVvwX3l9prPl2k/mxhfVhY+SDWg==",
"license": "MIT",
"dependencies": {
"component-emitter": "~1.3.0",
"component-inherit": "0.0.3",
"debug": "~3.1.0",
"engine.io-parser": "~2.2.0",
"has-cors": "1.1.0",
"indexof": "0.0.1",
"parseqs": "0.0.6",
"parseuri": "0.0.6",
"ws": "~7.5.10",
"xmlhttprequest-ssl": "~1.6.2",
"yeast": "0.1.2"
}
},
"node_modules/engine.io-parser": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.1.tgz",
"integrity": "sha512-x+dN/fBH8Ro8TFwJ+rkB2AmuVw9Yu2mockR/p3W8f8YtExwFgDvBDi0GWyb4ZLkpahtDGZgtr3zLovanJghPqg==",
"license": "MIT",
"dependencies": {
"after": "0.8.2",
"arraybuffer.slice": "~0.0.7",
"base64-arraybuffer": "0.1.4",
"blob": "0.0.5",
"has-binary2": "~1.0.2"
}
},
"node_modules/engine.io-parser/node_modules/base64-arraybuffer": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz",
"integrity": "sha512-a1eIFi4R9ySrbiMuyTGx5e92uRH5tQY6kArNcFaKBUleIoLjdjBg7Zxm3Mqm3Kmkf27HLR/1fnxX9q8GQ7Iavg==",
"engines": {
"node": ">= 0.6.0"
}
},
"node_modules/entities": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-7.0.0.tgz",
"integrity": "sha512-FDWG5cmEYf2Z00IkYRhbFrwIwvdFKH07uV8dvNy0omp/Qb1xcyCWp2UDtcwJF4QZZvk0sLudP6/hAu42TaqVhQ==",
"dev": true,
"license": "BSD-2-Clause",
"peer": true,
"engines": {
"node": ">=0.12"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/estree-walker": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
"dev": true,
"license": "MIT",
"peer": true
},
"node_modules/has-binary2": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz",
"integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==",
"license": "MIT",
"dependencies": {
"isarray": "2.0.1"
}
},
"node_modules/has-cors": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz",
"integrity": "sha512-g5VNKdkFuUuVCP9gYfDJHjK2nqdQJ7aDLTnycnc2+RvsOQbuLdF5pm7vuE5J76SEBIQjs4kQY/BWq74JUmjbXA==",
"license": "MIT"
},
"node_modules/html2canvas": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
@@ -60,18 +378,157 @@
"node": ">=8.0.0"
}
},
"node_modules/indexof": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
"integrity": "sha512-i0G7hLJ1z0DE8dsqJa2rycj9dBmNKgXBvotXtZYXakU9oivfB9Uj2ZBC27qqef2U58/ZLwalxa1X/RDCdkHtVg=="
},
"node_modules/isarray": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
"integrity": "sha512-c2cu3UxbI+b6kR3fy0nRnAhodsvR9dx7U5+znCOzdj6IfP3upFURTr0Xl5BlQZNKZjEtxrmVyfSdeE3O57smoQ==",
"license": "MIT"
},
"node_modules/js-md5": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/js-md5/-/js-md5-0.7.3.tgz",
"integrity": "sha512-ZC41vPSTLKGwIRjqDh8DfXoCrdQIyBgspJVPXHBGu4nZlAEvG3nf+jO9avM9RmLiGakg7vz974ms99nEV0tmTQ==",
"dev": true
},
"node_modules/magic-string": {
"version": "0.30.21",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
"integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.5"
}
},
"node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"license": "MIT"
},
"node_modules/nanoid": {
"version": "3.3.11",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"peer": true,
"bin": {
"nanoid": "bin/nanoid.cjs"
},
"engines": {
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/parseqs": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz",
"integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==",
"license": "MIT"
},
"node_modules/parseuri": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz",
"integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==",
"license": "MIT"
},
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
"dev": true,
"license": "ISC",
"peer": true
},
"node_modules/postcss": {
"version": "8.5.6",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
"integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
"dev": true,
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/postcss"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"nanoid": "^3.3.11",
"picocolors": "^1.1.1",
"source-map-js": "^1.2.1"
},
"engines": {
"node": "^10 || ^12 || >=14"
}
},
"node_modules/qr-image": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/qr-image/-/qr-image-3.2.0.tgz",
"integrity": "sha512-rXKDS5Sx3YipVsqmlMJsJsk6jXylEpiHRC2+nJy66fxA5ExYyGa4PqwteW69SaVmAb2OQ18HbYriT7cGQMbduw==",
"dev": true
},
"node_modules/socket.io-client": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.5.0.tgz",
"integrity": "sha512-lOO9clmdgssDykiOmVQQitwBAF3I6mYcQAo7hQ7AM6Ny5X7fp8hIJ3HcQs3Rjz4SoggoxA1OgrQyY8EgTbcPYw==",
"license": "MIT",
"dependencies": {
"backo2": "1.0.2",
"component-bind": "1.0.0",
"component-emitter": "~1.3.0",
"debug": "~3.1.0",
"engine.io-client": "~3.5.0",
"has-binary2": "~1.0.2",
"indexof": "0.0.1",
"parseqs": "0.0.6",
"parseuri": "0.0.6",
"socket.io-parser": "~3.3.0",
"to-array": "0.1.4"
}
},
"node_modules/socket.io-parser": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.4.tgz",
"integrity": "sha512-z/pFQB3x+EZldRRzORYW1vwVO8m/3ILkswtnpoeU6Ve3cbMWkmHEWDAVJn4QJtchiiFTo5j7UG2QvwxvaA9vow==",
"license": "MIT",
"dependencies": {
"component-emitter": "~1.3.0",
"debug": "~3.1.0",
"isarray": "2.0.1"
}
},
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
"dev": true,
"license": "BSD-3-Clause",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/text-segmentation": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
@@ -81,6 +538,11 @@
"utrie": "^1.0.2"
}
},
"node_modules/to-array": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz",
"integrity": "sha512-LhVdShQD/4Mk4zXNroIQZJC+Ap3zgLcDuwEdcmLv9CCO73NWockQDwyUnW/m8VX/EElfL6FcYx7EeutN4HJA6A=="
},
"node_modules/uni-read-pages": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/uni-read-pages/-/uni-read-pages-1.0.5.tgz",
@@ -111,6 +573,29 @@
"HBuilderX": "^3.1.0"
}
},
"node_modules/vue": {
"version": "3.5.26",
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.26.tgz",
"integrity": "sha512-SJ/NTccVyAoNUJmkM9KUqPcYlY+u8OVL1X5EW9RIs3ch5H2uERxyyIUI4MRxVCSOiEcupX9xNGde1tL9ZKpimA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@vue/compiler-dom": "3.5.26",
"@vue/compiler-sfc": "3.5.26",
"@vue/runtime-dom": "3.5.26",
"@vue/server-renderer": "3.5.26",
"@vue/shared": "3.5.26"
},
"peerDependencies": {
"typescript": "*"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/vuex": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/vuex/-/vuex-4.1.0.tgz",
@@ -122,6 +607,41 @@
"peerDependencies": {
"vue": "^3.2.0"
}
},
"node_modules/ws": {
"version": "7.5.10",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",
"integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==",
"license": "MIT",
"engines": {
"node": ">=8.3.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": "^5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/xmlhttprequest-ssl": {
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.6.3.tgz",
"integrity": "sha512-3XfeQE/wNkvrIktn2Kf0869fC0BN6UpydVasGIeSm2B1Llihf7/0UfZM+eCkOw3P7bP4+qPgqhm7ZoxuJtFU0Q==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/yeast": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz",
"integrity": "sha512-8HFIh676uyGYP6wP13R/j6OJ/1HwJ46snpvzE7aHAN3Ryqh2yX6Xox2B4CUmTwwOIzlG3Bs7ocsP5dZH/R1Qbg==",
"license": "MIT"
}
}
}
+1
View File
@@ -1,5 +1,6 @@
{
"dependencies": {
"socket.io-client": "^2.5.0",
"uview-ui": "^2.0.36"
},
"devDependencies": {
+536 -128
View File
@@ -2,30 +2,59 @@
<view class="page-container">
<!-- Top Header Area -->
<view class="top-header">
<image class="header-bg" src="/static/images/login_bg.png" mode="aspectFill"></image>
<image
class="header-bg"
src="/static/images/login_bg.png"
mode="aspectFill"
></image>
<view class="header-overlay"></view>
<view class="status-bar"></view>
<view class="header-content">
<!-- User Info Row -->
<view class="user-bar">
<view class="left-info" @click="goPage('/pages/user/index')">
<u-icon name="arrow-left" color="#f4c46f" size="20" v-if="false"></u-icon>
<view class="user-avatar">
<u-icon name="account-fill" color="#fff" size="24"></u-icon>
<view class="brand-side">
<view class="brand-logo-shell">
<image
class="brand-logo"
src="/static/logo.png"
mode="aspectFit"
></image>
</view>
</view>
<view class="header-right">
<view class="user-summary" @click="goPage('/pages/user/index')">
<text class="username">{{ userInfo.username || $lang.guest }}</text>
<view class="balance-pill">
<u-icon name="rmb-circle-fill" color="#f4c46f" size="16"></u-icon>
<text class="balance-text">{{ userInfo.money || '0.00' }}</text>
<text class="currency-symbol"></text>
<text class="balance-text">{{
$fk(userInfo.money) || "0.00"
}}</text>
</view>
</view>
<view class="right-actions">
<u-icon name="server-fill" color="#fff" size="24" @click="goService" style="margin-right: 15px;"></u-icon>
<u-icon name="grid-fill" color="#fff" size="24" @click="goPage('/pages/user/index')"></u-icon>
<view class="action-btn" @click="goService">
<u-icon name="server-fill" color="#f6e7bf" size="20"></u-icon>
</view>
<view class="action-btn" @click="goPage('/pages/user/index')">
<u-icon name="grid-fill" color="#f6e7bf" size="20"></u-icon>
</view>
</view>
</view>
</view>
<!-- Banner Area -->
<view class="banner-area">
<u-swiper :list="bannerList" height="140" radius="8" indicator indicatorMode="line" circular></u-swiper>
<u-swiper
:list="bannerList"
height="150"
radius="14"
indicator
indicatorMode="line"
circular
></u-swiper>
</view>
</view>
</view>
@@ -40,19 +69,26 @@
:class="{ active: currentCategory === cat.id }"
@click="switchCategory(cat.id)"
>
<view class="item-marker"></view>
<view class="icon-box">
<!-- Use local images or u-icons based on category -->
<image :src="cat.icon" mode="widthFix" style="width: 24px; height: 24px;" v-if="cat.icon" />
<u-icon :name="cat.uIcon" color="#ccc" size="28" v-else></u-icon>
<image :src="cat.icon" mode="widthFix" style="width: 22px; height: 22px;" v-if="cat.icon" />
<u-icon
:name="cat.uIcon"
:color="currentCategory === cat.id ? '#f1d392' : '#d1c6aa'"
size="24"
v-else
></u-icon>
</view>
<view class="cat-texts">
<text class="cat-name">{{ $lang[cat.nameKey] }}</text>
<text class="cat-count">({{ getCategoryCount(cat.id) }})</text>
<text class="cat-count">{{ getCategoryCount(cat.id) }}</text>
</view>
</view>
<!-- Online Count Bottom -->
<view class="online-count-box">
<text class="label">{{ $lang.onlineCount }}</text>
<text class="count">2506</text>
<text class="count">{{ onlineNum }}</text>
</view>
</scroll-view>
@@ -75,17 +111,18 @@
<text class="table-name">{{ item.table_name }}</text>
</view>
<view class="header-right">
<text class="limit-info">{{ $lang.maxLimit }}:50000 {{ $lang.minLimit }}:20</text>
<text class="limit-info">{{ $lang.maxLimit }}:{{ $fk((item.game_id == 4 || item.game_id == 5) && userInfo.limit_high_nn > 0 ? userInfo.limit_high_nn : (userInfo.limit_high || 0)) }} {{ $lang.minLimit }}:{{ (item.game_id == 4 || item.game_id == 5) && userInfo.limit_low_nn > 0 ? userInfo.limit_low_nn : (userInfo.limit_low || 0) }}</text>
<view class="status-live">
<view class="status-dot" :class="{ 'is-live': item.status===1 }"></view>
</view>
</view>
</view>
<!-- Roadmap Visualization (Body) -->
<view class="card-body">
<!-- Roadmap Grid (Zhupan / Bead Plate) -->
<!-- Assuming 6 rows x N columns -->
<view class="roadmap-grid">
<!-- Render grid cells -->
<view class="card-body-overlay"></view>
<!-- 百家乐/龙虎: 珠盘路圆圈 -->
<view class="roadmap-grid" v-if="item.game_id !== 4 && item.game_id !== 5">
<view
v-for="(cell, cIdx) in item.beadRoad"
:key="cIdx"
@@ -96,14 +133,33 @@
}"
:class="getCellClass(cell.result)"
>
<text class="cell-text" v-if="item.game_id !== 4 && item.game_id !== 5">{{ getResultText(cell.result) }}</text>
<!-- NN/ThreeCard specialized display could go here -->
<text class="cell-text">{{ getResultText(cell.result, item.game_id) }}</text>
</view>
</view>
<!-- 牛牛/三卡: 表格路单 -->
<view class="nn-roadmap" v-else>
<view class="nn-row" v-for="row in 4" :key="row">
<view class="nn-label" :class="row === 1 ? 'nn-label-banker' : 'nn-label-player'">
{{ ['', '庄', '闲1', '闲2', '闲3'][row] }}
</view>
<scroll-view scroll-x class="nn-cells">
<view class="nn-cells-inner">
<view
v-for="(cell, cIdx) in getNNRowData(item.beadRoad, row)"
:key="cIdx"
class="nn-cell"
:class="{ 'nn-win': cell.is_win == 1, 'nn-win-banker': cell.is_win == 1 && row === 1 }"
>
<text class="nn-text" :class="cell.type == 1 ? 'nn-text-red' : 'nn-text-blue'">{{ getNNResultText(cell.result) }}</text>
<text class="nn-win-tag" v-if="cell.is_win == 1">WIN</text>
</view>
</view>
</scroll-view>
</view>
</view>
<!-- Center Overlay Status -->
<view class="center-overlay" v-if="true">
<view class="status-badge-lg" :class="getStatusClass(item.bet_status)">
<u-icon name="hourglass" size="20" color="#fff" v-if="item.bet_status == 1"></u-icon>
<u-icon name="lock" size="20" color="#fff" v-else-if="item.bet_status == 2"></u-icon>
@@ -146,6 +202,7 @@ export default {
allTables: [],
loading: false,
timer: null,
onlineNum: 0,
// Roadmap config
cellWidth: 16.5, // slightly adjusted for mobile fit
@@ -179,9 +236,10 @@ export default {
uni.navigateTo({ url });
},
goService() {
// Mock service
const url = this.$store.state.app.customServiceUrl;
if(url) window.open(url, '_blank');
// 跳转到客服页面
uni.navigateTo({
url: '/pages/user/customservice'
});
},
switchCategory(id) {
this.currentCategory = id;
@@ -210,18 +268,34 @@ export default {
});
if (res.Success && res.Data) {
this.processData(res.Data);
this.updateOnlineNum();
}
} catch(e) {
console.error(e);
}
},
updateOnlineNum() {
const hour = new Date().getHours();
const base = 800;
const extra = (hour >= 0 && hour < 6) ? 200 : 0;
this.onlineNum = base + extra + Math.floor(Math.random() * 100);
},
processData(data) {
// Transform data for UI
this.allTables = data.map(item => {
// Extract Bead Road (showRoad usually)
// Note: In helper.php, waybill() returns { showRoad, bigRoad ... }
let beadRoad = [];
if (item.ludan && item.ludan.waybill && item.ludan.waybill.showRoad) {
if (item.game_id == 4 || item.game_id == 5) {
// 牛牛/三卡: ludan.waybill 直接就是数组,只取最后7列
if (item.ludan && Array.isArray(item.ludan.waybill)) {
let all = item.ludan.waybill;
let maxX = Math.max(...all.map(c => c.show_x), 0);
let keepCols = 7;
let cutX = Math.max(maxX - keepCols, 0);
beadRoad = all.filter(c => c.show_x > cutX).map(c => ({...c, show_x: c.show_x - cutX}));
}
} else if (item.ludan && item.ludan.waybill && item.ludan.waybill.showRoad) {
beadRoad = item.ludan.waybill.showRoad;
}
@@ -245,12 +319,29 @@ export default {
if (result === 3) return 'cell-green';
return '';
},
getResultText(result) {
getResultText(result, gameId) {
if (gameId == 2) {
if (result === 1) return '龙';
if (result === 2) return '虎';
if (result === 3) return '和';
}
if (result === 1) return '庄';
if (result === 2) return '闲';
if (result === 3) return '和';
return '';
},
getNNRowData(beadRoad, row) {
return beadRoad.filter(cell => cell.show_y === row);
},
getNNResultText(result) {
if (result == 0) return '无牛';
if (result >= 1 && result <= 9) return '牛' + result;
if (result == 10) return '牛牛';
if (result == 11) return '五公';
if (result == 12) return '豹子';
if (result == 13) return '同花顺';
return '牛' + result;
},
getStatusClass(status) {
// 1: betting, 2: dealing/disabled
if (status === 1) return 'status-betting';
@@ -277,8 +368,8 @@ export default {
display: flex;
flex-direction: column;
height: 100vh;
background-color: #0c0c0d;
color: #fff;
background: linear-gradient(180deg, #060505 0%, #0d0b09 100%);
color: #fff6e1;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
}
@@ -286,8 +377,7 @@ export default {
.top-header {
flex-shrink: 0;
position: relative;
/* background-image removed, using image tag instead */
padding-bottom: 5px;
padding-bottom: 14px;
overflow: hidden;
.header-bg {
@@ -297,6 +387,19 @@ export default {
width: 100%;
height: 100%;
z-index: 0;
opacity: 0.42;
}
.header-overlay {
position: absolute;
inset: 0;
z-index: 0;
background: linear-gradient(
180deg,
rgba(5, 4, 4, 0.86) 0%,
rgba(11, 9, 8, 0.66) 54%,
rgba(13, 11, 9, 0.96) 100%
);
}
.status-bar {
@@ -306,39 +409,104 @@ export default {
z-index: 1;
}
.user-bar {
.header-content {
position: relative;
z-index: 1;
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 15px;
padding: 8px 12px 0;
}
.left-info {
.user-bar {
display: flex;
align-items: center;
gap: 10px;
gap: 14px;
padding: 6px 4px 14px;
.brand-side {
flex-shrink: 0;
}
.brand-logo-shell {
width: 58px;
height: 58px;
display: flex;
align-items: center;
justify-content: center;
}
.brand-logo {
width: 44px;
height: 44px;
display: block;
}
.header-right {
min-width: 0;
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}
.user-summary {
min-width: 0;
flex: 1;
display: flex;
flex-direction: column;
gap: 7px;
}
.username {
font-size: 14px;
font-weight: bold;
color: #fff;
max-width: 100%;
font-size: 16px;
font-weight: 700;
color: #fbf3e0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.balance-pill {
background: rgba(0,0,0,0.5);
border: 1px solid #f4c46f;
border-radius: 12px;
padding: 2px 8px;
width: fit-content;
max-width: 100%;
min-height: 30px;
padding: 0 12px;
display: inline-flex;
align-items: center;
gap: 6px;
border-radius: 999px;
background: rgba(10, 9, 8, 0.72);
border: 1px solid rgba(223, 189, 120, 0.24);
box-shadow: inset 0 1px 0 rgba(255, 243, 219, 0.04);
.currency-symbol {
color: #f1cc84;
font-size: 13px;
font-weight: 700;
}
.balance-text {
color: #f6e1b2;
font-size: 12px;
font-weight: 700;
}
}
.right-actions {
display: flex;
align-items: center;
gap: 5px;
gap: 8px;
flex-shrink: 0;
.balance-text {
color: #f4c46f;
font-size: 12px;
font-weight: bold;
}
.action-btn {
width: 42px;
height: 42px;
border-radius: 15px;
display: flex;
align-items: center;
justify-content: center;
background: rgba(12, 11, 10, 0.72);
border: 1px solid rgba(223, 189, 120, 0.16);
box-shadow: inset 0 1px 0 rgba(255, 244, 220, 0.04);
}
}
}
@@ -346,7 +514,30 @@ export default {
.banner-area {
position: relative;
z-index: 1;
padding: 5px 10px;
padding: 0 2px;
::v-deep .u-swiper {
border-radius: 18px !important;
overflow: hidden;
border: 1px solid rgba(223, 189, 120, 0.14);
box-shadow: 0 16px 34px rgba(0, 0, 0, 0.24);
}
::v-deep .u-swiper__wrapper__item__wrapper {
border-radius: 18px !important;
}
::v-deep .u-swiper-indicator {
bottom: 10px !important;
}
::v-deep .u-swiper-indicator__wrapper__item {
background-color: rgba(255, 244, 220, 0.28) !important;
}
::v-deep .u-swiper-indicator__wrapper__item--active {
background-color: #dfbd78 !important;
}
}
}
@@ -355,122 +546,254 @@ export default {
flex: 1;
display: flex;
overflow: hidden;
gap: 10px;
padding: 0 12px 12px;
/* Sidebar styles */
.sidebar {
width: 80px;
background-color: #161618;
border-right: 1px solid #1f1f1f;
width: 86px;
background: linear-gradient(
180deg,
rgba(18, 15, 13, 0.98) 0%,
rgba(10, 9, 8, 0.98) 100%
);
border: 1px solid rgba(223, 189, 120, 0.14);
border-radius: 22px;
display: flex;
flex-direction: column;
overflow: hidden;
box-shadow: 0 14px 28px rgba(0, 0, 0, 0.18);
.sidebar-item {
padding: 15px 5px;
position: relative;
margin: 6px;
padding: 14px 6px 12px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border-bottom: 1px solid #222;
transition: all 0.3s;
border-radius: 18px;
transition: all 0.25s ease;
&.active {
background-color: #f4c46f;
.cat-name, .cat-count {
color: #000;
font-weight: bold;
.item-marker {
position: absolute;
left: 50%;
top: 0;
width: 20px;
height: 3px;
border-radius: 999px;
transform: translateX(-50%);
background: transparent;
}
// Could change icon color via filter if using svg
&.active {
background: linear-gradient(
180deg,
rgba(59, 43, 19, 0.24) 0%,
rgba(27, 20, 12, 0.08) 100%
);
box-shadow: inset 0 1px 0 rgba(255, 239, 203, 0.06);
.item-marker {
background: linear-gradient(90deg, #f2ddb3 0%, #dbaf57 100%);
}
.icon-box {
margin-bottom: 5px;
background: rgba(223, 189, 120, 0.08);
border-color: rgba(223, 189, 120, 0.18);
}
.cat-name,
.cat-count {
color: #f1d392;
}
}
.icon-box {
width: 40px;
height: 40px;
margin-bottom: 8px;
border-radius: 14px;
display: flex;
align-items: center;
justify-content: center;
background: rgba(14, 13, 12, 0.8);
border: 1px solid rgba(255, 255, 255, 0.03);
}
.cat-texts {
display: flex;
flex-direction: column;
align-items: center;
gap: 5px;
}
.cat-name {
font-size: 12px;
color: #999;
margin-bottom: 2px;
font-size: 11px;
color: #cdc2a3;
text-align: center;
word-break: break-word;
line-height: 1.25;
max-width: 70px;
}
.cat-count {
font-size: 10px;
color: #666;
min-width: 32px;
height: 22px;
padding: 0 9px;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 11px;
font-weight: 700;
line-height: 1;
color: #e3c27a;
font-variant-numeric: tabular-nums;
letter-spacing: 0.2px;
background: linear-gradient(
180deg,
rgba(29, 24, 19, 0.96) 0%,
rgba(16, 13, 11, 0.96) 100%
);
border: 1px solid rgba(223, 189, 120, 0.12);
box-shadow: inset 0 1px 0 rgba(255, 245, 223, 0.04);
border-radius: 999px;
}
}
.online-count-box {
margin-top: auto;
padding: 20px 5px;
margin: auto 6px 6px;
padding: 14px 6px calc(14px + env(safe-area-inset-bottom));
border-top: 1px solid rgba(223, 189, 120, 0.1);
text-align: center;
.label { font-size: 10px; color: #666; display: block; }
.count { font-size: 14px; color: #f4c46f; font-weight: bold; }
.label {
font-size: 10px;
color: #8d7a55;
display: block;
margin-bottom: 4px;
}
.count {
margin-top: 6px;
font-size: 15px;
color: #f1cc84;
font-weight: 700;
font-variant-numeric: tabular-nums;
letter-spacing: 0.3px;
}
}
}
/* Content styles */
.content-area {
flex: 1;
background-color: #0c0c0d;
padding: 10px;
background: rgba(8, 7, 6, 0.52);
border: 1px solid rgba(223, 189, 120, 0.1);
border-radius: 22px;
padding: 12px;
box-shadow: inset 0 1px 0 rgba(255, 244, 220, 0.03);
.table-list {
min-height: 100%;
}
.loading-state {
min-height: 180px;
display: flex;
align-items: center;
justify-content: center;
}
.game-card {
background-color: #1e1e1e;
border-radius: 6px;
margin-bottom: 12px;
border: 1px solid #333;
margin-bottom: 14px;
background: linear-gradient(
180deg,
rgba(21, 18, 15, 0.98) 0%,
rgba(14, 12, 10, 0.98) 100%
);
border: 1px solid rgba(223, 189, 120, 0.14);
border-radius: 18px;
overflow: hidden;
box-shadow: 0 14px 28px rgba(0, 0, 0, 0.16);
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
background: #252627;
padding: 5px 10px;
border-bottom: 1px solid #333;
height: 30px;
padding: 10px 12px;
min-height: 44px;
background: linear-gradient(
180deg,
rgba(30, 25, 20, 0.88) 0%,
rgba(19, 17, 14, 0.88) 100%
);
border-bottom: 1px solid rgba(223, 189, 120, 0.1);
.table-name {
font-size: 13px;
color: #fff;
font-weight: bold;
font-size: 14px;
color: #f9f1de;
font-weight: 700;
}
.header-right {
display: flex;
align-items: center;
gap: 8px;
}
.limit-info {
font-size: 10px;
color: #999;
color: #bca987;
text-align: right;
line-height: 1.35;
}
.status-live {
width: 18px;
height: 18px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 999px;
background: rgba(255, 255, 255, 0.03);
}
.status-dot {
width: 6px;
height: 6px;
width: 7px;
height: 7px;
border-radius: 50%;
background-color: #666;
&.is-live { background-color: #0f0; }
background-color: #6f6658;
&.is-live {
background-color: #53c57b;
box-shadow: 0 0 10px rgba(83, 197, 123, 0.28);
}
}
}
.card-body {
position: relative;
height: 110px; // Fixed height for roadmap
background: #fff; // White background for roadmap grid
height: 114px;
background: linear-gradient(180deg, #fbf9f3 0%, #f0ece3 100%);
}
.card-body-overlay {
position: absolute;
inset: 0;
pointer-events: none;
background: linear-gradient(
180deg,
rgba(255, 255, 255, 0.02) 0%,
rgba(0, 0, 0, 0.02) 100%
);
}
.roadmap-grid {
width: 100%;
height: 100%;
position: relative;
// Grid background lines
background-size: 16.5px 17px;
background-image:
linear-gradient(to right, #ccc 1px, transparent 1px),
linear-gradient(to bottom, #ccc 1px, transparent 1px);
background-image: linear-gradient(to right, #dad3c7 1px, transparent 1px),
linear-gradient(to bottom, #dad3c7 1px, transparent 1px);
.road-cell {
position: absolute;
@@ -480,31 +803,110 @@ export default {
display: flex;
justify-content: center;
align-items: center;
border: 1px solid rgba(0,0,0,0.1);
border: 1px solid rgba(0, 0, 0, 0.08);
background-color: #fff;
&.cell-red {
background-color: #fff;
border: 2px solid #d0021b;
color: #d0021b;
border: 2px solid #cf4444;
color: #cf4444;
}
&.cell-blue {
background-color: #fff;
border: 2px solid #4a90e2;
color: #4a90e2;
border: 2px solid #467ed7;
color: #467ed7;
}
&.cell-green {
background-color: #fff;
border: 2px solid #7ed321;
color: #7ed321;
border: 2px solid #4ba96f;
color: #4ba96f;
}
.cell-text {
font-size: 9px;
font-weight: bold;
font-weight: 700;
}
}
}
.nn-roadmap {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
background: linear-gradient(180deg, #fbf9f3 0%, #f0ece3 100%);
.nn-row {
display: flex;
flex: 1;
border-bottom: 1px solid #ddd4c8;
&:last-child {
border-bottom: none;
}
}
.nn-label {
width: 30px;
display: flex;
align-items: center;
justify-content: center;
font-size: 10px;
font-weight: 700;
color: #fff;
flex-shrink: 0;
&.nn-label-banker {
background: #a84237;
}
&.nn-label-player {
background: #3c6399;
}
}
.nn-cells {
flex: 1;
}
.nn-cells-inner {
display: flex;
height: 100%;
}
.nn-cell {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border-right: 1px solid #ddd4c8;
padding: 1px 0;
}
.nn-text {
font-size: 10px;
font-weight: 700;
&.nn-text-red {
color: #a84237;
}
&.nn-text-blue {
color: #3c6399;
}
}
.nn-win-tag {
font-size: 7px;
color: #fff;
background: #3c6399;
padding: 0 3px;
border-radius: 2px;
line-height: 1.4;
margin-top: 1px;
}
.nn-cell.nn-win-banker .nn-win-tag {
background: #a84237;
}
}
.center-overlay {
position: absolute;
top: 50%;
@@ -516,32 +918,38 @@ export default {
flex-direction: column;
align-items: center;
justify-content: center;
padding: 10px 20px;
background: rgba(0,0,0,0.7);
border-radius: 8px;
// Backdrop gradient
background: radial-gradient(circle, rgba(169,134,60,0.95) 0%, rgba(0,0,0,0.8) 100%);
min-width: 110px;
padding: 10px 18px;
border-radius: 16px;
color: #fff;
box-shadow: 0 4px 10px rgba(0,0,0,0.5);
width: 100px;
background: linear-gradient(
180deg,
rgba(47, 39, 28, 0.92) 0%,
rgba(17, 14, 11, 0.92) 100%
);
border: 1px solid rgba(223, 189, 120, 0.18);
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.18);
&.status-dealing {
// background: radial-gradient(circle, rgba(200,50,50,0.9) 0%, rgba(0,0,0,0.8) 100%);
&.status-betting {
background: linear-gradient(
180deg,
rgba(88, 67, 33, 0.92) 0%,
rgba(24, 18, 11, 0.94) 100%
);
}
.status-text-lg {
font-size: 14px;
font-weight: bold;
margin-top: 5px;
text-shadow: 1px 1px 2px #000;
font-size: 13px;
font-weight: 700;
margin-top: 4px;
}
.countdown-text {
font-size: 16px;
color: #fff;
font-size: 15px;
color: #fff5dc;
margin-top: 2px;
font-family: monospace;
font-weight: bold;
}
font-weight: 700;
}
}
}
+144 -49
View File
@@ -1,11 +1,11 @@
<template>
<view class="login">
<div class="langview">
<div class="select" @click="showLangselect(true)">
<view class="langview">
<view class="select" @click="showLangselect(true)">
{{ langList[language] }}
</div>
<div class="select-box" v-show="langselect">
<div
</view>
<view class="select-box" v-show="langselect">
<view
class="option"
v-for="item in Object.keys(langList)"
:key="item"
@@ -13,10 +13,11 @@
@click="choseLang(item)"
>
{{ langList[item] }}
</div>
</div>
</div>
</view>
</view>
</view>
<view class="content">
<view class="logo-shell">
<view class="logo">
<u--image
:showLoading="false"
@@ -26,12 +27,17 @@
mode="scaleToFill"
></u--image>
</view>
</view>
<view class="panel">
<u-input
class="input"
v-model="phone"
type="number"
type="text"
clearable
border="none"
color="#f7ecd2"
:placeholder="$lang.enterAccount"
placeholderStyle="color: rgba(245, 228, 184, 0.38); font-size: 14px;"
><!--
<view class="phone-code" slot="prefix" @click="countryShow = true">{{
countryData.country_code
@@ -41,15 +47,23 @@
class="input"
v-model="password"
:password="true"
border="none"
color="#f7ecd2"
:placeholder="$lang.enterPassword"
placeholderStyle="color: rgba(245, 228, 184, 0.38); font-size: 14px;"
>
</u-input>
<view class="btn-box">
<view class="btn" @tap="login('login')">{{ $lang.login }}</view>
<view class="btn" @tap="login('dome')">{{ $lang.dome }}</view>
<view class="btn btn-primary" @tap="login('login')">{{
$lang.login
}}</view>
<view class="btn btn-secondary" @tap="login('dome')">{{
$lang.dome
}}</view>
</view>
<view class="tip" @tap="goRegister">{{ $lang.goRegister }}</view>
</view>
</view>
<!-- 提示 -->
<u-toast ref="uToast" />
<!-- 区号 -->
@@ -202,65 +216,126 @@ export default {
overflow-y: auto;
.langview {
position: absolute;
top: 15px;
right: 15px;
top: 16px;
right: 16px;
z-index: 20;
.select {
border-radius: 4px;
width: 90px;
display: inline-block;
font-size: 14px;
color: #cfc189;
line-height: 35px;
background: #212121;
min-width: 96px;
padding: 0 14px;
font-size: 13px;
color: #e8d39b;
line-height: 34px;
background: rgba(15, 12, 10, 0.74);
border: 1px solid rgba(213, 181, 103, 0.18);
border-radius: 10px;
text-align: center;
&:active {
opacity: 0.6;
opacity: 0.82;
}
}
.select-box {
position: absolute;
right: 0;
top: 45px;
width: 90px;
line-height: 30px;
background: #212121;
border-radius: 4px;
top: 40px;
width: 108px;
padding: 4px 0;
line-height: 32px;
background: rgba(15, 12, 10, 0.92);
border: 1px solid rgba(213, 181, 103, 0.18);
border-radius: 10px;
text-align: center;
color: #fff;
font-size: 14px;
color: rgba(255, 246, 226, 0.88);
font-size: 13px;
z-index: 9;
.option {
padding: 0 8px;
}
.option:active {
opacity: 0.6;
}
.active {
color: #cfc189;
color: #e8d39b;
font-weight: bold;
}
}
}
.content {
width: 280px;
padding-bottom: 50px;
width: 86%;
max-width: 326px;
margin: 0 auto;
padding: 94px 0 48px;
.logo-shell {
margin-bottom: 20px;
}
.logo {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 20px;
margin-top: 20%;
width: 125px;
height: 119px;
margin: 0 auto;
}
.panel {
position: relative;
padding: 20px 18px 22px;
border-radius: 24px;
background: linear-gradient(
180deg,
rgba(14, 11, 9, 0.9) 0%,
rgba(10, 8, 7, 0.8) 100%
);
border: 1px solid rgba(213, 181, 103, 0.22);
box-shadow: 0 18px 40px rgba(0, 0, 0, 0.24),
inset 0 1px 0 rgba(255, 255, 255, 0.03);
overflow: hidden;
&::before {
content: "";
position: absolute;
top: 0;
left: 18px;
right: 18px;
height: 1px;
background: linear-gradient(
90deg,
rgba(213, 181, 103, 0),
rgba(244, 221, 169, 0.82),
rgba(213, 181, 103, 0)
);
}
}
.input {
height: 30px;
line-height: 30px;
margin-bottom: 15px;
background: #fff;
border-radius: 8px;
height: 50px;
line-height: 50px;
margin-bottom: 14px;
background: rgba(24, 20, 17, 0.96);
border: 1px solid rgba(213, 181, 103, 0.14);
border-radius: 15px;
overflow: hidden;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03),
inset 0 -1px 0 rgba(0, 0, 0, 0.16);
&:last-of-type {
margin-bottom: 0;
}
::v-deep .u-input__content {
min-height: 100%;
padding: 0 15px;
}
::v-deep .u-input__content__field-wrapper {
width: 100%;
}
::v-deep input {
color: #f7ecd2 !important;
font-size: 15px !important;
letter-spacing: 0.2px;
}
::v-deep input::placeholder {
color: rgba(245, 228, 184, 0.42) !important;
}
}
.phone-code {
min-width: 50px;
text-align: center;
border-right: 1px solid #ddd;
border-right: 1px solid rgba(213, 181, 103, 0.18);
}
.btn-box {
margin-top: 20px;
@@ -269,15 +344,33 @@ export default {
height: 48px;
line-height: 48px;
text-align: center;
font-size: 16px;
background: url("~@/static/images/btn_bg.png") no-repeat;
background-size: 100% 100%;
font-weight: 600;
margin-top: 15px;
font-size: 14px;
font-weight: 700;
letter-spacing: 0.5px;
border-radius: 15px;
margin-top: 12px;
&:active {
opacity: 0.8;
opacity: 0.86;
}
}
.btn-primary {
margin-top: 0;
color: #241804;
background: linear-gradient(
180deg,
#f2dfb6 0%,
#dfbd78 52%,
#bd8d39 100%
);
box-shadow: 0 12px 24px rgba(125, 84, 22, 0.24),
inset 0 1px 0 rgba(255, 255, 255, 0.42);
}
.btn-secondary {
color: #ead6a0;
background: rgba(18, 15, 12, 0.92);
border: 1px solid rgba(213, 181, 103, 0.2);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03);
}
}
}
.country {
@@ -287,12 +380,14 @@ export default {
}
.tip {
font-size: 12px;
color: #b38f3c;
margin-top: 20px;
color: rgba(234, 214, 160, 0.92);
margin-top: 16px;
padding-top: 14px;
border-top: 1px solid rgba(213, 181, 103, 0.1);
text-align: center;
margin-bottom: 20px;
letter-spacing: 0.2px;
&:active {
opacity: 0.6;
opacity: 0.7;
}
}
}
+851 -46
View File
File diff suppressed because it is too large Load Diff
+185 -34
View File
@@ -1,37 +1,101 @@
<template>
<view class="register">
<view class="content">
<view class="logo-shell">
<view class="logo">
<u--image :showLoading="false" :src="loginLogo" width="125px" height="119px" mode="scaleToFill"></u--image>
<u--image
:showLoading="false"
:src="loginLogo"
width="125px"
height="119px"
mode="scaleToFill"
></u--image>
</view>
<u-input class="input" :focus='focusUsername' v-model="username" type="number" clearable :placeholder="$lang.enterAccount">
</view>
<view class="panel">
<u-input
class="input"
:focus="focusUsername"
v-model="username"
type="text"
clearable
border="none"
color="#f7ecd2"
:placeholder="$lang.enterAccount"
placeholderStyle="color: rgba(245, 228, 184, 0.42); font-size: 14px;"
>
<text class="text" slot="prefix">{{ $lang.account }}</text>
</u-input>
<u-input class="input" :focus='focusPassword' v-model="password" :password="true" :placeholder="$lang.enterPassword" autocomplete="new-password">
<u-input
class="input"
:focus="focusPassword"
v-model="password"
:password="true"
border="none"
color="#f7ecd2"
:placeholder="$lang.enterPassword"
autocomplete="new-password"
placeholderStyle="color: rgba(245, 228, 184, 0.42); font-size: 14px;"
>
<text class="text" slot="prefix">{{ $lang.password }}</text>
</u-input>
<u-input class="input" :focus='focusRepass' v-model="repass" :password="true" :placeholder="$lang.enterPasswordAgain">
<u-input
class="input"
:focus="focusRepass"
v-model="repass"
:password="true"
border="none"
color="#f7ecd2"
:placeholder="$lang.enterPasswordAgain"
placeholderStyle="color: rgba(245, 228, 184, 0.42); font-size: 14px;"
>
<text class="text" slot="prefix">{{ $lang.confirmPassword }}</text>
</u-input>
<u-input class="input" :focus='focusPhone' v-model="phone" type="number" clearable
:placeholder="`${$lang.enterPhone}`">
<u-input
class="input"
:focus="focusPhone"
v-model="phone"
type="number"
clearable
border="none"
color="#f7ecd2"
:placeholder="`${$lang.enterPhone}`"
placeholderStyle="color: rgba(245, 228, 184, 0.42); font-size: 14px;"
>
<view class="phone-code" slot="prefix" @click="countryShow = true">
{{ countryData.country_code }}
</view>
</u-input>
<u-input class="input" v-model="referral_code" placeholder="TC176852" :disabled="referral_disabled">
<u-input
class="input"
v-model="referral_code"
border="none"
color="#f7ecd2"
placeholder="TC176852"
placeholderStyle="color: rgba(245, 228, 184, 0.42); font-size: 14px;"
:disabled="referral_disabled"
>
<text class="text" slot="prefix">{{ $lang.invitationCode }}</text>
</u-input>
<view class="btn-box">
<view class="btn" @tap="register()">{{ $lang.register }}</view>
<view class="btn btn-primary" @tap="register()">{{
$lang.register
}}</view>
</view>
<view class="tip" @tap="goLogin">{{ $lang.goLogin }}</view>
</view>
</view>
<!-- 提示 -->
<u-toast ref="uToast" />
<!-- 区号 -->
<country-code class="country" :show="countryShow" :anchor="countryData.anchor_index"
:country="countryData.country_en" @select="selectCountryTap" @close="countryShow = false"></country-code>
<country-code
class="country"
:show="countryShow"
:anchor="countryData.anchor_index"
:country="countryData.country_en"
@select="selectCountryTap"
@close="countryShow = false"
></country-code>
<view class="mb60"></view>
</view>
</template>
@@ -165,7 +229,7 @@
</script>
<style lang="scss" scoped>
.register {
.register {
width: 100%;
height: 100%;
position: fixed;
@@ -177,35 +241,109 @@
overflow-y: auto;
.content {
width: 280px;
padding-bottom: 50px;
width: 86%;
max-width: 326px;
margin: 0 auto;
padding: 94px 0 48px;
.logo-shell {
margin-bottom: 20px;
}
.logo {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 20px;
margin-top: 20%;
width: 125px;
height: 119px;
margin: 0 auto;
}
.panel {
position: relative;
padding: 20px 18px 22px;
border-radius: 24px;
background: linear-gradient(
180deg,
rgba(14, 11, 9, 0.9) 0%,
rgba(10, 8, 7, 0.8) 100%
);
border: 1px solid rgba(213, 181, 103, 0.22);
box-shadow: 0 18px 40px rgba(0, 0, 0, 0.24),
inset 0 1px 0 rgba(255, 255, 255, 0.03);
overflow: hidden;
&::before {
content: "";
position: absolute;
top: 0;
left: 18px;
right: 18px;
height: 1px;
background: linear-gradient(
90deg,
rgba(213, 181, 103, 0),
rgba(244, 221, 169, 0.82),
rgba(213, 181, 103, 0)
);
}
}
.input {
height: 30px;
line-height: 30px;
margin-bottom: 15px;
background: #fff;
border-radius: 8px;
height: 50px;
line-height: 50px;
margin-bottom: 14px;
background: rgba(24, 20, 17, 0.96);
border: 1px solid rgba(213, 181, 103, 0.14);
border-radius: 15px;
overflow: hidden;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03),
inset 0 -1px 0 rgba(0, 0, 0, 0.16);
&:last-of-type {
margin-bottom: 0;
}
::v-deep .u-input__content {
min-height: 100%;
padding: 0 15px;
}
::v-deep .u-input__content__field-wrapper {
width: 100%;
}
::v-deep input {
color: #f7ecd2 !important;
font-size: 15px !important;
letter-spacing: 0.2px;
}
::v-deep input::placeholder {
color: rgba(245, 228, 184, 0.42) !important;
}
::v-deep .u-input__content__prefix-icon,
::v-deep .u-input__content__subfix-icon {
color: #e8d39b !important;
}
}
.phone-code {
min-width: 50px;
min-width: 58px;
margin-right: 12px;
padding-right: 12px;
text-align: center;
border-right: 1px solid #ddd;
font-size: 13px;
color: #e8d39b;
border-right: 1px solid rgba(213, 181, 103, 0.18);
}
.text {
padding-right: 5px;
min-width: 74px;
margin-right: 12px;
font-size: 13px;
color: rgba(232, 211, 155, 0.92);
}
.btn-box {
@@ -216,16 +354,27 @@
height: 48px;
line-height: 48px;
text-align: center;
font-size: 16px;
background: url("~@/static/images/btn_bg.png") no-repeat;
background-size: 100% 100%;
font-weight: 600;
margin-top: 15px;
font-size: 14px;
font-weight: 700;
letter-spacing: 0.5px;
border-radius: 15px;
&:active {
opacity: 0.8;
opacity: 0.86;
}
}
.btn-primary {
color: #241804;
background: linear-gradient(
180deg,
#f2dfb6 0%,
#dfbd78 52%,
#bd8d39 100%
);
box-shadow: 0 12px 24px rgba(125, 84, 22, 0.24),
inset 0 1px 0 rgba(255, 255, 255, 0.42);
}
}
}
@@ -237,14 +386,16 @@
.tip {
font-size: 12px;
color: #b38f3c;
margin-top: 20px;
color: rgba(234, 214, 160, 0.92);
margin-top: 16px;
padding-top: 14px;
border-top: 1px solid rgba(213, 181, 103, 0.1);
text-align: center;
margin-bottom: 20px;
letter-spacing: 0.2px;
&:active {
opacity: 0.6;
}
opacity: 0.7;
}
}
}
</style>
+471 -67
View File
@@ -1,51 +1,81 @@
<template>
<view class="customservice">
<u-navbar
leftIconColor="#eee"
bgColor="#0c0c0d"
leftIconColor="#d9ac6b"
bgColor="#1f120e"
:placeholder="true"
:fixed="true"
height="60"
height="50"
@leftClick="back"
:title="$lang.customerService || '在线客服'"
titleStyle="color: #d9ac6b; font-weight: bold;"
></u-navbar>
<view class="cellBox">
<view class="cell">
<u--image
:showLoading="false"
:src="require('static/images/customservice.png')"
width="100%"
height="auto"
mode="widthFix"
class="icon"
></u--image>
<u-link
target="_blank"
:href="customServiceUrl"
text="Online service"
class="lable"
></u-link>
<!-- 聊天窗口 -->
<view class="chat-container">
<!-- 聊天头部状态 -->
<view class="chat-header">
<view class="chat-status" :class="{'online': sessionId}">
{{ sessionId ? ($lang.csConnected || '已连接') : ($lang.csConnecting || '连接中...') }}
</view>
<view class="cell">
<u--image
:showLoading="false"
:src="require('static/images/line.png')"
width="100%"
height="auto"
mode="widthFix"
class="icon"
></u--image>
<u-link target="_blank" :href="telegramUrl" text="Telegram" class="lable"></u-link>
</view>
<view class="cell">
<u--image
:showLoading="false"
:src="require('static/images/telegram.png')"
width="100%"
height="auto"
mode="widthFix"
class="icon"
></u--image>
<u-link target="_blank" :href="lineUrl" text="Line" class="lable"></u-link>
<!-- 消息列表 -->
<scroll-view class="chat-messages" scroll-y :scroll-top="scrollTop" scroll-with-animation>
<!-- 欢迎信息 -->
<view v-if="!sessionId" class="chat-welcome">
<text class="welcome-icon">💬</text>
<text class="welcome-title">{{ $lang.csWelcome || '欢迎使用在线客服' }}</text>
<text v-if="!isConnected" class="welcome-tip">{{ $lang.csConnecting || '正在连接...' }}</text>
<text v-else-if="sessionStatus === 0" class="welcome-tip warning">{{ $lang.csBusy || '客服繁忙请稍候...' }}</text>
<text v-else class="welcome-tip">{{ $lang.csInputTip || '请输入您的问题' }}</text>
</view>
<!-- 消息列表 -->
<view v-for="(msg, index) in messages" :key="index"
class="chat-message"
:class="{
'chat-message-own': msg.senderType === 1,
'chat-message-system': msg.senderType === 0
}">
<!-- 系统消息 -->
<view v-if="msg.senderType === 0" class="system-msg">
<text>{{ msg.content }}</text>
</view>
<!-- 普通消息 -->
<view v-else class="message-content">
<view class="message-avatar">
<text v-if="msg.senderType === 1">{{ $lang.csMe || '' }}</text>
<text v-else>{{ $lang.csAgent || '客服' }}</text>
</view>
<view class="message-bubble">
<text class="message-text">{{ msg.content }}</text>
<text class="message-time">{{ formatTime(msg.createTime) }}</text>
</view>
</view>
</view>
<!-- 底部占位 -->
<view style="height: 20px;"></view>
</scroll-view>
<!-- 输入区域 -->
<view class="chat-input-area">
<textarea
v-model="inputMessage"
:placeholder="$lang.csInputPlaceholder || '输入消息,点击发送...'"
:disabled="!isConnected || !sessionId"
class="chat-input"
:maxlength="500"
@confirm="sendMessage"
></textarea>
<view class="chat-actions">
<button
class="chat-btn-send"
@click="sendMessage"
:disabled="!isConnected || !sessionId || !inputMessage.trim()"
>{{ $lang.csSend || '发送' }}</button>
</view>
</view>
</view>
</view>
@@ -53,21 +83,210 @@
<script>
import { mapState } from "vuex";
import io from 'socket.io-client';
export default {
data() {
return {};
return {
socket: null,
isConnected: false,
sessionId: null,
sessionStatus: null,
messages: [],
inputMessage: '',
scrollTop: 0,
heartbeatTimer: null
};
},
computed: {
...mapState({
customServiceUrl: state => state.app.customServiceUrl,
telegramUrl: state => state.app.telegramUrl,
lineUrl: state => state.app.lineUrl
userInfo: state => state.app.userInfo,
sockUrl: state => state.app.sockUrl,
$lang: state => state.app.lang[state.app.language]
})
},
onLoad() {},
onLoad() {
this.connectWebSocket();
},
onUnload() {
this.disconnect();
},
methods: {
back() {
this.disconnect();
uni.navigateBack();
},
disconnect() {
if (this.heartbeatTimer) {
clearInterval(this.heartbeatTimer);
this.heartbeatTimer = null;
}
if (this.socket) {
this.socket.disconnect();
this.socket = null;
}
},
connectWebSocket() {
// 使用 store 中的 sockUrl
const sockUrl = this.sockUrl || 'wss://wss.g7g7.top';
const loginToken = this.userInfo.online_token || this.userInfo.login_token || '';
console.log('[CustomerService] 连接 WebSocket:', sockUrl);
console.log('[CustomerService] loginToken:', loginToken);
console.log('[CustomerService] userInfo:', JSON.stringify(this.userInfo));
// 客服连接:不带 connect=user 参数,避免触发游戏连接逻辑
// 连接成功后通过 chat.connect 事件进行客服认证
this.socket = io(sockUrl, {
transports: ['websocket'],
reconnection: true,
reconnectionDelay: 1000,
reconnectionAttempts: 5
});
this.socket.on('connect', () => {
console.log('[CustomerService] WebSocket 已连接, socket.id:', this.socket.id);
this.isConnected = true;
// 发送客服连接请求,后端通过 chat.connect 事件验证用户
const chatConnectData = {
token: loginToken,
role: 'user',
source: 3 // Portal端
};
console.log('[CustomerService] 发送 chat.connect:', JSON.stringify(chatConnectData));
this.socket.emit('chat.connect', chatConnectData);
// 启动心跳
this.startHeartbeat();
});
this.socket.on('disconnect', (reason) => {
console.log('[CustomerService] WebSocket 已断开, 原因:', reason);
this.isConnected = false;
});
this.socket.on('connect_error', (error) => {
console.log('[CustomerService] 连接错误:', error.message);
this.isConnected = false;
});
this.socket.on('error', (error) => {
console.log('[CustomerService] Socket错误:', error);
});
// 后端 ChatConnect.php 使用下划线格式的事件名
this.socket.on('chat_connected', (data) => {
console.log('[CustomerService] chat_connected:', data);
if (data.success) {
this.sessionId = data.sessionId;
this.sessionStatus = data.status;
if (data.agentInfo) {
this.addSystemMessage((this.$lang.csAgent || '客服') + ' ' + data.agentInfo.nickname + ' ' + (this.$lang.csAgentServing || '为您服务'));
}
} else {
uni.showToast({ title: (this.$lang.csConnectFailed || '连接失败') + ': ' + (data.error || '未知错误'), icon: 'none' });
}
});
this.socket.on('chat.session.assigned', (data) => {
console.log('[CustomerService] chat.session.assigned:', data);
this.sessionStatus = 1;
this.addSystemMessage((this.$lang.csAgent || '客服') + ' ' + data.agentInfo.nickname + ' ' + (this.$lang.csAgentJoined || '已接入'));
});
this.socket.on('chat_message_new', (data) => {
console.log('[CustomerService] chat_message_new:', data);
const msg = data.data || data;
this.messages.push({
msgId: msg.msgId,
senderType: msg.senderType,
msgType: msg.msgType,
content: msg.content,
createTime: msg.createTime || msg.time
});
this.scrollToBottom();
// 发送已读回执
if (msg.msgId) {
this.socket.emit('chat.message.ack', { msgId: msg.msgId });
}
});
this.socket.on('chat.session.ended', () => {
console.log('[CustomerService] chat.session.ended');
this.addSystemMessage(this.$lang.csSessionEnded || '会话已结束');
this.sessionStatus = 2;
});
// 后端使用下划线格式
this.socket.on('chat_offline_notice', (data) => {
console.log('[CustomerService] chat_offline_notice:', data);
this.addSystemMessage(data.message);
});
// 后端使用下划线格式
this.socket.on('chat_pong', () => {
// 心跳响应
});
},
startHeartbeat() {
if (this.heartbeatTimer) {
clearInterval(this.heartbeatTimer);
}
this.heartbeatTimer = setInterval(() => {
if (this.socket && this.socket.connected) {
this.socket.emit('chat.ping', {});
}
}, 25000);
},
sendMessage() {
const content = this.inputMessage.trim();
if (!content || !this.sessionId) return;
const clientMsgId = Date.now();
this.socket.emit('chat.message.send', {
sessionId: this.sessionId,
msgType: 1,
content: content,
clientMsgId: clientMsgId
});
// 乐观更新 UI
this.messages.push({
msgId: clientMsgId,
senderType: 1, // 用户发送
msgType: 1,
content: content,
createTime: Date.now()
});
this.inputMessage = '';
this.scrollToBottom();
},
addSystemMessage(text) {
this.messages.push({
msgId: Date.now(),
senderType: 0,
msgType: 1,
content: text,
createTime: Date.now()
});
this.scrollToBottom();
},
scrollToBottom() {
// 先重置为0,再设置大值,确保Vue检测到变化
this.scrollTop = 0;
this.$nextTick(() => {
this.scrollTop = 999999;
});
},
formatTime(timestamp) {
if (!timestamp) return '';
// 如果是毫秒时间戳
const ts = timestamp > 9999999999 ? timestamp : timestamp * 1000;
const date = new Date(ts);
return date.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' });
}
}
};
@@ -78,37 +297,222 @@ export default {
background: #0b1520;
width: 100%;
min-height: 100vh;
::v-deep .u-navbar__content__title {
color: #eee;
color: #d9ac6b;
font-weight: 600;
}
.cellBox {
position: absolute;
top: 30%;
left: 50%;
transform: translate(-50%, -50%);
width: 300px;
}
.cell {
/* 聊天容器 */
.chat-container {
position: fixed;
top: 50px;
left: 0;
right: 0;
bottom: 0;
display: flex;
padding: 15px;
flex-direction: column;
background: #3d2c22;
}
/* 聊天头部 */
.chat-header {
flex-shrink: 0;
display: flex;
justify-content: center;
align-items: center;
// background: #151617;
color: #deb366;
.icon {
width: 35px;
margin-right: 15px;
padding: 10px 15px;
background: #1f120e;
}
.lable {
// border-bottom: 1px solid;
color: #deb366 !important;
font-size: 30px !important;
line-height: 30px !important;
::v-deep span {
border-bottom: 1px solid;
padding-bottom: 4px;
.chat-status {
padding: 4px 16px;
background: rgba(255, 255, 255, 0.1);
border-radius: 12px;
font-size: 12px;
color: #999;
}
.chat-status.online {
background: rgba(76, 175, 80, 0.3);
color: #4caf50;
}
/* 消息区域 */
.chat-messages {
flex: 1;
padding: 15px;
background: #3d2c22;
overflow: hidden;
height: 0; /* 配合flex:1让scroll-view正常工作 */
}
/* 欢迎信息 */
.chat-welcome {
text-align: center;
padding: 60px 20px;
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
.welcome-icon {
font-size: 48px;
}
.welcome-title {
font-size: 18px;
font-weight: bold;
color: #d9ac6b;
}
.welcome-tip {
font-size: 14px;
color: #999;
}
.welcome-tip.warning {
color: #ff9800;
}
}
/* 消息项 */
.chat-message {
margin-bottom: 15px;
display: flex;
}
.chat-message-own {
justify-content: flex-end;
}
.chat-message-system {
justify-content: center;
}
/* 系统消息 */
.system-msg {
background: rgba(0, 0, 0, 0.3);
color: #999;
font-size: 12px;
padding: 5px 15px;
border-radius: 12px;
}
/* 消息内容 */
.message-content {
display: flex;
align-items: flex-start;
max-width: 80%;
}
.chat-message-own .message-content {
flex-direction: row-reverse;
}
/* 头像 */
.message-avatar {
width: 36px;
height: 36px;
border-radius: 50%;
background: #1f120e;
color: #d9ac6b;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
font-weight: bold;
flex-shrink: 0;
margin: 0 10px;
}
.chat-message-own .message-avatar {
background: linear-gradient(135deg, #d9ac6b 0%, #a67c3d 100%);
color: #1f120e;
}
/* 消息气泡 */
.message-bubble {
background: #2a1f18;
border-radius: 8px;
padding: 10px 12px;
}
.chat-message-own .message-bubble {
background: linear-gradient(135deg, #d9ac6b 0%, #a67c3d 100%);
}
.message-text {
color: #e0e0e0;
font-size: 14px;
line-height: 1.5;
word-break: break-word;
}
.chat-message-own .message-text {
color: #1f120e;
}
.message-time {
font-size: 11px;
color: #777;
margin-top: 5px;
display: block;
text-align: right;
}
.chat-message-own .message-time {
color: rgba(31, 18, 14, 0.6);
}
/* 输入区域 */
.chat-input-area {
flex-shrink: 0;
border-top: 1px solid #2a1f18;
padding: 12px;
background: #1f120e;
padding-bottom: calc(12px + env(safe-area-inset-bottom));
}
.chat-input {
width: 100%;
min-height: 60px;
max-height: 100px;
background: #3d2c22;
border: 1px solid #553e31;
border-radius: 6px;
padding: 10px;
font-size: 14px;
color: #e0e0e0;
box-sizing: border-box;
}
.chat-input[disabled] {
opacity: 0.5;
}
.chat-actions {
display: flex;
justify-content: flex-end;
margin-top: 10px;
}
.chat-btn-send {
padding: 10px 30px;
border: none;
border-radius: 20px;
font-size: 14px;
font-weight: bold;
background: linear-gradient(180deg, #f7ee99 0%, #78681c 50%, #c0b141 100%);
color: #1f120e;
}
.chat-btn-send:active {
opacity: 0.8;
}
.chat-btn-send[disabled] {
opacity: 0.5;
}
}
</style>
+3
View File
@@ -44,6 +44,9 @@
{{ $lang.tableNumber }} {{ item.table_name }}
</view>
<view class="box">{{ $lang.playingMethod }} {{ item.user_bet }}</view>
<view class="box" v-if="item.ximaliang"
>{{ $lang.ximaliang }} {{ item.ximaliang }}</view
>
<view class="box" v-if="item.maliang"
>{{ $lang.maliang }} {{ item.maliang }}</view
>
+462 -76
View File
@@ -1,70 +1,105 @@
<template>
<view class="user">
<view class="hero">
<view class="card">
<view class="card-sheen"></view>
<view class="card-orb"></view>
<view class="card-grid"></view>
<view class="card-head">
<view class="uid">ID:{{ userInfo.username }}</view>
<view class="logo-shell">
<u--image
class="logo"
:showLoading="true"
:src="loginLogo"
width="50px"
height="auto"
mode="widthFix"
width="42px"
height="42px"
mode="scaleToFill"
></u--image>
</view>
</view>
<view class="box">
<view class="text">{{ $lang.userBalance }}</view>
<view class="money-row">
<view class="money-icon"></view>
<view class="money">{{ money }}</view>
</view>
<u--image
:showLoading="false"
:src="require('static/images/card_bg.png')"
width="100%"
height="auto"
mode="widthFix"
></u--image>
</view>
</view>
</view>
<view class="content">
<view class="section-title">{{ $lang.tip }}</view>
<view class="menu-panel">
<view
class="cell"
v-for="(item, index) in userMenu"
:key="index"
@click="goPath(item)"
>
<view class="cell-left">
<view class="cell-dot"></view>
<view class="lab">{{ item.name }}</view>
</view>
<u-icon
class="icon"
name="arrow-right"
color="#757272"
color="#b9aa84"
size="16"
></u-icon>
</view>
</view>
<view class="logout" @tap="modalShow = true">{{ $lang.logout }}</view>
</view>
<u-picker
:title="$lang.languageSettings"
closeOnClickOverlay
:defaultIndex="defaultIndex"
<u-popup
:show="show"
:columns="langList"
:cancelText="$lang.cancel"
:confirmText="$lang.confirm"
keyName="name"
@close="show = false"
@cancel="show = false"
@confirm="confirm"
></u-picker>
<u-modal
:show="modalShow"
:title="$lang.tip"
:confirmText="$lang.confirm"
:cancelText="$lang.cancel"
@confirm="confirmLogout"
@cancel="modalShow = false"
:showCancelButton="true"
ref="uModal"
:asyncClose="true"
mode="bottom"
round="20"
closeOnClickOverlay
@close="closeLangPopup"
>
<view style="text-align: center">{{ $lang.logoutTip }}</view>
</u-modal>
<view class="lang-popup">
<view class="popup-header">
<view class="popup-action cancel" @click="closeLangPopup">{{
$lang.cancel
}}</view>
<view class="popup-title">{{ $lang.languageSettings }}</view>
<view class="popup-action confirm" @click="confirmLanguageSelection">{{
$lang.confirm
}}</view>
</view>
<scroll-view scroll-y class="popup-list">
<view
class="popup-item"
:class="{ active: tempLanguageKey === item.key }"
v-for="item in langList[0]"
:key="item.key"
@click="tempLanguageKey = item.key"
>
<text>{{ item.name }}</text>
<u-icon
v-if="tempLanguageKey === item.key"
name="checkmark"
color="#231705"
size="16"
></u-icon>
</view>
</scroll-view>
</view>
</u-popup>
<u-popup :show="modalShow" mode="center" round="20" @close="closeLogoutModal">
<view class="logout-modal">
<view class="logout-title">{{ $lang.tip }}</view>
<view class="logout-text">{{ $lang.logoutTip }}</view>
<view class="logout-actions">
<view class="logout-btn logout-btn-cancel" @click="closeLogoutModal">{{
$lang.cancel
}}</view>
<view class="logout-btn logout-btn-confirm" @click="confirmLogout">{{
$lang.confirm
}}</view>
</view>
</view>
</u-popup>
<view class="mb60"></view>
</view>
</template>
@@ -78,6 +113,7 @@ export default {
modalShow: false,
defaultIndex: [0],
tempLanguageKey: "cn",
langList: [
[
{ key: "en", name: "English" },
@@ -121,6 +157,7 @@ export default {
this.defaultIndex = [i];
}
});
this.tempLanguageKey = this.language;
this.getUserMoneyData()
},
methods: {
@@ -128,8 +165,22 @@ export default {
this.$store.commit("app/updateLanguage", item.value[0].key);
this.show = false;
},
closeLangPopup() {
this.tempLanguageKey = this.language;
this.show = false;
},
confirmLanguageSelection() {
if (this.tempLanguageKey) {
this.$store.commit("app/updateLanguage", this.tempLanguageKey);
}
this.show = false;
},
closeLogoutModal() {
this.modalShow = false;
},
goPath(item) {
if (item.id == 0) {
this.tempLanguageKey = this.language;
this.show = true;
} else if (item.id == 4 || item.id == 5 || item.id == 6) {
uni.switchTab({
@@ -149,8 +200,13 @@ export default {
}
},
confirmLogout() {
this.modalShow = false;
localStorage.removeItem("userInfo");
this.$router.replace({ path: "/" });
localStorage.removeItem("uni_id_token");
sessionStorage.clear();
const backSteps = window.history.length - 1;
window.history.go(-backSteps);
setTimeout(() => { window.location.replace("/"); }, 200);
},
getUserMoneyData() {
var that = this
@@ -179,83 +235,413 @@ export default {
<style lang="scss" scoped>
.user {
background: #0b1520;
width: 100%;
min-height: 100vh;
background: linear-gradient(180deg, #060505 0%, #0d0b09 100%);
color: #f7ecd0;
.hero {
padding: 14px 12px 0;
}
.card {
width: 100%;
padding: 10px;
box-sizing: border-box;
position: relative;
overflow: hidden;
border-radius: 28px;
min-height: 188px;
border: 1px solid rgba(226, 193, 117, 0.22);
box-shadow: 0 18px 42px rgba(0, 0, 0, 0.24),
inset 0 1px 0 rgba(255, 245, 223, 0.08);
background: linear-gradient(
180deg,
#f1d488 0%,
#ddaf4e 42%,
#c78f28 100%
);
&::before {
content: "";
position: absolute;
inset: 0;
background: linear-gradient(
135deg,
rgba(255, 255, 255, 0.2) 0%,
rgba(255, 255, 255, 0.04) 26%,
rgba(133, 88, 16, 0.08) 60%,
rgba(78, 50, 8, 0.18) 100%
);
pointer-events: none;
}
.card-sheen {
position: absolute;
top: -22px;
right: -36px;
width: 180px;
height: 180px;
border-radius: 50%;
background: radial-gradient(
circle,
rgba(255, 247, 218, 0.34) 0%,
rgba(255, 247, 218, 0.06) 46%,
rgba(255, 247, 218, 0) 74%
);
pointer-events: none;
}
.card-orb {
position: absolute;
left: -34px;
bottom: -48px;
width: 150px;
height: 150px;
border-radius: 50%;
background: radial-gradient(
circle,
rgba(169, 107, 20, 0.24) 0%,
rgba(169, 107, 20, 0.08) 45%,
rgba(169, 107, 20, 0) 76%
);
pointer-events: none;
}
.card-grid {
position: absolute;
inset: 0;
background-image: linear-gradient(
135deg,
rgba(255, 241, 204, 0.14) 12%,
transparent 12%,
transparent 50%,
rgba(160, 107, 22, 0.08) 50%,
rgba(160, 107, 22, 0.08) 62%,
transparent 62%
),
linear-gradient(
28deg,
rgba(255, 247, 228, 0.08) 14%,
transparent 14%,
transparent 56%,
rgba(149, 98, 21, 0.08) 56%,
rgba(149, 98, 21, 0.08) 70%,
transparent 70%
);
background-size: 180px 180px, 220px 220px;
opacity: 0.7;
pointer-events: none;
}
.card-head {
position: absolute;
top: 16px;
left: 16px;
right: 16px;
z-index: 3;
display: flex;
align-items: center;
justify-content: space-between;
}
.uid {
position: absolute;
left: 30px;
top: 25px;
z-index: 3;
font-size: 14px;
color: #573d14;
max-width: calc(100% - 82px);
padding: 8px 14px;
border-radius: 999px;
background: rgba(84, 64, 25, 0.38);
border: 1px solid rgba(113, 82, 24, 0.12);
color: rgba(92, 61, 12, 0.92);
font-size: 13px;
font-weight: 700;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.logo-shell {
width: 52px;
height: 52px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 16px;
background: rgba(255, 247, 224, 0.12);
border: 1px solid rgba(115, 81, 18, 0.1);
backdrop-filter: blur(2px);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18);
}
.logo {
position: absolute;
right: 25px;
top: 20px;
z-index: 3;
opacity: 0.96;
border-radius: 14px;
}
.box {
position: absolute;
left: 50%;
top: 50%;
top: 55%;
z-index: 3;
transform: translate(-50%, -50%);
font-size: 18px;
font-weight: 600;
color: #573d14;
width: calc(100% - 52px);
text-align: center;
.money {
padding-left: 38px;
padding-right: 36px;
padding-top: 10px;
padding-bottom: 4px;
color: #5d4312;
.text {
font-size: 16px;
font-weight: 600;
letter-spacing: 0.2px;
}
.money-row {
width: fit-content;
max-width: 100%;
margin: 10px auto 0;
display: flex;
align-items: center;
gap: 8px;
}
.money-icon {
width: 28px;
height: 28px;
flex-shrink: 0;
background: url("/static/images/balance_icon.png") no-repeat;
background-size: 33px auto;
background-position: left top;
background-size: 28px auto;
background-position: center;
}
.money {
padding: 0;
font-size: 30px;
font-weight: 700;
line-height: 1.1;
white-space: nowrap;
letter-spacing: 0.3px;
}
}
}
.content {
margin: 20px 15px;
border-radius: 5px;
margin: 18px 12px 0;
.section-title {
margin: 0 2px 12px;
font-size: 13px;
color: #a9956d;
letter-spacing: 0.3px;
}
.menu-panel {
border-radius: 24px;
overflow: hidden;
background: linear-gradient(
180deg,
rgba(16, 13, 11, 0.96) 0%,
rgba(10, 8, 7, 0.96) 100%
);
border: 1px solid rgba(223, 189, 120, 0.12);
box-shadow: 0 18px 42px rgba(0, 0, 0, 0.18),
inset 0 1px 0 rgba(255, 245, 223, 0.03);
}
.cell {
display: flex;
align-items: center;
justify-content: space-between;
font-size: 16px;
padding: 15px 10px;
color: #deb366;
border-bottom: 1px solid #594522;
background: #151617;
min-height: 58px;
padding: 0 16px;
color: #e1c483;
border-bottom: 1px solid rgba(223, 189, 120, 0.08);
background: rgba(19, 17, 15, 0.82);
&:active {
opacity: 0.8;
opacity: 0.82;
}
&:last-child {
border-bottom: none;
}
.cell-left {
display: flex;
align-items: center;
gap: 12px;
min-width: 0;
}
.cell-dot {
width: 10px;
height: 10px;
border-radius: 50%;
background: linear-gradient(180deg, #f2dfb6 0%, #dfbd78 52%, #bd8d39 100%);
box-shadow: 0 0 0 4px rgba(223, 189, 120, 0.06);
}
.lab {
font-size: 15px;
font-weight: 600;
color: #e0c283;
}
.icon {
flex-shrink: 0;
}
}
.logout {
width: 100%;
height: 48px;
line-height: 48px;
height: 50px;
line-height: 50px;
text-align: center;
font-size: 16px;
background: #e5b932;
font-weight: 600;
margin: 20px auto;
border-radius: 5px;
font-size: 15px;
color: #231705;
background: linear-gradient(180deg, #f2dfb6 0%, #dfbd78 52%, #bd8d39 100%);
font-weight: 700;
letter-spacing: 0.3px;
margin: 18px auto 0;
border-radius: 16px;
box-shadow: 0 12px 24px rgba(125, 84, 22, 0.18),
inset 0 1px 0 rgba(255, 255, 255, 0.36);
&:active {
opacity: 0.8;
opacity: 0.86;
}
}
}
.lang-popup {
background: linear-gradient(180deg, #17130f 0%, #0d0b09 100%);
border-top: 1px solid rgba(223, 189, 120, 0.14);
border-radius: 20px 20px 0 0;
overflow: hidden;
}
.popup-header {
display: flex;
align-items: center;
justify-content: space-between;
height: 54px;
padding: 0 16px;
border-bottom: 1px solid rgba(223, 189, 120, 0.1);
background: rgba(21, 18, 15, 0.96);
}
.popup-title {
font-size: 16px;
font-weight: 700;
color: #f4dfae;
}
.popup-action {
min-width: 52px;
font-size: 14px;
line-height: 1;
&.cancel {
color: #a9956d;
text-align: left;
}
&.confirm {
color: #dfbd78;
text-align: right;
}
}
.popup-list {
max-height: 50vh;
padding: 10px 12px calc(18px + env(safe-area-inset-bottom));
box-sizing: border-box;
}
.popup-item {
min-height: 48px;
padding: 0 14px;
margin-bottom: 10px;
border-radius: 14px;
display: flex;
align-items: center;
justify-content: space-between;
color: #d9c6a0;
font-size: 15px;
font-weight: 600;
background: linear-gradient(
180deg,
rgba(25, 21, 18, 0.96) 0%,
rgba(17, 14, 12, 0.96) 100%
);
border: 1px solid rgba(223, 189, 120, 0.12);
box-shadow: inset 0 1px 0 rgba(255, 244, 220, 0.03);
&:last-child {
margin-bottom: 0;
}
&.active {
color: #231705;
background: linear-gradient(180deg, #f2dfb6 0%, #dfbd78 52%, #bd8d39 100%);
border-color: rgba(242, 223, 182, 0.45);
box-shadow: 0 10px 20px rgba(125, 84, 22, 0.16),
inset 0 1px 0 rgba(255, 255, 255, 0.28);
}
}
.logout-modal {
width: 620rpx;
padding: 34rpx 34rpx 28rpx;
background: linear-gradient(
180deg,
rgba(20, 16, 12, 0.98) 0%,
rgba(11, 9, 7, 0.98) 100%
);
border: 1rpx solid rgba(223, 189, 120, 0.18);
border-radius: 20rpx;
box-sizing: border-box;
box-shadow: 0 24rpx 60rpx rgba(0, 0, 0, 0.3);
}
.logout-title {
text-align: center;
font-size: 30rpx;
font-weight: 700;
color: #f4dfae;
}
.logout-text {
margin-top: 18rpx;
color: #d9c6a0;
font-size: 24rpx;
line-height: 1.7;
text-align: center;
}
.logout-actions {
display: flex;
gap: 16rpx;
margin-top: 28rpx;
}
.logout-btn {
flex: 1;
height: 78rpx;
border-radius: 14rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 26rpx;
font-weight: 700;
&.logout-btn-cancel {
color: #d9c6a0;
background: rgba(255, 255, 255, 0.03);
border: 1rpx solid rgba(223, 189, 120, 0.12);
}
&.logout-btn-confirm {
color: #231705;
background: linear-gradient(180deg, #f2dfb6 0%, #dfbd78 52%, #bd8d39 100%);
box-shadow: 0 10rpx 20rpx rgba(125, 84, 22, 0.16),
inset 0 1px 0 rgba(255, 255, 255, 0.28);
}
}
}
</style>
+503 -48
View File
@@ -2,7 +2,7 @@
<view class="withdraw">
<u-navbar
title=""
bgColor="#000"
bgColor="transparent"
:placeholder="true"
:fixed="true"
leftIcon=""
@@ -18,11 +18,13 @@
>{{ $lang.balance }}{{ userInfo.money }}</view
>
</view>
<!-- USDT 提现 -->
<template v-if="userInfo.pay_channel != 'ALIN_VN'">
<view class="picker-view" @click="show = true">
<u-input
readonly
:placeholder="$lang.pleaseChoose"
color="#93979b"
color="#f7ecd0"
v-model="type"
border="none"
>
@@ -35,7 +37,7 @@
<u-icon
slot="suffix"
name="arrow-down-fill"
color="#757272"
color="#b9aa84"
size="16"
></u-icon>
</u-input>
@@ -55,10 +57,10 @@
<view class="lable">{{ $lang.walletAddress }}</view>
<u-input
class="input"
color="#947b2b"
color="#f7ecd0"
clearable
:placeholder="$lang.enterWithdrawalAddress"
border="surround"
border="none"
v-model="address"
></u-input>
</view>
@@ -66,10 +68,10 @@
<view class="lable">{{ $lang.amount }}</view>
<u-input
class="input"
color="#947b2b"
color="#f7ecd0"
clearable
:placeholder="$lang.enterWithdrawalamount"
border="surround"
border="none"
v-model="money"
></u-input>
</view>
@@ -89,6 +91,113 @@
<view class="tip">{{ $lang.withdrawTip }}</view>
<view class="tip">{{ $lang.commission }}:1 USDT</view>
</view>
</template>
<!-- 越南银行卡提现 -->
<template v-if="userInfo.pay_channel == 'ALIN_VN'">
<view class="picker-view" @click="openBankPicker">
<u-input
readonly
:placeholder="$lang.pleaseChoose"
color="#f7ecd0"
v-model="bankName"
border="none"
>
<u--text
:text="$lang.bankName"
slot="prefix"
margin="0 3px 0 0"
type="tips"
></u--text>
<u-icon
slot="suffix"
name="arrow-down-fill"
color="#b9aa84"
size="16"
></u-icon>
</u-input>
</view>
<u-popup
:show="showBankPicker"
mode="bottom"
round="20"
closeOnClickOverlay
@close="closeBankPicker"
>
<view class="bank-picker-popup">
<view class="bank-picker-header">
<view class="bank-picker-action cancel" @click="closeBankPicker">{{
$lang.cancel
}}</view>
<view class="bank-picker-title">{{ $lang.bankName }}</view>
<view class="bank-picker-action confirm" @click="confirmBankSelection">{{
$lang.confirm
}}</view>
</view>
<scroll-view scroll-y class="bank-picker-list">
<view
class="bank-picker-item"
:class="{ active: tempBankName === item.name }"
v-for="(item, index) in bankList"
:key="index"
@click="selectBankOption(item)"
>
<text>{{ item.name }}</text>
<u-icon
v-if="tempBankName === item.name"
name="checkmark"
color="#231705"
size="16"
></u-icon>
</view>
</scroll-view>
</view>
</u-popup>
<view class="list">
<view class="lable">{{ $lang.accountName }}</view>
<u-input
class="input"
color="#f7ecd0"
clearable
:placeholder="$lang.enterAccountName"
border="none"
v-model="accountName"
></u-input>
</view>
<view class="list">
<view class="lable">{{ $lang.accountNumber }}</view>
<u-input
class="input"
color="#f7ecd0"
clearable
:placeholder="$lang.enterAccountNumber"
border="none"
v-model="accountNumber"
></u-input>
</view>
<view class="list">
<view class="lable">{{ $lang.amount }}</view>
<u-input
class="input"
color="#f7ecd0"
clearable
type="number"
:placeholder="'Tối thiểu 1,000,000 VND'"
border="none"
v-model="money"
></u-input>
</view>
<view class="list">
<u-button
@tap="applyWithdrawBank"
class="button"
color="#e5b932"
:text="$lang.submit"
></u-button>
</view>
<view class="list">
<view class="tip">{{ $lang.withdrawTip }}</view>
</view>
</template>
</view>
<view class="mb60"></view>
</view>
@@ -104,6 +213,15 @@ export default {
type: "USDT",
show: false,
columns: [["USDT"]],
// 越南银行卡提现
bankName: "",
bankCode: "",
tempBankName: "",
accountName: "",
accountNumber: "",
showBankPicker: false,
bankColumns: [[]],
bankList: [],
};
},
computed: {
@@ -112,7 +230,12 @@ export default {
$lang: (state) => state.app.lang[state.app.language],
}),
},
onLoad() {},
onLoad() {
// 越南渠道加载银行列表
if (this.userInfo && this.userInfo.pay_channel === 'ALIN_VN') {
this.loadBankList();
}
},
methods: {
confirm(chose) {
this.type = chose.value[0];
@@ -169,86 +292,418 @@ export default {
});
}
},
// 加载越南银行列表
loadBankList() {
this.$api
.getBankListVn({ user_id: this.userInfo.id })
.then((res) => {
if (res.Data && res.Data.data) {
this.bankList = res.Data.data;
this.bankColumns = [res.Data.data.map((item) => item.name)];
}
})
.catch((err) => {
console.log(err);
});
},
openBankPicker() {
this.tempBankName = this.bankName;
this.showBankPicker = true;
},
closeBankPicker() {
this.showBankPicker = false;
},
selectBankOption(item) {
this.tempBankName = item.name;
},
// 选择银行
confirmBankSelection() {
if (!this.tempBankName) {
this.showBankPicker = false;
return;
}
this.bankName = this.tempBankName;
this.bankCode = this.tempBankName;
this.showBankPicker = false;
},
// 越南银行卡提现
applyWithdrawBank() {
if (!this.bankName) {
this.$toast({
message: this.$lang.bankName,
duration: 2000,
});
return;
}
if (!this.accountName) {
this.$toast({
message: this.$lang.enterAccountName,
duration: 2000,
});
return;
}
if (!this.accountNumber) {
this.$toast({
message: this.$lang.enterAccountNumber,
duration: 2000,
});
return;
}
if (!this.money || this.money <= 0) {
this.$toast({
message: this.$lang.amountCannotBe0,
duration: 2000,
});
return;
}
if (Number(this.money) < 1000000) {
this.$toast({
message: 'Số tiền rút tối thiểu là 1,000,000 VND',
duration: 2000,
});
return;
}
if (Number(this.money) > Number(this.userInfo.money)) {
this.$toast({
message: this.$lang.insufficientBalance,
duration: 2000,
});
return;
}
const params = {
user_id: this.userInfo.id,
account_name: this.accountName,
account_number: this.accountNumber,
bank_code: this.bankCode,
bank_name: this.bankName,
amount: this.money,
};
this.$toast({
type: "loading",
message: this.$lang.submittingApplication,
duration: 200000,
});
this.$api
.applyWithdrawBank(params)
.then((res) => {
if (res.Success) {
this.$toast({
type: "success",
message: res.Msg,
duration: 2000,
});
this.bankName = "";
this.bankCode = "";
this.accountName = "";
this.accountNumber = "";
this.money = "";
} else {
this.$toast({
message: res.Msg,
duration: 2000,
});
}
})
.catch((err) => {
console.log(err);
})
.finally(() => {
this.$toastHide();
});
},
},
};
</script>
<style lang="scss" scoped>
.withdraw {
background: #0b1520;
width: 100%;
min-height: 100vh;
background: linear-gradient(180deg, #060505 0%, #0d0b09 100%);
color: #f7ecd0;
::v-deep .u-navbar {
background: rgba(0, 0, 0, 0.72) !important;
}
::v-deep .u-navbar__content {
background: transparent !important;
}
::v-deep .u-picker__view__column__item {
color: #f3e3b8 !important;
font-size: 16px !important;
font-weight: 600;
}
::v-deep .u-toolbar {
background: #15120f !important;
border-bottom-color: rgba(223, 189, 120, 0.12) !important;
}
::v-deep .u-toolbar__title {
color: #f4dfae !important;
}
::v-deep .u-toolbar__wrapper__cancel {
color: #a9956d !important;
}
::v-deep .u-toolbar__wrapper__confirm {
color: #dfbd78 !important;
}
.navbar-lab {
color: #fff;
font-weight: 500;
font-size: 18px;
color: #fbf2de;
font-weight: 700;
font-size: 19px;
letter-spacing: 0.3px;
}
.content {
margin: 5px 5px;
border: 2px solid #947b2b;
background: #222222;
width: calc(100% - 24px);
max-width: 760px;
margin: 10px auto 0;
padding: 18px 16px 22px;
box-sizing: border-box;
padding: 15px;
border-radius: 24px;
background: linear-gradient(
180deg,
rgba(16, 13, 11, 0.96) 0%,
rgba(10, 8, 7, 0.96) 100%
);
border: 1px solid rgba(223, 189, 120, 0.18);
box-shadow: 0 18px 42px rgba(0, 0, 0, 0.24),
inset 0 1px 0 rgba(255, 245, 223, 0.03);
min-height: 400px;
.picker-view {
border: 2px solid #947b2b;
padding: 8px;
border-radius: 5px;
min-height: 56px;
margin-bottom: 14px;
padding: 0 14px;
display: flex;
align-items: center;
background: linear-gradient(
180deg,
rgba(25, 21, 18, 0.96) 0%,
rgba(17, 14, 12, 0.96) 100%
);
border: 1px solid rgba(223, 189, 120, 0.14);
border-radius: 16px;
box-shadow: inset 0 1px 0 rgba(255, 244, 220, 0.03),
inset 0 -1px 0 rgba(0, 0, 0, 0.12);
::v-deep .u-input {
flex: 1;
}
::v-deep .u-input__content {
min-height: 54px;
padding: 0;
}
::v-deep .u-input__content__field-wrapper {
width: 100%;
}
::v-deep input {
color: #f7ecd0 !important;
font-size: 15px !important;
letter-spacing: 0.2px;
}
::v-deep input::placeholder {
color: rgba(245, 228, 184, 0.4) !important;
}
::v-deep .u-text__value {
color: #baa67f !important;
font-size: 13px !important;
}
}
.list {
margin-bottom: 14px;
padding: 14px;
border-radius: 16px;
background: linear-gradient(
180deg,
rgba(23, 19, 16, 0.92) 0%,
rgba(14, 12, 10, 0.92) 100%
);
border: 1px solid rgba(223, 189, 120, 0.1);
font-size: 14px;
text-align: center;
.lab {
color: #757272;
margin: 10px 0;
color: #b9aa84;
margin: 0 0 10px;
text-align: left;
font-size: 13px;
}
.lable {
text-align: left;
color: #ddd;
margin-top: 20px;
font-size: 16px;
color: #d9c6a0;
margin-top: 0;
font-size: 15px;
margin-bottom: 10px;
font-weight: 600;
}
.money {
font-size: 16px;
min-height: 52px;
padding: 0 16px;
display: flex;
align-items: center;
justify-content: center;
font-size: 17px;
margin-top: 0;
padding: 15px 0;
color: #e5b932;
}
.btn {
height: 30px;
font-weight: 600;
color: #0b1520 !important;
color: #f1d392;
font-weight: 700;
border-radius: 16px;
background: linear-gradient(
180deg,
rgba(27, 22, 18, 0.96) 0%,
rgba(17, 14, 12, 0.96) 100%
);
border: 1px solid rgba(223, 189, 120, 0.14);
box-shadow: inset 0 1px 0 rgba(255, 244, 220, 0.04);
}
.type {
width: 70px;
height: 35px;
background: #e5b932;
border-radius: 40px;
min-width: 86px;
height: 36px;
padding: 0 16px;
display: inline-flex;
align-items: center;
justify-content: center;
background: linear-gradient(180deg, #f2dfb6 0%, #dfbd78 52%, #bd8d39 100%);
border-radius: 999px;
text-align: center;
line-height: 35px;
font-weight: 600;
margin: 10px auto;
line-height: 36px;
font-weight: 700;
color: #231705;
box-shadow: 0 8px 18px rgba(125, 84, 22, 0.16),
inset 0 1px 0 rgba(255, 255, 255, 0.28);
margin: 0 auto;
}
.input {
line-height: 30px;
height: 30px;
min-height: 48px;
padding: 0 12px;
background: rgba(255, 255, 255, 0.02);
border: 1px solid rgba(223, 189, 120, 0.12);
border-radius: 14px;
::v-deep .u-input__content {
min-height: 48px;
padding: 0;
}
::v-deep .u-input__content__field-wrapper {
width: 100%;
}
::v-deep input {
color: #f7ecd0 !important;
font-size: 15px !important;
letter-spacing: 0.2px;
}
::v-deep input::placeholder {
color: rgba(245, 228, 184, 0.4) !important;
}
}
.button {
line-height: 45px;
height: 45px;
color: #0b1520 !important;
font-weight: bold;
margin-top: 30px;
margin-bottom: 10px;
height: 50px !important;
margin-top: 8px;
margin-bottom: 2px;
border: none !important;
border-radius: 16px !important;
color: #231705 !important;
font-weight: 700;
letter-spacing: 0.3px;
box-shadow: 0 12px 24px rgba(125, 84, 22, 0.18),
inset 0 1px 0 rgba(255, 255, 255, 0.36);
}
.tip {
color: #cc4c0e;
color: #bca47a;
font-size: 13px;
text-align: justify;
line-height: 1.6;
}
}
}
.bank-picker-popup {
background: linear-gradient(180deg, #17130f 0%, #0d0b09 100%);
border-top: 1px solid rgba(223, 189, 120, 0.14);
border-radius: 20px 20px 0 0;
overflow: hidden;
}
.bank-picker-header {
display: flex;
align-items: center;
justify-content: space-between;
height: 54px;
padding: 0 16px;
border-bottom: 1px solid rgba(223, 189, 120, 0.1);
background: rgba(21, 18, 15, 0.96);
}
.bank-picker-title {
font-size: 16px;
font-weight: 700;
color: #f4dfae;
}
.bank-picker-action {
min-width: 52px;
font-size: 14px;
line-height: 1;
&.cancel {
color: #a9956d;
text-align: left;
}
&.confirm {
color: #dfbd78;
text-align: right;
}
}
.bank-picker-list {
max-height: 52vh;
padding: 10px 12px calc(18px + env(safe-area-inset-bottom));
box-sizing: border-box;
}
.bank-picker-item {
min-height: 48px;
padding: 0 14px;
margin-bottom: 10px;
border-radius: 14px;
display: flex;
align-items: center;
justify-content: space-between;
color: #d9c6a0;
font-size: 15px;
font-weight: 600;
background: linear-gradient(
180deg,
rgba(25, 21, 18, 0.96) 0%,
rgba(17, 14, 12, 0.96) 100%
);
border: 1px solid rgba(223, 189, 120, 0.12);
box-shadow: inset 0 1px 0 rgba(255, 244, 220, 0.03);
&:last-child {
margin-bottom: 0;
}
&.active {
color: #231705;
background: linear-gradient(180deg, #f2dfb6 0%, #dfbd78 52%, #bd8d39 100%);
border-color: rgba(242, 223, 182, 0.45);
box-shadow: 0 10px 20px rgba(125, 84, 22, 0.16),
inset 0 1px 0 rgba(255, 255, 255, 0.28);
}
}
}
</style>
+28
View File
@@ -53,6 +53,34 @@ let api = {
ybfDeposit: async (params) => {
return await ajax.post("/deposit", params);
},
// 越南AlinPay充值
alinDeposit: async (params) => {
return await ajax.post("/alin_online_order", params);
},
// 彩虹易支付充值(USDT TRC20 / 支付宝 / 微信 等,默认 usdt)
epayDeposit: async (params) => {
return await ajax.post("/epay_online_order", params);
},
// 易支付订单状态轮询(内嵌二维码支付用)
epayOrderStatus: async (params) => {
return await ajax.post("/epay_order_status", params);
},
// CCpay越南银行QR充值
ccpayDeposit: async (params) => {
return await ajax.post("/ccpay_online_order", params);
},
// CCpay订单状态轮询
ccpayOrderStatus: async (params) => {
return await ajax.post("/ccpay_order_status", params);
},
// 越南银行卡提现
applyWithdrawBank: async (params) => {
return await ajax.post("/apply_withdraw_bank", params);
},
// 获取越南银行列表
getBankListVn: async (params) => {
return await ajax.post("/get_bank_list_vn", params);
},
// 获取用户信息
getUserInfo: async (params) => {
return await ajax.post("/get_user_info", params);
Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 21 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 21 KiB