版本更新
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:
hahwu 2025-11-10 16:40:10 +08:00
parent a3a280787e
commit b58800738c
71 changed files with 6630 additions and 2975 deletions

View File

@ -50,6 +50,7 @@
"vue": "catalog:",
"vue-router": "catalog:",
"vue3-pixi": "1.0.0-beta.3",
"vxe-table": "^4.6.25"
"vxe-pc-ui": "4.10.18",
"vxe-table": "^4.17.11"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 280 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -4,7 +4,6 @@ import { registerAccessDirective } from '@vben/access';
import { preferences } from '@vben/preferences';
import { initStores } from '@vben/stores';
import '@vben/styles';
import '@vben/styles/antd';
import { useTitle } from '@vueuse/core';
import { $t, setupI18n } from '#/locales';

View File

@ -6,8 +6,10 @@ import {
CardHeader,
CardTitle,
VbenIcon,
VbenPopover
} from '../../../../../packages/@core/ui-kit/shadcn-ui';
import type { Order } from '#/model/type';
import { computed, toRefs } from 'vue';
interface Props {
items: Order[];
title: string;
@ -17,9 +19,10 @@ defineOptions({
name: 'WorkbenchProject',
});
withDefaults(defineProps<Props>(), {
const props = withDefaults(defineProps<Props>(), {
items: () => [],
});
const { items, title } = toRefs(props);
function getTagColor(diff: number): string {
if (diff === 1) {
return 'green';
@ -32,13 +35,69 @@ function getTagColor(diff: number): string {
}
return 'red';
}
const orderTypeMeta: Record<number, { name: string; desc: string }> = {
1: { name: '普通订单', desc: '自动生成的基础订单。' },
2: { name: '额外订单(弃用)', desc: '历史类型,当前已弃用。' },
3: { name: '超级订单', desc: '奖励更高,难度更大的订单类型。' },
4: { name: '预热订单', desc: '用于活动或阶段开始前的预热内容。' },
5: { name: '触发订单', desc: '由特定事件或条件触发生成。' },
6: { name: '退役发射器清理订单', desc: '用于清理退役发射器相关棋子。' },
7: { name: '清理无法生成订单的棋子', desc: '处理异常或失效的棋子。' },
8: { name: '棋盘空格不足清理订单', desc: '当空间不足时清理低优先级棋子。' },
9: { name: '安慰订单', desc: '与安慰或情绪相关的特殊订单。' },
10: { name: '引导订单', desc: '用于新手或阶段引导流程。' },
11: { name: '消耗品订单', desc: '与宠物系统相关的订单。' },
12: { name: '预览订单', desc: '提前展示后续内容的预览类订单。' },
13: { name: '预设订单', desc: '新手过程从配置中生成的订单!' },
14: { name: 'Playroom装饰物订单', desc: '生成与Playroom装饰物相关的订单。' },
15: { name: '零件订单', desc: '用于收集或合成零件的订单。' },
};
const popoverTypes = computed(() => {
const types = new Set<number>();
(items.value || []).forEach(it => {
const t = Number((it as any).group);
if (!isNaN(t)) types.add(t);
});
return Array.from(types.values()).sort((a, b) => a - b).map(id => ({
id,
...orderTypeMeta[id],
}));
});
defineEmits(['click']);
</script>
<template>
<Card>
<CardHeader class="py-4">
<CardTitle class="text-lg">{{ title }}</CardTitle>
<CardTitle class="text-lg">
<div class="flex">
<span class="text-center">{{ title }}</span>
<VbenPopover class="ml-2" :content-props="{ side: 'left' }">
<template #trigger>
<VbenIcon icon="solar:question-circle-bold" class="ml-2" />
</template>
<div class="max-w-xs text-sm">
<h3 class="font-semibold mb-2">订单类型说明</h3>
<ul v-if="popoverTypes.length" class="list-disc pl-5 space-y-1">
<li v-for="t in popoverTypes" :key="t.id">
<b>{{ t.name }}</b>{{ t.desc }}
</li>
</ul>
<div v-else class="text-xs text-gray-500">暂无订单类型数据</div>
<h3 class="font-semibold mt-4 mb-2">订单难度说明</h3>
<ul>
<li><b>简单</b>订单总消耗体力在15-150之间</li>
<li><b>中等</b>订单总消耗体力在100-600之间</li>
<li><b>困难</b>订单总消耗体力在500-1200之间</li>
</ul>
</div>
</VbenPopover>
</div>
</CardTitle>
</CardHeader>
<CardContent class="flex flex-wrap p-0">
<template v-for="(item, index) in items" :key="item.title">
@ -50,8 +109,7 @@ defineEmits(['click']);
class="border-border group w-full cursor-pointer border-b border-r border-t p-4 transition-all hover:shadow-xl md:w-1/2 lg:w-1/3">
<div class="flex items-center">
<VbenIcon :color="item.color" :icon="item.icon"
class="size-8 transition-all duration-300 group-hover:scale-110"
@click="$emit('click', item)" />
class="size-8 transition-all duration-300 group-hover:scale-110" />
<span class="ml-2 text-lg font-medium">{{ item.id }}</span>
<tag class="ml-2 text-sm" :color="getTagColor(item.diff)">{{ item.diffName }}</tag>
</div>

View File

@ -1,14 +1,94 @@
{
"common":{
"save": "Save",
"cancel": "Cancel",
"edit": "Edit",
"delete": "Delete",
"search": "Search",
"gitCommit":"GitCommit",
"addLine": "AddLine",
"searchField": "Search Field",
"value": "Value",
"startTime": "Start Time",
"endTime": "End Time"
},
"auth": {
"login": "Login",
"register": "Register",
"codeLogin": "Code Login",
"qrcodeLogin": "Qr Code Login",
"qrcodeLogin": "QR Code Login",
"forgetPassword": "Forget Password"
},
"admin": {
"title": "Admin",
"user": "User",
"setting": "Setting",
"log": "Log"
},
"dashboard": {
"title": "Dashboard",
"analytics": "Analytics",
"workspace": "Workspace"
"server-list": "Server List",
"node-list": "Node List",
"mysql-list": "MySQL List",
"app-list": "App List"
},
"userlog": {
"title": "User Log",
"userlist": "User List",
"assetlog": "Asset Log",
"eventlog": "Event Log",
"orderlog": "Order Log"
},
"language": {
"title": "Language",
"languageList": "Language List",
"translationList": "Translation List",
"lastUpdate": "Last update",
"newLineContent": "New Translation"
},
"operation": {
"title": "Operation",
"level": "Level",
"mail": "Mail",
"order": "Order",
"language": "Language"
},
"log": {
"event": {
"order_finish": "Finish Order",
"time_limited_event_enable": "Open Time-limited Event",
"collection_add": "Add Collection",
"mutil_merge_change": "Change Merge Multiplier",
"sell_item": "Sell Item",
"buy_product_diamond": "Purchase Item",
"store_buy": "Purchase in Store",
"refresh_store_diamond": "Refresh Store",
"one_click_decoration": "Build All",
"championship_reward": "Tournament Reward",
"piggy_bank_open": "Open Piggy Bank",
"get_chest": "Collect Chest",
"weekly_gift": "Weekly Gift",
"finish_deco": "Build",
"plot_unlock": "Unlock Scene",
"scene_reward": "Scene Reward",
"piggy_bank_income": "Gain from Piggy Bank",
"card_pack_open": "Open Card Pack",
"get_new_card": "Collect New Card",
"gift_free": "Free Gift from Store",
"item_change": "Item Change",
"daily_task": "Daily Task",
"weekly_task": "Weekly Task",
"level_up": "Level Up",
"property_level_up": "Property Level Up",
"time_limited_slot": "Time Limited Event",
"buy_energy_diamond": "Buy Energy",
"time_limited_event_action": "Choose Time-limited Event",
"petname_set": "Set Pet Name",
"emoji_income": "Collect Emote",
"avatarIcon_income": "Collect Avatar",
"gm": "Use GM Tool",
"nickname_set": "Set Nickname"
}
}
}

View File

@ -1,4 +1,17 @@
{
"common":{
"save": "保存",
"cancel": "取消",
"edit": "编辑",
"delete": "删除",
"search": "搜索",
"gitCommit":"git提交",
"addLine": "新增行",
"searchField": "搜索列",
"value": "值",
"startTime": "开始时间",
"endTime": "结束时间"
},
"auth": {
"login": "登录",
"register": "注册",
@ -30,7 +43,9 @@
"language": {
"title": "翻译管理",
"languageList": "语言列表",
"translationList": "翻译列表"
"translationList": "翻译列表",
"lastUpdate": "最后修改日期",
"newLineContent": "新增翻译"
},
"operation": {
"title": "运营管理",

View File

@ -51,6 +51,7 @@ export interface languageType {
key: string;
English: string;
ChineseSimplified: string;
Portuguese: string;
}

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,7 @@ import type { languageType } from '#/model/type';
import type { VxeGridProps } from '#/adapter/vxe-table';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { addLanguageList } from '#/api/core/statistics';
import { $t } from '#/locales'
defineOptions({
name: 'AddLanguageModal',
});
@ -11,15 +12,15 @@ let ld = [] as languageType[];
const gridOptions: VxeGridProps<languageType> = {
border: true,
columns: [
{ title: '序号', field: 'Id', width: 50 },
{ editRender: { name: 'input' }, field: 'key', title: '键值' },
{ editRender: { name: 'input' }, field: 'English', title: '英文' },
{ title: 'Id', field: 'Id', width: 50 },
{ editRender: { name: 'input' }, field: 'key', title: 'key' },
{ editRender: { name: 'input' }, field: 'English', title: 'English' },
{
editRender: { name: 'input' },
field: 'ChineseSimplified',
title: '简体中文',
title: 'ChineseSimplified',
},
{ editRender: { name: 'input' }, field: 'Portuguese', title: '葡萄牙语' },
{ editRender: { name: 'input' }, field: 'Portuguese', title: 'Portuguese' },
],
data: ld,
pagerConfig: {
@ -56,10 +57,10 @@ const [Form] = useVbenForm({
{
component: 'Textarea',
fieldName: 'ToUids',
label: '新增翻译',
label: $t('page.language.newLineContent'),
componentProps: {
disabled: false,
placeholder: 'key | English | 简体中文| 葡萄牙语,一行一条记录',
placeholder: 'key | English | ChineseSimplified| PortugueseOne record per line',
type: 'textarea',
rows: 8,
onChange: (e: Event) => {
@ -94,7 +95,7 @@ const [Modal, modalApi] = useVbenModal({
});
</script>
<template>
<Modal width="100%" title="添加翻译">
<Modal width="100%">
<Form />
<Grid />
</Modal>

View File

@ -9,6 +9,7 @@ import type { VbenFormProps } from '#/adapter/form';
import type { languageType, languageRecord } from '#/model/type';
import type { languageParam } from '#/api/core/statistics';
import { useVbenModal } from '@vben/common-ui';
import { $t } from '#/locales'
import dayjs from 'dayjs';
const [AddLanguageModal, AddLanguageModalApi] = useVbenModal({
connectedComponent: addLanguage,
@ -18,6 +19,13 @@ let newData: languageType[] = [];
let op: languageRecord[] = [];
let lastOp: languageRecord[] = [];
let lastUpdate: string = '';
let total: languageType = {
Id: 1,
key: '',
English: '',
ChineseSimplified: '',
Portuguese: '',
};
const startDate = dayjs().subtract(7, 'day').startOf('day');
const endDate = dayjs().endOf('day');
const formOptions: VbenFormProps = {
@ -29,16 +37,16 @@ const formOptions: VbenFormProps = {
componentProps: {
filterOption: true,
options: [
{ label: '键值', value: 'key' },
{ label: '英文', value: 'English' },
{ label: '简体中文', value: 'ChineseSimplified' },
{ label: '葡萄牙语', value: 'Portuguese' },
{ label: 'key', value: 'key' },
{ label: 'English', value: 'English' },
{ label: 'ChineseSimplified', value: 'ChineseSimplified' },
{ label: 'Portuguese', value: 'Portuguese' },
],
placeholder: 'key',
showSearch: true,
},
fieldName: 'SearchField',
label: '搜索列',
label: $t('page.common.searchField') + '',
},
{
component: 'Input',
@ -48,50 +56,35 @@ const formOptions: VbenFormProps = {
showSearch: true,
},
fieldName: 'SearchValue',
label: '值',
label: $t('page.common.value') + '',
},
{
component: 'DatePicker',
defaultValue: startDate,
componentProps: {
format: 'YYYY-MM-DD',
showTime: true,
valueFormat: 'YYYY-MM-DD HH:mm:ss',
},
fieldName: 'StartTime',
label: '开始时间',
label: $t('page.common.startTime'),
formItemClass: 'col-start-1',
},
{
component: 'TimePicker',
componentProps: {
placeholder: '时间',
},
fieldName: 'StartTime',
label: '--',
},
{
component: 'DatePicker',
defaultValue: endDate,
componentProps: {
format: 'YYYY-MM-DD',
showTime: true,
valueFormat: 'YYYY-MM-DD HH:mm:ss',
},
fieldName: 'EndTime',
label: '结束时间',
label: $t('page.common.endTime'),
},
{
component: 'TimePicker',
componentProps: {
placeholder: '时间',
},
fieldName: 'EndTime',
label: '--',
}
],
//
showCollapseButton: true,
submitButtonOptions: {
content: '查询',
content: $t('page.common.search'),
},
wrapperClass: 'grid-cols-1 md:grid-cols-5',
//
@ -102,16 +95,20 @@ const formOptions: VbenFormProps = {
const gridOptions: VxeGridProps<languageType> = {
border: true,
columns: [
{ title: '序号', field: 'Id', width: 50 },
{ editRender: { name: 'input' }, field: 'key', title: '键值' },
{ editRender: { name: 'input' }, field: 'English', title: '英文' },
{ title: 'Id', field: 'Id', width: 100 },
{ editRender: { name: 'input' }, field: 'key', title: 'key', filters: [{ data: "" }], filterRender: { name: "input" } },
{ editRender: { name: 'input' }, field: 'English', title: 'English', filters: [{ data: "" }], filterRender: { name: "input" } },
{
editRender: { name: 'input' },
field: 'ChineseSimplified',
title: '简体中文',
title: 'ChineseSimplified', filters: [{ data: "" }], filterRender: { name: "input" }
},
{ editRender: { name: 'input' }, field: 'Portuguese', title: '葡萄牙语' },
{ editRender: { name: 'input' }, field: 'Portuguese', title: 'Portuguese', filters: [{ data: "" }], filterRender: { name: "input" } }
],
scrollY: {
enabled: true,
gt: 0
},
toolbarConfig: {
custom: true,
refresh: true,
@ -178,6 +175,50 @@ const gridOptions: VxeGridProps<languageType> = {
} else {
lastUpdate = '';
}
// response.data English don'tmother-in-law
const englishCount = (response.data || []).reduce((sum: number, item: languageType) => {
const s = item?.English || '';
const matches = s.match(/[A-Za-z]+(?:['-][A-Za-z]+)*/g);
return sum + (matches ? matches.length : 0);
}, 0);
// total footerData
total.English = String(englishCount);
if (gridOptions && Array.isArray(gridOptions.footerData) && gridOptions.footerData.length > 0) {
(gridOptions.footerData[0] as any).English = String(englishCount);
}
// ChineseSimplified
const countHan = (str: string) => {
try {
const m = str.match(/\p{Script=Han}/gu);
return m ? m.length : 0;
} catch (e) {
const m = str.match(/[\u3400-\u4DBF\u4E00-\u9FFF\uF900-\uFAFF]/g);
return m ? m.length : 0;
}
};
const chineseCount = (response.data || []).reduce((sum: number, item: languageType) => {
return sum + countHan(item?.ChineseSimplified || '');
}, 0);
total.ChineseSimplified = String(chineseCount);
if (gridOptions && Array.isArray(gridOptions.footerData) && gridOptions.footerData.length > 0) {
(gridOptions.footerData[0] as any).ChineseSimplified = String(chineseCount);
}
GridApi.setGridOptions({
pagerConfig: {
enabled: true,
pageSize: page.pageSize,
pageSizes: [40, 80, 100, 200, 500, 1000, 3000, 10000],
},
footerData: [{
Id: 'Word',
key: '-',
English: total.English,
ChineseSimplified: total.ChineseSimplified,
Portuguese: '',
}],
});
return {
data: response.data || [],
total: response.total || 0,
@ -185,13 +226,28 @@ const gridOptions: VxeGridProps<languageType> = {
}
}
},
keepSource: true,
keyboardConfig: {
isArrow: true,
isTab: true,
isEnter: true,
},
footerData: [{
Id: '字符数统计',
key: '-',
English: total.English,
ChineseSimplified: '',
Portuguese: '',
}],
showFooter: true,
editConfig: {
mode: 'cell',
trigger: 'dblclick',
showStatus: true,
},
pagerConfig: {
enabled: true,
pageSize: 80,
pageSizes: [40, 80, 100, 200, 500, 1000],
},
height: 'auto',
showOverflow: true,
@ -231,6 +287,9 @@ const [Grid, GridApi] = useVbenVxeGrid({ formOptions, gridOptions, gridEvents })
function addRow() {
AddLanguageModalApi.open();
AddLanguageModalApi.setState({
title: $t('page.language.newLineContent'),
});
}
function saveAll() {
saveLanguageList(op).then((response) => {
@ -273,27 +332,28 @@ function exportLang() {
<style lang="css">
.row-green {
background-color: #1ecf0d;
background-color: #0ea800;
}
.row-yellow {
background-color: #f2ff00;
background-color: #c9bc04;
}
</style>
<template>
<Page auto-content-height>
<AddLanguageModal width="1200px" title="添加翻译"></AddLanguageModal />
<div class="h-full flex flex-col">
<Page auto-content-height class="h-[800px]">
<AddLanguageModal width="1200px" height="1200px"></AddLanguageModal />
<Grid>
<template #toolbar-tools>
<span class="mr-4 font-bold">最后修改日期{{ lastUpdate }}</span>
<span class="mr-4 font-bold">{{ $t('page.language.lastUpdate') }}{{ lastUpdate }}</span>
<Button class="mr-2" type="primary" @click="addRow">
新增行
{{ $t('page.common.addLine') }}
</Button>
<Button type="primary" @click="saveAll" class="mr-2"> 保存 </Button>
<Button type="primary" @click="exportLang"> git提交 </Button>
<Button type="primary" @click="saveAll" class="mr-2"> {{ $t('page.common.save') }} </Button>
<Button type="primary" @click="exportLang"> {{ $t('page.common.gitCommit') }} </Button>
</template>
</Grid>
</Page>
</div>
</template>

View File

@ -146,7 +146,7 @@ onMounted(async () => {
</script>
<template>
<Page auto-content-height>
<Page auto-content-height class="h-[800px]">
<Grid />
</Page>
</template>

View File

@ -206,7 +206,7 @@ async function deleteRow(row: MailData) {
</script>
<template>
<Page auto-content-height>
<Page auto-content-height class="h-[800px]">
<AddMailM class="w-[50%]" />
<AddMailM2 class="w-[50%]" />
<Card class="mb-5" title="邮件操作">

View File

@ -88,9 +88,14 @@ const formOptions: VbenFormProps = {
const gridOptions: VxeGridProps<RowType> = {
columns: [
{ field: 'Type', title: '订单类型' },
{ field: 'Num', title: '该类订单持有数量' },
{ field: 'Num', title: '该类订单持有数量', formatter: ({ cellValue }) => cellValue === 0 ? '总数' : cellValue },
{ field: 'Sum', title: '流失玩家数' },
{ field: 'Prop', title: '占比', formatter: ({ cellValue }) => `${cellValue}%` },
{ field: 'Prop', title: '占比', formatter: ({ cellValue }) => `${cellValue}%`, cellRender: { name: 'pie' } },
],
border: true,
mergeCells: [
{ row: 0, col: 0, rowspan: 5, colspan: 1 },
{ row: 5, col: 0, rowspan: 5, colspan: 1 },
],
height: 'auto',
pagerConfig: {},
@ -110,10 +115,6 @@ const gridOptions: VxeGridProps<RowType> = {
},
},
},
rowConfig: {
isHover: true,
},
};
const [Grid, GridApi] = useVbenVxeGrid({ formOptions, gridOptions });
@ -146,7 +147,7 @@ onMounted(async () => {
<template>
<div>
<Page auto-content-height>
<Page auto-content-height class="h-[800px]">
<Grid>
<template #toolbar-tools>
<span class="mr-5 font-semibold" style="color: red;">该类订单持有数量为0的流失玩家数为该订单难度的总流失玩家数</span>

View File

@ -1,6 +1,6 @@
<script setup lang="ts">
import { Page, useVbenModal } from '@vben/common-ui';
import type { VxeGridListeners } from 'vxe-table';
import type { VxeGridListeners } from '#/adapter/vxe-table';
import { getUserLogAssetApi } from '#/api/core/log';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { inject, ref } from 'vue';
@ -24,6 +24,7 @@ interface RowType {
item_id: string;
timestamp: string;
}
const formatType = (cellValue: string) => {
switch (cellValue) {
case "gain":
@ -45,6 +46,11 @@ const d = ref({
});
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: {
@ -70,19 +76,31 @@ const formOptions: VbenFormProps = {
component: 'DatePicker',
defaultValue: startDate,
componentProps: {
format: 'YYYY-MM-DD',
showTime: true,
valueFormat: 'YYYY-MM-DD HH:mm:ss',
},
fieldName: 'StartTime',
label: '开始时间',
},
{
component: 'TimePicker',
component: 'DatePicker',
defaultValue: endDate,
componentProps: {
placeholder: '时间',
showTime: true,
valueFormat: 'YYYY-MM-DD HH:mm:ss',
},
fieldName: 'StartTime',
label: '--',
wrapperClass: 'col-span-3 col-start-2',
fieldName: 'EndTime',
label: '结束时间',
},
{
component: 'Select',
componentProps: {
options: itemIdOptions,
allowClear: true,
},
fieldName: 'ItemId',
label: '道具id',
},
{
component: 'Select',
@ -96,37 +114,6 @@ const formOptions: VbenFormProps = {
fieldName: 'Event',
label: '变化类型',
},
{
component: 'DatePicker',
defaultValue: endDate,
componentProps: {
format: 'YYYY-MM-DD',
},
fieldName: 'EndTime',
label: '结束时间',
},
{
component: 'TimePicker',
componentProps: {
placeholder: '时间',
},
fieldName: 'EndTime',
label: '--',
wrapperClass: 'col-span-3 col-start-2',
},
{
component: 'Select',
componentProps: {
options: [
{ label: '能量', value: 100001 },
{ label: '宠物币', value: '100002' },
{ label: '钻石', value: '100003' },
],
allowClear: true,
},
fieldName: 'ItemId',
label: '道具id',
},
],
//
showCollapseButton: true,
@ -150,16 +137,17 @@ const gridEvents: VxeGridListeners<RowType> = {
};
const gridOptions: VxeGridProps<RowType> = {
columns: [
{ field: 'Uid', title: 'Uid' },
{ field: 'change_type', title: '变化类型', formatter: ({ cellValue }) => formatType(cellValue) },
{ field: 'change_num', title: '变化数值' },
{ field: 'change_after', title: '变化后数值' },
{ field: 'item_id', title: '道具名称', formatter: ({ cellValue }) => formatItemName(cellValue) },
{ field: 'item_id', title: '道具id' },
{ field: 'timestamp', title: '时间', formatter: ({ cellValue }) => new Date(cellValue * 1000).toLocaleString() },
{ 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',
keepSource: true,
exportConfig: {
filename: '用户资产日志',
type: 'csv',
@ -198,6 +186,29 @@ const gridOptions: VxeGridProps<RowType> = {
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;
@ -217,8 +228,15 @@ const [Grid] = useVbenVxeGrid({ formOptions, gridOptions, gridEvents });
<template>
<div>
<Page auto-content-height>
<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>
@ -226,6 +244,6 @@ const [Grid] = useVbenVxeGrid({ formOptions, gridOptions, gridEvents });
</template>
</Grid>
</Page>
<Modal class="w-[1200px]" "> </Modal>
<Modal class="w-[1200px]"> </Modal>
</div>
</template>

View File

@ -51,40 +51,23 @@ const formOptions: VbenFormProps = {
component: 'DatePicker',
defaultValue: startDate,
componentProps: {
format: 'YYYY-MM-DD',
showTime: true,
valueFormat: 'YYYY-MM-DD HH:mm:ss',
},
fieldName: 'StartTime',
label: '开始时间',
formItemClass: 'col-start-1',
},
{
component: 'TimePicker',
componentProps: {
placeholder: '时间',
},
fieldName: 'StartTime',
label: '--',
},
{
component: 'DatePicker',
defaultValue: endDate,
componentProps: {
format: 'YYYY-MM-DD',
showTime: true,
valueFormat: 'YYYY-MM-DD HH:mm:ss',
},
fieldName: 'EndTime',
label: '结束时间',
},
{
component: 'TimePicker',
componentProps: {
placeholder: '时间',
},
fieldName: 'EndTime',
label: '--',
},
}
],
//
showCollapseButton: true,
@ -154,7 +137,7 @@ const [Grid] = useVbenVxeGrid({ formOptions, gridOptions, gridEvents });
<template>
<div>
<Page auto-content-height>
<Page auto-content-height class="h-[800px]">
<Grid />
</Page>
<Modal class="w-[1200px]"> </Modal>

View File

@ -155,7 +155,7 @@ onMounted(async () => {
</script>
<template>
<Page auto-content-height>
<Page auto-content-height class="h-[800px]">
<Grid />
</Page>
</template>

View File

@ -1,10 +1,10 @@
<script lang="ts" setup>
import { ref, watch } from 'vue';
import { ref, watch, computed } from 'vue';
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 } from 'ant-design-vue';
import { message, Card } from 'ant-design-vue';
import { getUserlogInfoApi } from '#/api/core/log';
import { userGmApi, userBanApi } from '#/api/core/user';
import { calendar } from '#/component/index';
@ -26,6 +26,8 @@ import { AccessControl } from '@vben/access';
// url: /dashboard/workspace
const projectItems: WorkbenchProjectItem[] = [];
const chargeDisplay = computed(() => (Number(info.value?.Charge ?? 0)).toFixed(2));
const [BaseForm] = useVbenForm({
//
commonConfig: {
@ -42,10 +44,64 @@ const [BaseForm] = useVbenForm({
// labelinput
schema: [
{
component: 'Input',
component: 'Mentions',
defaultValue: '',
componentProps: {
placeholder: '请输入gm命令',
placeholder: '请输入gm命令输入@可查看命令列表',
options: [
//
{ label: 'additem 100002 100 增加宠物币100', value: 'additem 100002 100' },
{ label: 'additem 100001 100 增加能量100', value: 'additem 100001 100' },
{ label: 'additem 100003 100 增加钻石100', value: 'additem 100003 100' },
{ label: 'subitem 100002 100 减少宠物币100', value: 'subitem 100002 100' },
{ label: 'addexp 100 增加100经验', value: 'addexp 100' },
{ label: 'setlv 1 设置为1级', value: 'setlv 1' },
{ label: 'AllFace 获取所有头像和头像框', value: 'AllFace' },
//
{ label: 'reset_order 重置订单', value: 'reset_order' },
{ label: 'orderMerge 获取订单所需棋子', value: 'orderMerge' },
//
{ label: 'add_card_star 5 增加5点卡包碎片', value: 'add_card_star 5' },
{ label: 'add_card 1 增加id为1的卡牌', value: 'add_card 1' },
{ label: 'addAddCard 获取所有卡牌', value: 'addAddCard' },
{ label: 'addAddCard 获取当前轮次全部卡牌', value: 'addAddCard' },
{ label: 'resetCardSeasonFirst 重置卡牌赛季初始奖励', value: 'resetCardSeasonFirst' },
//
{ label: 'setSevenLoginActive 20 设置签到进度为20', value: 'setSevenLoginActive 20' },
//
{ label: 'setProgress 4 设置转盘进度为4', value: 'setProgress 4' },
{ label: 'setProgressReward 完成限时事件转盘', value: 'setProgressReward' },
//
{ label: 'champshipGroup 锦标赛分组', value: 'champshipGroup' },
//
{ label: 'zeroUpdate 模拟0点更新', value: 'zeroUpdate' },
// Playroom
{ label: 'playroomTrigger 生成playroom触发式订单', value: 'playroomTrigger' },
{ label: 'playroomCollect 获取playroom所有装饰', value: 'playroomCollect' },
{ label: 'addChip 增加playroom房间纸屑', value: 'addChip' },
{ label: 'addFriendStar 4 在宠物宝藏中增加4个宠物币', value: 'addFriendStar 4' },
{ label: 'addPhysiology type num 增加生理类型为type的数值num', value: 'addPhysiology type num' },
{ label: 'resetTriggerTime 重置playroom触发订单cd', value: 'resetTriggerTime' },
{ label: 'playroomDress 获取playroom所有服装', value: 'playroomDress' },
{ label: 'playroomAir 获取playroom所有飞行背包', value: 'playroomAir' },
//
{ label: 'addFriend 对方uid 仅用于调试,对方好友列表不会增加', value: 'addFriend 对方uid' },
//
{ label: 'setDecorateArea 1 设置装饰区域id', value: 'setDecorateArea 1' },
{ label: 'setDecorateProgresse 1 设置装饰进度', value: 'setDecorateProgresse 1' },
//
{ label: 'handbook 解锁所有图鉴', value: 'handbook' },
],
},
label: 'Gm:',
fieldName: 'gm',
@ -53,11 +109,13 @@ const [BaseForm] = useVbenForm({
],
handleSubmit: async (values) => {
const cv = modalApi.getData<Record<string, any>>();
let gm = values.gm;
gm = String(gm || '').replace(/@/g, '');
const r = await userGmApi({
Uid: cv.uid,
AppId: cv.AppId,
ServerId: cv.ServerId,
Command: values.gm,
Command: gm,
});
message.success(r.Msg);
},
@ -163,12 +221,7 @@ const info = ref<{
Chess: [],
});
let trendItems: WorkbenchTrendItem[] = [
{
avatar: 'svg:avatar-1',
content: `在 <a>开源组</a> 创建了项目 <a>Vue</a>`,
date: '刚刚',
title: '威廉',
}
];
const [Modal, modalApi] = useVbenModal({
onCancel() {
@ -189,10 +242,12 @@ const [Modal, modalApi] = useVbenModal({
CurrentPage: 1, // replace 1 with the actual current page
});
trendItems = [];
let id = 0;
if (r.ActLog) {
for (const logEntry of r.ActLog.reverse()) {
let [title, content] = formatActLog(logEntry.Type, logEntry.Param)
trendItems.push({
Id: id++,
avatar: 'svg:avatar-1',
content: content || '',
date: dayjs(logEntry.Time * 1000).format('YYYY-MM-DD HH:mm:ss'),
@ -406,21 +461,15 @@ watch(
<template #diamond>{{ info.Diamond }}</template>
</UserHeader>
<AccessControl :codes="['super', 'admin']" type="role">
<div class="mt-5">
<Card class="card-box flex flex-col p-5">
<div class="mt-5 flex">
<Card class="card-box flex flex-col p-5 w-[50%]">
<BaseForm />
</Card>
</div>
</AccessControl>
<AccessControl :codes="['super', 'admin']" type="role">
<div class="mt-5">
<Card class="card-box flex flex-col p-5">
<Card class="card-box flex flex-col p-5 w-[45%] ml-5">
<BanForm />
</Card>
</div>
</AccessControl>
<div class="mt-5 flex flex-col lg:flex-row">
<div class="mr-4 w-full lg:w-3/5">
<orderComponent :items="info.Order" title="订单" />
@ -429,7 +478,7 @@ watch(
<div class="w-full lg:w-2/5">
<WorkbenchDetail :items="projectItems" class="mt-5 lg:mt-0" title="玩家详情">
<template #areaid> {{ info.AreaId }}</template>
<template #charge> <b>$</b>{{ info.Charge.toFixed(2) }}</template>
<template #charge> <b>$</b>{{ chargeDisplay }}</template>
<template #RegisterTime> {{ info.RegisterTime }}</template>
<template #logintime> {{ info.LoginTime }}</template>
<template #Cumulative>{{ info.Cumulative }}</template>

View File

@ -99,39 +99,24 @@ const formOptions: VbenFormProps = {
component: 'DatePicker',
defaultValue: startDate,
componentProps: {
format: 'YYYY-MM-DD',
showTime: true,
valueFormat: 'YYYY-MM-DD HH:mm:ss',
},
fieldName: 'StartTime',
label: '开始时间',
formItemClass: 'col-start-1',
},
{
component: 'TimePicker',
componentProps: {
placeholder: '时间',
},
fieldName: 'StartTime',
label: '--',
},
{
component: 'DatePicker',
defaultValue: endDate,
componentProps: {
format: 'YYYY-MM-DD',
showTime: true,
valueFormat: 'YYYY-MM-DD HH:mm:ss',
},
fieldName: 'EndTime',
label: '结束时间',
},
{
component: 'TimePicker',
componentProps: {
placeholder: '时间',
},
fieldName: 'EndTime',
label: '--',
}
],
//
showCollapseButton: true,
@ -245,13 +230,13 @@ function getTagColor(online: string): string {
</script>
<template>
<Page auto-content-height>
<Page auto-content-height class="h-[800px]">
<Grid>
<template #online="{ row }">
<Tag :color="getTagColor(row.Online)">{{ row.Online }}</Tag>
</template>
</Grid>
<userModal class="w-[100%]" />
<userModal class="w-[98%]" />
</Page>
</template>

View File

@ -45,11 +45,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
<PopoverTrigger>
<slot name="trigger"></slot>
<PopoverContent
:class="contentClass"
class="side-content z-[1000]"
v-bind="contentProps"
>
<PopoverContent :class="contentClass" class="side-content z-[1000]" v-bind="contentProps">
<slot></slot>
</PopoverContent>
</PopoverTrigger>

View File

@ -86,26 +86,20 @@ onMounted(() => {
<template>
<div class="relative">
<div
v-if="
<div v-if="
description ||
$slots.description ||
title ||
$slots.title ||
$slots.extra
"
ref="headerRef"
:class="
cn(
" ref="headerRef" :class="cn(
'bg-card relative px-6 py-4',
headerClass,
fixedHeader
? 'border-border border-b transition-all duration-200'
: '',
)
"
:style="headerStyle"
>
" :style="headerStyle">
<slot name="title">
<div v-if="title" class="mb-2 flex text-lg font-semibold">
{{ title }}
@ -127,16 +121,11 @@ onMounted(() => {
<slot></slot>
</div>
<div
v-if="$slots.footer"
ref="footerRef"
:class="
cn(
<div v-if="$slots.footer" ref="footerRef" :class="cn(
footerClass,
'bg-card align-center absolute bottom-0 left-0 right-0 flex px-6 py-4',
)
"
>
">
<slot name="footer"></slot>
</div>
</div>

View File

@ -20,6 +20,7 @@ interface WorkbenchProjectItem {
}
interface WorkbenchTrendItem {
Id: number;
avatar: string;
content: string;
date: string;

View File

@ -2,4 +2,8 @@ export { setupVbenVxeTable } from './init';
export * from './use-vxe-grid';
export { default as VbenVxeGrid } from './use-vxe-grid.vue';
export type { VxeGridListeners, VxeGridProps } from 'vxe-table';
export type {
VxeGridListeners,
VxeGridProps,
VxeColumnPropTypes,
} from 'vxe-table';

File diff suppressed because it is too large Load Diff

View File

@ -176,8 +176,8 @@ catalog:
vue-i18n: ^10.0.5
vue-router: ^4.5.0
vue-tsc: ^2.1.10
vxe-pc-ui: ^4.3.14
vxe-table: ^4.9.14
vxe-pc-ui: ^4.10.18
vxe-table: ^4.17.10
watermark-js-plus: ^1.5.7
zod: ^3.23.8
zod-defaults: ^0.1.3