活动优化
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
e0d7b5c509
commit
b1383a7091
41
apps/web-antd/src/api/core/activity.ts
Normal file
41
apps/web-antd/src/api/core/activity.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import { requestClient } from '#/api/request';
|
||||||
|
|
||||||
|
export interface ActivityData {
|
||||||
|
id: number;
|
||||||
|
type: number;
|
||||||
|
title?: string;
|
||||||
|
mail_title?: string;
|
||||||
|
mail_content?: string;
|
||||||
|
start_time: number;
|
||||||
|
end_time: number;
|
||||||
|
level?: number;
|
||||||
|
cfg?: string;
|
||||||
|
extra?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ActivityListParam {
|
||||||
|
AppId : number;
|
||||||
|
ServerId: number;
|
||||||
|
PageSize: number;
|
||||||
|
CurrentPage: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EditActivityParam {
|
||||||
|
AppId : number;
|
||||||
|
Cfg : ActivityData;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export async function getActivityListApi(p:ActivityListParam) {
|
||||||
|
return requestClient.post<ActivityData[]>('/activity/list', p);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function editActivityApi(p: EditActivityParam) {
|
||||||
|
return requestClient.post('/activity/edit', p);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export async function addActivityApi(p: EditActivityParam) {
|
||||||
|
return requestClient.post('/activity/add', p);
|
||||||
|
}
|
||||||
|
|
||||||
@ -58,6 +58,7 @@ export interface UserLogInfo {
|
|||||||
ActLog?:actlog[];
|
ActLog?:actlog[];
|
||||||
MaxCharge?: number;
|
MaxCharge?: number;
|
||||||
FriendList?: friendRecord[];
|
FriendList?: friendRecord[];
|
||||||
|
AdWatch?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface actlog {
|
export interface actlog {
|
||||||
|
|||||||
@ -4,5 +4,5 @@ import type { copyUserParam } from '#/model/type';
|
|||||||
|
|
||||||
|
|
||||||
export async function copyUser(data:copyUserParam) {
|
export async function copyUser(data:copyUserParam) {
|
||||||
return requestClient.post('/operation/copyUser', data);
|
return requestClient.post('/operation/copyUser', data, {timeout: 120000});
|
||||||
}
|
}
|
||||||
@ -16,6 +16,8 @@ export interface UserListParam {
|
|||||||
StartTime?: number;
|
StartTime?: number;
|
||||||
EndTime?: number;
|
EndTime?: number;
|
||||||
Nickname?: string;
|
Nickname?: string;
|
||||||
|
Username?: string;
|
||||||
|
DeviceId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -56,7 +56,8 @@
|
|||||||
"mail": "邮件管理",
|
"mail": "邮件管理",
|
||||||
"order": "订单管理",
|
"order": "订单管理",
|
||||||
"language": "翻译管理",
|
"language": "翻译管理",
|
||||||
"copyUser": "用户数据复制"
|
"copyUser": "用户数据复制",
|
||||||
|
"activity": "活动管理"
|
||||||
},
|
},
|
||||||
"server":{
|
"server":{
|
||||||
"merge_pet_test":"测试服",
|
"merge_pet_test":"测试服",
|
||||||
|
|||||||
@ -43,7 +43,7 @@ const routes: RouteRecordRaw[] = [
|
|||||||
affixTab: false,
|
affixTab: false,
|
||||||
icon: 'lucide:app-window',
|
icon: 'lucide:app-window',
|
||||||
title: $t('page.dashboard.app-list'),
|
title: $t('page.dashboard.app-list'),
|
||||||
authority: ['super', 'admin'],
|
authority: ['super'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -54,7 +54,7 @@ const routes: RouteRecordRaw[] = [
|
|||||||
affixTab: false,
|
affixTab: false,
|
||||||
icon: 'lucide:server',
|
icon: 'lucide:server',
|
||||||
title: $t('page.dashboard.node-list'),
|
title: $t('page.dashboard.node-list'),
|
||||||
authority: ['super', 'admin'],
|
authority: ['super'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -65,7 +65,7 @@ const routes: RouteRecordRaw[] = [
|
|||||||
affixTab: false,
|
affixTab: false,
|
||||||
icon: 'lucide:database',
|
icon: 'lucide:database',
|
||||||
title: $t('page.dashboard.mysql-list'),
|
title: $t('page.dashboard.mysql-list'),
|
||||||
authority: ['super', 'admin'],
|
authority: ['super'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@ -55,6 +55,16 @@ const routes: RouteRecordRaw[] = [
|
|||||||
icon: 'lets-icons:order',
|
icon: 'lets-icons:order',
|
||||||
title: $t('page.operation.order'),
|
title: $t('page.operation.order'),
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Activity',
|
||||||
|
path: '/activity',
|
||||||
|
component: () => import('#/views/operation/activity/index.vue'),
|
||||||
|
meta: {
|
||||||
|
affixTab: true,
|
||||||
|
icon: 'lets-icons:order',
|
||||||
|
title: $t('page.operation.activity'),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@ -33,6 +33,7 @@ const routes: RouteRecordRaw[] = [
|
|||||||
affixTab: true,
|
affixTab: true,
|
||||||
icon: 'solar:stars-bold',
|
icon: 'solar:stars-bold',
|
||||||
title: $t('page.userlog.assetlog'),
|
title: $t('page.userlog.assetlog'),
|
||||||
|
authority: ['super'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -43,6 +44,7 @@ const routes: RouteRecordRaw[] = [
|
|||||||
affixTab: true,
|
affixTab: true,
|
||||||
icon: 'lucide:apple',
|
icon: 'lucide:apple',
|
||||||
title: $t('page.userlog.eventlog'),
|
title: $t('page.userlog.eventlog'),
|
||||||
|
authority: ['super'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -53,9 +55,9 @@ const routes: RouteRecordRaw[] = [
|
|||||||
affixTab: true,
|
affixTab: true,
|
||||||
icon: 'solar:chat-round-money-bold',
|
icon: 'solar:chat-round-money-bold',
|
||||||
title: $t('page.userlog.orderlog'),
|
title: $t('page.userlog.orderlog'),
|
||||||
|
authority: ['super'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
8594
apps/web-antd/src/store/Item.json
Normal file
8594
apps/web-antd/src/store/Item.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -27,3 +27,13 @@ export const triggerTypeData: Record<string, string> = {
|
|||||||
'Order': '订单触发器',
|
'Order': '订单触发器',
|
||||||
'Lv': '等级触发器',
|
'Lv': '等级触发器',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const activityTypeData: Record<number, string> = {
|
||||||
|
1: '挖矿活动',
|
||||||
|
2: '猜颜色',
|
||||||
|
3: '赛跑活动',
|
||||||
|
4: '限时特惠礼包',
|
||||||
|
5: '买一赠一礼包',
|
||||||
|
6: '超值加购礼包',
|
||||||
|
7: '好友合作活动',
|
||||||
|
};
|
||||||
@ -80,9 +80,26 @@ export const getItemUrl = (itemId: number): string => {
|
|||||||
switch (itemId) {
|
switch (itemId) {
|
||||||
case 100001:
|
case 100001:
|
||||||
return './Assets/Art_SubModule/Art_Resource/Art_UISprites/Shop/Big/shop_energy_LV1.png';
|
return './Assets/Art_SubModule/Art_Resource/Art_UISprites/Shop/Big/shop_energy_LV1.png';
|
||||||
|
case 100002:
|
||||||
|
return './Assets/GameMain/UI/UISprites/MergeObj/Packed/Other/Production_star_LV1.png';
|
||||||
case 100003:
|
case 100003:
|
||||||
return './Assets/Art_SubModule/Art_Resource/Art_UISprites/Shop/Big/shop_diamond_LV2.png';
|
return './Assets/Art_SubModule/Art_Resource/Art_UISprites/Shop/Big/shop_diamond_LV2.png';
|
||||||
default:
|
default:
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const formatItems = (items: string) => {
|
||||||
|
try {
|
||||||
|
const itemList = JSON.parse(items);
|
||||||
|
const r = itemList.map((item: { Id: number; Num: number }) => ({
|
||||||
|
...item,
|
||||||
|
url: getItemUrl(item.Id),
|
||||||
|
}));
|
||||||
|
return r;
|
||||||
|
} catch (e) {
|
||||||
|
//console.error('Failed to parse items:', e);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,6 +5,8 @@ import { restartServer, getServerListApi, reloadServer } from '#/api/core/server
|
|||||||
import AddServerModal from './addServer.vue'
|
import AddServerModal from './addServer.vue'
|
||||||
import EditServer from './editServer.vue';
|
import EditServer from './editServer.vue';
|
||||||
import { useVbenModal } from '@vben/common-ui'
|
import { useVbenModal } from '@vben/common-ui'
|
||||||
|
import { useAccess } from '@vben/access';
|
||||||
|
const { hasAccessByRoles } = useAccess();
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'AppList',
|
name: 'AppList',
|
||||||
@ -20,6 +22,9 @@ const [editServerM, editServerApi] = useVbenModal({
|
|||||||
connectedComponent: EditServer,
|
connectedComponent: EditServer,
|
||||||
});
|
});
|
||||||
async function editServer(Server: ServerData) {
|
async function editServer(Server: ServerData) {
|
||||||
|
if (!hasAccessByRoles(['super'])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
editServerApi.setData(Server);
|
editServerApi.setData(Server);
|
||||||
editServerApi.open();
|
editServerApi.open();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import type { AppData, ServerData } from '#/api/core/server';
|
|||||||
import { useVbenModal } from '@vben/common-ui'
|
import { useVbenModal } from '@vben/common-ui'
|
||||||
import { ref, onMounted } from 'vue';
|
import { ref, onMounted } from 'vue';
|
||||||
import addServerModal from './addServer.vue';
|
import addServerModal from './addServer.vue';
|
||||||
|
import { AccessControl } from '@vben/access';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { $t } from '#/locales'
|
import { $t } from '#/locales'
|
||||||
const appId = ref<number>(1);
|
const appId = ref<number>(1);
|
||||||
@ -124,10 +125,10 @@ onMounted(async () => {
|
|||||||
]);
|
]);
|
||||||
const serverResponse = await getServerListApi({ AppId: app.AppId });
|
const serverResponse = await getServerListApi({ AppId: app.AppId });
|
||||||
ServerList.value = Array.isArray(serverResponse) ? serverResponse : [];
|
ServerList.value = Array.isArray(serverResponse) ? serverResponse : [];
|
||||||
setInterval(async () => {
|
// setInterval(async () => {
|
||||||
const serverResponse = await getServerListApi({ AppId: appId.value });
|
// const serverResponse = await getServerListApi({ AppId: appId.value });
|
||||||
ServerList.value = Array.isArray(serverResponse) ? serverResponse : [];
|
// ServerList.value = Array.isArray(serverResponse) ? serverResponse : [];
|
||||||
}, 60000);
|
// }, 60000);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
appList.value = serverList;
|
appList.value = serverList;
|
||||||
//console.log(e);
|
//console.log(e);
|
||||||
@ -227,10 +228,14 @@ async function updateReview() {
|
|||||||
<Card class="mb-5" title="服务器操作">
|
<Card class="mb-5" title="服务器操作">
|
||||||
<BaseForm />
|
<BaseForm />
|
||||||
<Space>
|
<Space>
|
||||||
<Button type="primary" @click="addServer">新增</Button>
|
<AccessControl :codes="['super']" type="role">
|
||||||
<Button type="primary" @click="confirmUpdate" :loading="reload"> 更新正式环境 </Button>
|
<Button type="primary" @click="addServer">新增</Button>
|
||||||
<Button type="primary" @click="confirmUpdateReview" :loading="reloadReview"> 更新review环境 </Button>
|
</AccessControl>
|
||||||
<Button type="primary"> 更新配置 </Button>
|
<Button type="primary" @click="confirmUpdate" :loading="reload"> 更新游戏文件 </Button>
|
||||||
|
<AccessControl :codes="['super']" type="role">
|
||||||
|
<Button type="primary" @click="confirmUpdateReview" :loading="reloadReview"> 更新review环境 </Button>
|
||||||
|
</AccessControl>
|
||||||
|
<!-- <Button type="primary"> 更新配置 </Button> -->
|
||||||
</Space>
|
</Space>
|
||||||
</Card>
|
</Card>
|
||||||
<div class="p-5">
|
<div class="p-5">
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { message } from "ant-design-vue";
|
||||||
import { useVbenForm, useVbenModal } from '@vben/common-ui';
|
import { useVbenForm, useVbenModal } from '@vben/common-ui';
|
||||||
import type { languageType } from '#/model/type';
|
import type { languageType } from '#/model/type';
|
||||||
import type { VxeGridProps } from '#/adapter/vxe-table';
|
import type { VxeGridProps } from '#/adapter/vxe-table';
|
||||||
@ -21,6 +22,7 @@ const gridOptions: VxeGridProps<languageType> = {
|
|||||||
title: 'zh_CN',
|
title: 'zh_CN',
|
||||||
},
|
},
|
||||||
{ editRender: { name: 'input' }, field: 'pt_BR', title: 'pt_BR' },
|
{ editRender: { name: 'input' }, field: 'pt_BR', title: 'pt_BR' },
|
||||||
|
{ editRender: { name: 'input' }, field: 'es_LATAM', title: 'es_LATAM' },
|
||||||
],
|
],
|
||||||
data: ld,
|
data: ld,
|
||||||
pagerConfig: {
|
pagerConfig: {
|
||||||
@ -44,7 +46,17 @@ const [Form] = useVbenForm({
|
|||||||
handleSubmit: async (formValues) => {
|
handleSubmit: async (formValues) => {
|
||||||
// 调用添加语言接口
|
// 调用添加语言接口
|
||||||
try {
|
try {
|
||||||
await addLanguageList(ld);
|
const response = await addLanguageList(ld);
|
||||||
|
if (response) {
|
||||||
|
// 处理成功响应,例如显示成功消息或刷新数据
|
||||||
|
message.success('Languages added successfully');
|
||||||
|
console.log('Languages added successfully:', response);
|
||||||
|
modalApi.close();
|
||||||
|
} else {
|
||||||
|
// 处理错误响应,例如显示错误消息
|
||||||
|
message.error('Failed to add languages');
|
||||||
|
console.error('Failed to add languages:', response);
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error adding languages:', error);
|
console.error('Error adding languages:', error);
|
||||||
}
|
}
|
||||||
@ -57,7 +69,7 @@ const [Form] = useVbenForm({
|
|||||||
label: $t('page.language.newLineContent'),
|
label: $t('page.language.newLineContent'),
|
||||||
componentProps: {
|
componentProps: {
|
||||||
disabled: false,
|
disabled: false,
|
||||||
placeholder: 'key | en_US | zh_CN| pt_BR record per line',
|
placeholder: 'key | en_US | zh_CN| pt_BR| es_LATAM record per line',
|
||||||
type: 'textarea',
|
type: 'textarea',
|
||||||
rows: 8,
|
rows: 8,
|
||||||
onChange: (e: Event) => {
|
onChange: (e: Event) => {
|
||||||
@ -73,6 +85,7 @@ const [Form] = useVbenForm({
|
|||||||
en_US: parts[1] || '',
|
en_US: parts[1] || '',
|
||||||
zh_CN: parts[2] || '',
|
zh_CN: parts[2] || '',
|
||||||
pt_BR: parts[3] || '',
|
pt_BR: parts[3] || '',
|
||||||
|
es_LATAM: parts[4] || '',
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
ld = ld.concat(newData);
|
ld = ld.concat(newData);
|
||||||
|
|||||||
@ -265,14 +265,14 @@ const gridOptions: VxeGridProps<languageType> = {
|
|||||||
title: 'Image',
|
title: 'Image',
|
||||||
width: 60,
|
width: 60,
|
||||||
},
|
},
|
||||||
{ editRender: { name: 'input' }, field: 'en_US', title: 'en_US', filters: [{ data: "" }], filterRender: { name: "input" }, visible: en_USVisible },
|
{ editRender: { name: 'input' }, field: 'en_US', title: 'en_US', filters: [{ data: "" }], filterRender: { name: "input" }, visible: en_USVisible, className:'en-us-column' },
|
||||||
{
|
{
|
||||||
editRender: { name: 'input' },
|
editRender: { name: 'input' },
|
||||||
field: 'zh_CN',
|
field: 'zh_CN',
|
||||||
title: 'zh_CN', filters: [{ data: "" }], filterRender: { name: "input" }, visible: chineseVisible
|
title: 'zh_CN', filters: [{ data: "" }], filterRender: { name: "input" }, visible: chineseVisible, className: 'zh-cn-column'
|
||||||
},
|
},
|
||||||
{ editRender: { name: 'input' }, field: 'pt_BR', title: 'pt_BR', filters: [{ data: "" }], filterRender: { name: "input" }, visible: pt_BRVisible },
|
{ editRender: { name: 'input' }, field: 'pt_BR', title: 'pt_BR', filters: [{ data: "" }], filterRender: { name: "input" }, visible: pt_BRVisible, className: 'en-us-column' },
|
||||||
{ editRender: { name: 'input' }, field: 'es_LATAM', title: 'es_LATAM', filters: [{ data: "" }], filterRender: { name: "input" }, visible: es_LATAMVisible },
|
{ editRender: { name: 'input' }, field: 'es_LATAM', title: 'es_LATAM', filters: [{ data: "" }], filterRender: { name: "input" }, visible: es_LATAMVisible, className: 'en-us-column' },
|
||||||
{ slots: { default: 'glossary' }, title: 'Glossary', width: 150 },
|
{ slots: { default: 'glossary' }, title: 'Glossary', width: 150 },
|
||||||
{ slots: { default: 'action' }, title: $t('page.common.action'), width: 150, visible: actionVisible },
|
{ slots: { default: 'action' }, title: $t('page.common.action'), width: 150, visible: actionVisible },
|
||||||
],
|
],
|
||||||
@ -452,7 +452,12 @@ function getGlossary(row: languageType) {
|
|||||||
.row-green {
|
.row-green {
|
||||||
background-color: #0ea800;
|
background-color: #0ea800;
|
||||||
}
|
}
|
||||||
|
.zh-cn-column {
|
||||||
|
font-family: "猫啃什锦黑", sans-serif;
|
||||||
|
}
|
||||||
|
.en-us-column {
|
||||||
|
font-family: "Poetsen One","Arial", "Helvetica", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", sans-serif;
|
||||||
|
}
|
||||||
.row-yellow {
|
.row-yellow {
|
||||||
background-color: #c9bc04;
|
background-color: #c9bc04;
|
||||||
}
|
}
|
||||||
|
|||||||
176
apps/web-antd/src/views/operation/activity/activity-add.vue
Normal file
176
apps/web-antd/src/views/operation/activity/activity-add.vue
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { useVbenForm, useVbenModal } from '@vben/common-ui';
|
||||||
|
import { Image } from "ant-design-vue";
|
||||||
|
import { Tag } from 'ant-design-vue';
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { addActivityApi } from '#/api/core/activity';
|
||||||
|
import type { EditActivityParam } from '#/api/core/activity';
|
||||||
|
import { getUnixTime } from '#/store/util';
|
||||||
|
interface MailItem {
|
||||||
|
Id: string | number;
|
||||||
|
Num: number;
|
||||||
|
url?: string;
|
||||||
|
}
|
||||||
|
let items = ref<MailItem[]>([]);
|
||||||
|
defineOptions({
|
||||||
|
name: 'DetailMailModal',
|
||||||
|
});
|
||||||
|
const [Form, FormApi] = useVbenForm({
|
||||||
|
// 所有表单项共用,可单独在表单内覆盖
|
||||||
|
commonConfig: {
|
||||||
|
// 所有表单项
|
||||||
|
componentProps: {
|
||||||
|
class: 'w-full h-full',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// 使用 tailwindcss grid布局
|
||||||
|
// 提交函数
|
||||||
|
// 垂直布局,label和input在不同行,值为vertical
|
||||||
|
layout: 'horizontal',
|
||||||
|
showDefaultActions: false,
|
||||||
|
// 水平布局,label和input在同一行
|
||||||
|
schema: [
|
||||||
|
{
|
||||||
|
component: 'Select',
|
||||||
|
fieldName: 'type',
|
||||||
|
label: '活动类型',
|
||||||
|
componentProps: {
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: '挖矿活动',
|
||||||
|
value: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '猜颜色',
|
||||||
|
value: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '赛跑活动',
|
||||||
|
value: 3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '限时特惠礼包',
|
||||||
|
value: 4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '买一赠一礼包',
|
||||||
|
value: 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '超值加购礼包',
|
||||||
|
value: 6,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '好友合作活动',
|
||||||
|
value: 7,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: 'Input',
|
||||||
|
fieldName: 'level',
|
||||||
|
label: '解锁等级',
|
||||||
|
componentProps: {
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: 'DatePicker',
|
||||||
|
fieldName: 'start_time',
|
||||||
|
label: '开始时间',
|
||||||
|
componentProps: {
|
||||||
|
showTime: true,
|
||||||
|
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: 'DatePicker',
|
||||||
|
fieldName: 'end_time',
|
||||||
|
label: '结束时间',
|
||||||
|
componentProps: {
|
||||||
|
showTime: true,
|
||||||
|
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: 'Input',
|
||||||
|
fieldName: 'title',
|
||||||
|
label: '活动标题',
|
||||||
|
rules: 'required',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: 'Input',
|
||||||
|
fieldName: 'mail_title',
|
||||||
|
label: '回收邮件标题',
|
||||||
|
rules: 'required',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: 'Input',
|
||||||
|
fieldName: 'mail_content',
|
||||||
|
label: '回收邮件内容',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: 'Textarea',
|
||||||
|
fieldName: 'cfg',
|
||||||
|
label: '配置',
|
||||||
|
defaultValue: '{}',
|
||||||
|
componentProps: {
|
||||||
|
type: 'textarea',
|
||||||
|
rows: 8,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: 'Textarea',
|
||||||
|
defaultValue: '{}',
|
||||||
|
fieldName: 'extra',
|
||||||
|
label: '额外配置',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const [Modal, modalApi] = useVbenModal({
|
||||||
|
confirmText: '提交',
|
||||||
|
onConfirm: async () => {
|
||||||
|
const values = await FormApi.getValues();
|
||||||
|
const mMdata = modalApi.getData();
|
||||||
|
const cfgjson = JSON.parse(values.cfg);
|
||||||
|
const params: EditActivityParam = {
|
||||||
|
AppId: mMdata.AppId,
|
||||||
|
Cfg: {
|
||||||
|
id: 0,
|
||||||
|
type: values.type,
|
||||||
|
start_time: values.start_time ? getUnixTime(values.start_time) : 0,
|
||||||
|
end_time: values.end_time ? getUnixTime(values.end_time) : 0,
|
||||||
|
title: values.title,
|
||||||
|
level: values.level,
|
||||||
|
mail_title: values.mail_title,
|
||||||
|
mail_content: values.mail_content,
|
||||||
|
cfg: JSON.stringify(cfgjson),
|
||||||
|
extra: values.extra,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
await addActivityApi(params);
|
||||||
|
modalApi.close();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<Modal :width="800" title="邮件详情">
|
||||||
|
<Form>
|
||||||
|
<template #items>
|
||||||
|
<div class="flex flex-wrap items-center justify-center">
|
||||||
|
<div v-for="item in items" :key="item.Id" class="flex items-center gap-1">
|
||||||
|
<template v-if="item.url">
|
||||||
|
<Image :src="item.url" width="30px" />
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<Tag class="w-[45px] h-[30px] flex items-center justify-center text-xs">
|
||||||
|
{{ item.Id }}
|
||||||
|
</Tag>
|
||||||
|
</template>
|
||||||
|
<span>x{{ item.Num }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</Form>
|
||||||
|
</Modal>
|
||||||
|
</template>
|
||||||
184
apps/web-antd/src/views/operation/activity/activity-detail.vue
Normal file
184
apps/web-antd/src/views/operation/activity/activity-detail.vue
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { useVbenForm, useVbenModal } from '@vben/common-ui';
|
||||||
|
import { Image, message } from "ant-design-vue";
|
||||||
|
import { formatItems } from '#/store/util';
|
||||||
|
import { activityTypeData } from '#/store/order';
|
||||||
|
import { Tag } from 'ant-design-vue';
|
||||||
|
import { ref } from "vue";
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import { editActivityApi } from '#/api/core/activity';
|
||||||
|
import type { EditActivityParam } from '#/api/core/activity';
|
||||||
|
import { getUnixTime } from '#/store/util';
|
||||||
|
interface MailItem {
|
||||||
|
Id: string | number;
|
||||||
|
Num: number;
|
||||||
|
url?: string;
|
||||||
|
}
|
||||||
|
let items = ref<MailItem[]>([]);
|
||||||
|
defineOptions({
|
||||||
|
name: 'DetailMailModal',
|
||||||
|
});
|
||||||
|
const [Form, FormApi] = useVbenForm({
|
||||||
|
// 所有表单项共用,可单独在表单内覆盖
|
||||||
|
commonConfig: {
|
||||||
|
// 所有表单项
|
||||||
|
componentProps: {
|
||||||
|
class: 'w-full h-full',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// 使用 tailwindcss grid布局
|
||||||
|
// 提交函数
|
||||||
|
// 垂直布局,label和input在不同行,值为vertical
|
||||||
|
layout: 'horizontal',
|
||||||
|
showDefaultActions: false,
|
||||||
|
// 水平布局,label和input在同一行
|
||||||
|
schema: [
|
||||||
|
{
|
||||||
|
component: 'Input',
|
||||||
|
fieldName: 'id',
|
||||||
|
label: 'Id',
|
||||||
|
componentProps: {
|
||||||
|
disabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: 'Input',
|
||||||
|
fieldName: 'type',
|
||||||
|
label: '活动类型',
|
||||||
|
componentProps: {
|
||||||
|
disabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: 'Input',
|
||||||
|
fieldName: 'level',
|
||||||
|
label: '解锁等级',
|
||||||
|
componentProps: {
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: 'DatePicker',
|
||||||
|
fieldName: 'start_time',
|
||||||
|
label: '开始时间(北京时间)',
|
||||||
|
componentProps: {
|
||||||
|
ariaLabel: 'start_time',
|
||||||
|
showTime: true,
|
||||||
|
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: 'DatePicker',
|
||||||
|
fieldName: 'end_time',
|
||||||
|
label: '结束时间(北京时间)',
|
||||||
|
componentProps: {
|
||||||
|
showTime: true,
|
||||||
|
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: 'Input',
|
||||||
|
fieldName: 'title',
|
||||||
|
label: '活动标题',
|
||||||
|
rules: 'required',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: 'Input',
|
||||||
|
fieldName: 'mail_title',
|
||||||
|
label: '回收邮件标题',
|
||||||
|
rules: 'required',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: 'Input',
|
||||||
|
fieldName: 'mail_content',
|
||||||
|
label: '回收邮件内容',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: 'Textarea',
|
||||||
|
fieldName: 'cfg',
|
||||||
|
label: '配置',
|
||||||
|
componentProps: {
|
||||||
|
type: 'textarea',
|
||||||
|
rows: 8,
|
||||||
|
},
|
||||||
|
rules: 'required',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: 'Textarea',
|
||||||
|
fieldName: 'extra',
|
||||||
|
label: '额外配置',
|
||||||
|
rules: 'required',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const [Modal, modalApi] = useVbenModal({
|
||||||
|
confirmText: '提交',
|
||||||
|
onOpened: async () => {
|
||||||
|
const mMdata = modalApi.getData();
|
||||||
|
const modalData = mMdata.cfg || {};
|
||||||
|
const st = modalData.start_time ? dayjs(modalData.start_time*1000) : null;
|
||||||
|
const et = modalData.end_time ? dayjs(modalData.end_time*1000) : null;
|
||||||
|
FormApi.setValues({
|
||||||
|
id: modalData.id,
|
||||||
|
type: activityTypeData[modalData.type],
|
||||||
|
start_time: st,
|
||||||
|
end_time: et,
|
||||||
|
title: modalData.title,
|
||||||
|
level: modalData.level,
|
||||||
|
mail_title: modalData.mail_title,
|
||||||
|
mail_content: modalData.mail_content,
|
||||||
|
cfg: modalData.cfg,
|
||||||
|
extra: modalData.extra,
|
||||||
|
});
|
||||||
|
items.value = formatItems(modalData.items);
|
||||||
|
},
|
||||||
|
onConfirm: async () => {
|
||||||
|
const values = await FormApi.getValues();
|
||||||
|
const mMdata = modalApi.getData();
|
||||||
|
const modalData = mMdata.cfg || {};
|
||||||
|
const cfgjson = JSON.parse(values.cfg);
|
||||||
|
const level: number = Number(values.level) || 0;
|
||||||
|
const params: EditActivityParam = {
|
||||||
|
AppId: mMdata.AppId,
|
||||||
|
Cfg: {
|
||||||
|
id: modalData.id,
|
||||||
|
type: modalData.type,
|
||||||
|
start_time: values.start_time ? getUnixTime(values.start_time) : 0,
|
||||||
|
end_time: values.end_time ? getUnixTime(values.end_time) : 0,
|
||||||
|
title: values.title,
|
||||||
|
level: level,
|
||||||
|
mail_title: values.mail_title,
|
||||||
|
mail_content: values.mail_content,
|
||||||
|
cfg: JSON.stringify(cfgjson),
|
||||||
|
extra: values.extra,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const response = await editActivityApi(params);
|
||||||
|
if (response) {
|
||||||
|
// 这里可以根据实际情况进行提示
|
||||||
|
message.success('活动更新成功');
|
||||||
|
}
|
||||||
|
modalApi.close();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<Modal :width="800" title="邮件详情">
|
||||||
|
<Form>
|
||||||
|
<template #items>
|
||||||
|
<div class="flex flex-wrap items-center justify-center">
|
||||||
|
<div v-for="item in items" :key="item.Id" class="flex items-center gap-1">
|
||||||
|
<template v-if="item.url">
|
||||||
|
<Image :src="item.url" width="30px" />
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<Tag class="w-[45px] h-[30px] flex items-center justify-center text-xs">
|
||||||
|
{{ item.Id }}
|
||||||
|
</Tag>
|
||||||
|
</template>
|
||||||
|
<span>x{{ item.Num }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</Form>
|
||||||
|
</Modal>
|
||||||
|
</template>
|
||||||
187
apps/web-antd/src/views/operation/activity/activity-table.vue
Normal file
187
apps/web-antd/src/views/operation/activity/activity-table.vue
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { Page } from '@vben/common-ui';
|
||||||
|
import { Button, Card, Space } from 'ant-design-vue';
|
||||||
|
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||||
|
import type { VxeGridListeners, VxeGridProps } from '#/adapter/vxe-table';
|
||||||
|
import type { VbenFormProps } from '#/adapter/form';
|
||||||
|
import type { ActivityData } from '#/api/core/activity';
|
||||||
|
import { getServerListApi, getAppListApi } from '#/api/core/server';
|
||||||
|
import { getActivityListApi } from '#/api/core/activity';
|
||||||
|
import type { AppData, ServerData } from '#/api/core/server';
|
||||||
|
import { useVbenModal } from '@vben/common-ui';
|
||||||
|
import { onMounted, ref } from 'vue';
|
||||||
|
import AddActivityModal from './activity-add.vue';
|
||||||
|
import DetailActivityModal from './activity-detail.vue';
|
||||||
|
import { activityTypeData } from '#/store/order';
|
||||||
|
import { $t } from '#/locales'
|
||||||
|
|
||||||
|
const appList = ref<AppData[]>([]);
|
||||||
|
const ServerList = ref<ServerData[]>([]);
|
||||||
|
const formOptions: VbenFormProps = {
|
||||||
|
// 默认展开
|
||||||
|
collapsed: false,
|
||||||
|
schema: [
|
||||||
|
{
|
||||||
|
component: 'Select',
|
||||||
|
defaultValue: 1,
|
||||||
|
componentProps: {
|
||||||
|
onChange: async (value: number) => {
|
||||||
|
const serverResponse = await getServerListApi({
|
||||||
|
AppId: value,
|
||||||
|
Type: 1,
|
||||||
|
});
|
||||||
|
ServerList.value = Array.isArray(serverResponse)
|
||||||
|
? serverResponse
|
||||||
|
: [];
|
||||||
|
GridApi.formApi.updateSchema([
|
||||||
|
{
|
||||||
|
component: 'Select',
|
||||||
|
componentProps: {
|
||||||
|
options: ServerList.value.map((item) => ({
|
||||||
|
label: item.ServerName,
|
||||||
|
value: item.ServerId,
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
fieldName: 'ServerId',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
filterOption: true,
|
||||||
|
options: [],
|
||||||
|
placeholder: '请选择',
|
||||||
|
showSearch: true,
|
||||||
|
},
|
||||||
|
fieldName: 'AppId',
|
||||||
|
label: 'APP:',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
// 控制表单是否显示折叠按钮
|
||||||
|
showCollapseButton: true,
|
||||||
|
submitButtonOptions: {
|
||||||
|
content: '查询',
|
||||||
|
},
|
||||||
|
// 是否在字段值改变时提交表单
|
||||||
|
submitOnChange: false,
|
||||||
|
// 按下回车时是否提交表单
|
||||||
|
submitOnEnter: false,
|
||||||
|
};
|
||||||
|
const gridOptions: VxeGridProps<ActivityData> = {
|
||||||
|
columns: [
|
||||||
|
{ field: 'id', title: 'id' },
|
||||||
|
{ field: 'type', title: '活动类型', formatter: ({ cellValue }) => activityTypeData[cellValue] || cellValue },
|
||||||
|
{ field: 'level',title: '开启等级',},
|
||||||
|
{ field: 'start_time', title: '开启时间', formatter: ({ cellValue }) => new Date(cellValue * 1000).toLocaleString(), },
|
||||||
|
{ field: 'end_time', title: '结束时间', formatter: ({ cellValue }) => new Date(cellValue * 1000).toLocaleString(), },
|
||||||
|
],
|
||||||
|
height: 'auto',
|
||||||
|
pagerConfig: {},
|
||||||
|
proxyConfig: {
|
||||||
|
response: {
|
||||||
|
total: 'total',
|
||||||
|
result: 'data',
|
||||||
|
},
|
||||||
|
ajax: {
|
||||||
|
query: async ({ page }, formValues) => {
|
||||||
|
let AppId = parseInt(formValues.AppId, 10);
|
||||||
|
const response = await getActivityListApi({
|
||||||
|
AppId: AppId,
|
||||||
|
ServerId: formValues.ServerId,
|
||||||
|
PageSize: page.pageSize,
|
||||||
|
CurrentPage: page.currentPage,
|
||||||
|
});
|
||||||
|
return response;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
showOverflow: false,
|
||||||
|
rowConfig: {
|
||||||
|
isHover: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const gridEvents: VxeGridListeners<ActivityData> = {
|
||||||
|
cellClick: async ({ row }) => {
|
||||||
|
const Value = await GridApi.formApi.getValues();
|
||||||
|
DetailActivityApi.setData({AppId:Value.AppId, cfg:row});
|
||||||
|
DetailActivityApi.open();
|
||||||
|
// message.info(`cell-click: ${row.title}`);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const [Grid, GridApi] = useVbenVxeGrid({
|
||||||
|
gridEvents,
|
||||||
|
formOptions,
|
||||||
|
gridOptions,
|
||||||
|
});
|
||||||
|
const [AddActivityM, AddActivityApi] = useVbenModal({
|
||||||
|
connectedComponent: AddActivityModal,
|
||||||
|
onClosed: async () => {
|
||||||
|
AddActivityApi.close();
|
||||||
|
GridApi.query();
|
||||||
|
//console.log("close")
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const [DetailActivityM, DetailActivityApi] = useVbenModal({
|
||||||
|
connectedComponent: DetailActivityModal,
|
||||||
|
});
|
||||||
|
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: $t('page.server.' + item.AppName),
|
||||||
|
value: item.AppId,
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
fieldName: 'AppId',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const serverResponse = await getServerListApi({
|
||||||
|
AppId: app.AppId,
|
||||||
|
Type: 1,
|
||||||
|
});
|
||||||
|
ServerList.value = Array.isArray(serverResponse) ? serverResponse : [];
|
||||||
|
GridApi.formApi.updateSchema([
|
||||||
|
{
|
||||||
|
component: 'Select',
|
||||||
|
componentProps: {
|
||||||
|
options: ServerList.value.map((item) => ({
|
||||||
|
label: item.ServerName,
|
||||||
|
value: item.ServerId,
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
fieldName: 'ServerId',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
} catch (e) {
|
||||||
|
appList.value = [];
|
||||||
|
//console.log(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
async function addActivity() {
|
||||||
|
//console.log('addActivity');
|
||||||
|
const Value = await GridApi.formApi.getValues();
|
||||||
|
AddActivityApi.setData({ AppId: Value.AppId, ServerId: Value.ServerId });
|
||||||
|
AddActivityApi.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Page auto-content-height class="h-[800px]">
|
||||||
|
<AddActivityM class="w-[50%]" />
|
||||||
|
<DetailActivityM class="w-[50%]" />
|
||||||
|
<Card class="mb-5" title="活动操作">
|
||||||
|
<Space>
|
||||||
|
<Button @click="addActivity">新增活动</Button>
|
||||||
|
</Space>
|
||||||
|
</Card>
|
||||||
|
<Grid />
|
||||||
|
</Page>
|
||||||
|
</template>
|
||||||
12
apps/web-antd/src/views/operation/activity/index.vue
Normal file
12
apps/web-antd/src/views/operation/activity/index.vue
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
|
||||||
|
|
||||||
|
import AnalyticsVisitsTable from './activity-table.vue';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<template #table>
|
||||||
|
<AnalyticsVisitsTable />
|
||||||
|
</template>
|
||||||
|
|
||||||
258
apps/web-antd/src/views/operation/activity/mail-table.vue
Normal file
258
apps/web-antd/src/views/operation/activity/mail-table.vue
Normal file
@ -0,0 +1,258 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { Page } from '@vben/common-ui';
|
||||||
|
import { Button, Card, Space, Image, Tag } from 'ant-design-vue';
|
||||||
|
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||||
|
import type { VxeGridListeners, VxeGridProps } from '#/adapter/vxe-table';
|
||||||
|
import type { VbenFormProps } from '#/adapter/form';
|
||||||
|
import type { MailData } from '#/api/core/mail';
|
||||||
|
import { getServerListApi, getAppListApi } from '#/api/core/server';
|
||||||
|
import { getMailListApi, deleteMailApi } from '#/api/core/mail';
|
||||||
|
import type { AppData, ServerData } from '#/api/core/server';
|
||||||
|
import { useVbenModal } from '@vben/common-ui';
|
||||||
|
import { onMounted, ref } from 'vue';
|
||||||
|
import AddMailModal from './activity-add.vue';
|
||||||
|
import DetailMailModal from './activity-detail.vue';
|
||||||
|
import { getItemUrl } from '#/store/util';
|
||||||
|
const appList = ref<AppData[]>([]);
|
||||||
|
const ServerList = ref<ServerData[]>([]);
|
||||||
|
const formOptions: VbenFormProps = {
|
||||||
|
// 默认展开
|
||||||
|
collapsed: false,
|
||||||
|
schema: [
|
||||||
|
{
|
||||||
|
component: 'Select',
|
||||||
|
defaultValue: 1,
|
||||||
|
componentProps: {
|
||||||
|
onChange: async (value: number) => {
|
||||||
|
const serverResponse = await getServerListApi({
|
||||||
|
AppId: value,
|
||||||
|
Type: 1,
|
||||||
|
});
|
||||||
|
ServerList.value = Array.isArray(serverResponse)
|
||||||
|
? serverResponse
|
||||||
|
: [];
|
||||||
|
GridApi.formApi.updateSchema([
|
||||||
|
{
|
||||||
|
component: 'Select',
|
||||||
|
componentProps: {
|
||||||
|
options: ServerList.value.map((item) => ({
|
||||||
|
label: item.ServerName,
|
||||||
|
value: item.ServerId,
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
fieldName: 'ServerId',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
filterOption: true,
|
||||||
|
options: [],
|
||||||
|
placeholder: '请选择',
|
||||||
|
showSearch: true,
|
||||||
|
},
|
||||||
|
fieldName: 'AppId',
|
||||||
|
label: 'APP:',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: 'Select',
|
||||||
|
defaultValue: 1,
|
||||||
|
componentProps: {
|
||||||
|
options: [],
|
||||||
|
},
|
||||||
|
fieldName: 'ServerId',
|
||||||
|
label: '区服',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
// 控制表单是否显示折叠按钮
|
||||||
|
showCollapseButton: true,
|
||||||
|
submitButtonOptions: {
|
||||||
|
content: '查询',
|
||||||
|
},
|
||||||
|
// 是否在字段值改变时提交表单
|
||||||
|
submitOnChange: false,
|
||||||
|
// 按下回车时是否提交表单
|
||||||
|
submitOnEnter: false,
|
||||||
|
};
|
||||||
|
const gridOptions: VxeGridProps<MailData> = {
|
||||||
|
columns: [
|
||||||
|
{ field: 'mail_id', title: 'id' },
|
||||||
|
{ field: 'title', title: '邮件标题' },
|
||||||
|
// { field: 'title_en', title: '英文邮件标题' },
|
||||||
|
{ field: 'subtitle', title: '邮件副标题' },
|
||||||
|
// { field: 'subtitleEN', title: '英文邮件副标题' },
|
||||||
|
{ field: 'content', title: '邮件内容' },
|
||||||
|
// { field: 'content_en', title: '英文邮件内容' },
|
||||||
|
{ field: 'items', title: '道具', slots: { default: 'items' } },
|
||||||
|
{
|
||||||
|
field: 'start_time',
|
||||||
|
title: '开始时间',
|
||||||
|
formatter: ({ cellValue }) =>
|
||||||
|
cellValue ? new Date(cellValue * 1000).toLocaleString() : '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'mail_type',
|
||||||
|
title: '邮件类型',
|
||||||
|
formatter: ({ cellValue }) => (cellValue == 1 ? '普通邮件' : '节日邮件'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'send_type',
|
||||||
|
title: '邮件发送类型',
|
||||||
|
formatter: ({ cellValue }) => (cellValue == 1 ? '全服邮件' : '个人邮件'),
|
||||||
|
},
|
||||||
|
{ field: 'to_uids', title: '接收者' },
|
||||||
|
{ field: 'create_time', title: '创建时间' },
|
||||||
|
{ slots: { default: 'action' }, title: '操作', width: 100 },
|
||||||
|
],
|
||||||
|
height: 'auto',
|
||||||
|
pagerConfig: {},
|
||||||
|
proxyConfig: {
|
||||||
|
response: {
|
||||||
|
total: 'total',
|
||||||
|
result: 'data',
|
||||||
|
},
|
||||||
|
ajax: {
|
||||||
|
query: async ({ page }, formValues) => {
|
||||||
|
let AppId = parseInt(formValues.AppId, 10);
|
||||||
|
return await getMailListApi({
|
||||||
|
AppId: AppId,
|
||||||
|
ServerId: formValues.ServerId,
|
||||||
|
PageSize: page.pageSize,
|
||||||
|
CurrentPage: page.currentPage,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
showOverflow: false,
|
||||||
|
rowConfig: {
|
||||||
|
isHover: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const gridEvents: VxeGridListeners<MailData> = {
|
||||||
|
cellClick: ({ row }) => {
|
||||||
|
AddMailApi2.setData(row);
|
||||||
|
AddMailApi2.open();
|
||||||
|
// message.info(`cell-click: ${row.title}`);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const [Grid, GridApi] = useVbenVxeGrid({
|
||||||
|
gridEvents,
|
||||||
|
formOptions,
|
||||||
|
gridOptions,
|
||||||
|
});
|
||||||
|
const [AddMailM, AddMailApi] = useVbenModal({
|
||||||
|
connectedComponent: AddMailModal,
|
||||||
|
onClosed: async () => {
|
||||||
|
AddMailApi.close();
|
||||||
|
GridApi.query();
|
||||||
|
//console.log("close")
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const [AddMailM2, AddMailApi2] = useVbenModal({
|
||||||
|
connectedComponent: DetailMailModal,
|
||||||
|
});
|
||||||
|
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',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const serverResponse = await getServerListApi({
|
||||||
|
AppId: app.AppId,
|
||||||
|
Type: 1,
|
||||||
|
});
|
||||||
|
ServerList.value = Array.isArray(serverResponse) ? serverResponse : [];
|
||||||
|
GridApi.formApi.updateSchema([
|
||||||
|
{
|
||||||
|
component: 'Select',
|
||||||
|
componentProps: {
|
||||||
|
options: ServerList.value.map((item) => ({
|
||||||
|
label: item.ServerName,
|
||||||
|
value: item.ServerId,
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
fieldName: 'ServerId',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
} catch (e) {
|
||||||
|
appList.value = [];
|
||||||
|
//console.log(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
async function addMail() {
|
||||||
|
//console.log('addMail');
|
||||||
|
const Value = await GridApi.formApi.getValues();
|
||||||
|
AddMailApi.setData({ AppId: Value.AppId, ServerId: Value.ServerId });
|
||||||
|
AddMailApi.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deleteRow(row: MailData) {
|
||||||
|
//console.log(row);
|
||||||
|
GridApi.setLoading(true);
|
||||||
|
if (typeof row.mail_id == 'number') {
|
||||||
|
await deleteMailApi(row.AppId, row.ServerId, row.mail_id);
|
||||||
|
} else {
|
||||||
|
//console.error('Invalid mail_id:', row.mail_id);
|
||||||
|
}
|
||||||
|
GridApi.setLoading(false);
|
||||||
|
GridApi.query();
|
||||||
|
}
|
||||||
|
|
||||||
|
function fromatItems(items: string) {
|
||||||
|
try {
|
||||||
|
const itemList = JSON.parse(items);
|
||||||
|
const r = itemList.map((item: { Id: number; Num: number }) => ({
|
||||||
|
...item,
|
||||||
|
url: getItemUrl(item.Id),
|
||||||
|
}));
|
||||||
|
return r;
|
||||||
|
} catch (e) {
|
||||||
|
//console.error('Failed to parse items:', e);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Page auto-content-height class="h-[800px]">
|
||||||
|
<AddMailM class="w-[50%]" />
|
||||||
|
<AddMailM2 class="w-[50%]" />
|
||||||
|
<Card class="mb-5" title="邮件操作">
|
||||||
|
<Space>
|
||||||
|
<Button @click="addMail">新增邮件</Button>
|
||||||
|
</Space>
|
||||||
|
</Card>
|
||||||
|
<Grid>
|
||||||
|
<template #items="{row}">
|
||||||
|
<div class="flex flex-wrap items-center justify-center">
|
||||||
|
<div v-for="item in fromatItems(row.items)" :key="item.Id" class="flex items-center gap-1">
|
||||||
|
<template v-if="item.url">
|
||||||
|
<Image :src="item.url" width="30px" />
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<Tag class="w-[45px] h-[30px] flex items-center justify-center text-xs">
|
||||||
|
{{item.Id}}
|
||||||
|
</Tag>
|
||||||
|
</template>
|
||||||
|
<span>x{{ item.Num }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #action="{ row }">
|
||||||
|
<Button type="link" @click="deleteRow(row)" style="color: #cc0000">删除</Button>
|
||||||
|
</template>
|
||||||
|
</Grid>
|
||||||
|
</Page>
|
||||||
|
</template>
|
||||||
@ -1,8 +1,15 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useVbenForm, useVbenModal } from '@vben/common-ui';
|
import { useVbenForm, useVbenModal } from '@vben/common-ui';
|
||||||
import {Image} from "ant-design-vue";
|
import {Image} from "ant-design-vue";
|
||||||
import Icon from '../../../../../../packages/@core/ui-kit/shadcn-ui/src/components/icon/icon.vue';
|
import { formatItems } from '#/store/util';
|
||||||
|
import { Tag } from 'ant-design-vue';
|
||||||
|
import {ref} from "vue";
|
||||||
|
interface MailItem {
|
||||||
|
Id: string | number;
|
||||||
|
Num: number;
|
||||||
|
url?: string;
|
||||||
|
}
|
||||||
|
let items = ref<MailItem[]>([]);
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'DetailMailModal',
|
name: 'DetailMailModal',
|
||||||
});
|
});
|
||||||
@ -63,10 +70,44 @@ const [Form, FormApi] = useVbenForm({
|
|||||||
},
|
},
|
||||||
rules: 'required',
|
rules: 'required',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
component: 'Input',
|
||||||
|
fieldName: 'TitlePTBR',
|
||||||
|
label: '葡萄牙(巴西)邮件标题',
|
||||||
|
rules: 'required',
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
component: 'Textarea',
|
||||||
|
fieldName: 'ContentPTBR',
|
||||||
|
label: '葡萄牙(巴西)邮件内容',
|
||||||
|
componentProps: {
|
||||||
|
type: 'textarea',
|
||||||
|
rows: 8,
|
||||||
|
},
|
||||||
|
rules: 'required',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: 'Input',
|
||||||
|
fieldName: 'TitleESLatam',
|
||||||
|
label: '西班牙(拉美)邮件标题',
|
||||||
|
rules: 'required',
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
component: 'Textarea',
|
||||||
|
fieldName: 'ContentESLatam',
|
||||||
|
label: '西班牙(拉美)邮件内容',
|
||||||
|
componentProps: {
|
||||||
|
type: 'textarea',
|
||||||
|
rows: 8,
|
||||||
|
},
|
||||||
|
rules: 'required',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
component: 'Textarea',
|
component: 'Textarea',
|
||||||
fieldName: 'items',
|
fieldName: 'items',
|
||||||
label: '邮件道具11',
|
label: '邮件道具',
|
||||||
componentProps: {
|
componentProps: {
|
||||||
placeholder: '{}',
|
placeholder: '{}',
|
||||||
type: 'textarea',
|
type: 'textarea',
|
||||||
@ -158,6 +199,10 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
TitleEN: modalData.title_en,
|
TitleEN: modalData.title_en,
|
||||||
SubtitleEN: modalData.subtitle_en,
|
SubtitleEN: modalData.subtitle_en,
|
||||||
ContentEN: modalData.content_en,
|
ContentEN: modalData.content_en,
|
||||||
|
TitlePTBR: modalData.title_ptbr,
|
||||||
|
ContentPTBR: modalData.content_ptbr,
|
||||||
|
TitleESLatam: modalData.title_es_latam,
|
||||||
|
ContentESLatam: modalData.content_es_latam,
|
||||||
items: modalData.items,
|
items: modalData.items,
|
||||||
start_time: 0,
|
start_time: 0,
|
||||||
register_time: modalData.register_time,
|
register_time: modalData.register_time,
|
||||||
@ -165,6 +210,7 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
send_type: modalData.send_type === 1 ? '全服邮件' : '个人邮件',
|
send_type: modalData.send_type === 1 ? '全服邮件' : '个人邮件',
|
||||||
ToUids: modalData.to_uids,
|
ToUids: modalData.to_uids,
|
||||||
});
|
});
|
||||||
|
items = formatItems(modalData.items);
|
||||||
FormApi.updateSchema([
|
FormApi.updateSchema([
|
||||||
{
|
{
|
||||||
component: 'Input',
|
component: 'Input',
|
||||||
@ -196,6 +242,26 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
disabled: true,
|
disabled: true,
|
||||||
fieldName: 'ContentEN',
|
fieldName: 'ContentEN',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
component: 'Input',
|
||||||
|
disabled: true,
|
||||||
|
fieldName: 'TitlePTBR',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: 'Textarea',
|
||||||
|
disabled: true,
|
||||||
|
fieldName: 'ContentPTBR',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: 'Input',
|
||||||
|
disabled: true,
|
||||||
|
fieldName: 'TitleESLatam',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: 'Textarea',
|
||||||
|
disabled: true,
|
||||||
|
fieldName: 'ContentESLatam',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
component: 'Input',
|
component: 'Input',
|
||||||
disabled: true,
|
disabled: true,
|
||||||
@ -234,10 +300,19 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
<Modal :width="800" title="邮件详情">
|
<Modal :width="800" title="邮件详情">
|
||||||
<Form>
|
<Form>
|
||||||
<template #items>
|
<template #items>
|
||||||
<div class="border-2 border-solid border-x-sky-50 rounded-xl p-1">
|
<div class="flex flex-wrap items-center justify-center">
|
||||||
<Image src="../../../../public/item/mini-gamesWK_icon_yanzhao.png" width="30px" />x20
|
<div v-for="item in items" :key="item.Id" class="flex items-center gap-1">
|
||||||
|
<template v-if="item.url">
|
||||||
|
<Image :src="item.url" width="30px" />
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<Tag class="w-[45px] h-[30px] flex items-center justify-center text-xs">
|
||||||
|
{{item.Id}}
|
||||||
|
</Tag>
|
||||||
|
</template>
|
||||||
|
<span>x{{ item.Num }}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
</Form>
|
</Form>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|||||||
@ -1,9 +1,15 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useVbenForm, useVbenModal } from '@vben/common-ui';
|
import { useVbenForm, useVbenModal } from '@vben/common-ui';
|
||||||
|
import { Select, Input, SelectOption, Image, SelectOptGroup } from 'ant-design-vue';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
|
import { ref } from 'vue';
|
||||||
import { addMailApi } from '#/api/core/mail';
|
import { addMailApi } from '#/api/core/mail';
|
||||||
import type { MailData } from '#/api/core/mail';
|
import type { MailData } from '#/api/core/mail';
|
||||||
|
import { VbenIcon } from '../../../../../../packages/@core/ui-kit/shadcn-ui/src/components';
|
||||||
|
import { getItemUrl } from '#/store/util';
|
||||||
|
const value1 = ref<string>();
|
||||||
|
const value2 = ref<number>();
|
||||||
|
const items = ref<{ Id: string | number; Num: number; url?: string }[]>([]);
|
||||||
const [Form, FormApi] = useVbenForm({
|
const [Form, FormApi] = useVbenForm({
|
||||||
// 所有表单项共用,可单独在表单内覆盖
|
// 所有表单项共用,可单独在表单内覆盖
|
||||||
commonConfig: {
|
commonConfig: {
|
||||||
@ -113,6 +119,16 @@ const [Form, FormApi] = useVbenForm({
|
|||||||
rows: 3,
|
rows: 3,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
component: 'Textarea',
|
||||||
|
fieldName: 'ItemList',
|
||||||
|
label: '道具',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '[{"Id":1,"Num":1},{"Id":2,"Num":2}]',
|
||||||
|
type: 'textarea',
|
||||||
|
rows: 3,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
component: 'RangePicker',
|
component: 'RangePicker',
|
||||||
fieldName: 'start_time',
|
fieldName: 'start_time',
|
||||||
@ -189,7 +205,9 @@ const [Form, FormApi] = useVbenForm({
|
|||||||
});
|
});
|
||||||
const [Modal, modalApi] = useVbenModal({
|
const [Modal, modalApi] = useVbenModal({
|
||||||
confirmText: '提交',
|
confirmText: '提交',
|
||||||
|
onOpened: () => {
|
||||||
|
items.value = [];
|
||||||
|
},
|
||||||
onConfirm: async () => {
|
onConfirm: async () => {
|
||||||
// 提交表单
|
// 提交表单
|
||||||
const values = await FormApi.getValues();
|
const values = await FormApi.getValues();
|
||||||
@ -212,8 +230,7 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
const TitleEN = values.TitleEN;
|
const TitleEN = values.TitleEN;
|
||||||
const SubtitleEN = values.SubtitleEN;
|
const SubtitleEN = values.SubtitleEN;
|
||||||
const ContentEN = values.ContentEN;
|
const ContentEN = values.ContentEN;
|
||||||
const Items = values.Items;
|
const ToUids = values.ToUids ? String(values.ToUids) : '';
|
||||||
const ToUids = values.ToUids;
|
|
||||||
const modalData = modalApi.getData();
|
const modalData = modalApi.getData();
|
||||||
const param: MailData = {
|
const param: MailData = {
|
||||||
AppId: modalData.AppId,
|
AppId: modalData.AppId,
|
||||||
@ -230,7 +247,7 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
title_es_latam: values.TitleESLatam,
|
title_es_latam: values.TitleESLatam,
|
||||||
subTitle_es_latam: values.SubtitleESLatam,
|
subTitle_es_latam: values.SubtitleESLatam,
|
||||||
content_es_latam: values.ContentESLatam,
|
content_es_latam: values.ContentESLatam,
|
||||||
items: Items,
|
items: values.ItemList,
|
||||||
to_uids: ToUids,
|
to_uids: ToUids,
|
||||||
start_time: start_time,
|
start_time: start_time,
|
||||||
end_time: end_time,
|
end_time: end_time,
|
||||||
@ -242,13 +259,54 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
modalApi.close();
|
modalApi.close();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
function addItem() {
|
||||||
|
if (!value1.value || !value2.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const itemId: number = parseInt(value1.value);
|
||||||
|
const num: number = Number(value2.value);
|
||||||
|
items.value.push({
|
||||||
|
Id: itemId,
|
||||||
|
Num: num,
|
||||||
|
});
|
||||||
|
value1.value = '';
|
||||||
|
value2.value = undefined;
|
||||||
|
FormApi.setFieldValue('ItemList', JSON.stringify(items.value));
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeItem(index: number) {
|
||||||
|
items.value.splice(index, 1);
|
||||||
|
}
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'AddMailModal',
|
name: 'AddMailModal',
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<Modal :width="800" title="添加邮件">
|
<Modal :width="800" title="添加邮件">
|
||||||
<Form />
|
<Form>
|
||||||
|
<template #Items>
|
||||||
|
<span>Id:</span>
|
||||||
|
<Select class="ml-2 w-[200px]" v-model:value="value1">
|
||||||
|
<SelectOptGroup>
|
||||||
|
<template #label>
|
||||||
|
<span>内置道具</span>
|
||||||
|
</template>
|
||||||
|
<SelectOption value="100001">能量</SelectOption>
|
||||||
|
<SelectOption value="100002">宠物币</SelectOption>
|
||||||
|
<SelectOption value="100003">钻石</SelectOption>
|
||||||
|
<SelectOption value="100021">小猪存钱罐</SelectOption>
|
||||||
|
</SelectOptGroup>
|
||||||
|
|
||||||
|
</Select>
|
||||||
|
|
||||||
|
<span class="ml-2">Num:</span>
|
||||||
|
<Input type="number" class="ml-2 border w-[200px]" v-model:value="value2" />
|
||||||
|
<div @click="addItem">
|
||||||
|
<VbenIcon icon="material-symbols:add-2" class="ml-2 border-2" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</Form>
|
||||||
</Modal>
|
</Modal>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -13,9 +13,10 @@ import { onMounted, ref } from 'vue';
|
|||||||
import AddMailModal from './mail-info.vue';
|
import AddMailModal from './mail-info.vue';
|
||||||
import DetailMailModal from './mail-detail.vue';
|
import DetailMailModal from './mail-detail.vue';
|
||||||
import { getItemUrl } from '#/store/util';
|
import { getItemUrl } from '#/store/util';
|
||||||
|
import { $t } from '#/locales'
|
||||||
|
|
||||||
const appList = ref<AppData[]>([]);
|
const appList = ref<AppData[]>([]);
|
||||||
const ServerList = ref<ServerData[]>([]);
|
const ServerList = ref<ServerData[]>([]);
|
||||||
|
|
||||||
const formOptions: VbenFormProps = {
|
const formOptions: VbenFormProps = {
|
||||||
// 默认展开
|
// 默认展开
|
||||||
collapsed: false,
|
collapsed: false,
|
||||||
@ -53,15 +54,6 @@ const formOptions: VbenFormProps = {
|
|||||||
fieldName: 'AppId',
|
fieldName: 'AppId',
|
||||||
label: 'APP:',
|
label: 'APP:',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
component: 'Select',
|
|
||||||
defaultValue: 1,
|
|
||||||
componentProps: {
|
|
||||||
options: [],
|
|
||||||
},
|
|
||||||
fieldName: 'ServerId',
|
|
||||||
label: '区服',
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
// 控制表单是否显示折叠按钮
|
// 控制表单是否显示折叠按钮
|
||||||
showCollapseButton: true,
|
showCollapseButton: true,
|
||||||
@ -115,7 +107,7 @@ const gridOptions: VxeGridProps<MailData> = {
|
|||||||
let AppId = parseInt(formValues.AppId, 10);
|
let AppId = parseInt(formValues.AppId, 10);
|
||||||
return await getMailListApi({
|
return await getMailListApi({
|
||||||
AppId: AppId,
|
AppId: AppId,
|
||||||
ServerId: formValues.ServerId,
|
ServerId: 1,
|
||||||
PageSize: page.pageSize,
|
PageSize: page.pageSize,
|
||||||
CurrentPage: page.currentPage,
|
CurrentPage: page.currentPage,
|
||||||
});
|
});
|
||||||
@ -162,30 +154,14 @@ onMounted(async () => {
|
|||||||
component: 'Select',
|
component: 'Select',
|
||||||
componentProps: {
|
componentProps: {
|
||||||
options: appList.value.map((item) => ({
|
options: appList.value.map((item) => ({
|
||||||
label: item.AppName,
|
label: $t('page.server.' + item.AppName),
|
||||||
value: item.AppId,
|
value: item.AppId,
|
||||||
})),
|
})),
|
||||||
},
|
},
|
||||||
fieldName: 'AppId',
|
fieldName: 'AppId',
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
const serverResponse = await getServerListApi({
|
|
||||||
AppId: app.AppId,
|
|
||||||
Type: 1,
|
|
||||||
});
|
|
||||||
ServerList.value = Array.isArray(serverResponse) ? serverResponse : [];
|
|
||||||
GridApi.formApi.updateSchema([
|
|
||||||
{
|
|
||||||
component: 'Select',
|
|
||||||
componentProps: {
|
|
||||||
options: ServerList.value.map((item) => ({
|
|
||||||
label: item.ServerName,
|
|
||||||
value: item.ServerId,
|
|
||||||
})),
|
|
||||||
},
|
|
||||||
fieldName: 'ServerId',
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
appList.value = [];
|
appList.value = [];
|
||||||
//console.log(e);
|
//console.log(e);
|
||||||
@ -236,7 +212,7 @@ function fromatItems(items: string) {
|
|||||||
</Space>
|
</Space>
|
||||||
</Card>
|
</Card>
|
||||||
<Grid>
|
<Grid>
|
||||||
<template #items="{ row }">
|
<template #items="{row}">
|
||||||
<div class="flex flex-wrap items-center justify-center">
|
<div class="flex flex-wrap items-center justify-center">
|
||||||
<div v-for="item in fromatItems(row.items)" :key="item.Id" class="flex items-center gap-1">
|
<div v-for="item in fromatItems(row.items)" :key="item.Id" class="flex items-center gap-1">
|
||||||
<template v-if="item.url">
|
<template v-if="item.url">
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { Page } from '@vben/common-ui';
|
import { Page } from '@vben/common-ui';
|
||||||
import { Button, Card, Space, notification, Tag } from 'ant-design-vue';
|
import { Button, notification, Tag } from 'ant-design-vue';
|
||||||
import { useVbenDrawer, VbenButton } from '@vben/common-ui';
|
import { useVbenDrawer } from '@vben/common-ui';
|
||||||
import ExtraDrawer from './drawer.vue';
|
import ExtraDrawer from './drawer.vue';
|
||||||
const [Drawer, drawerApi] = useVbenDrawer({
|
const [Drawer, drawerApi] = useVbenDrawer({
|
||||||
connectedComponent: ExtraDrawer,
|
connectedComponent: ExtraDrawer,
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import type { VxeGridProps } from '#/adapter/vxe-table';
|
|||||||
import type { VbenFormProps } from '#/adapter/form';
|
import type { VbenFormProps } from '#/adapter/form';
|
||||||
import { ItemData } from '#/store/item';
|
import { ItemData } from '#/store/item';
|
||||||
import { eventModal } from '#/component';
|
import { eventModal } from '#/component';
|
||||||
|
import { getUnixTime } from "#/store/util";
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
// 接收父组件传递的 props
|
// 接收父组件传递的 props
|
||||||
@ -138,7 +139,7 @@ const gridEvents: VxeGridListeners<RowType> = {
|
|||||||
cellDblclick: async ({ row }) => {
|
cellDblclick: async ({ row }) => {
|
||||||
console.log(row);
|
console.log(row);
|
||||||
modalApi.setData({
|
modalApi.setData({
|
||||||
StartTime: row.timestamp,
|
StartTime: getUnixTime(row.timestamp),
|
||||||
EndTime: row.timestamp,
|
EndTime: row.timestamp,
|
||||||
});
|
});
|
||||||
modalApi.open();
|
modalApi.open();
|
||||||
@ -184,14 +185,14 @@ const gridOptions: VxeGridProps<RowType> = {
|
|||||||
|
|
||||||
state.uid = uid;
|
state.uid = uid;
|
||||||
const ItemId = parseInt(formValues.ItemId, 10);
|
const ItemId = parseInt(formValues.ItemId, 10);
|
||||||
|
const StartTime = getUnixTime(formValues.StartTime);
|
||||||
console.log(formValues.StartTime.unix());
|
const EndTime = getUnixTime(formValues.EndTime);
|
||||||
const r = await getUserLogAssetApi({
|
const r = await getUserLogAssetApi({
|
||||||
Id: uid,
|
Id: uid,
|
||||||
AppId: props.app,
|
AppId: props.app,
|
||||||
Event: formValues.Event,
|
Event: formValues.Event,
|
||||||
StartTime: formValues.StartTime.unix(),
|
StartTime: StartTime,
|
||||||
EndTime: formValues.EndTime.unix(),
|
EndTime: EndTime,
|
||||||
ItemId: ItemId,
|
ItemId: ItemId,
|
||||||
CurrentPage: page.currentPage,
|
CurrentPage: page.currentPage,
|
||||||
PageSize: page.pageSize,
|
PageSize: page.pageSize,
|
||||||
|
|||||||
@ -233,6 +233,7 @@ const info = ref<{
|
|||||||
Chess: Chess[];
|
Chess: Chess[];
|
||||||
Friend: friendRecord[];
|
Friend: friendRecord[];
|
||||||
MaxCharge?: number;
|
MaxCharge?: number;
|
||||||
|
AdWatch?: number;
|
||||||
}>({
|
}>({
|
||||||
Level: 0,
|
Level: 0,
|
||||||
Star: 0,
|
Star: 0,
|
||||||
@ -252,6 +253,7 @@ const info = ref<{
|
|||||||
Chess: [],
|
Chess: [],
|
||||||
Friend: [],
|
Friend: [],
|
||||||
MaxCharge: 0,
|
MaxCharge: 0,
|
||||||
|
AdWatch: 0,
|
||||||
});
|
});
|
||||||
let trendItems: WorkbenchTrendItem[] = [
|
let trendItems: WorkbenchTrendItem[] = [
|
||||||
|
|
||||||
@ -296,6 +298,7 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
info.value.AreaId = r.AreaId;
|
info.value.AreaId = r.AreaId;
|
||||||
info.value.MaxCharge = r.MaxCharge;
|
info.value.MaxCharge = r.MaxCharge;
|
||||||
info.value.Friend = r.FriendList || [];
|
info.value.Friend = r.FriendList || [];
|
||||||
|
info.value.AdWatch = r.AdWatch || 0;
|
||||||
// 计算封号剩余天数(如果Ban为时间戳且大于当前时间,则计算剩余天数,否则为0或-1)
|
// 计算封号剩余天数(如果Ban为时间戳且大于当前时间,则计算剩余天数,否则为0或-1)
|
||||||
if (r.Ban && r.Ban > 0) {
|
if (r.Ban && r.Ban > 0) {
|
||||||
const now = Math.floor(Date.now() / 1000);
|
const now = Math.floor(Date.now() / 1000);
|
||||||
@ -512,6 +515,7 @@ watch(
|
|||||||
<template #AreaId>{{ info.AreaId }}</template>
|
<template #AreaId>{{ info.AreaId }}</template>
|
||||||
<template #Code>{{ info.Code || 0 }}</template>
|
<template #Code>{{ info.Code || 0 }}</template>
|
||||||
<template #TodayCumulative>{{ info.TodayCumulative }}</template>
|
<template #TodayCumulative>{{ info.TodayCumulative }}</template>
|
||||||
|
<template #ad_watch>{{ info.AdWatch ? '是' : '否' }}</template>
|
||||||
</WorkbenchDetail>
|
</WorkbenchDetail>
|
||||||
<chessComponent :items="info.Chess" title="棋盘" class="mt-6" />
|
<chessComponent :items="info.Chess" title="棋盘" class="mt-6" />
|
||||||
<friendComponent :Items="info.Friend" title="好友" class="mt-6" />
|
<friendComponent :Items="info.Friend" title="好友" class="mt-6" />
|
||||||
|
|||||||
@ -95,6 +95,19 @@ const formOptions: VbenFormProps = {
|
|||||||
placeholder: '请输入',
|
placeholder: '请输入',
|
||||||
showSearch: true,
|
showSearch: true,
|
||||||
},
|
},
|
||||||
|
fieldName: 'Username',
|
||||||
|
label: '登录名:',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
filterOption: true,
|
||||||
|
options: [
|
||||||
|
|
||||||
|
],
|
||||||
|
placeholder: '请输入',
|
||||||
|
showSearch: true,
|
||||||
|
},
|
||||||
fieldName: 'Nickname',
|
fieldName: 'Nickname',
|
||||||
label: '昵称:',
|
label: '昵称:',
|
||||||
},
|
},
|
||||||
@ -120,6 +133,19 @@ const formOptions: VbenFormProps = {
|
|||||||
label: '结束时间',
|
label: '结束时间',
|
||||||
|
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
filterOption: true,
|
||||||
|
options: [
|
||||||
|
|
||||||
|
],
|
||||||
|
placeholder: '请输入',
|
||||||
|
showSearch: true,
|
||||||
|
},
|
||||||
|
fieldName: 'DeviceId',
|
||||||
|
label: '设备ID:',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
// 控制表单是否显示折叠按钮
|
// 控制表单是否显示折叠按钮
|
||||||
showCollapseButton: true,
|
showCollapseButton: true,
|
||||||
@ -144,16 +170,16 @@ const gridEvents: VxeGridListeners<RowType> = {
|
|||||||
|
|
||||||
const gridOptions: VxeGridProps<RowType> = {
|
const gridOptions: VxeGridProps<RowType> = {
|
||||||
columns: [
|
columns: [
|
||||||
{ field: 'Uid', title: 'id' , sortable: true, sortBy: 'Uid'},
|
{ field: 'Uid', title: 'id', sortable: true, sortBy: 'Uid' },
|
||||||
{ field: 'UserName', title: '登录名' },
|
{ field: 'UserName', title: '登录名' },
|
||||||
{ field: 'Level', title: '等级', formatter: ({ cellValue }: { cellValue: string | number }) => `${cellValue} 级`, sortable: true, sortBy: 'Level' },
|
{ field: 'Level', title: '等级', formatter: ({ cellValue }: { cellValue: string | number }) => `${cellValue} 级`, sortable: true, sortBy: 'Level' },
|
||||||
{ field: 'Node', title: '节点', },
|
{ field: 'Node', title: '节点', },
|
||||||
{ field: 'Nickname', title: '昵称', },
|
{ field: 'Nickname', title: '昵称', },
|
||||||
{ field: 'Diamond', title: '钻石', formatter: ({ cellValue }: { cellValue: string | number }) => `${cellValue} 💎`, sortable: true, sortBy: 'Diamond' },
|
{ field: 'Diamond', title: '钻石', formatter: ({ cellValue }: { cellValue: string | number }) => `${cellValue} 💎`, sortable: true, sortBy: 'Diamond' },
|
||||||
{ field: 'Star', title: '星星', formatter: ({ cellValue }: { cellValue: string | number }) => `${cellValue} ⭐`, sortable: true, sortBy: 'Star' },
|
{ field: 'Star', title: '星星', formatter: ({ cellValue }: { cellValue: string | number }) => `${cellValue} ⭐`, sortable: true, sortBy: 'Star' },
|
||||||
{ field: 'Energy', title: '能量', formatter: ({ cellValue }: { cellValue: string | number }) => `${cellValue} ⚡`, sortable: true, sortBy: 'Energy' },
|
{ field: 'Energy', title: '能量', formatter: ({ cellValue }: { cellValue: string | number }) => `${cellValue} ⚡`, sortable: true, sortBy: 'Energy' },
|
||||||
{ field: 'LoginTime', sortable: true, title: '登录时间', formatter: ({ cellValue }: { cellValue: number }) => dayjs(cellValue * 1000).format('YYYY-MM-DD HH:mm:ss'),sortBy: 'LoginTime' },
|
{ field: 'LoginTime', sortable: true, title: '登录时间', formatter: ({ cellValue }: { cellValue: number }) => dayjs(cellValue * 1000).format('YYYY-MM-DD HH:mm:ss'), sortBy: 'LoginTime' },
|
||||||
{ field: 'Online', title: '在线状态', slots: { default: 'online' } , sortable: true, sortBy: 'Online' },
|
{ field: 'Online', title: '在线状态', slots: { default: 'online' }, sortable: true, sortBy: 'Online' },
|
||||||
],
|
],
|
||||||
height: 'auto',
|
height: 'auto',
|
||||||
pagerConfig: {},
|
pagerConfig: {},
|
||||||
@ -180,7 +206,9 @@ const gridOptions: VxeGridProps<RowType> = {
|
|||||||
let ServerId = 1;
|
let ServerId = 1;
|
||||||
let Uid = parseInt(formValues.Uid, 10);
|
let Uid = parseInt(formValues.Uid, 10);
|
||||||
let Nickname = formValues.Nickname ? String(formValues.Nickname) : '';
|
let Nickname = formValues.Nickname ? String(formValues.Nickname) : '';
|
||||||
let r = await getUserListApi({ Id: Id, ServerId: ServerId, pageSize: page.pageSize, currentPage: page.currentPage, Uid: Uid, Nickname:Nickname, StartTime: formValues.StartTime ? Math.floor(new Date(formValues.StartTime).getTime() / 1000) : undefined, EndTime: formValues.EndTime ? Math.floor(new Date(formValues.EndTime).getTime() / 1000) : undefined });
|
let Username = formValues.Username ? String(formValues.Username) : '';
|
||||||
|
let DeviceId = formValues.DeviceId ? String(formValues.DeviceId) : '';
|
||||||
|
let r = await getUserListApi({ Id: Id, ServerId: ServerId, pageSize: page.pageSize, currentPage: page.currentPage, Uid: Uid, Nickname: Nickname, Username: Username, DeviceId: DeviceId, StartTime: formValues.StartTime ? Math.floor(new Date(formValues.StartTime).getTime() / 1000) : undefined, EndTime: formValues.EndTime ? Math.floor(new Date(formValues.EndTime).getTime() / 1000) : undefined });
|
||||||
return r;
|
return r;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
291
apps/web-antd/template.json
Normal file
291
apps/web-antd/template.json
Normal file
@ -0,0 +1,291 @@
|
|||||||
|
{
|
||||||
|
"Name": "挖矿活动",
|
||||||
|
"PassNum": 20,
|
||||||
|
"itemCost": [
|
||||||
|
{
|
||||||
|
"Id": 100026,
|
||||||
|
"Num": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ItemId": 100026,
|
||||||
|
"startItemnum": 2,
|
||||||
|
"Gem": {
|
||||||
|
"1": {
|
||||||
|
"Area": "1*1"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"Area": "1*2"
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"Area": "1*3"
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
|
"Area": "1*4"
|
||||||
|
},
|
||||||
|
"5": {
|
||||||
|
"Area": "2*2"
|
||||||
|
},
|
||||||
|
"6": {
|
||||||
|
"Area": "2*3"
|
||||||
|
},
|
||||||
|
"7": {
|
||||||
|
"Area": "3*3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Jackpot": {
|
||||||
|
"1": {
|
||||||
|
"Prob": 15,
|
||||||
|
"Items": [
|
||||||
|
{
|
||||||
|
"Id": 100001,
|
||||||
|
"Num": 5
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"Prob": 10,
|
||||||
|
"Items": [
|
||||||
|
{
|
||||||
|
"Id": 100026,
|
||||||
|
"Num": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"Prob": 10,
|
||||||
|
"Items": [
|
||||||
|
{
|
||||||
|
"Id": 100001,
|
||||||
|
"Num": 2
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
|
"Prob": 65,
|
||||||
|
"Items": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Pass": {
|
||||||
|
"1": {
|
||||||
|
"Items": [
|
||||||
|
{
|
||||||
|
"Id": 100001,
|
||||||
|
"Num": 8
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Area": "4*4",
|
||||||
|
"Gem": 2,
|
||||||
|
"StarReward": null
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"Items": [
|
||||||
|
{
|
||||||
|
"Id": 100001,
|
||||||
|
"Num": 15
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Area": "6*4",
|
||||||
|
"Gem": "3|4",
|
||||||
|
"StarReward": null
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"Items": [
|
||||||
|
{
|
||||||
|
"Id": 100026,
|
||||||
|
"Num": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": 100005,
|
||||||
|
"Num": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Area": "6*6",
|
||||||
|
"Gem": "1|2|5",
|
||||||
|
"StarReward": 40
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
|
"Items": [
|
||||||
|
{
|
||||||
|
"Id": 100001,
|
||||||
|
"Num": 30
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Area": "7*5",
|
||||||
|
"Gem": "3|3|4",
|
||||||
|
"StarReward": null
|
||||||
|
},
|
||||||
|
"5": {
|
||||||
|
"Items": [
|
||||||
|
{
|
||||||
|
"Id": 100001,
|
||||||
|
"Num": 15
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Area": "5*5",
|
||||||
|
"Gem": "2|3|3",
|
||||||
|
"StarReward": null
|
||||||
|
},
|
||||||
|
"6": {
|
||||||
|
"Items": [
|
||||||
|
{
|
||||||
|
"Id": 100026,
|
||||||
|
"Num": 5
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Area": "5*5",
|
||||||
|
"Gem": "2|4|4",
|
||||||
|
"StarReward": 55
|
||||||
|
},
|
||||||
|
"7": {
|
||||||
|
"Items": [
|
||||||
|
{
|
||||||
|
"Id": 100001,
|
||||||
|
"Num": 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": 100006,
|
||||||
|
"Num": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Area": "6*6",
|
||||||
|
"Gem": "3|5|5",
|
||||||
|
"StarReward": null
|
||||||
|
},
|
||||||
|
"8": {
|
||||||
|
"Items": [
|
||||||
|
{
|
||||||
|
"Id": 100001,
|
||||||
|
"Num": 60
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Area": "6*6",
|
||||||
|
"Gem": "1|2|3|6",
|
||||||
|
"StarReward": null
|
||||||
|
},
|
||||||
|
"9": {
|
||||||
|
"Items": [
|
||||||
|
{
|
||||||
|
"Id": 100001,
|
||||||
|
"Num": 25
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Area": "5*5",
|
||||||
|
"Gem": "1|5",
|
||||||
|
"StarReward": null
|
||||||
|
},
|
||||||
|
"10": {
|
||||||
|
"Items": [
|
||||||
|
{
|
||||||
|
"Id": 100026,
|
||||||
|
"Num": 8
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Area": "7*4",
|
||||||
|
"Gem": "2|2|5|5",
|
||||||
|
"StarReward": 80
|
||||||
|
},
|
||||||
|
"11": {
|
||||||
|
"Items": [
|
||||||
|
{
|
||||||
|
"Id": 100001,
|
||||||
|
"Num": 40
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Area": "6*5",
|
||||||
|
"Gem": "1|4|4",
|
||||||
|
"StarReward": null
|
||||||
|
},
|
||||||
|
"12": {
|
||||||
|
"Items": [
|
||||||
|
{
|
||||||
|
"Id": 100001,
|
||||||
|
"Num": 90
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": 100007,
|
||||||
|
"Num": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Area": "7*7",
|
||||||
|
"Gem": "4|6|6",
|
||||||
|
"StarReward": null
|
||||||
|
},
|
||||||
|
"13": {
|
||||||
|
"Items": null,
|
||||||
|
"Area": "6*7",
|
||||||
|
"Gem": "1|6|6",
|
||||||
|
"StarReward": 160
|
||||||
|
},
|
||||||
|
"14": {
|
||||||
|
"Items": [
|
||||||
|
{
|
||||||
|
"Id": 100001,
|
||||||
|
"Num": 45
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Area": "7*7",
|
||||||
|
"Gem": "2|2|5|6",
|
||||||
|
"StarReward": null
|
||||||
|
},
|
||||||
|
"15": {
|
||||||
|
"Items": [
|
||||||
|
{
|
||||||
|
"Id": 100001,
|
||||||
|
"Num": 75
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Area": "5*5",
|
||||||
|
"Gem": "2|2|6",
|
||||||
|
"StarReward": null
|
||||||
|
},
|
||||||
|
"16": {
|
||||||
|
"Items": [
|
||||||
|
{
|
||||||
|
"Id": 100026,
|
||||||
|
"Num": 8
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Area": "7*7",
|
||||||
|
"Gem": "2|7|7",
|
||||||
|
"StarReward": 275
|
||||||
|
},
|
||||||
|
"17": {
|
||||||
|
"Items": null,
|
||||||
|
"Area": "7*7",
|
||||||
|
"Gem": "1|1|5|6",
|
||||||
|
"StarReward": 345
|
||||||
|
},
|
||||||
|
"18": {
|
||||||
|
"Items": [
|
||||||
|
{
|
||||||
|
"Id": 101508,
|
||||||
|
"Num": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Area": "7*7",
|
||||||
|
"Gem": "2|2|6|6",
|
||||||
|
"StarReward": null
|
||||||
|
},
|
||||||
|
"19": {
|
||||||
|
"Items": null,
|
||||||
|
"Area": "6*7",
|
||||||
|
"Gem": "7|3|5",
|
||||||
|
"StarReward": 500
|
||||||
|
},
|
||||||
|
"20": {
|
||||||
|
"Items": [
|
||||||
|
{
|
||||||
|
"Id": 100001,
|
||||||
|
"Num": 300
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": 100023,
|
||||||
|
"Num": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Area": "7*7",
|
||||||
|
"Gem": "7|7",
|
||||||
|
"StarReward": 550
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -114,6 +114,18 @@ defineEmits(['click']);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="flex w-full">
|
||||||
|
<div class="text-foreground/80 leading-2 mt-3 flex h-4 p-1 md:w-1/2">
|
||||||
|
<span class="font-bold">是否终身看广告:</span>
|
||||||
|
</div>
|
||||||
|
<div class="text-foreground/80 leading-2 mt-3 flex h-4 justify-start p-1 md:w-1/2">
|
||||||
|
<div class="Value">
|
||||||
|
<span v-if="$slots.ad_watch">
|
||||||
|
<slot name="ad_watch"></slot>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="flex w-full">
|
<div class="flex w-full">
|
||||||
<div class="text-foreground/80 leading-2 mt-3 flex h-4 p-1 md:w-1/2">
|
<div class="text-foreground/80 leading-2 mt-3 flex h-4 p-1 md:w-1/2">
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user