登录页优化
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<div class="hostList">
|
||||
<div>
|
||||
<div style="display: flex;">
|
||||
@@ -52,10 +52,18 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="直播场次" width="120">
|
||||
<el-table-column :label="$t('hostList.liveSessions')" width="120">
|
||||
<template #default="scope">
|
||||
<el-button class="live-btn" size="small" @click="getliveHost(scope.row.hostId)">
|
||||
查看场次
|
||||
{{ $t('hostList.viewSessions') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column :label="$t('hostList.liveRevenue')" width="120">
|
||||
<template #default="scope">
|
||||
<el-button class="live-btn" size="small" @click="getRevenueStats(scope.row.hostId)">
|
||||
{{ $t('hostList.viewRevenue') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -119,14 +127,16 @@
|
||||
<div><label>{{ $t('hostList.sortType') }}</label></div>
|
||||
|
||||
|
||||
<el-select v-model="sortData.sortType" filterable placeholder="请选择" style="width: 240px">
|
||||
<el-select v-model="sortData.sortType" filterable :placeholder="$t('hostList.selectPlaceholder')"
|
||||
style="width: 240px">
|
||||
<el-option v-for="item in sortNameOptions" :key="item.type" :label="item.label" :value="item.type" />
|
||||
</el-select>
|
||||
</el-col>
|
||||
<el-col :span="10">
|
||||
<div><label>{{ $t('hostList.ascending') }}/{{ $t('hostList.descending') }}</label></div>
|
||||
|
||||
<el-select v-model="sortData.sortForm" filterable placeholder="请选择" style="width: 240px">
|
||||
<el-select v-model="sortData.sortForm" filterable :placeholder="$t('hostList.selectPlaceholder')"
|
||||
style="width: 240px">
|
||||
<el-option
|
||||
v-for="item in [{ label: $t('hostList.ascending'), value: 'asc' }, { label: $t('hostList.descending'), value: 'desc' }]"
|
||||
:key="item.value" :label="item.label" :value="item.value" />
|
||||
@@ -150,6 +160,55 @@
|
||||
<LiveRecordDialog v-model:modelValue="liveDetailDialogVisible" :rows="liveDetailRecords"
|
||||
@select="handleLiveSelect" />
|
||||
|
||||
<el-dialog v-model="revenueDialogVisible" :title="$t('hostList.liveRevenue')" width="80vw" top="6vh"
|
||||
:close-on-click-modal="false" destroy-on-close>
|
||||
<el-table :data="revenueRecords" border height="62vh" style="width: 100%" v-loading="revenueLoading"
|
||||
table-layout="auto">
|
||||
<el-table-column prop="displayId" :label="$t('hostList.revenueHost')" />
|
||||
<el-table-column prop="todayRevenue" :label="$t('hostList.todayRevenueUsd')" />
|
||||
<el-table-column prop="totalRevenue" :label="$t('hostList.totalRevenueUsd')" />
|
||||
<el-table-column prop="lastDaysCount" :label="$t('hostList.liveDays')" />
|
||||
<el-table-column prop="history" :label="$t('hostList.historyRevenueUsd')">
|
||||
<template #default="{ row }">
|
||||
<el-tooltip v-if="hasHistory(row.history)" effect="dark" placement="top">
|
||||
<template #content>{{ buildHistoryTitle(row.history) }}</template>
|
||||
<div class="history-sparkline-wrap">
|
||||
<div class="history-sparkline-top">
|
||||
<span class="history-sparkline-min-top">
|
||||
{{ $t('hostList.revenueLow') }}: {{ formatRevenueValue(getHistoryMin(row.history)) }}
|
||||
</span>
|
||||
<span class="history-sparkline-max">
|
||||
{{ $t('hostList.revenueHigh') }}: {{ formatRevenueValue(getHistoryMax(row.history)) }}
|
||||
</span>
|
||||
</div>
|
||||
<svg class="history-sparkline" viewBox="0 0 180 48" preserveAspectRatio="none">
|
||||
<line x1="2" y1="46" x2="178" y2="46" stroke="#e6eef7" stroke-width="1" />
|
||||
<polyline :points="buildSparklinePoints(row.history)" fill="none" stroke="#45a1ff" stroke-width="2" />
|
||||
</svg>
|
||||
<div class="history-sparkline-bottom">
|
||||
<div class="history-sparkline-dates">
|
||||
<span class="history-sparkline-date">{{ getHistoryStartDate(row.history) }}</span>
|
||||
<span class="history-sparkline-date">{{ getHistoryEndDate(row.history) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- <el-table-column prop="updatedAt" label="updatedAt" /> -->
|
||||
<el-table-column prop="createdAt" :label="$t('hostList.revenueTime')">
|
||||
<template #default="scope">
|
||||
{{ formatTimestamp(scope.row.createdAt) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="revenueDialogVisible = false">{{ $t('hostList.close') }}</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
@@ -157,7 +216,7 @@
|
||||
|
||||
<script setup>
|
||||
// import { getToken, setToken, removeToken } from '@/utils/storage'
|
||||
import { tkhostdata, dicts, tkhostdetail, downList, getStaffList, managerhosts, upholdinfo, getCountryinfo, accountName, liveHostDetail } from '@/api/account';
|
||||
import { tkhostdata, dicts, tkhostdetail, downList, getStaffList, managerhosts, upholdinfo, getCountryinfo, accountName, liveHostDetail, revenueStats } from '@/api/account';
|
||||
import { usePythonBridge, } from '@/utils/pythonBridge'
|
||||
import { getUser, setSerch, getSerch } from '@/utils/storage'
|
||||
import { ref, reactive, onMounted } from 'vue';
|
||||
@@ -239,6 +298,9 @@ let commentHost = ref('')
|
||||
let liveDetailDialogVisible = ref(false)
|
||||
let liveDetailRecords = ref([])
|
||||
let liveDetailLoading = ref(false)
|
||||
let revenueDialogVisible = ref(false)
|
||||
let revenueRecords = ref([])
|
||||
let revenueLoading = ref(false)
|
||||
//分页
|
||||
let pageSize = ref(10)
|
||||
let page = ref(1)
|
||||
@@ -397,6 +459,146 @@ function handleLiveSelect(row) {
|
||||
liveDetailDialogVisible.value = false
|
||||
}
|
||||
|
||||
function getRevenueStats(hostId) {
|
||||
revenueLoading.value = true
|
||||
revenueStats(hostId).then(res => {
|
||||
const detailList = Array.isArray(res) ? res : (res?.records || [])
|
||||
revenueRecords.value = detailList
|
||||
revenueDialogVisible.value = true
|
||||
}).catch(err => {
|
||||
console.log('revenueStats error', err)
|
||||
}).finally(() => {
|
||||
revenueLoading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
function parseHistoryItems(history) {
|
||||
if (!history) return []
|
||||
let arr = history
|
||||
if (typeof history === 'string') {
|
||||
try {
|
||||
arr = JSON.parse(history)
|
||||
} catch {
|
||||
return []
|
||||
}
|
||||
}
|
||||
if (!Array.isArray(arr)) return []
|
||||
return arr
|
||||
.map((item, index) => {
|
||||
if (typeof item === 'number') {
|
||||
return { date: `Day ${index + 1}`, value: item }
|
||||
}
|
||||
if (item && typeof item === 'object') {
|
||||
return {
|
||||
date: item.date ? String(item.date) : '',
|
||||
value: Number(item.value ?? 0),
|
||||
}
|
||||
}
|
||||
return null
|
||||
})
|
||||
.filter(Boolean)
|
||||
}
|
||||
|
||||
function hasHistory(history) {
|
||||
return parseHistoryItems(history).length > 0
|
||||
}
|
||||
|
||||
function getHistoryStats(history) {
|
||||
const items = parseHistoryItems(history)
|
||||
if (items.length === 0) {
|
||||
return { min: 0, max: 0, start: '', end: '' }
|
||||
}
|
||||
const values = items.map(item => item.value)
|
||||
return {
|
||||
min: Math.min(...values),
|
||||
max: Math.max(...values),
|
||||
start: items[0].date || '',
|
||||
end: items[items.length - 1].date || '',
|
||||
}
|
||||
}
|
||||
|
||||
function getHistoryMin(history) {
|
||||
return getHistoryStats(history).min
|
||||
}
|
||||
|
||||
function getHistoryMax(history) {
|
||||
return getHistoryStats(history).max
|
||||
}
|
||||
|
||||
function getHistoryStartDate(history) {
|
||||
return getHistoryStats(history).start
|
||||
}
|
||||
|
||||
function getHistoryEndDate(history) {
|
||||
return getHistoryStats(history).end
|
||||
}
|
||||
|
||||
function formatRevenueValue(value) {
|
||||
const num = Number(value)
|
||||
if (!Number.isFinite(num)) return ''
|
||||
const fixed = num.toFixed(3)
|
||||
return fixed.replace(/\.0+$/, '').replace(/(\.\d*?)0+$/, '$1')
|
||||
}
|
||||
|
||||
function buildHistoryTitle(history) {
|
||||
const items = parseHistoryItems(history)
|
||||
if (items.length === 0) return '-'
|
||||
return items.map(item => `${item.date}: ${formatRevenueValue(item.value)}`).join('\n')
|
||||
}
|
||||
|
||||
function buildSparklinePoints(history) {
|
||||
const items = parseHistoryItems(history)
|
||||
if (items.length === 0) return ''
|
||||
const values = items.map(item => item.value)
|
||||
const min = Math.min(...values)
|
||||
const max = Math.max(...values)
|
||||
const range = max - min || 1
|
||||
const width = 180
|
||||
const height = 48
|
||||
const padding = 2
|
||||
const step = items.length > 1 ? (width - padding * 2) / (items.length - 1) : 0
|
||||
return items.map((item, index) => {
|
||||
const x = padding + index * step
|
||||
const y = padding + (height - padding * 2) * (1 - (item.value - min) / range)
|
||||
return `${x},${y}`
|
||||
}).join(' ')
|
||||
}
|
||||
function formatTimestamp(value) {
|
||||
if (value === null || value === undefined || value === '') {
|
||||
return ''
|
||||
}
|
||||
if (value instanceof Date) {
|
||||
return formatDate(value)
|
||||
}
|
||||
if (typeof value === 'number') {
|
||||
const ms = value < 1e12 ? value * 1000 : value
|
||||
return formatDate(new Date(ms))
|
||||
}
|
||||
if (typeof value === 'string') {
|
||||
const trimmed = value.trim()
|
||||
if (/^\d+$/.test(trimmed)) {
|
||||
const num = Number(trimmed)
|
||||
const ms = num < 1e12 ? num * 1000 : num
|
||||
return formatDate(new Date(ms))
|
||||
}
|
||||
const parsed = Date.parse(trimmed)
|
||||
if (!Number.isNaN(parsed)) {
|
||||
return formatDate(new Date(parsed))
|
||||
}
|
||||
return trimmed
|
||||
}
|
||||
return String(value)
|
||||
}
|
||||
|
||||
function formatDate(date) {
|
||||
const y = date.getFullYear()
|
||||
const m = String(date.getMonth() + 1).padStart(2, '0')
|
||||
const d = String(date.getDate()).padStart(2, '0')
|
||||
const hh = String(date.getHours()).padStart(2, '0')
|
||||
const mm = String(date.getMinutes()).padStart(2, '0')
|
||||
const ss = String(date.getSeconds()).padStart(2, '0')
|
||||
return `${y}-${m}-${d} ${hh}:${mm}:${ss}`
|
||||
}
|
||||
//修改主播维护状态
|
||||
// function handleSelectChange(event, data) {
|
||||
|
||||
@@ -644,6 +846,51 @@ function openHTML(id) {
|
||||
</style>
|
||||
|
||||
<style scoped lang="less">
|
||||
.history-sparkline {
|
||||
width: 180px;
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
.history-sparkline-wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
width: 180px;
|
||||
}
|
||||
|
||||
.history-sparkline-top {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 12px;
|
||||
color: #1f5fa8;
|
||||
}
|
||||
|
||||
.history-sparkline-bottom {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 12px;
|
||||
color: #7a8aa0;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.history-sparkline-min-top {
|
||||
color: #4a5b73;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.history-sparkline-dates {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.history-sparkline-date {
|
||||
font-size: 12px;
|
||||
color: #7a8aa0;
|
||||
}
|
||||
|
||||
::v-deep(.el-input__wrapper) {
|
||||
background-color: #F2FAF9;
|
||||
border: 1px solid @bg-color;
|
||||
|
||||
@@ -128,13 +128,13 @@
|
||||
<div class="input-group">
|
||||
<label>{{ $t('workbenchesSetup.setNum') }}</label>
|
||||
<label style="color: #00000070; font-size: 15px;">({{ $t('workbenchesSetup.prompt')
|
||||
}})</label>
|
||||
}})</label>
|
||||
<el-button type="primary" @click="isLimit = true" :disabled="!pyData.isStart">{{
|
||||
$t('workbenchesSetup.setHostNum')
|
||||
}}</el-button>
|
||||
}}</el-button>
|
||||
<el-button type="info" @click="isLimit = false" :disabled="!pyData.isStart">{{
|
||||
$t('workbenchesSetup.unlimitedQuantity')
|
||||
}}</el-button>
|
||||
}}</el-button>
|
||||
<!-- <el-input type='number' v-model="pyData.frequency.hour" @input="handleInputHour" -->
|
||||
<div v-if="isLimit" class="center-justify">
|
||||
<el-input type='number' v-model="hostNum" :placeholder="$t('workbenchesSetup.num')"
|
||||
|
||||
Reference in New Issue
Block a user