7 changed files with 565 additions and 75 deletions
@ -0,0 +1,48 @@
|
||||
// 在 Vue 组件的 setup 或普通方法中使用
|
||||
import { ElMessageBox } from 'element-plus'; |
||||
import { nextTick } from 'vue'; |
||||
|
||||
export function showCountdownConfirm(message, title = '提示', confirmText = '确定', cancelText = '取消', timeout = 5) { |
||||
return new Promise((resolve) => { |
||||
let countdown = timeout; |
||||
let timer = null; |
||||
|
||||
// 自定义消息内容(包含确认和取消按钮)
|
||||
ElMessageBox.confirm(message, title, { |
||||
confirmButtonText: countdown + 's后' + confirmText, |
||||
cancelButtonText: cancelText, |
||||
type: 'warning', |
||||
confirmButtonClass: 'countdown-confirm', |
||||
showClose: false, |
||||
dangerouslyUseHTMLString: true, |
||||
// 关闭前的回调,会阻止关闭操作
|
||||
beforeClose: (action, instance, done) => { |
||||
// 当提交操作时执行后面的步骤
|
||||
if (action !== 'confirm') return done(); |
||||
if (!timer) done(); |
||||
}, |
||||
}) |
||||
.then((result) => { |
||||
console.log('then: ', result); |
||||
resolve(true); |
||||
}) |
||||
.catch((err) => { |
||||
clearInterval(timer); |
||||
console.error('err: ', err); |
||||
resolve(false); |
||||
}); |
||||
|
||||
nextTick(() => { |
||||
timer = setInterval(() => { |
||||
countdown--; |
||||
const countdownNum = document.getElementsByClassName('countdown-confirm'); |
||||
if (countdownNum.length > 0) countdownNum[0].textContent = countdown + 's后' + confirmText; |
||||
if (countdown <= 0) { |
||||
clearInterval(timer); |
||||
timer = null; |
||||
if (countdownNum.length > 0) countdownNum[0].textContent = confirmText; |
||||
} |
||||
}, 1000); |
||||
}); |
||||
}); |
||||
} |
@ -0,0 +1,257 @@
|
||||
<template> |
||||
<div class="system-edit-post-container"> |
||||
<el-form size="default" label-width="80px"> |
||||
<el-card shadow="hover" header="战令历史"> |
||||
<template #header> |
||||
战令历史 |
||||
<el-button v-show="item.show === false" @click="item.show = true" class="button-caret" type="text"> |
||||
<el-icon> |
||||
<ele-CaretBottom /> |
||||
</el-icon> |
||||
</el-button> |
||||
<el-button v-show="item.show === true" @click="item.show = false" class="button-caret" type="text"> |
||||
<el-icon> |
||||
<ele-CaretTop /> |
||||
</el-icon> |
||||
</el-button> |
||||
</template> |
||||
<div v-show="item.show"> |
||||
<div class="flex-warp"> |
||||
<el-form :inline="true"> |
||||
<!-- <el-form-item label="服务器">--> |
||||
<!-- <el-select v-model="serverSwitch" class="m-2" placeholder="选择服务器" size="large" style="width: 80px">--> |
||||
<!-- <el-option v-for="item in serverCategorize" :key="item.value" :label="item.label" :value="item.value" />--> |
||||
<!-- </el-select>--> |
||||
<!-- <el-select v-model="query.serverId" placeholder="选择服务器" @change="getProp" filterable>--> |
||||
<!-- <el-option v-for="item in switchServer()" :key="item.id" :label="item.name" :value="item.id" />--> |
||||
<!-- </el-select>--> |
||||
<!-- </el-form-item>--> |
||||
<el-form-item prop="periodId" label="显示期数"> |
||||
<el-select size="default" placeholder="请选择显示期数" filterable v-model="query.periodId"> |
||||
<el-option v-for="item in unique()" :key="item.PeriodId" :label="item.PeriodId + '期'" :value="item.PeriodId" /> |
||||
</el-select> |
||||
</el-form-item> |
||||
|
||||
<el-form-item> |
||||
<el-button type="primary" @click="getProp">确认</el-button> |
||||
</el-form-item> |
||||
</el-form> |
||||
</div> |
||||
<div class="flex-warp"> |
||||
<el-form :inline="true"> |
||||
<el-form-item prop="total" label="总数">{{ tableData.total }}</el-form-item> |
||||
<el-form-item prop="total" label="总比例"> |
||||
<div v-if="tableData.total && tableData.rechargeTotal">{{ (tableData.total / tableData.rechargeTotal) * 100 }}%</div> |
||||
<div v-else>0%</div> |
||||
</el-form-item> |
||||
</el-form> |
||||
</div> |
||||
<div class="flex-warp"> |
||||
<el-table :data="tableData.list" style="width: 100%" :span-method="objectSpanMethod" border> |
||||
<el-table-column prop="platform" label="渠道" width="80"> |
||||
<template #default="scope"> |
||||
<div v-if="scope.row.sort == 0">其他</div> |
||||
<div v-else-if="scope.row.sort == 1">ios</div> |
||||
<div v-else-if="scope.row.sort == 2">官服</div> |
||||
<div v-else-if="scope.row.sort == 3">渠道</div> |
||||
<div v-else>其他</div> |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column prop="area" label="区服编号" width="85"> |
||||
<template #default="scope"> {{ scope.row.area }}区</template> |
||||
</el-table-column> |
||||
<el-table-column prop="name" label="服务器名称" width="200"> |
||||
<template #default="scope"> |
||||
{{ scope.row.name }} |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column prop="State" label="购买数量" width="100"> |
||||
<template #default="scope"> |
||||
{{ scope.row.num }} |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column prop="State" label="购买比例" width="100"> |
||||
<template #default="scope"> |
||||
{{ scope.row.num / tableData.total }} |
||||
</template> |
||||
</el-table-column> |
||||
</el-table> |
||||
</div> |
||||
</div> |
||||
</el-card> |
||||
</el-form> |
||||
</div> |
||||
</template> |
||||
<script lang="ts"> |
||||
import { defineComponent, onMounted, reactive, ref, toRefs } from 'vue'; |
||||
import { gameGMGetBattlePassLog } from '/@/api/game/gameConfig'; |
||||
import BattlePassConfigCategory from '/@/api/config/BattlePassConfigCategory.json'; |
||||
import { ElLoading } from 'element-plus'; |
||||
import { ServerCategorize, serverList } from '/@/utils/game'; |
||||
import { gSwitchServer, uniquePeriodId } from '/@/utils/utils'; |
||||
|
||||
interface TableDataState { |
||||
query: object; |
||||
tableData: { list: object[]; total: number; rechargeTotal: number }; |
||||
battlePassConfig: object; |
||||
servers: object; |
||||
serverCategorize: object[]; |
||||
serverSwitch: number; |
||||
} |
||||
|
||||
interface SpanMethodProps { |
||||
row: object; |
||||
column: object; |
||||
rowIndex: number; |
||||
columnIndex: number; |
||||
} |
||||
|
||||
export default defineComponent({ |
||||
name: 'apiV1ServerBattlePassShopLog', |
||||
setup: function () { |
||||
const tableRef = ref(); |
||||
const state = reactive<TableDataState>({ |
||||
item: { topShow: true, show: true }, |
||||
query: { |
||||
periodId: BattlePassConfigCategory[0].PeriodId, |
||||
}, |
||||
tableData: { list: [], total: 0 }, |
||||
battlePassConfig: BattlePassConfigCategory, |
||||
servers: [], |
||||
serverCategorize: ServerCategorize, |
||||
serverSwitch: 0, |
||||
}); |
||||
|
||||
onMounted(() => { |
||||
serverList().then((res) => { |
||||
state.servers = res; |
||||
}); |
||||
}); |
||||
const getProp = () => { |
||||
const loading = ElLoading.service({ |
||||
lock: true, |
||||
text: 'Loading', |
||||
background: 'rgba(0, 0, 0, 0.7)', |
||||
}); |
||||
state.tableData.list = []; |
||||
gameGMGetBattlePassLog(state.query) |
||||
.then((res) => { |
||||
console.log('gameGMGetBattlePass: ', res); |
||||
if (res.code != 0 || !res.data || !res.data.list) { |
||||
return; |
||||
} |
||||
// state.tableData.list = res.data.list; |
||||
state.tableData.total = res.data.total; |
||||
state.tableData.rechargeTotal = res.data.rechargeTotal; |
||||
let now = new Date().getTime() / 1000; |
||||
console.log('gameGMGetBattlePass: time ', now); |
||||
// let BattlePassConfig = unique(); |
||||
console.log('gameGMGetBattlePass: state.servers ', state.servers); |
||||
for (let i in state.servers) { |
||||
let data = { |
||||
id: state.servers[i].id, |
||||
name: state.servers[i].name, |
||||
area: state.servers[i].area, |
||||
sort: state.servers[i].sort, |
||||
num: 0, |
||||
}; |
||||
let battlePass = res.data.list.find((r) => r.server == state.servers[i].id); |
||||
if (battlePass) { |
||||
data.num = battlePass.uid; |
||||
} |
||||
state.tableData.list.push(data); |
||||
} |
||||
|
||||
state.tableData.list.sort((a, b) => a.sort * 100000 + a.id - (b.sort * 100000 + b.id)); |
||||
state.rows = {}; |
||||
for (let i in state.tableData.list) { |
||||
let server = state.tableData.list[i]; |
||||
if (!state.rows[server.sort]) { |
||||
state.rows[server.sort] = { num: 0, id: server.id }; |
||||
} |
||||
state.rows[server.sort].num++; |
||||
if (state.rows[server.sort].id > server.id) { |
||||
state.rows[server.sort].id = server.id; |
||||
} |
||||
} |
||||
|
||||
console.log('gameGMGetBattlePass: state.tableData.list', state.tableData.list); |
||||
}) |
||||
.finally(() => { |
||||
loading.close(); |
||||
}); |
||||
}; |
||||
|
||||
const unique = () => { |
||||
return uniquePeriodId(BattlePassConfigCategory); |
||||
}; |
||||
const switchServer = () => { |
||||
return gSwitchServer(state.serverSwitch, state.servers); |
||||
}; |
||||
const objectSpanMethod = ({ row, column, rowIndex, columnIndex }: SpanMethodProps) => { |
||||
if (columnIndex === 0) { |
||||
if (state.rows[row.sort].id == row.id) { |
||||
return { |
||||
rowspan: state.rows[row.sort].num, |
||||
colspan: 1, |
||||
}; |
||||
} else { |
||||
return { |
||||
rowspan: 0, |
||||
colspan: 0, |
||||
}; |
||||
} |
||||
} |
||||
}; |
||||
return { |
||||
objectSpanMethod, |
||||
unique, |
||||
switchServer, |
||||
tableRef, |
||||
getProp, |
||||
...toRefs(state), |
||||
}; |
||||
}, |
||||
}); |
||||
</script> |
||||
|
||||
<style scoped lang="scss"> |
||||
.el-table { |
||||
--el-table-border-color: var(--el-border-color-lighter); |
||||
--el-table-border: 2px solid var(--el-table-border-color); |
||||
} |
||||
|
||||
.table-item { |
||||
margin-top: 10px; |
||||
margin-bottom: -10px; |
||||
} |
||||
|
||||
.box-card .el-card__header { |
||||
background-color: #062ce6; |
||||
color: #fff; |
||||
} |
||||
|
||||
::v-deep .el-table--striped .el-table__body tr.el-table__row--striped td { |
||||
background: #f0ffd5; |
||||
} |
||||
|
||||
.warning-row { |
||||
background: #f0ffd5ff; |
||||
} |
||||
|
||||
.white-row { |
||||
background: #ffffff; |
||||
} |
||||
|
||||
::v-deep .warning-row .el-table__body tr { |
||||
background-color: #f0ffd5ff; |
||||
} |
||||
|
||||
::v-deep .warning-row .el-table--enable-row-hover .el-table__body tr:hover > td { |
||||
background-color: inherit; |
||||
} |
||||
|
||||
::v-deep .warning-row .el-table__cell { |
||||
background-color: #f0ffd5ff; |
||||
} |
||||
</style> |
@ -0,0 +1,127 @@
|
||||
<template> |
||||
<div> |
||||
<el-dialog title="战令历史" v-model="isShowDialog" width="769px"> |
||||
<div class="flex-warp"> |
||||
<el-table ref="tableRef" :data="tableData.list" style="width: 100%" border> |
||||
<el-table-column prop="PeriodId" label="当前期数" width="85"> |
||||
<template #default="scope"> {{ scope.row.PeriodId }}期</template> |
||||
</el-table-column> |
||||
<el-table-column prop="State" label="状态" width="100"> |
||||
<template #default="scope"> |
||||
<div v-if="scope.row.State == 1" style="color: green">开启</div> |
||||
<div v-else-if="scope.row.State == 2" style="color: red">关闭</div> |
||||
<div v-else-if="scope.row.State == 3">永久关闭</div> |
||||
<div v-else-if="scope.row.State == 4" style="color: #66b7cf">未开启</div> |
||||
<div v-else>{{ scope.row.State }}</div> |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column prop="BeginTime" label="开始时间" width="100" /> |
||||
<el-table-column prop="EndTime" label="结束时间" width="100" /> |
||||
</el-table> |
||||
</div> |
||||
</el-dialog> |
||||
</div> |
||||
</template> |
||||
|
||||
<script lang="ts"> |
||||
import { reactive, toRefs, defineComponent } from 'vue'; |
||||
import { ElLoading } from 'element-plus'; |
||||
import {gameGMGetBattlePass} from "/@/api/game/gameConfig"; |
||||
import {uniquePeriodId} from "/@/utils/utils"; |
||||
import BattlePassConfigCategory from "/@/api/config/BattlePassConfigCategory.json"; |
||||
|
||||
interface TableDataState { |
||||
isShowDialog: boolean; |
||||
isNew: boolean; |
||||
query: object; |
||||
channels: object[]; |
||||
tableData: { list: object[] }; |
||||
} |
||||
|
||||
export default defineComponent({ |
||||
name: 'serverBattlePassLog', |
||||
setup(prop, { emit }) { |
||||
const state = reactive<TableDataState>({ |
||||
isShowDialog: false, |
||||
isNew: false, |
||||
query: {}, |
||||
channels: [], |
||||
tableData: { list: [] }, |
||||
}); |
||||
// 打开弹窗 |
||||
const openDialog = (server: number ) => { |
||||
if (!server) { |
||||
return; |
||||
} |
||||
state.isShowDialog = true; |
||||
state.query = { serverId: server }; |
||||
getProp(); |
||||
}; |
||||
// 关闭弹窗 |
||||
const closeDialog = () => { |
||||
state.isShowDialog = false; |
||||
}; |
||||
// 取消 |
||||
const onCancel = () => { |
||||
closeDialog(); |
||||
}; |
||||
|
||||
const getProp = () => { |
||||
const loading = ElLoading.service({ |
||||
lock: true, |
||||
text: 'Loading', |
||||
background: 'rgba(0, 0, 0, 0.7)', |
||||
}); |
||||
state.tableData.list = []; |
||||
gameGMGetBattlePass({ serverId: state.query.serverId }) |
||||
.then((res) => { |
||||
console.log('gameGMGetBattlePass: ', res); |
||||
if (res.code != 0 || !res.data || !res.data.list) { |
||||
return; |
||||
} |
||||
state.tableData.list = res.data.list; |
||||
let now = new Date().getTime() / 1000; |
||||
console.log('gameGMGetBattlePass: time ', now); |
||||
let battlePassConfig = unique(); |
||||
console.log('gameGMGetBattlePass: battlePassConfig ', battlePassConfig); |
||||
battlePassConfig.forEach((data) => { |
||||
let item = state.tableData.list.find((r) => r.PeriodId === data.PeriodId); |
||||
if (!item) { |
||||
item = { PeriodId: data.PeriodId }; |
||||
let bt = state.tableData.list.find((r) => r.PeriodId > data.PeriodId && r.BeginTime <= now); |
||||
if (bt) { |
||||
item.State = 3; |
||||
} |
||||
state.tableData.list.push(item); |
||||
return; |
||||
} |
||||
if (item.BeginTime >= now) { |
||||
item.State = 4; |
||||
} |
||||
}); |
||||
state.tableData.list.sort((a, b) => { |
||||
return a.PeriodId - b.PeriodId; |
||||
}); |
||||
state.tableData.list.forEach((item) => { |
||||
if (item.BeginTime) item.BeginTime = new Date(item.BeginTime * 1000).toLocaleDateString(); |
||||
if (item.EndTime) item.EndTime = new Date(item.EndTime * 1000).toLocaleDateString(); |
||||
}); |
||||
console.log('gameGMGetBattlePass: state.tableData.data', state.tableData.list); |
||||
}) |
||||
.finally(() => { |
||||
loading.close(); |
||||
}); |
||||
}; |
||||
|
||||
const unique = () => { |
||||
return uniquePeriodId(BattlePassConfigCategory); |
||||
}; |
||||
return { |
||||
openDialog, |
||||
closeDialog, |
||||
onCancel, |
||||
...toRefs(state), |
||||
}; |
||||
}, |
||||
}); |
||||
</script> |
Loading…
Reference in new issue