Merge branch 'jk8_new'

This commit is contained in:
2026-06-08 13:59:58 +08:00
3 changed files with 312 additions and 151 deletions

View File

@@ -36,4 +36,80 @@ export default {
second: 'Second', second: 'Second',
day: 'Day', day: 'Day',
'Number of attachments Uploaded': 'Number of attachments upload', 'Number of attachments Uploaded': 'Number of attachments upload',
'Available Bank Balance': 'Available Bank Balance',
'Bank Name': 'Bank Name',
'Current Balance': 'Current Balance',
'Transaction Breakdown': 'Transaction Breakdown',
'Safe Alert': 'Safe Alert',
Transfer: 'Transfer',
'No Alert': 'No Alert',
'No bank data': 'No bank data',
'Show less': 'Show less',
'More info': 'More info',
'Customer Summary': 'Customer Summary',
'Create New Transaction': 'Create New Transaction',
'Edit Transaction': 'Edit Transaction #{id}',
'Webhook enabled': 'The Transaction Mode you currently set has the Webhook (JDK) feature enabled',
'Webhook hint':
'Hint: If a transaction approved in the JK backend is not automatically recorded here within 10 minutes, click "Create New Transaction" to record it manually.',
'Start Date': 'Start Date',
'End Date': 'End Date',
Today: 'Today',
'Date of data': 'Date of data',
'Date range': '{start} to {end} ({days} {unit})',
Day: 'Day',
Days: 'Days',
'Total Deposit / IN': 'Total Deposit / IN',
'Total Withdraw / OUT': 'Total Withdraw / OUT',
'Deposit Count': 'Deposit Count',
'Withdraw Count': 'Withdraw Count',
'Active Player': 'Active Player',
'First Deposit Player': 'First Deposit Player',
'Unclaimed Amount': 'Unclaimed Amount',
'Unclaimed Receipt': 'Unclaimed Receipt',
'Created by': 'Created by',
'Created Time': 'Created Time',
Category: 'Category',
Username: 'Username',
Remark: 'Remark',
Bank: 'Bank',
Type: 'Type',
'Amount (AUD)': 'Amount (AUD)',
Label: 'Label',
'Game Ticket': 'Game Ticket',
Action: 'Action',
History: 'History',
'Date & Time': 'Date & Time',
Auto: 'Auto',
Manual: 'Manual',
Customer: 'Customer',
'Other Adjust': 'Other Adjust',
Deposit: 'Deposit',
Withdraw: 'Withdraw',
'Username placeholder': 'e.g. PLAYER001',
Optional: '(optional)',
'Optional select': '- (optional) -',
'First Deposit': 'First Deposit',
Unclaim: 'Unclaim',
'Game Ticket Auto': 'Game Ticket Auto',
'Auto generate ticket': 'Auto generate ticket',
'Transaction Edit History': 'Transaction Edit History',
'History retention note': 'Transaction edit history is only kept for the most recent 12 months.',
'No Record': 'No Record',
'Tx ID': 'Tx ID',
'Edit By': 'Edit By',
'Edit Time': 'Edit Time',
Changes: 'Changes (Old → New)',
'Bank change': 'Bank:{before}→{after}',
'Bank Transfer': 'Bank Transfer',
'Transfer (From)': 'Transfer (From)',
'Transfer (To)': 'Transfer (To)',
'Select Bank': '- Select Bank -',
Amount: 'Amount',
'Hourly Alert': 'Hourly Alert',
'Daily Alert': 'Daily Alert',
'Weekly Alert': 'Weekly Alert',
'Monthly Alert': 'Monthly Alert',
'Yearly Alert': 'Yearly Alert',
'Lifetime Alert': 'Lifetime Alert',
} }

View File

@@ -36,4 +36,79 @@ export default {
second: '秒', second: '秒',
day: '天', day: '天',
'Number of attachments Uploaded': '附件上传量', 'Number of attachments Uploaded': '附件上传量',
'Available Bank Balance': '可用银行余额',
'Bank Name': '银行名称',
'Current Balance': '当前余额',
'Transaction Breakdown': '交易明细',
'Safe Alert': '安全提醒',
Transfer: '转账',
'No Alert': '无提醒',
'No bank data': '暂无银行数据',
'Show less': '收起',
'More info': '查看更多',
'Customer Summary': '客户汇总',
'Create New Transaction': '新建交易',
'Edit Transaction': '编辑交易 #{id}',
'Webhook enabled': '当前设置的交易模式已启用 WebhookJDK功能',
'Webhook hint': '提示:如果 JK 后台已批准的交易在 10 分钟内没有自动记录,请点击“新建交易”手动记录。',
'Start Date': '开始日期',
'End Date': '结束日期',
Today: '今天',
'Date of data': '数据日期',
'Date range': '{start} 至 {end}{days} {unit}',
Day: '天',
Days: '天',
'Total Deposit / IN': '总存款 / 转入',
'Total Withdraw / OUT': '总提款 / 转出',
'Deposit Count': '存款笔数',
'Withdraw Count': '提款笔数',
'Active Player': '活跃玩家',
'First Deposit Player': '首存玩家',
'Unclaimed Amount': '未认领金额',
'Unclaimed Receipt': '未认领凭证',
'Created by': '创建者',
'Created Time': '创建时间',
Category: '分类',
Username: '用户名',
Remark: '备注',
Bank: '银行',
Type: '类型',
'Amount (AUD)': '金额AUD',
Label: '标签',
'Game Ticket': '游戏票据',
Action: '操作',
History: '历史记录',
'Date & Time': '日期和时间',
Auto: '自动',
Manual: '手动',
Customer: '客户',
'Other Adjust': '其他调整',
Deposit: '存款',
Withdraw: '提款',
'Username placeholder': '例如 PLAYER001',
Optional: '(可选)',
'Optional select': '- 可选 -',
'First Deposit': '首次存款',
Unclaim: '未认领',
'Game Ticket Auto': '自动游戏票据',
'Auto generate ticket': '自动生成票据',
'Transaction Edit History': '交易编辑历史',
'History retention note': '交易编辑历史仅保留最近 12 个月。',
'No Record': '暂无记录',
'Tx ID': '交易 ID',
'Edit By': '编辑者',
'Edit Time': '编辑时间',
Changes: '变更内容(旧 → 新)',
'Bank change': '银行:{before}→{after}',
'Bank Transfer': '银行转账',
'Transfer (From)': '转出银行',
'Transfer (To)': '转入银行',
'Select Bank': '- 选择银行 -',
Amount: '金额',
'Hourly Alert': '每小时提醒',
'Daily Alert': '每日提醒',
'Weekly Alert': '每周提醒',
'Monthly Alert': '每月提醒',
'Yearly Alert': '每年提醒',
'Lifetime Alert': '永久提醒',
} }

View File

@@ -2,15 +2,15 @@
<div class="default-main bookkeeping-dashboard"> <div class="default-main bookkeeping-dashboard">
<section class="dashboard-grid"> <section class="dashboard-grid">
<div class="dashboard-panel bank-panel"> <div class="dashboard-panel bank-panel">
<div class="panel-title">Available Bank Balance</div> <div class="panel-title">{{ t('dashboard.Available Bank Balance') }}</div>
<div class="table-scroll"> <div class="table-scroll">
<table class="bank-table"> <table class="bank-table">
<thead> <thead>
<tr> <tr>
<th>Bank Name</th> <th>{{ t('dashboard.Bank Name') }}</th>
<th>Current Balance</th> <th>{{ t('dashboard.Current Balance') }}</th>
<th>Transaction Breakdown</th> <th>{{ t('dashboard.Transaction Breakdown') }}</th>
<th>Safe Alert</th> <th>{{ t('dashboard.Safe Alert') }}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@@ -23,7 +23,7 @@
<td> <td>
<div class="bank-operate"> <div class="bank-operate">
<el-button size="small" :icon="Coin" circle /> <el-button size="small" :icon="Coin" circle />
<el-button size="small" :icon="Switch" @click="openTransfer(bank)">Transfer</el-button> <el-button size="small" :icon="Switch" @click="openTransfer(bank)">{{ t('dashboard.Transfer') }}</el-button>
<div class="breakdown"> <div class="breakdown">
<span><i class="dot income"></i> ({{ bank.depositCount }}) {{ money(bank.deposit) }}</span> <span><i class="dot income"></i> ({{ bank.depositCount }}) {{ money(bank.deposit) }}</span>
<span><i class="dot outcome"></i> ({{ bank.withdrawCount }}) {{ money(bank.withdraw) }}</span> <span><i class="dot outcome"></i> ({{ bank.withdrawCount }}) {{ money(bank.withdraw) }}</span>
@@ -31,24 +31,26 @@
</div> </div>
</td> </td>
<td> <td>
<el-tag size="small" effect="plain" :type="bank.alert ? 'danger' : 'info'">{{ bank.alert || 'No Alert' }}</el-tag> <el-tag size="small" effect="plain" :type="bank.alertCode !== '0' ? 'danger' : 'info'">
{{ safeAlertText(bank.alertCode) }}
</el-tag>
</td> </td>
</tr> </tr>
<tr v-if="!visibleBanks.length"> <tr v-if="!visibleBanks.length">
<td class="empty-banks" colspan="4">No bank data</td> <td class="empty-banks" colspan="4">{{ t('dashboard.No bank data') }}</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>
<button v-if="banks.length > 4" class="more-info" type="button" @click="showAllBanks = !showAllBanks"> <button v-if="banks.length > 4" class="more-info" type="button" @click="showAllBanks = !showAllBanks">
{{ showAllBanks ? 'show less' : 'more info' }} {{ showAllBanks ? t('dashboard.Show less') : t('dashboard.More info') }}
<Icon :name="showAllBanks ? 'fa fa-caret-up' : 'fa fa-caret-down'" /> <Icon :name="showAllBanks ? 'fa fa-caret-up' : 'fa fa-caret-down'" />
</button> </button>
</div> </div>
<aside class="summary-side"> <aside class="summary-side">
<div class="dashboard-panel summary-panel"> <div class="dashboard-panel summary-panel">
<div class="panel-title">Customer Summary</div> <div class="panel-title">{{ t('dashboard.Customer Summary') }}</div>
<dl> <dl>
<template v-for="item in summary" :key="item.label"> <template v-for="item in summary" :key="item.label">
<dt>{{ item.label }}:</dt> <dt>{{ item.label }}:</dt>
@@ -56,66 +58,68 @@
</template> </template>
</dl> </dl>
</div> </div>
<el-button class="create-button" type="success" @click="openCreate">CREATE NEW TRANSACTION</el-button> <el-button class="create-button" type="success" @click="openCreate">{{ t('dashboard.Create New Transaction') }}</el-button>
</aside> </aside>
</section> </section>
<el-alert class="webhook-alert" type="warning" :closable="true" show-icon> <el-alert class="webhook-alert" type="warning" :closable="true" show-icon>
<template #title> <template #title>
<strong>The Transaction Mode you currently set has the Webhook (JDK) feature enabled</strong> <strong>{{ t('dashboard.Webhook enabled') }}</strong>
</template> </template>
<p> <p>{{ t('dashboard.Webhook hint') }}</p>
Hint: If a transaction approved in the JK backend is not automatically recorded here within 10 minutes, click "Create New Transaction"
to record it manually.
</p>
<p>提示如果 JK 后台 Approved Transaction 在这里 10 分钟内没有自动记录请点击 "Create New Transaction" 手动记录</p>
</el-alert> </el-alert>
<section class="transaction-section"> <section class="transaction-section">
<div class="filter-row"> <div class="filter-row">
<div class="date-filter"> <div class="date-filter">
<label>Start Date:</label> <label>{{ t('dashboard.Start Date') }}:</label>
<el-date-picker v-model="filters.startDate" type="date" value-format="YYYY-MM-DD" /> <el-date-picker v-model="filters.startDate" type="date" value-format="YYYY-MM-DD" />
<label>End Date:</label> <label>{{ t('dashboard.End Date') }}:</label>
<el-date-picker v-model="filters.endDate" type="date" value-format="YYYY-MM-DD" /> <el-date-picker v-model="filters.endDate" type="date" value-format="YYYY-MM-DD" />
<el-button @click="search">Search</el-button> <el-button @click="search">{{ t('Search') }}</el-button>
<el-button @click="setToday">Today</el-button> <el-button @click="setToday">{{ t('dashboard.Today') }}</el-button>
</div> </div>
<div class="totals"> <div class="totals">
<span>Date of data: {{ dateRangeText }}</span> <span>{{ t('dashboard.Date of data') }}: {{ dateRangeText }}</span>
<b <b
>Total Deposit / IN: <em>AUD {{ money(totalDeposit) }}</em></b >{{ t('dashboard.Total Deposit / IN') }}: <em>AUD {{ money(totalDeposit) }}</em></b
> >
<b <b
>Total Withdraw / OUT: <em>AUD {{ money(totalWithdraw) }}</em></b >{{ t('dashboard.Total Withdraw / OUT') }}: <em>AUD {{ money(totalWithdraw) }}</em></b
> >
</div> </div>
</div> </div>
<el-table :data="transactions" border size="small" class="transaction-table" :row-class-name="transactionRowClass"> <el-table :data="transactions" border size="small" class="transaction-table" :row-class-name="transactionRowClass">
<el-table-column prop="createdBy" label="Created by" width="110" /> <el-table-column prop="createdBy" :label="t('dashboard.Created by')" width="110" />
<el-table-column prop="createdTime" label="Created Time" width="170" /> <el-table-column prop="createdTime" :label="t('dashboard.Created Time')" width="170" />
<el-table-column prop="category" label="Category" width="100" /> <el-table-column :label="t('dashboard.Category')" width="100">
<el-table-column prop="username" label="Username" width="110" /> <template #default="{ row }">{{ categoryText(row.categoryId) }}</template>
<el-table-column prop="remark" label="Remark" min-width="205" /> </el-table-column>
<el-table-column prop="bank" label="Bank" min-width="165" /> <el-table-column prop="username" :label="t('dashboard.Username')" width="110" />
<el-table-column prop="type" label="Type" width="95" /> <el-table-column prop="remark" :label="t('dashboard.Remark')" min-width="205" />
<el-table-column label="Amount (AUD)" width="130" align="right"> <el-table-column prop="bank" :label="t('dashboard.Bank')" min-width="165" />
<el-table-column :label="t('dashboard.Type')" width="95">
<template #default="{ row }">{{ typeText(row.typeId) }}</template>
</el-table-column>
<el-table-column :label="t('dashboard.Amount (AUD)')" width="130" align="right">
<template #default="{ row }"> <template #default="{ row }">
<strong :class="row.flow === 'in' ? 'amount-in' : 'amount-out'">{{ money(row.amount) }}</strong> <strong :class="row.flow === 'in' ? 'amount-in' : 'amount-out'">{{ money(row.amount) }}</strong>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="label" label="Label" width="100" /> <el-table-column :label="t('dashboard.Label')" width="100">
<el-table-column label="Game Ticket" min-width="140"> <template #default="{ row }">{{ transactionLabelText(row.labelId) }}</template>
</el-table-column>
<el-table-column :label="t('dashboard.Game Ticket')" min-width="140">
<template #default="{ row }"> <template #default="{ row }">
<div v-for="(ticket, index) in row.ticket" :key="`${ticket}-${index}`">{{ ticket }}</div> <div v-for="(ticket, index) in row.ticket" :key="`${ticket}-${index}`">{{ ticket }}</div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="Action" fixed="right" width="180"> <el-table-column :label="t('dashboard.Action')" fixed="right" width="180">
<template #default="{ row }"> <template #default="{ row }">
<el-button link type="primary" size="small" @click="openHistory(row)">history</el-button> <el-button link type="primary" size="small" @click="openHistory(row)">{{ t('dashboard.History') }}</el-button>
<el-button link type="primary" size="small" @click="openEdit(row)">edit</el-button> <el-button link type="primary" size="small" @click="openEdit(row)">{{ t('Edit') }}</el-button>
<el-button link type="danger" size="small" @click="removeTransaction(row)">delete</el-button> <el-button link type="danger" size="small" @click="removeTransaction(row)">{{ t('Delete') }}</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@@ -132,80 +136,85 @@
</div> </div>
</section> </section>
<el-dialog v-model="transactionDialog.visible" :title="transactionDialog.title" width="680px"> <el-dialog v-model="transactionDialog.visible" :title="transactionDialogTitle" width="680px">
<el-form :model="transactionForm" label-width="145px"> <el-form :model="transactionForm" label-width="145px">
<el-form-item label="Date & Time"> <el-form-item :label="t('dashboard.Date & Time')">
<el-date-picker v-model="transactionForm.time" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" /> <el-date-picker v-model="transactionForm.time" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" />
<el-radio-group v-model="transactionForm.timeMode" class="inline-mode"> <el-radio-group v-model="transactionForm.timeMode" class="inline-mode">
<el-radio value="Auto">Auto</el-radio> <el-radio value="Auto">{{ t('dashboard.Auto') }}</el-radio>
<el-radio value="Manual">Manual</el-radio> <el-radio value="Manual">{{ t('dashboard.Manual') }}</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="Category"> <el-form-item :label="t('dashboard.Category')">
<el-select v-model="transactionForm.category"> <el-select v-model="transactionForm.category">
<el-option label="Customer" :value="1" /> <el-option :label="t('dashboard.Customer')" :value="1" />
<el-option label="Other Adjust" :value="2" /> <el-option :label="t('dashboard.Other Adjust')" :value="2" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="Type"> <el-form-item :label="t('dashboard.Type')">
<el-radio-group v-model="transactionForm.type"> <el-radio-group v-model="transactionForm.type">
<el-radio-button :value="1">Deposit</el-radio-button> <el-radio-button :value="1">{{ t('dashboard.Deposit') }}</el-radio-button>
<el-radio-button :value="2">Withdraw</el-radio-button> <el-radio-button :value="2">{{ t('dashboard.Withdraw') }}</el-radio-button>
<el-radio-button :value="3">IN</el-radio-button> <el-radio-button :value="3">IN</el-radio-button>
<el-radio-button :value="4">OUT</el-radio-button> <el-radio-button :value="4">OUT</el-radio-button>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="Username"> <el-form-item :label="t('dashboard.Username')">
<el-input v-model="transactionForm.username" :disabled="transactionDialog.mode === 'edit'" placeholder="e.g. PLAYER001" /> <el-input
v-model="transactionForm.username"
:disabled="transactionDialog.mode === 'edit'"
:placeholder="t('dashboard.Username placeholder')"
/>
</el-form-item> </el-form-item>
<el-form-item label="Remark"> <el-form-item :label="t('dashboard.Remark')">
<el-input v-model="transactionForm.remark" placeholder="(optional)" /> <el-input v-model="transactionForm.remark" :placeholder="t('dashboard.Optional')" />
</el-form-item> </el-form-item>
<el-form-item label="Amount (AUD)"> <el-form-item :label="t('dashboard.Amount (AUD)')">
<el-input-number v-model="transactionForm.amount" :min="0" :precision="2" /> <el-input-number v-model="transactionForm.amount" :min="0" :precision="2" />
</el-form-item> </el-form-item>
<el-form-item label="Bank"> <el-form-item :label="t('dashboard.Bank')">
<el-select v-model="transactionForm.bank" placeholder="- (optional) -"> <el-select v-model="transactionForm.bank" :placeholder="t('dashboard.Optional select')">
<el-option v-for="bank in banks" :key="bank.id" :label="bank.name" :value="bank.id" /> <el-option v-for="bank in banks" :key="bank.id" :label="bank.name" :value="bank.id" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="Label"> <el-form-item :label="t('dashboard.Label')">
<el-select v-model="transactionForm.label" placeholder="- (optional) -"> <el-select v-model="transactionForm.label" :placeholder="t('dashboard.Optional select')">
<el-option label="First Deposit" :value="1" /> <el-option :label="t('dashboard.First Deposit')" :value="1" />
<el-option label="Unclaim" :value="2" /> <el-option :label="t('dashboard.Unclaim')" :value="2" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="Game Ticket Auto"> <el-form-item :label="t('dashboard.Game Ticket Auto')">
<el-checkbox v-model="transactionForm.ticketAuto">Auto generate ticket</el-checkbox> <el-checkbox v-model="transactionForm.ticketAuto">{{ t('dashboard.Auto generate ticket') }}</el-checkbox>
</el-form-item> </el-form-item>
</el-form> </el-form>
<template #footer> <template #footer>
<el-button type="primary" :loading="transactionDialog.loading" @click="submitTransaction">CONFIRM</el-button> <el-button type="primary" :loading="transactionDialog.loading" @click="submitTransaction">{{ t('Confirm') }}</el-button>
<el-button @click="transactionDialog.visible = false">CANCEL</el-button> <el-button @click="transactionDialog.visible = false">{{ t('Cancel') }}</el-button>
</template> </template>
</el-dialog> </el-dialog>
<el-dialog v-model="historyDialog.visible" title="Transaction Edit History" width="720px"> <el-dialog v-model="historyDialog.visible" :title="t('dashboard.Transaction Edit History')" width="720px">
<p class="dialog-note">Transaction edit history is only kept for the most recent 12 months.</p> <p class="dialog-note">{{ t('dashboard.History retention note') }}</p>
<p class="dialog-note">Transaction 的编辑历史记录仅保存最近 12 个月</p> <el-table v-loading="historyDialog.loading" :data="historyDialog.rows" border size="small" :empty-text="t('dashboard.No Record')">
<el-table v-loading="historyDialog.loading" :data="historyDialog.rows" border size="small" empty-text="No Record"> <el-table-column prop="id" :label="t('dashboard.Tx ID')" width="100" />
<el-table-column prop="id" label="Tx ID" width="100" /> <el-table-column prop="editedBy" :label="t('dashboard.Edit By')" width="120" />
<el-table-column prop="editedBy" label="Edit By" width="120" /> <el-table-column prop="editedTime" :label="t('dashboard.Edit Time')" width="170" />
<el-table-column prop="editedTime" label="Edit Time" width="170" /> <el-table-column :label="t('dashboard.Changes')">
<el-table-column prop="changes" label="Changes (Old → New)" /> <template #default="{ row }">{{ historyChangeText(row) }}</template>
</el-table-column>
</el-table> </el-table>
<template #footer> <template #footer>
<el-button @click="historyDialog.visible = false">CANCEL</el-button> <el-button @click="historyDialog.visible = false">{{ t('Cancel') }}</el-button>
</template> </template>
</el-dialog> </el-dialog>
<el-dialog v-model="transferDialog.visible" title="Bank Transfer" width="560px"> <el-dialog v-model="transferDialog.visible" :title="t('dashboard.Bank Transfer')" width="560px">
<el-form :model="transferForm" label-width="125px"> <el-form :model="transferForm" label-width="125px">
<el-form-item label="Transfer (From)"> <el-form-item :label="t('dashboard.Transfer (From)')">
<el-input v-model="transferForm.fromName" disabled /> <el-input v-model="transferForm.fromName" disabled />
</el-form-item> </el-form-item>
<el-form-item label="Transfer (To)"> <el-form-item :label="t('dashboard.Transfer (To)')">
<el-select v-model="transferForm.bankTo" placeholder="- Select Bank -"> <el-select v-model="transferForm.bankTo" :placeholder="t('dashboard.Select Bank')">
<el-option <el-option
v-for="bank in banks" v-for="bank in banks"
:key="bank.id" :key="bank.id"
@@ -215,16 +224,16 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="Amount"> <el-form-item :label="t('dashboard.Amount')">
<el-input-number v-model="transferForm.money" :min="0" :precision="2" /> <el-input-number v-model="transferForm.money" :min="0" :precision="2" />
</el-form-item> </el-form-item>
<el-form-item label="Remark"> <el-form-item :label="t('dashboard.Remark')">
<el-input v-model="transferForm.remark" placeholder="(optional)" /> <el-input v-model="transferForm.remark" :placeholder="t('dashboard.Optional')" />
</el-form-item> </el-form-item>
</el-form> </el-form>
<template #footer> <template #footer>
<el-button type="primary" :loading="transferDialog.loading" @click="submitBankTransfer">CONFIRM</el-button> <el-button type="primary" :loading="transferDialog.loading" @click="submitBankTransfer">{{ t('Confirm') }}</el-button>
<el-button @click="transferDialog.visible = false">CANCEL</el-button> <el-button @click="transferDialog.visible = false">{{ t('Cancel') }}</el-button>
</template> </template>
</el-dialog> </el-dialog>
</div> </div>
@@ -233,6 +242,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { Coin, Switch } from '@element-plus/icons-vue' import { Coin, Switch } from '@element-plus/icons-vue'
import { computed, onMounted, reactive, ref } from 'vue' import { computed, onMounted, reactive, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import { bankTransact, delTransact, editTransact, index as getDashboard, logHistory, newTransact } from '/@/api/backend/dashboard' import { bankTransact, delTransact, editTransact, index as getDashboard, logHistory, newTransact } from '/@/api/backend/dashboard'
import type { DashboardTransactPayload } from '/@/api/backend/dashboard' import type { DashboardTransactPayload } from '/@/api/backend/dashboard'
@@ -240,6 +250,8 @@ defineOptions({
name: 'dashboard', name: 'dashboard',
}) })
const { t } = useI18n()
interface Bank { interface Bank {
id: number | string id: number | string
name: string name: string
@@ -249,7 +261,7 @@ interface Bank {
withdraw: number withdraw: number
depositCount: number depositCount: number
withdrawCount: number withdrawCount: number
alert?: string alertCode: string
rowClass?: string rowClass?: string
labelColor?: string labelColor?: string
} }
@@ -279,14 +291,15 @@ interface Transaction {
id: number id: number
createdBy: string createdBy: string
createdTime: string createdTime: string
category: string categoryId: string
username: string username: string
remark: string remark: string
bank: string bank: string
type: string bankId: number | string
typeId: string
flow: 'in' | 'out' flow: 'in' | 'out'
amount: number amount: number
label: string labelId: string
ticket: string[] ticket: string[]
} }
@@ -340,7 +353,8 @@ interface HistoryRow {
id: number | string id: number | string
editedBy: string editedBy: string
editedTime: string editedTime: string
changes: string bankBefore: string
bankAfter: string
} }
const today = () => { const today = () => {
@@ -355,15 +369,6 @@ const money = (value: number) =>
maximumFractionDigits: 2, maximumFractionDigits: 2,
}) })
const safeAlertLabels: Record<string, string> = {
'1': 'Hourly Alert',
'2': 'Daily Alert',
'3': 'Weekly Alert',
'4': 'Monthly Alert',
'5': 'Yearly Alert',
'6': 'Lifetime Alert',
}
const toNumber = (value: unknown) => { const toNumber = (value: unknown) => {
const number = Number(value) const number = Number(value)
return Number.isFinite(number) ? number : 0 return Number.isFinite(number) ? number : 0
@@ -396,7 +401,7 @@ const mapBank = (bank: DashboardBank): Bank => {
withdraw: fundOut, withdraw: fundOut,
depositCount: toNumber(bank.count_fund_in ?? bank.deposit_count ?? bank.tx_in), depositCount: toNumber(bank.count_fund_in ?? bank.deposit_count ?? bank.tx_in),
withdrawCount: toNumber(bank.count_fund_out ?? bank.withdraw_count ?? bank.tx_out), withdrawCount: toNumber(bank.count_fund_out ?? bank.withdraw_count ?? bank.tx_out),
alert: safeAlertLabels[safeAlert], alertCode: safeAlert,
rowClass: String(bank.status ?? '1') === '0' ? 'bank-muted' : '', rowClass: String(bank.status ?? '1') === '0' ? 'bank-muted' : '',
labelColor: bank.label_color || '', labelColor: bank.label_color || '',
} }
@@ -433,26 +438,33 @@ const dateRangeText = computed(() => {
const start = new Date(`${filters.startDate}T00:00:00`) const start = new Date(`${filters.startDate}T00:00:00`)
const end = new Date(`${filters.endDate}T00:00:00`) const end = new Date(`${filters.endDate}T00:00:00`)
const diffDays = Math.max(1, Math.floor((end.getTime() - start.getTime()) / 86400000) + 1) const diffDays = Math.max(1, Math.floor((end.getTime() - start.getTime()) / 86400000) + 1)
return `${filters.startDate} to ${filters.endDate} (${diffDays} ${diffDays === 1 ? 'Day' : 'Days'})` return t('dashboard.Date range', {
start: filters.startDate,
end: filters.endDate,
days: diffDays,
unit: t(diffDays === 1 ? 'dashboard.Day' : 'dashboard.Days'),
})
}) })
const summary = computed(() => [ const summary = computed(() => [
{ label: 'Total Deposit / IN', value: `AUD ${money(totalDeposit.value)}` }, { label: t('dashboard.Total Deposit / IN'), value: `AUD ${money(totalDeposit.value)}` },
{ label: 'Total Withdraw / OUT', value: `AUD ${money(totalWithdraw.value)}` }, { label: t('dashboard.Total Withdraw / OUT'), value: `AUD ${money(totalWithdraw.value)}` },
{ label: 'Deposit Count', value: customerSummary.countDeposit }, { label: t('dashboard.Deposit Count'), value: customerSummary.countDeposit },
{ label: 'Withdraw Count', value: customerSummary.countWithdraw }, { label: t('dashboard.Withdraw Count'), value: customerSummary.countWithdraw },
{ label: 'Active Player', value: customerSummary.activePlayer }, { label: t('dashboard.Active Player'), value: customerSummary.activePlayer },
{ label: 'First Deposit Player', value: customerSummary.firstDeposit }, { label: t('dashboard.First Deposit Player'), value: customerSummary.firstDeposit },
{ label: 'Unclaimed Amount', value: `AUD ${money(customerSummary.unclaimAmount)}` }, { label: t('dashboard.Unclaimed Amount'), value: `AUD ${money(customerSummary.unclaimAmount)}` },
{ label: 'Unclaimed Receipt', value: customerSummary.unclaimReceipt }, { label: t('dashboard.Unclaimed Receipt'), value: customerSummary.unclaimReceipt },
]) ])
const transactionDialog = reactive<{ visible: boolean; title: string; loading: boolean; mode: 'create' | 'edit'; editId: number | string | '' }>({ const transactionDialog = reactive<{ visible: boolean; loading: boolean; mode: 'create' | 'edit'; editId: number | string | '' }>({
visible: false, visible: false,
title: 'Create New Transaction',
loading: false, loading: false,
mode: 'create', mode: 'create',
editId: '', editId: '',
}) })
const transactionDialogTitle = computed(() =>
transactionDialog.mode === 'edit' ? t('dashboard.Edit Transaction', { id: transactionDialog.editId }) : t('dashboard.Create New Transaction')
)
const transactionForm = reactive({ const transactionForm = reactive({
time: '', time: '',
timeMode: 'Auto', timeMode: 'Auto',
@@ -479,38 +491,42 @@ const transferForm = reactive<{ bankFrom: Bank['id'] | ''; fromName: string; ban
remark: '', remark: '',
}) })
const typeLabels: Record<string, string> = { const safeAlertText = (code: string) => {
'1': 'Deposit', const labels: Record<string, string> = {
'2': 'Withdraw', '1': t('dashboard.Hourly Alert'),
'2': t('dashboard.Daily Alert'),
'3': t('dashboard.Weekly Alert'),
'4': t('dashboard.Monthly Alert'),
'5': t('dashboard.Yearly Alert'),
'6': t('dashboard.Lifetime Alert'),
}
return labels[code] || t('dashboard.No Alert')
}
const typeText = (type: string) => {
const labels: Record<string, string> = {
'1': t('dashboard.Deposit'),
'2': t('dashboard.Withdraw'),
'3': 'IN', '3': 'IN',
'4': 'OUT', '4': 'OUT',
} }
return labels[type] || type
const categoryLabels: Record<string, string> = {
'1': 'Customer',
'2': 'Other Adjust',
} }
const transactionLabelTexts: Record<string, string> = { const categoryText = (category: string) => {
'1': 'First Deposit', const labels: Record<string, string> = {
'2': 'Unclaim', '1': t('dashboard.Customer'),
'2': t('dashboard.Other Adjust'),
}
return labels[category] || category
} }
const categoryValues: Record<string, number> = { const transactionLabelText = (label: string) => {
Customer: 1, const labels: Record<string, string> = {
'Other Adjust': 2, '1': t('dashboard.First Deposit'),
'2': t('dashboard.Unclaim'),
} }
return labels[label] || ''
const typeValues: Record<string, number> = {
Deposit: 1,
Withdraw: 2,
IN: 3,
OUT: 4,
}
const labelValues: Record<string, number> = {
'First Deposit': 1,
Unclaim: 2,
} }
const mapTransaction = (transaction: DashboardTransaction): Transaction => { const mapTransaction = (transaction: DashboardTransaction): Transaction => {
@@ -519,14 +535,15 @@ const mapTransaction = (transaction: DashboardTransaction): Transaction => {
id: transaction.id, id: transaction.id,
createdBy: transaction.created_by || '', createdBy: transaction.created_by || '',
createdTime: formatDateTime(transaction.create_time), createdTime: formatDateTime(transaction.create_time),
category: categoryLabels[String(transaction.category ?? '')] || '', categoryId: String(transaction.category ?? ''),
username: transaction.user_name || '', username: transaction.user_name || '',
remark: transaction.memo || '', remark: transaction.memo || '',
bank: transaction.bank_name || '', bank: transaction.bank_name || '',
type: typeLabels[type] || type, bankId: transaction.bank_id || '',
typeId: type,
flow: ['1', '3'].includes(type) ? 'in' : 'out', flow: ['1', '3'].includes(type) ? 'in' : 'out',
amount: toNumber(transaction.money), amount: toNumber(transaction.money),
label: transactionLabelTexts[String(transaction.label ?? '')] || '', labelId: String(transaction.label ?? ''),
ticket: Array.isArray(transaction.scoreLog) ticket: Array.isArray(transaction.scoreLog)
? transaction.scoreLog.map((score) => `${score.game_type_text || ''} : ${score.score ?? ''}`).filter((score) => score.trim() !== ':') ? transaction.scoreLog.map((score) => `${score.game_type_text || ''} : ${score.score ?? ''}`).filter((score) => score.trim() !== ':')
: [], : [],
@@ -579,7 +596,6 @@ const resetTransactionForm = () => {
const openCreate = () => { const openCreate = () => {
resetTransactionForm() resetTransactionForm()
transactionDialog.title = 'Create New Transaction'
transactionDialog.mode = 'create' transactionDialog.mode = 'create'
transactionDialog.editId = '' transactionDialog.editId = ''
transactionDialog.visible = true transactionDialog.visible = true
@@ -589,16 +605,15 @@ const openEdit = (row: Transaction) => {
Object.assign(transactionForm, { Object.assign(transactionForm, {
time: row.createdTime, time: row.createdTime,
timeMode: 'Manual', timeMode: 'Manual',
category: categoryValues[row.category] || 1, category: toNumber(row.categoryId) || 1,
type: typeValues[row.type] || 1, type: toNumber(row.typeId) || 1,
username: row.username, username: row.username,
remark: row.remark, remark: row.remark,
amount: row.amount, amount: row.amount,
bank: banks.value.find((bank) => bank.name === row.bank)?.id || '', bank: row.bankId || banks.value.find((bank) => bank.name === row.bank)?.id || '',
label: labelValues[row.label] || '', label: row.labelId ? toNumber(row.labelId) : '',
ticketAuto: row.ticket.length > 0, ticketAuto: row.ticket.length > 0,
}) })
transactionDialog.title = `Edit Transaction #${row.id}`
transactionDialog.mode = 'edit' transactionDialog.mode = 'edit'
transactionDialog.editId = row.id transactionDialog.editId = row.id
transactionDialog.visible = true transactionDialog.visible = true
@@ -644,21 +659,16 @@ const submitTransaction = () => {
}) })
} }
const stringifyChange = (history: Record<string, unknown>) => {
if (history.bank_befter !== undefined || history.bank_after !== undefined) {
return `Bank:${history.bank_befter ?? ''}${history.bank_after ?? ''}`
}
return JSON.stringify(history)
}
const mapHistory = (history: Record<string, unknown>): HistoryRow => ({ const mapHistory = (history: Record<string, unknown>): HistoryRow => ({
id: (history.id || history.money_log_id || '') as number | string, id: (history.id || history.money_log_id || '') as number | string,
editedBy: String(history.admin_name || ''), editedBy: String(history.admin_name || ''),
editedTime: formatDateTime(history.create_time), editedTime: formatDateTime(history.create_time),
changes: stringifyChange(history), bankBefore: String(history.bank_befter ?? ''),
bankAfter: String(history.bank_after ?? ''),
}) })
const historyChangeText = (row: HistoryRow) => t('dashboard.Bank change', { before: row.bankBefore, after: row.bankAfter })
const openHistory = (row: Transaction) => { const openHistory = (row: Transaction) => {
historyDialog.visible = true historyDialog.visible = true
historyDialog.loading = true historyDialog.loading = true