活动优化
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[];
|
||||
MaxCharge?: number;
|
||||
FriendList?: friendRecord[];
|
||||
AdWatch?: number;
|
||||
}
|
||||
|
||||
export interface actlog {
|
||||
|
||||
@ -4,5 +4,5 @@ import type { copyUserParam } from '#/model/type';
|
||||
|
||||
|
||||
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;
|
||||
EndTime?: number;
|
||||
Nickname?: string;
|
||||
Username?: string;
|
||||
DeviceId?: string;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -56,7 +56,8 @@
|
||||
"mail": "邮件管理",
|
||||
"order": "订单管理",
|
||||
"language": "翻译管理",
|
||||
"copyUser": "用户数据复制"
|
||||
"copyUser": "用户数据复制",
|
||||
"activity": "活动管理"
|
||||
},
|
||||
"server":{
|
||||
"merge_pet_test":"测试服",
|
||||
|
||||
@ -43,7 +43,7 @@ const routes: RouteRecordRaw[] = [
|
||||
affixTab: false,
|
||||
icon: 'lucide:app-window',
|
||||
title: $t('page.dashboard.app-list'),
|
||||
authority: ['super', 'admin'],
|
||||
authority: ['super'],
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -54,7 +54,7 @@ const routes: RouteRecordRaw[] = [
|
||||
affixTab: false,
|
||||
icon: 'lucide:server',
|
||||
title: $t('page.dashboard.node-list'),
|
||||
authority: ['super', 'admin'],
|
||||
authority: ['super'],
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -65,7 +65,7 @@ const routes: RouteRecordRaw[] = [
|
||||
affixTab: false,
|
||||
icon: 'lucide:database',
|
||||
title: $t('page.dashboard.mysql-list'),
|
||||
authority: ['super', 'admin'],
|
||||
authority: ['super'],
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
@ -55,6 +55,16 @@ const routes: RouteRecordRaw[] = [
|
||||
icon: 'lets-icons: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,
|
||||
icon: 'solar:stars-bold',
|
||||
title: $t('page.userlog.assetlog'),
|
||||
authority: ['super'],
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -43,6 +44,7 @@ const routes: RouteRecordRaw[] = [
|
||||
affixTab: true,
|
||||
icon: 'lucide:apple',
|
||||
title: $t('page.userlog.eventlog'),
|
||||
authority: ['super'],
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -53,9 +55,9 @@ const routes: RouteRecordRaw[] = [
|
||||
affixTab: true,
|
||||
icon: 'solar:chat-round-money-bold',
|
||||
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': '订单触发器',
|
||||
'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) {
|
||||
case 100001:
|
||||
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:
|
||||
return './Assets/Art_SubModule/Art_Resource/Art_UISprites/Shop/Big/shop_diamond_LV2.png';
|
||||
default:
|
||||
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 EditServer from './editServer.vue';
|
||||
import { useVbenModal } from '@vben/common-ui'
|
||||
import { useAccess } from '@vben/access';
|
||||
const { hasAccessByRoles } = useAccess();
|
||||
|
||||
defineOptions({
|
||||
name: 'AppList',
|
||||
@ -20,6 +22,9 @@ const [editServerM, editServerApi] = useVbenModal({
|
||||
connectedComponent: EditServer,
|
||||
});
|
||||
async function editServer(Server: ServerData) {
|
||||
if (!hasAccessByRoles(['super'])) {
|
||||
return;
|
||||
}
|
||||
editServerApi.setData(Server);
|
||||
editServerApi.open();
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ import type { AppData, ServerData } from '#/api/core/server';
|
||||
import { useVbenModal } from '@vben/common-ui'
|
||||
import { ref, onMounted } from 'vue';
|
||||
import addServerModal from './addServer.vue';
|
||||
import { AccessControl } from '@vben/access';
|
||||
import dayjs from 'dayjs';
|
||||
import { $t } from '#/locales'
|
||||
const appId = ref<number>(1);
|
||||
@ -124,10 +125,10 @@ onMounted(async () => {
|
||||
]);
|
||||
const serverResponse = await getServerListApi({ AppId: app.AppId });
|
||||
ServerList.value = Array.isArray(serverResponse) ? serverResponse : [];
|
||||
setInterval(async () => {
|
||||
const serverResponse = await getServerListApi({ AppId: appId.value });
|
||||
ServerList.value = Array.isArray(serverResponse) ? serverResponse : [];
|
||||
}, 60000);
|
||||
// setInterval(async () => {
|
||||
// const serverResponse = await getServerListApi({ AppId: appId.value });
|
||||
// ServerList.value = Array.isArray(serverResponse) ? serverResponse : [];
|
||||
// }, 60000);
|
||||
} catch (e) {
|
||||
appList.value = serverList;
|
||||
//console.log(e);
|
||||
@ -227,10 +228,14 @@ async function updateReview() {
|
||||
<Card class="mb-5" title="服务器操作">
|
||||
<BaseForm />
|
||||
<Space>
|
||||
<AccessControl :codes="['super']" type="role">
|
||||
<Button type="primary" @click="addServer">新增</Button>
|
||||
<Button type="primary" @click="confirmUpdate" :loading="reload"> 更新正式环境 </Button>
|
||||
</AccessControl>
|
||||
<Button type="primary" @click="confirmUpdate" :loading="reload"> 更新游戏文件 </Button>
|
||||
<AccessControl :codes="['super']" type="role">
|
||||
<Button type="primary" @click="confirmUpdateReview" :loading="reloadReview"> 更新review环境 </Button>
|
||||
<Button type="primary"> 更新配置 </Button>
|
||||
</AccessControl>
|
||||
<!-- <Button type="primary"> 更新配置 </Button> -->
|
||||
</Space>
|
||||
</Card>
|
||||
<div class="p-5">
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
<script lang="ts" setup>
|
||||
import { message } from "ant-design-vue";
|
||||
import { useVbenForm, useVbenModal } from '@vben/common-ui';
|
||||
import type { languageType } from '#/model/type';
|
||||
import type { VxeGridProps } from '#/adapter/vxe-table';
|
||||
@ -21,6 +22,7 @@ const gridOptions: VxeGridProps<languageType> = {
|
||||
title: 'zh_CN',
|
||||
},
|
||||
{ editRender: { name: 'input' }, field: 'pt_BR', title: 'pt_BR' },
|
||||
{ editRender: { name: 'input' }, field: 'es_LATAM', title: 'es_LATAM' },
|
||||
],
|
||||
data: ld,
|
||||
pagerConfig: {
|
||||
@ -44,7 +46,17 @@ const [Form] = useVbenForm({
|
||||
handleSubmit: async (formValues) => {
|
||||
// 调用添加语言接口
|
||||
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) {
|
||||
console.error('Error adding languages:', error);
|
||||
}
|
||||
@ -57,7 +69,7 @@ const [Form] = useVbenForm({
|
||||
label: $t('page.language.newLineContent'),
|
||||
componentProps: {
|
||||
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',
|
||||
rows: 8,
|
||||
onChange: (e: Event) => {
|
||||
@ -73,6 +85,7 @@ const [Form] = useVbenForm({
|
||||
en_US: parts[1] || '',
|
||||
zh_CN: parts[2] || '',
|
||||
pt_BR: parts[3] || '',
|
||||
es_LATAM: parts[4] || '',
|
||||
};
|
||||
});
|
||||
ld = ld.concat(newData);
|
||||
|
||||
@ -265,14 +265,14 @@ const gridOptions: VxeGridProps<languageType> = {
|
||||
title: 'Image',
|
||||
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' },
|
||||
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: 'es_LATAM', title: 'es_LATAM', filters: [{ data: "" }], filterRender: { name: "input" }, visible: es_LATAMVisible },
|
||||
{ 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, className: 'en-us-column' },
|
||||
{ slots: { default: 'glossary' }, title: 'Glossary', width: 150 },
|
||||
{ slots: { default: 'action' }, title: $t('page.common.action'), width: 150, visible: actionVisible },
|
||||
],
|
||||
@ -452,7 +452,12 @@ function getGlossary(row: languageType) {
|
||||
.row-green {
|
||||
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 {
|
||||
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>
|
||||
import { useVbenForm, useVbenModal } from '@vben/common-ui';
|
||||
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({
|
||||
name: 'DetailMailModal',
|
||||
});
|
||||
@ -63,10 +70,44 @@ const [Form, FormApi] = useVbenForm({
|
||||
},
|
||||
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',
|
||||
fieldName: 'items',
|
||||
label: '邮件道具11',
|
||||
label: '邮件道具',
|
||||
componentProps: {
|
||||
placeholder: '{}',
|
||||
type: 'textarea',
|
||||
@ -158,6 +199,10 @@ const [Modal, modalApi] = useVbenModal({
|
||||
TitleEN: modalData.title_en,
|
||||
SubtitleEN: modalData.subtitle_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,
|
||||
start_time: 0,
|
||||
register_time: modalData.register_time,
|
||||
@ -165,6 +210,7 @@ const [Modal, modalApi] = useVbenModal({
|
||||
send_type: modalData.send_type === 1 ? '全服邮件' : '个人邮件',
|
||||
ToUids: modalData.to_uids,
|
||||
});
|
||||
items = formatItems(modalData.items);
|
||||
FormApi.updateSchema([
|
||||
{
|
||||
component: 'Input',
|
||||
@ -196,6 +242,26 @@ const [Modal, modalApi] = useVbenModal({
|
||||
disabled: true,
|
||||
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',
|
||||
disabled: true,
|
||||
@ -234,10 +300,19 @@ const [Modal, modalApi] = useVbenModal({
|
||||
<Modal :width="800" title="邮件详情">
|
||||
<Form>
|
||||
<template #items>
|
||||
<div class="border-2 border-solid border-x-sky-50 rounded-xl p-1">
|
||||
<Image src="../../../../public/item/mini-gamesWK_icon_yanzhao.png" width="30px" />x20
|
||||
<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>
|
||||
|
||||
@ -1,9 +1,15 @@
|
||||
<script lang="ts" setup>
|
||||
import { useVbenForm, useVbenModal } from '@vben/common-ui';
|
||||
import { Select, Input, SelectOption, Image, SelectOptGroup } from 'ant-design-vue';
|
||||
import dayjs from 'dayjs';
|
||||
import { ref } from 'vue';
|
||||
import { addMailApi } 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({
|
||||
// 所有表单项共用,可单独在表单内覆盖
|
||||
commonConfig: {
|
||||
@ -113,6 +119,16 @@ const [Form, FormApi] = useVbenForm({
|
||||
rows: 3,
|
||||
},
|
||||
},
|
||||
{
|
||||
component: 'Textarea',
|
||||
fieldName: 'ItemList',
|
||||
label: '道具',
|
||||
componentProps: {
|
||||
placeholder: '[{"Id":1,"Num":1},{"Id":2,"Num":2}]',
|
||||
type: 'textarea',
|
||||
rows: 3,
|
||||
},
|
||||
},
|
||||
{
|
||||
component: 'RangePicker',
|
||||
fieldName: 'start_time',
|
||||
@ -189,7 +205,9 @@ const [Form, FormApi] = useVbenForm({
|
||||
});
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
confirmText: '提交',
|
||||
|
||||
onOpened: () => {
|
||||
items.value = [];
|
||||
},
|
||||
onConfirm: async () => {
|
||||
// 提交表单
|
||||
const values = await FormApi.getValues();
|
||||
@ -212,8 +230,7 @@ const [Modal, modalApi] = useVbenModal({
|
||||
const TitleEN = values.TitleEN;
|
||||
const SubtitleEN = values.SubtitleEN;
|
||||
const ContentEN = values.ContentEN;
|
||||
const Items = values.Items;
|
||||
const ToUids = values.ToUids;
|
||||
const ToUids = values.ToUids ? String(values.ToUids) : '';
|
||||
const modalData = modalApi.getData();
|
||||
const param: MailData = {
|
||||
AppId: modalData.AppId,
|
||||
@ -230,7 +247,7 @@ const [Modal, modalApi] = useVbenModal({
|
||||
title_es_latam: values.TitleESLatam,
|
||||
subTitle_es_latam: values.SubtitleESLatam,
|
||||
content_es_latam: values.ContentESLatam,
|
||||
items: Items,
|
||||
items: values.ItemList,
|
||||
to_uids: ToUids,
|
||||
start_time: start_time,
|
||||
end_time: end_time,
|
||||
@ -242,13 +259,54 @@ const [Modal, modalApi] = useVbenModal({
|
||||
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({
|
||||
name: 'AddMailModal',
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<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>
|
||||
</template>
|
||||
|
||||
@ -13,9 +13,10 @@ import { onMounted, ref } from 'vue';
|
||||
import AddMailModal from './mail-info.vue';
|
||||
import DetailMailModal from './mail-detail.vue';
|
||||
import { getItemUrl } from '#/store/util';
|
||||
import { $t } from '#/locales'
|
||||
|
||||
const appList = ref<AppData[]>([]);
|
||||
const ServerList = ref<ServerData[]>([]);
|
||||
|
||||
const formOptions: VbenFormProps = {
|
||||
// 默认展开
|
||||
collapsed: false,
|
||||
@ -53,15 +54,6 @@ const formOptions: VbenFormProps = {
|
||||
fieldName: 'AppId',
|
||||
label: 'APP:',
|
||||
},
|
||||
{
|
||||
component: 'Select',
|
||||
defaultValue: 1,
|
||||
componentProps: {
|
||||
options: [],
|
||||
},
|
||||
fieldName: 'ServerId',
|
||||
label: '区服',
|
||||
},
|
||||
],
|
||||
// 控制表单是否显示折叠按钮
|
||||
showCollapseButton: true,
|
||||
@ -115,7 +107,7 @@ const gridOptions: VxeGridProps<MailData> = {
|
||||
let AppId = parseInt(formValues.AppId, 10);
|
||||
return await getMailListApi({
|
||||
AppId: AppId,
|
||||
ServerId: formValues.ServerId,
|
||||
ServerId: 1,
|
||||
PageSize: page.pageSize,
|
||||
CurrentPage: page.currentPage,
|
||||
});
|
||||
@ -162,30 +154,14 @@ onMounted(async () => {
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
options: appList.value.map((item) => ({
|
||||
label: item.AppName,
|
||||
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);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { Page } from '@vben/common-ui';
|
||||
import { Button, Card, Space, notification, Tag } from 'ant-design-vue';
|
||||
import { useVbenDrawer, VbenButton } from '@vben/common-ui';
|
||||
import { Button, notification, Tag } from 'ant-design-vue';
|
||||
import { useVbenDrawer } from '@vben/common-ui';
|
||||
import ExtraDrawer from './drawer.vue';
|
||||
const [Drawer, drawerApi] = useVbenDrawer({
|
||||
connectedComponent: ExtraDrawer,
|
||||
|
||||
@ -9,6 +9,7 @@ import type { VxeGridProps } from '#/adapter/vxe-table';
|
||||
import type { VbenFormProps } from '#/adapter/form';
|
||||
import { ItemData } from '#/store/item';
|
||||
import { eventModal } from '#/component';
|
||||
import { getUnixTime } from "#/store/util";
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
// 接收父组件传递的 props
|
||||
@ -138,7 +139,7 @@ const gridEvents: VxeGridListeners<RowType> = {
|
||||
cellDblclick: async ({ row }) => {
|
||||
console.log(row);
|
||||
modalApi.setData({
|
||||
StartTime: row.timestamp,
|
||||
StartTime: getUnixTime(row.timestamp),
|
||||
EndTime: row.timestamp,
|
||||
});
|
||||
modalApi.open();
|
||||
@ -184,14 +185,14 @@ const gridOptions: VxeGridProps<RowType> = {
|
||||
|
||||
state.uid = uid;
|
||||
const ItemId = parseInt(formValues.ItemId, 10);
|
||||
|
||||
console.log(formValues.StartTime.unix());
|
||||
const StartTime = getUnixTime(formValues.StartTime);
|
||||
const EndTime = getUnixTime(formValues.EndTime);
|
||||
const r = await getUserLogAssetApi({
|
||||
Id: uid,
|
||||
AppId: props.app,
|
||||
Event: formValues.Event,
|
||||
StartTime: formValues.StartTime.unix(),
|
||||
EndTime: formValues.EndTime.unix(),
|
||||
StartTime: StartTime,
|
||||
EndTime: EndTime,
|
||||
ItemId: ItemId,
|
||||
CurrentPage: page.currentPage,
|
||||
PageSize: page.pageSize,
|
||||
|
||||
@ -233,6 +233,7 @@ const info = ref<{
|
||||
Chess: Chess[];
|
||||
Friend: friendRecord[];
|
||||
MaxCharge?: number;
|
||||
AdWatch?: number;
|
||||
}>({
|
||||
Level: 0,
|
||||
Star: 0,
|
||||
@ -252,6 +253,7 @@ const info = ref<{
|
||||
Chess: [],
|
||||
Friend: [],
|
||||
MaxCharge: 0,
|
||||
AdWatch: 0,
|
||||
});
|
||||
let trendItems: WorkbenchTrendItem[] = [
|
||||
|
||||
@ -296,6 +298,7 @@ const [Modal, modalApi] = useVbenModal({
|
||||
info.value.AreaId = r.AreaId;
|
||||
info.value.MaxCharge = r.MaxCharge;
|
||||
info.value.Friend = r.FriendList || [];
|
||||
info.value.AdWatch = r.AdWatch || 0;
|
||||
// 计算封号剩余天数(如果Ban为时间戳且大于当前时间,则计算剩余天数,否则为0或-1)
|
||||
if (r.Ban && r.Ban > 0) {
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
@ -512,6 +515,7 @@ watch(
|
||||
<template #AreaId>{{ info.AreaId }}</template>
|
||||
<template #Code>{{ info.Code || 0 }}</template>
|
||||
<template #TodayCumulative>{{ info.TodayCumulative }}</template>
|
||||
<template #ad_watch>{{ info.AdWatch ? '是' : '否' }}</template>
|
||||
</WorkbenchDetail>
|
||||
<chessComponent :items="info.Chess" title="棋盘" class="mt-6" />
|
||||
<friendComponent :Items="info.Friend" title="好友" class="mt-6" />
|
||||
|
||||
@ -95,6 +95,19 @@ const formOptions: VbenFormProps = {
|
||||
placeholder: '请输入',
|
||||
showSearch: true,
|
||||
},
|
||||
fieldName: 'Username',
|
||||
label: '登录名:',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
filterOption: true,
|
||||
options: [
|
||||
|
||||
],
|
||||
placeholder: '请输入',
|
||||
showSearch: true,
|
||||
},
|
||||
fieldName: 'Nickname',
|
||||
label: '昵称:',
|
||||
},
|
||||
@ -120,6 +133,19 @@ const formOptions: VbenFormProps = {
|
||||
label: '结束时间',
|
||||
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
filterOption: true,
|
||||
options: [
|
||||
|
||||
],
|
||||
placeholder: '请输入',
|
||||
showSearch: true,
|
||||
},
|
||||
fieldName: 'DeviceId',
|
||||
label: '设备ID:',
|
||||
},
|
||||
],
|
||||
// 控制表单是否显示折叠按钮
|
||||
showCollapseButton: true,
|
||||
@ -180,7 +206,9 @@ const gridOptions: VxeGridProps<RowType> = {
|
||||
let ServerId = 1;
|
||||
let Uid = parseInt(formValues.Uid, 10);
|
||||
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;
|
||||
},
|
||||
},
|
||||
|
||||
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 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="text-foreground/80 leading-2 mt-3 flex h-4 p-1 md:w-1/2">
|
||||
|
||||
Loading…
Reference in New Issue
Block a user