版本更新
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CodeQL / Analyze (${{ matrix.language }}) (none, javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
CI / CI OK (push) Has been cancelled
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CodeQL / Analyze (${{ matrix.language }}) (none, javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
CI / CI OK (push) Has been cancelled
This commit is contained in:
parent
abab4f3637
commit
86037f0933
@ -77,6 +77,10 @@ export async function updateAppApi(AppId: number){
|
||||
return requestClient.post('/server/updateApp', {AppId: AppId}, {timeout: 120000});
|
||||
}
|
||||
|
||||
export async function updateAppReviewApi(AppId: number){
|
||||
return requestClient.post('/server/updateAppReview', {AppId: AppId}, {timeout: 120000});
|
||||
}
|
||||
|
||||
export async function releaseApp(appId: number, appName: string){
|
||||
return requestClient.post(`/server/release`, {AppId: appId, AppName: appName}, {timeout: 120000});
|
||||
}
|
||||
@ -89,8 +93,8 @@ export async function reloadServer(appId: number, serverId: number, serverName:
|
||||
return requestClient.post(`/server/reload`, {AppId: appId, ServerId: serverId, ServerName: serverName}, {timeout: 120000});
|
||||
}
|
||||
|
||||
export async function addServer(AppId:number, ServerId:number, ServerName: string, Status: number, OpenServerTime: number){
|
||||
return requestClient.post(`/server/addServer`, {AppId:AppId, ServerId: ServerId, ServerName: ServerName, Status: Status, OpenServerTime: OpenServerTime});
|
||||
export async function addServer(AppId:number, ServerId:number, ServerName: string, Status: number, OpenServerTime: number, Host?: string, Port?: number, WsPort?: number, Version?: string, Ecs?: number, WorkDir?: string){
|
||||
return requestClient.post(`/server/addServer`, {AppId:AppId, ServerId: ServerId, ServerName: ServerName, Status: Status, OpenServerTime: OpenServerTime, Host: Host, Port: Port, WsPort: WsPort, ClientVersion: Version, Ecs: Ecs, WorkDir: WorkDir});
|
||||
}
|
||||
|
||||
export async function editServer(editParam: editServerParam){
|
||||
|
||||
@ -57,6 +57,81 @@ const [Form, FormApi] = useVbenForm({
|
||||
label: 'ServerName:',
|
||||
formItemClass:'col-span-2',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
defaultValue: '',
|
||||
componentProps: {
|
||||
placeholder: 'google.bywaystudios.com',
|
||||
},
|
||||
rules: "required",
|
||||
fieldName: 'Host',
|
||||
label: 'Host',
|
||||
formItemClass:'col-span-2',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
defaultValue: '',
|
||||
componentProps: {
|
||||
placeholder: '3601',
|
||||
},
|
||||
rules: "required",
|
||||
fieldName: 'Port',
|
||||
label: 'Port',
|
||||
formItemClass:'col-span-2',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
defaultValue: '',
|
||||
componentProps: {
|
||||
placeholder: '3701',
|
||||
},
|
||||
rules: "required",
|
||||
fieldName: 'WsPort',
|
||||
label: 'WsPort',
|
||||
formItemClass:'col-span-2',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
defaultValue: '',
|
||||
componentProps: {
|
||||
placeholder: '1.0.50',
|
||||
},
|
||||
rules: "required",
|
||||
fieldName: 'ClientVersion',
|
||||
label: 'ClientVersion',
|
||||
formItemClass:'col-span-2',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
defaultValue: '',
|
||||
componentProps: {
|
||||
placeholder: '/usr/local/game',
|
||||
},
|
||||
rules: "required",
|
||||
fieldName: 'WorkDir',
|
||||
label: 'WorkDir',
|
||||
formItemClass:'col-span-2',
|
||||
},
|
||||
{
|
||||
component: 'Select',
|
||||
defaultValue: '',
|
||||
componentProps: {
|
||||
options: [
|
||||
{
|
||||
label: 'ECS-tencent',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
label: 'ECS-aliyun-us-silicon',
|
||||
value: 2,
|
||||
},
|
||||
],
|
||||
},
|
||||
rules: "required",
|
||||
fieldName: 'Ecs',
|
||||
label: 'Ecs',
|
||||
formItemClass:'col-span-2',
|
||||
},
|
||||
{
|
||||
component: 'DatePicker',
|
||||
fieldName: 'datePicker',
|
||||
@ -134,7 +209,7 @@ const [Modal, modalApi] = useVbenModal({
|
||||
const dateTime = dayjs(`${date} ${time}`).valueOf()/1000;
|
||||
const modalData = modalApi.getData();
|
||||
const ServerId = parseInt(values.ServerId, 10);
|
||||
await addServer(modalData.AppId, ServerId, values.ServerName, values.Status, dateTime);
|
||||
await addServer(modalData.AppId, ServerId, values.ServerName, values.Status, dateTime, values.Host, parseInt(values.Port,10), parseInt(values.WsPort,10), values.ClientVersion, values.Ecs, values.WorkDir);
|
||||
modalApi.close();
|
||||
},
|
||||
});
|
||||
|
||||
@ -30,6 +30,10 @@ function getColor(status: number) {
|
||||
return 'red';
|
||||
case 1:
|
||||
return 'green';
|
||||
case 2:
|
||||
return 'gray';
|
||||
case 3:
|
||||
return 'orange';
|
||||
default:
|
||||
return 'blue';
|
||||
}
|
||||
@ -114,6 +118,21 @@ function confirmUpdate(Server: ServerData) {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function getStatusName(status: number) {
|
||||
switch (status){
|
||||
case 0:
|
||||
return 'Inactive';
|
||||
case 1:
|
||||
return 'Running';
|
||||
case 2:
|
||||
return 'Stopped';
|
||||
case 3:
|
||||
return 'Maintenance';
|
||||
default:
|
||||
return 'Unknown';
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@ -138,7 +157,7 @@ function confirmUpdate(Server: ServerData) {
|
||||
<div class="flex flex-col justify-center md:mt-0 lg:w-1/12">
|
||||
<h1 class="text-md font-semibold md:text-ml text-center">
|
||||
<Tag :color="getColor(item.Status || 0)">
|
||||
{{ item.Status == 0 ? 'Inactive' : item.Status == 1 ? 'Running' : 'Unknown' }}
|
||||
{{ getStatusName(item.Status || 0) }}
|
||||
</Tag>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
<script lang="ts" setup>
|
||||
import { Page } from '@vben/common-ui';
|
||||
import { Button, Card, Space, notification } from 'ant-design-vue';
|
||||
import { Button, Card, Space, notification, Modal } from 'ant-design-vue';
|
||||
import { useVbenForm } from '#/adapter/form';
|
||||
import AppList from './appList.vue';
|
||||
import { getServerListApi, getAppListApi, updateAppApi } from '#/api/core/server';
|
||||
import { getServerListApi, getAppListApi, updateAppApi,updateAppReviewApi } from '#/api/core/server';
|
||||
import type { AppData, ServerData } from '#/api/core/server';
|
||||
import { useVbenModal } from '@vben/common-ui'
|
||||
import { ref,onMounted } from 'vue';
|
||||
@ -69,7 +69,7 @@ const [addServerM, addServerApi] = useVbenModal({
|
||||
connectedComponent: addServerModal,
|
||||
onClosed: async () => {
|
||||
const Value = await BaseFormApi.getValues();
|
||||
const serverResponse = await getServerListApi(Value.fieldOptions);
|
||||
const serverResponse = await getServerListApi({AppId:Value.fieldOptions});
|
||||
ServerList.value = Array.isArray(serverResponse) ? serverResponse : [];
|
||||
addServerApi.close();
|
||||
},
|
||||
@ -99,6 +99,7 @@ const serverList = [
|
||||
const appList = ref<AppData[]>([]);
|
||||
const ServerList = ref<ServerData[]>([]);
|
||||
const reload = ref(false);
|
||||
const reloadReview = ref(false);
|
||||
onMounted(async() => {
|
||||
try{
|
||||
const response = await getAppListApi();
|
||||
@ -137,7 +138,31 @@ async function addServer() {
|
||||
|
||||
|
||||
|
||||
function confirmUpdate() {
|
||||
Modal.confirm({
|
||||
title: '确认更新',
|
||||
content: `你确定要更新吗?`,
|
||||
onOk() {
|
||||
update();
|
||||
},
|
||||
onCancel() {
|
||||
//console.log('取消更新');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function confirmUpdateReview() {
|
||||
Modal.confirm({
|
||||
title: '确认更新',
|
||||
content: `你确定要更新吗?`,
|
||||
onOk() {
|
||||
updateReview();
|
||||
},
|
||||
onCancel() {
|
||||
//console.log('取消更新');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function update() {
|
||||
reload.value = true;
|
||||
@ -163,6 +188,31 @@ async function update() {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async function updateReview() {
|
||||
reloadReview.value = true;
|
||||
const Value = await BaseFormApi.getValues();
|
||||
try{
|
||||
await updateAppReviewApi(Value.fieldOptions);
|
||||
reloadReview.value = false;
|
||||
notification.info({
|
||||
duration:10,
|
||||
message:"服务器更新成功"
|
||||
})
|
||||
const response = await getAppListApi();
|
||||
appList.value = Array.isArray(response) ? response : [];
|
||||
const app = appList.value.find((item) => item.AppId === Value.fieldOptions);
|
||||
if (!app) return;
|
||||
const updateTime = dayjs((app.Update ?? 0) * 1000).format('YYYY-MM-DD HH:mm:ss')
|
||||
BaseFormApi.setFieldValue("update", updateTime)
|
||||
}catch(e){
|
||||
reloadReview.value = false;
|
||||
notification.error({
|
||||
duration:10,
|
||||
message:"服务器更新失败"
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<Page>
|
||||
@ -172,7 +222,8 @@ async function update() {
|
||||
<BaseForm />
|
||||
<Space>
|
||||
<Button type="primary" @click="addServer">新增</Button>
|
||||
<Button type="primary" @click="update" :loading="reload"> 更新 </Button>
|
||||
<Button type="primary" @click="confirmUpdate" :loading="reload"> 更新正式环境 </Button>
|
||||
<Button type="primary" @click="confirmUpdateReview" :loading="reloadReview"> 更新review环境 </Button>
|
||||
<Button type="primary"> 更新配置 </Button>
|
||||
</Space>
|
||||
</Card>
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
import type { VxeGridProps, VxeGridListeners } from '#/adapter/vxe-table';
|
||||
import { Button, notification,Image } from 'ant-design-vue';
|
||||
import { Page } from '@vben/common-ui';
|
||||
import { getLanguageList, exportLanguageFile, saveLanguageList, deleteLanguageItem } from '#/api/core/statistics';
|
||||
import { getLanguageList, saveLanguageList, deleteLanguageItem } from '#/api/core/statistics';
|
||||
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import addLanguage from './addLanguage.vue';
|
||||
import type { VbenFormProps } from '#/adapter/form';
|
||||
@ -97,15 +97,12 @@ const formOptions: VbenFormProps = {
|
||||
},
|
||||
wrapperClass: 'grid-cols-1 md:grid-cols-5',
|
||||
// 是否在字段值改变时提交表单
|
||||
submitOnChange: true,
|
||||
submitOnChange: false,
|
||||
// 按下回车时是否提交表单
|
||||
submitOnEnter: false,
|
||||
}
|
||||
const gridOptions: VxeGridProps<languageType> = {
|
||||
border: true,
|
||||
cellConfig:{
|
||||
height:60,
|
||||
},
|
||||
columns: [
|
||||
{ title: 'Id', field: 'Id', width: 100 },
|
||||
{ editRender: { name: 'input' }, field: 'key', title: 'key', filters: [{ data: "" }], filterRender: { name: "input" }, visible: keyVisible },
|
||||
@ -317,7 +314,7 @@ const gridOptions: VxeGridProps<languageType> = {
|
||||
pageSizes: [40, 80, 100, 200, 500, 1000],
|
||||
},
|
||||
height: 'auto',
|
||||
showOverflow: true,
|
||||
showOverflow: false,
|
||||
};
|
||||
const gridEvents: VxeGridListeners<languageType> = {
|
||||
editClosed: ({ row, column }) => {
|
||||
@ -374,23 +371,6 @@ function saveAll() {
|
||||
}
|
||||
|
||||
|
||||
function exportLang() {
|
||||
exportLanguageFile().then((response) => {
|
||||
const code = response.code || 0;
|
||||
const msg = response.msg || '';
|
||||
if (code !== 0) {
|
||||
notification.error({
|
||||
duration: 10,
|
||||
message: msg,
|
||||
});
|
||||
return;
|
||||
}
|
||||
notification.success({
|
||||
duration: 10,
|
||||
message: $t('page.language.exportSuccess'),
|
||||
});
|
||||
});
|
||||
}
|
||||
function deleteRow(row: languageType) {
|
||||
deleteLanguageItem({ key: row.key }).then((response) => {
|
||||
const code = response.code || 0;
|
||||
|
||||
@ -115,7 +115,7 @@ const gridOptions: VxeGridProps<MailData> = {
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
showOverflow: false,
|
||||
rowConfig: {
|
||||
isHover: true,
|
||||
},
|
||||
|
||||
@ -35,16 +35,12 @@ function startScript(id:number) {
|
||||
<span>Script Name</span>
|
||||
</h1>
|
||||
</div>
|
||||
<div class="flex flex-col justify-center md:mt-0 lg:w-1/12">
|
||||
<div class="flex flex-col justify-center md:mt-0 lg:w-3/12">
|
||||
<h1 class="text-md font-semibold md:text-ml text-center">
|
||||
<span>TAGS</span>
|
||||
</h1>
|
||||
</div>
|
||||
<div class="flex flex-col justify-center md:mt-0 lg:w-1/12">
|
||||
<h1 class="text-md font-semibold md:text-ml text-center">
|
||||
<span>Last Running</span>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col justify-center md:mt-0 lg:w-1/12">
|
||||
<h1 class="text-md font-semibold md:text-ml text-center">
|
||||
<span>Start</span>
|
||||
@ -60,16 +56,12 @@ function startScript(id:number) {
|
||||
<span>文案自动化脚本</span>
|
||||
</h1>
|
||||
</div>
|
||||
<div class="flex flex-col justify-center md:mt-0 lg:w-1/12">
|
||||
<div class="flex flex-col justify-center md:mt-0 lg:w-3/12">
|
||||
<h1 class="text-md font-semibold md:text-ml text-center">
|
||||
<Tag>xlsx</Tag>
|
||||
</h1>
|
||||
</div>
|
||||
<div class="flex flex-col justify-center md:mt-0 lg:w-1/12">
|
||||
<h1 class="text-md font-semibold md:text-ml text-center">
|
||||
<span>2026-01-01 12:00:00</span>
|
||||
<Tag>xlsx</Tag><Tag>文案</Tag><Tag>策划</Tag>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col justify-center md:mt-0 lg:w-1/12">
|
||||
<h1 class="text-md font-semibold md:text-ml text-center">
|
||||
<Button type="primary" @click="startScript(1)">Start</Button>
|
||||
|
||||
250
apps/web-antd/src/views/userlog/userlist/asset-table.vue
Normal file
250
apps/web-antd/src/views/userlog/userlist/asset-table.vue
Normal file
@ -0,0 +1,250 @@
|
||||
<script setup lang="ts">
|
||||
import { Page, useVbenModal } from '@vben/common-ui';
|
||||
import type { VxeGridListeners } from '#/adapter/vxe-table';
|
||||
import { getUserLogAssetApi } from '#/api/core/log';
|
||||
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import { inject, ref } from 'vue';
|
||||
import { globalState } from '#/store/globalState';
|
||||
import type { VxeGridProps } from '#/adapter/vxe-table';
|
||||
import type { VbenFormProps } from '#/adapter/form';
|
||||
import { ItemData } from '#/store/item';
|
||||
import { eventModal } from '#/component';
|
||||
import dayjs from 'dayjs';
|
||||
const state = inject('globalState', globalState);
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
connectedComponent: eventModal,
|
||||
class: 'width:1800px;',
|
||||
|
||||
});
|
||||
interface RowType {
|
||||
Uid: number;
|
||||
change_type: string;
|
||||
change_num: string;
|
||||
change_after: string;
|
||||
item_id: string;
|
||||
timestamp: string;
|
||||
}
|
||||
|
||||
const formatType = (cellValue: string) => {
|
||||
switch (cellValue) {
|
||||
case "gain":
|
||||
return '增加';
|
||||
case "consume":
|
||||
return '减少';
|
||||
default:
|
||||
return cellValue;
|
||||
}
|
||||
}
|
||||
const formatItemName = (cellValue: number) => {
|
||||
// console.log(cellValue);
|
||||
return ItemData.find((item) => item.Id === cellValue)?.Name || cellValue;
|
||||
}
|
||||
const d = ref({
|
||||
sum: 0,
|
||||
psum: 0,
|
||||
nsum: 0,
|
||||
});
|
||||
const startDate = dayjs().startOf('day');
|
||||
const endDate = dayjs().endOf('day');
|
||||
const itemIdOptions = ref([
|
||||
{ label: '能量', value: 100001 },
|
||||
{ label: '宠物币', value: 100002 },
|
||||
{ label: '钻石', value: 100003 },
|
||||
]);
|
||||
const formOptions: VbenFormProps = {
|
||||
// 所有表单项共用,可单独在表单内覆盖
|
||||
commonConfig: {
|
||||
// 所有表单项
|
||||
componentProps: {
|
||||
class: 'w-full',
|
||||
},
|
||||
},
|
||||
layout: 'horizontal',
|
||||
// 默认展开
|
||||
collapsed: false,
|
||||
schema: [
|
||||
{
|
||||
disabled: true,
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: 'Uid',
|
||||
},
|
||||
defaultValue: state.uid,
|
||||
fieldName: 'Uid',
|
||||
label: 'Uid',
|
||||
},
|
||||
{
|
||||
component: 'DatePicker',
|
||||
defaultValue: startDate,
|
||||
componentProps: {
|
||||
showTime: true,
|
||||
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||
},
|
||||
fieldName: 'StartTime',
|
||||
label: '开始时间',
|
||||
},
|
||||
|
||||
{
|
||||
component: 'DatePicker',
|
||||
defaultValue: endDate,
|
||||
componentProps: {
|
||||
showTime: true,
|
||||
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||
},
|
||||
fieldName: 'EndTime',
|
||||
label: '结束时间',
|
||||
},
|
||||
{
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
options: itemIdOptions,
|
||||
allowClear: true,
|
||||
},
|
||||
fieldName: 'ItemId',
|
||||
label: '道具id',
|
||||
},
|
||||
{
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
options: [
|
||||
{ label: '增加', value: 'gain' },
|
||||
{ label: '减少', value: 'consume' },
|
||||
],
|
||||
allowClear: true,
|
||||
},
|
||||
fieldName: 'Event',
|
||||
label: '变化类型',
|
||||
},
|
||||
],
|
||||
// 控制表单是否显示折叠按钮
|
||||
showCollapseButton: true,
|
||||
submitButtonOptions: {
|
||||
content: '查询',
|
||||
},
|
||||
// 是否在字段值改变时提交表单
|
||||
submitOnChange: false,
|
||||
// 按下回车时是否提交表单
|
||||
submitOnEnter: false,
|
||||
}
|
||||
const gridEvents: VxeGridListeners<RowType> = {
|
||||
cellDblclick: async ({ row }) => {
|
||||
console.log(row);
|
||||
modalApi.setData({
|
||||
StartTime: row.timestamp,
|
||||
EndTime: row.timestamp,
|
||||
});
|
||||
modalApi.open();
|
||||
},
|
||||
};
|
||||
const gridOptions: VxeGridProps<RowType> = {
|
||||
columns: [
|
||||
{ field: 'Uid', title: 'Uid', align: 'center' },
|
||||
{ field: 'change_type', title: '变化类型', formatter: ({ cellValue }) => formatType(cellValue), align: 'center' },
|
||||
{ field: 'change_num', title: '变化数值', align: 'center' },
|
||||
{ field: 'change_after', title: '变化后数值', align: 'center' },
|
||||
{ field: 'item_id', title: '道具名称', formatter: ({ cellValue }) => formatItemName(cellValue), align: 'center' },
|
||||
{ field: 'item_id', title: '道具id', align: 'center' },
|
||||
{ field: 'timestamp', title: '时间', formatter: ({ cellValue }) => new Date(cellValue * 1000).toLocaleString(), align: 'center' },
|
||||
],
|
||||
stripe: true,
|
||||
round: true,
|
||||
height: 'auto',
|
||||
exportConfig: {
|
||||
filename: '用户资产日志',
|
||||
type: 'csv',
|
||||
mode: 'current',
|
||||
download: true,
|
||||
},
|
||||
toolbarConfig: {
|
||||
custom: true,
|
||||
export: true,
|
||||
refresh: true,
|
||||
zoom: true,
|
||||
},
|
||||
pagerConfig: {},
|
||||
proxyConfig: {
|
||||
response: {
|
||||
total: "total",
|
||||
result: "data"
|
||||
},
|
||||
ajax: {
|
||||
query: async ({ page }, formValues) => {
|
||||
let uid = parseInt(formValues.Uid, 10);
|
||||
if (uid == 0) {
|
||||
return []
|
||||
}
|
||||
|
||||
state.uid = uid;
|
||||
const ItemId = parseInt(formValues.ItemId, 10);
|
||||
|
||||
console.log(formValues.StartTime.unix());
|
||||
const r = await getUserLogAssetApi({
|
||||
Id: uid,
|
||||
Event: formValues.Event,
|
||||
StartTime: formValues.StartTime.unix(),
|
||||
EndTime: formValues.EndTime.unix(),
|
||||
ItemId: ItemId,
|
||||
CurrentPage: page.currentPage,
|
||||
PageSize: page.pageSize,
|
||||
});
|
||||
// 动态收集 item_id 与 item_name 生成下拉
|
||||
if (Array.isArray(r.data)) {
|
||||
itemIdOptions.value = [
|
||||
{ label: '能量', value: 100001 },
|
||||
{ label: '宠物币', value: 100002 },
|
||||
{ label: '钻石', value: 100003 },
|
||||
];
|
||||
const exist = new Set(itemIdOptions.value.map(o => String(o.value)));
|
||||
for (const row of r.data as any[]) {
|
||||
const idRaw = (row as any).item_id;
|
||||
const nameRaw = String(formatItemName(idRaw));
|
||||
if (idRaw !== undefined && idRaw !== null) {
|
||||
const idStr = String(idRaw);
|
||||
if (!exist.has(idStr)) {
|
||||
exist.add(idStr);
|
||||
itemIdOptions.value.push({
|
||||
label: nameRaw,
|
||||
value: parseInt(idStr, 10) || idRaw,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
d.value.sum = r.sum;
|
||||
d.value.psum = r.psum;
|
||||
d.value.nsum = r.nsum;
|
||||
return r
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
rowConfig: {
|
||||
isHover: true,
|
||||
},
|
||||
};
|
||||
|
||||
const [Grid] = useVbenVxeGrid({ formOptions, gridOptions, gridEvents });
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<Page auto-content-height class="h-[800px]">
|
||||
<Grid>
|
||||
<template #empty>
|
||||
<div style="display:flex;flex-direction:column;align-items:center;justify-content:center;">
|
||||
<img src="https://n.sinaimg.cn/sinacn17/w120h120/20180314/89fc-fyscsmv5911424.gif" alt="no-data"
|
||||
style="max-width:200px;display:block;">
|
||||
<p style="margin:8px 0 0;">没有更多数据了!</p>
|
||||
</div>
|
||||
</template>
|
||||
<template #toolbar-tools>
|
||||
总数:<span style="margin-right: 10px;margin-left: 5px;"> {{ d.sum }} </span>
|
||||
正数和: <span style="margin-right: 10px;margin-left: 5px;color:green">{{ d.psum }} </span>
|
||||
负数和: <span style="color: red;margin-left: 5px;">{{ d.nsum }} </span>
|
||||
</template>
|
||||
</Grid>
|
||||
</Page>
|
||||
<Modal class="w-[1200px]"> </Modal>
|
||||
</div>
|
||||
</template>
|
||||
173
apps/web-antd/src/views/userlog/userlist/event-table.vue
Normal file
173
apps/web-antd/src/views/userlog/userlist/event-table.vue
Normal file
@ -0,0 +1,173 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import { getUserlogEventApi } from '#/api/core/log';
|
||||
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import { inject } from 'vue';
|
||||
import type { VxeGridListeners } from 'vxe-table';
|
||||
import { globalState } from '#/store/globalState';
|
||||
import { $t } from '#/locales';
|
||||
import type { VxeGridProps } from '#/adapter/vxe-table';
|
||||
import type { VbenFormProps } from '#/adapter/form';
|
||||
import { Page, useVbenModal } from '@vben/common-ui';
|
||||
import { assetModal } from '#/component';
|
||||
import dayjs from 'dayjs';
|
||||
const state = inject('globalState', globalState);
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
connectedComponent: assetModal,
|
||||
class: 'width:1800px;',
|
||||
|
||||
});
|
||||
const startDate = dayjs().startOf('day');
|
||||
const endDate = dayjs().endOf('day');
|
||||
interface RowType {
|
||||
Uid: string;
|
||||
Event: string;
|
||||
Param: string;
|
||||
Timestamp: string;
|
||||
}
|
||||
const formOptions: VbenFormProps = {
|
||||
// 默认展开
|
||||
collapsed: false,
|
||||
schema: [
|
||||
{
|
||||
disabled: true,
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: 'Uid',
|
||||
},
|
||||
defaultValue: state.uid,
|
||||
fieldName: 'Uid',
|
||||
label: 'Uid',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: 'Event',
|
||||
},
|
||||
defaultValue: state.Event,
|
||||
fieldName: 'Event',
|
||||
label: '事件类型',
|
||||
},
|
||||
{
|
||||
component: 'DatePicker',
|
||||
defaultValue: startDate,
|
||||
componentProps: {
|
||||
showTime: true,
|
||||
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||
},
|
||||
fieldName: 'StartTime',
|
||||
label: '开始时间',
|
||||
},
|
||||
{
|
||||
component: 'DatePicker',
|
||||
defaultValue: endDate,
|
||||
componentProps: {
|
||||
showTime: true,
|
||||
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||
},
|
||||
fieldName: 'EndTime',
|
||||
label: '结束时间',
|
||||
}
|
||||
],
|
||||
// 控制表单是否显示折叠按钮
|
||||
showCollapseButton: true,
|
||||
submitButtonOptions: {
|
||||
content: '查询',
|
||||
},
|
||||
// 是否在字段值改变时提交表单
|
||||
submitOnChange: false,
|
||||
// 按下回车时是否提交表单
|
||||
submitOnEnter: false,
|
||||
wrapperClass: 'grid-cols-1 md:grid-cols-5',
|
||||
}
|
||||
const gridEvents: VxeGridListeners<RowType> = {
|
||||
cellDblclick: async ({ row }) => {
|
||||
console.log(row);
|
||||
modalApi.setData({
|
||||
StartTime: row.Timestamp,
|
||||
EndTime: row.Timestamp,
|
||||
});
|
||||
modalApi.open();
|
||||
},
|
||||
};
|
||||
const gridOptions: VxeGridProps<RowType> = {
|
||||
columns: [
|
||||
{ field: 'Uid', title: 'Uid' },
|
||||
{ field: 'Event', title: '事件类型', formatter: ({ cellValue }) => $t('page.log.event.' + `${cellValue}`) || cellValue },
|
||||
{ field: 'Label', title: 'Label' },
|
||||
{ field: 'Param', title: '参数' },
|
||||
{ field: 'Timestamp', title: '时间', formatter: ({ cellValue }) => new Date(cellValue * 1000).toLocaleString() },
|
||||
],
|
||||
stripe: true,
|
||||
height: '800px',
|
||||
pagerConfig: {},
|
||||
proxyConfig: {
|
||||
response: {
|
||||
total: "total",
|
||||
result: "data"
|
||||
},
|
||||
ajax: {
|
||||
query: async ({ page }, formValues) => {
|
||||
let Uid = parseInt(formValues.Uid, 10);
|
||||
if (Uid == 0) {
|
||||
return []
|
||||
}
|
||||
state.uid = Uid;
|
||||
state.Event = formValues.Event;
|
||||
let startTimeUnix = 0;
|
||||
let endTimeUnix = 0;
|
||||
// formValues.StartTime/EndTime 可能是 string(当 DatePicker 设置了 valueFormat 时)
|
||||
// 也可能是 dayjs 对象(未设置 valueFormat 时)
|
||||
if (formValues.StartTime) {
|
||||
if (typeof formValues.StartTime === 'string') {
|
||||
startTimeUnix = dayjs(formValues.StartTime).unix();
|
||||
} else if (dayjs.isDayjs(formValues.StartTime)) {
|
||||
startTimeUnix = formValues.StartTime.unix();
|
||||
} else if (typeof (formValues.StartTime as any).unix === 'function') {
|
||||
startTimeUnix = (formValues.StartTime as any).unix();
|
||||
} else {
|
||||
startTimeUnix = dayjs(formValues.StartTime).unix();
|
||||
}
|
||||
}
|
||||
if (formValues.EndTime) {
|
||||
if (typeof formValues.EndTime === 'string') {
|
||||
endTimeUnix = dayjs(formValues.EndTime).unix();
|
||||
} else if (dayjs.isDayjs(formValues.EndTime)) {
|
||||
endTimeUnix = formValues.EndTime.unix();
|
||||
} else if (typeof (formValues.EndTime as any).unix === 'function') {
|
||||
endTimeUnix = (formValues.EndTime as any).unix();
|
||||
} else {
|
||||
endTimeUnix = dayjs(formValues.EndTime).unix();
|
||||
}
|
||||
}
|
||||
// 使用计算好的 unix 时间调用接口
|
||||
return await getUserlogEventApi({
|
||||
Id: Uid,
|
||||
Event: formValues.Event,
|
||||
StartTime: startTimeUnix,
|
||||
EndTime: endTimeUnix,
|
||||
CurrentPage: page.currentPage,
|
||||
PageSize: page.pageSize,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
rowConfig: {
|
||||
isHover: true,
|
||||
},
|
||||
};
|
||||
|
||||
const [Grid] = useVbenVxeGrid({ formOptions, gridOptions, gridEvents });
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<Page class="h-[800px]">
|
||||
<Grid />
|
||||
</Page>
|
||||
<Modal class="w-[800px]"> </Modal>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
150
apps/web-antd/src/views/userlog/userlist/order-table.vue
Normal file
150
apps/web-antd/src/views/userlog/userlist/order-table.vue
Normal file
@ -0,0 +1,150 @@
|
||||
<script setup lang="ts">
|
||||
import type { VbenFormProps } from '#/adapter/form';
|
||||
import type { VxeGridProps } from '#/adapter/vxe-table';
|
||||
import type { AppData } from '#/api/core/server';
|
||||
|
||||
import { inject, onMounted, ref } from 'vue';
|
||||
|
||||
import { Page } from '@vben/common-ui';
|
||||
|
||||
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import { getUserlogOrderApi } from '#/api/core/log';
|
||||
import { getAppListApi } from '#/api/core/server';
|
||||
import { globalState } from '#/store/globalState';
|
||||
import { rechargeData } from '#/store/recharge';
|
||||
|
||||
const state = inject('globalState', globalState);
|
||||
|
||||
interface RowType {
|
||||
Uid: string;
|
||||
Event: string;
|
||||
Param: string;
|
||||
timestamp: string;
|
||||
}
|
||||
const appList = ref<AppData[]>([]);
|
||||
|
||||
const formOptions: VbenFormProps = {
|
||||
// 默认展开
|
||||
collapsed: false,
|
||||
schema: [
|
||||
{
|
||||
disabled: true,
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: 'Uid',
|
||||
},
|
||||
defaultValue: state.uid,
|
||||
fieldName: 'Uid',
|
||||
label: 'Uid',
|
||||
},
|
||||
],
|
||||
// 控制表单是否显示折叠按钮
|
||||
showCollapseButton: false,
|
||||
submitButtonOptions: {
|
||||
show:false,
|
||||
},
|
||||
resetButtonOptions: {
|
||||
show:false,
|
||||
},
|
||||
|
||||
};
|
||||
const gridOptions: VxeGridProps<RowType> = {
|
||||
columns: [
|
||||
{ field: 'Uid', title: 'id' },
|
||||
{ field: 'OrderId', title: '订单号' },
|
||||
{ field: 'PayChannelOrderId', title: '3th订单号' },
|
||||
{ field: 'Price', title: '金额' },
|
||||
{
|
||||
field: 'ProductId',
|
||||
title: 'chargeId',
|
||||
formatter: ({ cellValue }) => {
|
||||
return rechargeData[cellValue] || cellValue;
|
||||
},
|
||||
},
|
||||
{ field: 'CreateTimeStr', title: '创建时间' },
|
||||
{ field: 'PayTimeStr', title: '支付时间' },
|
||||
{
|
||||
field: 'PayType',
|
||||
title: '支付类型',
|
||||
formatter: ({ cellValue }) => {
|
||||
if (cellValue === 0) return '谷歌';
|
||||
if (cellValue === 1) return '微信';
|
||||
if (cellValue === 2) return '支付宝';
|
||||
if (cellValue === 3) return '苹果内购';
|
||||
return cellValue;
|
||||
},
|
||||
},
|
||||
{ field: 'Param', title: '参数' },
|
||||
],
|
||||
exportConfig: {
|
||||
filename: '用户订单日志',
|
||||
type: 'csv',
|
||||
mode: 'current',
|
||||
download: true,
|
||||
},
|
||||
toolbarConfig: {
|
||||
custom: true,
|
||||
export: true,
|
||||
refresh: true,
|
||||
zoom: true,
|
||||
},
|
||||
stripe: true,
|
||||
height: 'auto',
|
||||
pagerConfig: {},
|
||||
proxyConfig: {
|
||||
response: {
|
||||
total: 'total',
|
||||
result: 'data',
|
||||
},
|
||||
ajax: {
|
||||
query: async ({ page }, formValues) => {
|
||||
const Uid = Number.parseInt(formValues.Uid, 10);
|
||||
state.uid = Uid;
|
||||
state.Event = formValues.Event;
|
||||
return await getUserlogOrderApi({
|
||||
Id: Uid,
|
||||
Event: formValues.Event,
|
||||
CurrentPage: page.currentPage,
|
||||
PageSize: page.pageSize,
|
||||
AppId: 1,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
rowConfig: {
|
||||
isHover: true,
|
||||
},
|
||||
};
|
||||
|
||||
const [Grid, GridApi] = useVbenVxeGrid({ formOptions, gridOptions });
|
||||
onMounted(async () => {
|
||||
try {
|
||||
const response = await getAppListApi();
|
||||
appList.value = Array.isArray(response) ? response : [];
|
||||
const app = appList.value[0];
|
||||
if (!app) return;
|
||||
GridApi.formApi.updateSchema([
|
||||
{
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
options: appList.value.map((item) => ({
|
||||
label: item.AppName,
|
||||
value: item.AppId,
|
||||
})),
|
||||
},
|
||||
fieldName: 'AppId',
|
||||
},
|
||||
]);
|
||||
} catch {
|
||||
appList.value = [];
|
||||
// console.log(e);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page auto-content-height class="h-[800px]">
|
||||
<Grid />
|
||||
</Page>
|
||||
</template>
|
||||
@ -4,7 +4,7 @@ import MergeData from '#/store/MergeData.json';
|
||||
import { orderTypeData, orderDiffData } from '#/store/order';
|
||||
import { faceTypeData } from '#/store/face';
|
||||
import { useVbenModal, useVbenForm, WorkbenchTrends } from '@vben/common-ui';
|
||||
import { message, Card } from 'ant-design-vue';
|
||||
import { message, Card, Tabs } from 'ant-design-vue';
|
||||
import { getUserlogInfoApi } from '#/api/core/log';
|
||||
import { userGmApi, userBanApi } from '#/api/core/user';
|
||||
import { calendar } from '#/component/index';
|
||||
@ -18,7 +18,9 @@ import dayjs from 'dayjs';
|
||||
import { WorkbenchDetail } from '@vben/common-ui';
|
||||
import UserHeader from './user-header.vue';
|
||||
import { AccessControl } from '@vben/access';
|
||||
|
||||
import eventTable from './event-table.vue';
|
||||
import assetTable from './asset-table.vue';
|
||||
import orderTable from './order-table.vue';
|
||||
|
||||
|
||||
// 这是一个示例数据,实际项目中需要根据实际情况进行调整
|
||||
@ -252,6 +254,7 @@ let trendItems: WorkbenchTrendItem[] = [
|
||||
|
||||
];
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
fullscreen: true,
|
||||
onCancel() {
|
||||
modalApi.close();
|
||||
},
|
||||
@ -464,8 +467,10 @@ watch(
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<Modal title="玩家详情">
|
||||
<Modal title="玩家详情" class="h-[100%]">
|
||||
<div class="p-5">
|
||||
<Tabs>
|
||||
<Tabs.TabPane key="1" tab="玩家信息">
|
||||
<UserHeader :avatar="info.Face" :ban="info.Ban">
|
||||
<template #nick_name> nick_name: {{ info.Name || 'N/A' }} </template>
|
||||
<template #user_name> user_name: {{ info.Mac }} </template>
|
||||
@ -502,19 +507,22 @@ watch(
|
||||
<template #TodayCumulative>{{ info.TodayCumulative }}</template>
|
||||
</WorkbenchDetail>
|
||||
<chessComponent :items="info.Chess" title="棋盘" class="mt-6" />
|
||||
<calendar v-if="info.Heatmap.length > 0" style="margin-top: 15px" :dataList="info.Heatmap" title="热力图"
|
||||
:key="`heatmap-${info.Uid}`" />
|
||||
<div v-else style="
|
||||
margin-top: 15px;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
color: #999;
|
||||
">
|
||||
暂无热力图数据
|
||||
</div>
|
||||
<!-- <WorkbenchTodo :items="todoItems" class="mt-5" title="待办事项" /> -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane key="2" tab="操作日志">
|
||||
<eventTable :uid="info.Uid" :serverId="data?.Node" />
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane key="3" tab="资产日志">
|
||||
<assetTable :uid="info.Uid" :serverId="data?.Node" />
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane key="4" tab="订单日志">
|
||||
<orderTable :uid="info.Uid" :serverId="data?.Node" />
|
||||
</Tabs.TabPane>
|
||||
</Tabs>
|
||||
|
||||
</div>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
@ -12,6 +12,8 @@ import { onMounted, ref, inject } from 'vue';
|
||||
import { globalState } from '#/store/globalState';
|
||||
import { getServerListApi, getAppListApi } from '#/api/core/server';
|
||||
import type { AppData, ServerData } from '#/api/core/server';
|
||||
import { $t } from '#/locales'
|
||||
|
||||
const state = inject('globalState', globalState);
|
||||
const appList = ref<AppData[]>([]);
|
||||
const ServerList = ref<ServerData[]>([]);
|
||||
@ -142,7 +144,7 @@ const gridEvents: VxeGridListeners<RowType> = {
|
||||
|
||||
const gridOptions: VxeGridProps<RowType> = {
|
||||
columns: [
|
||||
{ field: 'Uid', title: 'id' },
|
||||
{ field: 'Uid', title: 'id' , sortable: true, sortBy: 'Uid'},
|
||||
{ field: 'UserName', title: '登录名' },
|
||||
{ field: 'Level', title: '等级', formatter: ({ cellValue }) => `${cellValue} 级`, sortable: true, sortBy: 'Level' },
|
||||
{ field: 'Node', title: '节点', },
|
||||
@ -150,8 +152,8 @@ const gridOptions: VxeGridProps<RowType> = {
|
||||
{ field: 'Diamond', title: '钻石', formatter: ({ cellValue }) => `${cellValue} 💎`, sortable: true, sortBy: 'Diamond' },
|
||||
{ field: 'Star', title: '星星', formatter: ({ cellValue }) => `${cellValue} ⭐`, sortable: true, sortBy: 'Star' },
|
||||
{ field: 'Energy', title: '能量', formatter: ({ cellValue }) => `${cellValue} ⚡`, sortable: true, sortBy: 'Energy' },
|
||||
{ field: 'LoginTime', sortable: true, title: '登录时间', formatter: ({ cellValue }) => dayjs(cellValue * 1000).format('YYYY-MM-DD HH:mm:ss') },
|
||||
{ field: 'Online', title: '在线状态', slots: { default: 'online' } },
|
||||
{ field: 'LoginTime', sortable: true, title: '登录时间', formatter: ({ cellValue }) => dayjs(cellValue * 1000).format('YYYY-MM-DD HH:mm:ss'),sortBy: 'LoginTime' },
|
||||
{ field: 'Online', title: '在线状态', slots: { default: 'online' } , sortable: true, sortBy: 'Online' },
|
||||
],
|
||||
height: 'auto',
|
||||
pagerConfig: {},
|
||||
@ -200,7 +202,7 @@ onMounted(async () => {
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
options: appList.value.map((item) => ({
|
||||
label: item.AppName,
|
||||
label: $t('page.server.' + item.AppName),
|
||||
value: item.AppId,
|
||||
})),
|
||||
},
|
||||
@ -233,13 +235,13 @@ function getTagColor(online: string): string {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page auto-content-height class="h-[800px]">
|
||||
<Page auto-content-height class="h-[1200px]">
|
||||
<Grid>
|
||||
<template #online="{ row }">
|
||||
<Tag :color="getTagColor(row.Online)">{{ row.Online }}</Tag>
|
||||
</template>
|
||||
</Grid>
|
||||
<userModal class="w-[98%]" />
|
||||
<userModal class="w-[100%]" />
|
||||
</Page>
|
||||
|
||||
</template>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user