更新
This commit is contained in:
77
src/api/modules/game.ts
Normal file
77
src/api/modules/game.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import { http } from "@/utils/http";
|
||||
|
||||
type Result = {
|
||||
code: string;
|
||||
data: any;
|
||||
msg: string;
|
||||
};
|
||||
|
||||
// 游戏列表
|
||||
export const getMonsterList = params => {
|
||||
return http.request<Result>("get", "/adminapi/Monster/get_monster_list", {
|
||||
params
|
||||
});
|
||||
};
|
||||
|
||||
// 游戏详情
|
||||
export const getMonsterDetail = params => {
|
||||
return http.request<Result>("get", "/adminapi/Monster/get_monster_info", {
|
||||
params
|
||||
});
|
||||
};
|
||||
|
||||
// 编辑游戏
|
||||
export const editMonster = data => {
|
||||
return http.request<Result>("post", "/adminapi/Monster/edit_monster", {
|
||||
data
|
||||
});
|
||||
};
|
||||
|
||||
// 获取礼物列表
|
||||
export const getGiftList = params => {
|
||||
return http.request<Result>("get", "/adminapi/Monster/get_gift_list", {
|
||||
params
|
||||
});
|
||||
};
|
||||
|
||||
// 获取期数列表
|
||||
export const getMonsterLog = params => {
|
||||
return http.request<Result>("get", "/adminapi/Monster/get_monster_log", {
|
||||
params
|
||||
});
|
||||
};
|
||||
|
||||
// 获取投入记录
|
||||
export const getUserMonsterLog = params => {
|
||||
return http.request<Result>("get", "/adminapi/Monster/get_user_monster_log", {
|
||||
params
|
||||
});
|
||||
};
|
||||
|
||||
// 获取中奖人员
|
||||
export const getUserMonsterWinLog = params => {
|
||||
return http.request<Result>("get", "/adminapi/Monster/get_user_monster_win_log", {
|
||||
params
|
||||
});
|
||||
};
|
||||
|
||||
// 获取倍数列表
|
||||
export const getMonsterMultipleList = params => {
|
||||
return http.request<Result>("get", "/adminapi/Monster/get_monster_multiple_list", {
|
||||
params
|
||||
});
|
||||
};
|
||||
|
||||
// 获取倍数详情
|
||||
export const getMonsterMultipleDetail = params => {
|
||||
return http.request<Result>("get", "/adminapi/Monster/get_monster_multiple_info", {
|
||||
params
|
||||
});
|
||||
};
|
||||
|
||||
// 编辑倍数
|
||||
export const editMonsterMultiple = data => {
|
||||
return http.request<Result>("post", "/adminapi/Monster/edit_monster_multiple", {
|
||||
data
|
||||
});
|
||||
};
|
||||
@@ -66,3 +66,9 @@ export const realTimeByluckyList = params => {
|
||||
params
|
||||
});
|
||||
};
|
||||
// 幸运币抽奖统计
|
||||
export const getLotteryPoolFlow = params => {
|
||||
return http.request<Result>("get", "/adminapi/Lottery/pool_flow_list", {
|
||||
params
|
||||
});
|
||||
};
|
||||
|
||||
200
src/views/LXlegend/gameList/detail.vue
Normal file
200
src/views/LXlegend/gameList/detail.vue
Normal file
@@ -0,0 +1,200 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from "vue";
|
||||
import { getMonsterDetail } from "@/api/modules/game";
|
||||
|
||||
const props = defineProps(["id"]);
|
||||
const loading = ref(true);
|
||||
const detailData = ref<any>({});
|
||||
|
||||
const basicInfo = ref([
|
||||
{ label: "游戏名称", prop: "type_name" },
|
||||
{ label: "礼物名称", prop: "gift_name" },
|
||||
{ label: "礼物数量", prop: "num" },
|
||||
{ label: "倍数", prop: "multiple" },
|
||||
{ label: "创建时间", prop: "createtime" },
|
||||
{ label: "更新时间", prop: "updatetime" }
|
||||
]);
|
||||
|
||||
const fetchDetail = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const { data, code } = await getMonsterDetail({ id: props.id });
|
||||
if (code) {
|
||||
detailData.value = data;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("获取详情失败:", error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
fetchDetail();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-loading="loading" class="detail-container">
|
||||
<div v-if="!loading && detailData.id" class="detail-content">
|
||||
<!-- 头部信息 -->
|
||||
<div class="detail-header">
|
||||
<div class="header-left">
|
||||
<el-image v-if="detailData.gift_icon" :src="detailData.gift_icon" fit="cover"
|
||||
style="width: 120px; height: 120px; border-radius: 8px" />
|
||||
<div v-else class="no-image">
|
||||
<el-icon :size="60">
|
||||
<Picture />
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="header-info">
|
||||
<h2>{{ detailData.type_name || "未命名" }}</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-divider />
|
||||
|
||||
<!-- 基本信息 -->
|
||||
<div class="info-section">
|
||||
<h3>基本信息</h3>
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item v-for="item in basicInfo" :key="item.prop" :label="item.label">
|
||||
{{ detailData[item.prop] || "-" }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
|
||||
<!-- 礼物信息 -->
|
||||
<div v-if="detailData.gift_name" class="info-section">
|
||||
<h3>礼物信息</h3>
|
||||
<el-card shadow="never">
|
||||
<div class="gift-info">
|
||||
<el-image v-if="detailData.gift_icon" :src="detailData.gift_icon" fit="cover"
|
||||
style="width: 80px; height: 80px; border-radius: 4px" />
|
||||
<div class="gift-details">
|
||||
<div class="gift-name">{{ detailData.gift_name }}</div>
|
||||
<div class="gift-count">数量: {{ detailData.num }}</div>
|
||||
<div v-if="detailData.gift_price" class="gift-price">
|
||||
价格: {{ detailData.gift_price }} 金币
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<!-- 统计信息 -->
|
||||
<div v-if="detailData.total_count || detailData.total_amount" class="info-section">
|
||||
<h3>统计信息</h3>
|
||||
<el-row :gutter="20">
|
||||
<el-col v-if="detailData.total_count" :span="12">
|
||||
<el-statistic title="总参与次数" :value="detailData.total_count" group-separator="," />
|
||||
</el-col>
|
||||
<el-col v-if="detailData.total_amount" :span="12">
|
||||
<el-statistic title="总金额" :value="detailData.total_amount" prefix="¥" :precision="2" group-separator="," />
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
<!-- 其他信息 -->
|
||||
<div v-if="detailData.remark || detailData.desc" class="info-section">
|
||||
<h3>其他信息</h3>
|
||||
<el-card shadow="never">
|
||||
<div class="remark-content">
|
||||
{{ detailData.remark || detailData.desc || "暂无备注" }}
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-empty v-else-if="!loading" description="暂无数据" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.detail-container {
|
||||
padding: 20px;
|
||||
min-height: 400px;
|
||||
|
||||
.detail-content {
|
||||
.detail-header {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 20px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.header-left {
|
||||
.no-image {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
border-radius: 8px;
|
||||
background-color: #f5f7fa;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #c0c4cc;
|
||||
}
|
||||
}
|
||||
|
||||
.header-info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.info-tags {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.info-section {
|
||||
margin-top: 30px;
|
||||
|
||||
h3 {
|
||||
margin-bottom: 15px;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.gift-info {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
align-items: center;
|
||||
|
||||
.gift-details {
|
||||
flex: 1;
|
||||
|
||||
.gift-name {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.gift-count,
|
||||
.gift-price {
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.remark-content {
|
||||
line-height: 1.8;
|
||||
color: #606266;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
84
src/views/LXlegend/gameList/form.vue
Normal file
84
src/views/LXlegend/gameList/form.vue
Normal file
@@ -0,0 +1,84 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from "vue";
|
||||
import { getGiftList } from "@/api/modules/game";
|
||||
|
||||
defineProps(["formInline"]);
|
||||
|
||||
const ruleFormRef = ref();
|
||||
const giftList = ref([]);
|
||||
const loading = ref(false);
|
||||
|
||||
const getRef = () => {
|
||||
return ruleFormRef.value;
|
||||
};
|
||||
|
||||
defineExpose({ getRef });
|
||||
|
||||
const rules = {
|
||||
gid: [{ required: true, message: "请选择礼物", trigger: "change" }],
|
||||
num: [{ required: true, message: "请输入数量", trigger: "blur" }],
|
||||
type_name: [{ required: true, message: "请输入游戏名称", trigger: "blur" }],
|
||||
edit_monster_multiple: [
|
||||
{ required: true, message: "请输入倍率", trigger: "blur" }
|
||||
]
|
||||
};
|
||||
|
||||
// 获取礼物列表
|
||||
const fetchGiftList = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const { data, code } = await getGiftList({});
|
||||
if (code) {
|
||||
giftList.value = data.lists || data.data || [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("获取礼物列表失败:", error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
fetchGiftList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-form ref="ruleFormRef" :model="formInline" :rules="rules" label-width="100px">
|
||||
<el-form-item label="活动ID" prop="id">
|
||||
<el-input v-model="formInline.id" disabled />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="礼物" prop="gid">
|
||||
<el-select v-model="formInline.gid" placeholder="请选择礼物" clearable filterable :loading="loading"
|
||||
style="width: 100%">
|
||||
<el-option v-for="gift in giftList" :key="gift.id" :label="gift.name || gift.gift_name" :value="gift.gid">
|
||||
<div style="display: flex; align-items: center; gap: 10px">
|
||||
<!-- <el-image v-if="gift.icon || gift.gift_icon" :src="gift.icon || gift.gift_icon"
|
||||
style="width: 30px; height: 30px" fit="cover" /> -->
|
||||
<span>{{ gift.name || gift.gift_name }}</span>
|
||||
</div>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="数量" prop="num">
|
||||
<el-input-number v-model="formInline.num" :min="1" :max="99999" controls-position="right" style="width: 100%" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="游戏名称" prop="type_name">
|
||||
<el-input v-model="formInline.type_name" placeholder="请输入游戏名称" clearable />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="倍率" prop="edit_monster_multiple">
|
||||
<el-input-number v-model="formInline.edit_monster_multiple" :min="1" :max="10000" :step="0.1" :precision="1"
|
||||
controls-position="right" style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.el-form {
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
||||
173
src/views/LXlegend/gameList/hook.tsx
Normal file
173
src/views/LXlegend/gameList/hook.tsx
Normal file
@@ -0,0 +1,173 @@
|
||||
import { ref, h } from "vue";
|
||||
import { getMonsterList, editMonster } from "@/api/modules/game";
|
||||
import { message } from "@/utils/message";
|
||||
import { addDialog } from "@/components/ReDialog";
|
||||
import detailView from "./detail.vue";
|
||||
import editFormView from "./form.vue";
|
||||
|
||||
export function useData() {
|
||||
const formRef = ref();
|
||||
const loading = ref(true);
|
||||
const tableList = ref([]);
|
||||
const isShow = ref(false);
|
||||
const pagination = ref({
|
||||
total: 0,
|
||||
pageSize: 10,
|
||||
pageSizes: [10, 20, 50, 100, 500, 1000, 2000],
|
||||
currentPage: 1,
|
||||
background: true
|
||||
});
|
||||
|
||||
const searchForm = ref({
|
||||
order: "id",
|
||||
sort: "desc"
|
||||
});
|
||||
|
||||
const tableLabel = ref([
|
||||
{
|
||||
label: "ID",
|
||||
prop: "id"
|
||||
},
|
||||
{
|
||||
label: "游戏名称",
|
||||
prop: "type_name"
|
||||
},
|
||||
{
|
||||
label: "礼物",
|
||||
prop: "gift_name"
|
||||
},
|
||||
{
|
||||
label: "礼物图标",
|
||||
prop: "icon",
|
||||
cellRenderer: ({ row }) => (
|
||||
<el-image
|
||||
fit="cover"
|
||||
preview-teleported={true}
|
||||
src={row.base_image}
|
||||
preview-src-list={Array.of(row.base_image)}
|
||||
class="w-[50px] h-[50px] align-middle"
|
||||
/>
|
||||
)
|
||||
},
|
||||
{
|
||||
label: "礼物价格",
|
||||
prop: "gift_price"
|
||||
},
|
||||
{
|
||||
label: "数量",
|
||||
prop: "num"
|
||||
},
|
||||
{
|
||||
label: "比率",
|
||||
prop: "rate"
|
||||
},
|
||||
{
|
||||
label: "创建时间",
|
||||
prop: "createtime"
|
||||
},
|
||||
{
|
||||
label: "操作",
|
||||
fixed: "right",
|
||||
width: 200,
|
||||
slot: "operation"
|
||||
}
|
||||
]);
|
||||
|
||||
const onSearch = async formData => {
|
||||
loading.value = true;
|
||||
searchForm.value = { ...formData };
|
||||
const { data, code } = await getMonsterList({
|
||||
...formData,
|
||||
page: pagination.value.currentPage,
|
||||
limit: pagination.value.pageSize
|
||||
});
|
||||
if (code) {
|
||||
tableList.value = data.data || [];
|
||||
pagination.value.total = data.count || data.total || 0;
|
||||
pagination.value.currentPage = data.page || pagination.value.currentPage;
|
||||
}
|
||||
loading.value = false;
|
||||
};
|
||||
|
||||
const handleSizeChange = (val: number) => {
|
||||
pagination.value.pageSize = val;
|
||||
onSearch(searchForm.value);
|
||||
};
|
||||
|
||||
const handleCurrentChange = (val: number) => {
|
||||
pagination.value.currentPage = val;
|
||||
onSearch(searchForm.value);
|
||||
};
|
||||
|
||||
// 查看详情
|
||||
const viewDetail = rowData => {
|
||||
addDialog({
|
||||
title: `游戏详情`,
|
||||
props: {
|
||||
id: rowData.id
|
||||
},
|
||||
width: "70%",
|
||||
closeOnClickModal: false,
|
||||
hideFooter: true,
|
||||
contentRenderer: () => h(detailView)
|
||||
});
|
||||
};
|
||||
|
||||
// 编辑游戏
|
||||
const openEditDialog = rowData => {
|
||||
addDialog({
|
||||
title: `编辑游戏`,
|
||||
props: {
|
||||
formInline: {
|
||||
id: rowData.id,
|
||||
gid: rowData.gid || "",
|
||||
num: rowData.num || 1,
|
||||
type_name: rowData.type_name || rowData.name || "",
|
||||
edit_monster_multiple: rowData.multiple || 1
|
||||
}
|
||||
},
|
||||
width: "40%",
|
||||
closeOnClickModal: false,
|
||||
contentRenderer: () =>
|
||||
h(editFormView, { ref: formRef, formInline: null }),
|
||||
beforeSure: (done, { options }) => {
|
||||
const FormRef = formRef.value.getRef();
|
||||
const curData = options.props.formInline;
|
||||
|
||||
FormRef.validate(async valid => {
|
||||
if (!valid) return;
|
||||
|
||||
const { code, msg } = await editMonster({
|
||||
id: curData.id,
|
||||
gid: curData.gid,
|
||||
num: curData.num,
|
||||
type_name: curData.type_name,
|
||||
edit_monster_multiple: curData.edit_monster_multiple
|
||||
});
|
||||
|
||||
if (code) {
|
||||
message("编辑成功", { type: "success" });
|
||||
onSearch(searchForm.value);
|
||||
done();
|
||||
} else {
|
||||
message(msg || "编辑失败", { type: "error" });
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
searchForm,
|
||||
onSearch,
|
||||
isShow,
|
||||
tableList,
|
||||
tableLabel,
|
||||
pagination,
|
||||
handleSizeChange,
|
||||
handleCurrentChange,
|
||||
loading,
|
||||
viewDetail,
|
||||
openEditDialog
|
||||
};
|
||||
}
|
||||
55
src/views/LXlegend/gameList/index.vue
Normal file
55
src/views/LXlegend/gameList/index.vue
Normal file
@@ -0,0 +1,55 @@
|
||||
<script setup lang="ts">
|
||||
import { onBeforeMount } from "vue";
|
||||
import { useData } from "./hook";
|
||||
import { PureTableBar } from "@/components/RePureTableBar";
|
||||
import { deviceDetection } from "@pureadmin/utils";
|
||||
|
||||
const {
|
||||
searchForm,
|
||||
onSearch,
|
||||
isShow,
|
||||
tableList,
|
||||
pagination,
|
||||
tableLabel,
|
||||
handleSizeChange,
|
||||
handleCurrentChange,
|
||||
loading,
|
||||
viewDetail,
|
||||
openEditDialog
|
||||
} = useData();
|
||||
|
||||
onBeforeMount(() => {
|
||||
onSearch(searchForm.value);
|
||||
});
|
||||
|
||||
defineOptions({
|
||||
name: "gameList"
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="main">
|
||||
<div ref="contentRef" :class="['flex', deviceDetection() ? 'flex-wrap' : '']">
|
||||
<PureTableBar v-if="!loading" title="游戏列表" :class="[isShow && !deviceDetection() ? '!w-[60vw]' : 'w-full']"
|
||||
:columns="tableLabel" @refresh="onSearch">
|
||||
<template v-slot="{ size, dynamicColumns }">
|
||||
<pure-table ref="tableRef" align-whole="center" showOverflowTooltip table-layout="auto" default-expand-all
|
||||
:loading="loading" :size="size" row-key="id" adaptive :adaptiveConfig="{ offsetBottom: 108 }"
|
||||
:data="tableList" :columns="dynamicColumns" :pagination="{ ...pagination, size }" :header-cell-style="{
|
||||
background: 'var(--el-fill-color-light)',
|
||||
color: 'var(--el-text-color-primary)'
|
||||
}" @page-current-change="handleCurrentChange" @page-size-change="handleSizeChange">
|
||||
<template #operation="{ row }">
|
||||
<el-button type="primary" size="small" link @click="viewDetail(row)">
|
||||
详情
|
||||
</el-button>
|
||||
<el-button type="primary" size="small" link @click="openEditDialog(row)">
|
||||
编辑
|
||||
</el-button>
|
||||
</template>
|
||||
</pure-table>
|
||||
</template>
|
||||
</PureTableBar>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
188
src/views/LXlegend/multipleList/detail.vue
Normal file
188
src/views/LXlegend/multipleList/detail.vue
Normal file
@@ -0,0 +1,188 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from "vue";
|
||||
import { getMonsterMultipleDetail } from "@/api/modules/game";
|
||||
|
||||
const props = defineProps(["id"]);
|
||||
const loading = ref(true);
|
||||
const detailData = ref<any>({});
|
||||
|
||||
const basicInfo = ref([
|
||||
{ label: "ID", prop: "id" },
|
||||
{ label: "类型名称", prop: "type_name" },
|
||||
{ label: "倍率", prop: "multiple" },
|
||||
{ label: "礼物ID", prop: "gift_id" },
|
||||
{ label: "礼物名称", prop: "gift_name" },
|
||||
{ label: "礼物价格", prop: "gift_price" },
|
||||
{ label: "数量", prop: "num" },
|
||||
{ label: "中奖概率", prop: "probability" },
|
||||
{ label: "创建时间", prop: "createtime" },
|
||||
{ label: "更新时间", prop: "updatetime" }
|
||||
]);
|
||||
|
||||
const fetchDetail = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const { data, code } = await getMonsterMultipleDetail({ id: props.id });
|
||||
if (code) {
|
||||
detailData.value = data;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("获取详情失败:", error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
fetchDetail();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-loading="loading" class="detail-container">
|
||||
<div v-if="!loading && detailData.id" class="detail-content">
|
||||
<!-- 头部信息 -->
|
||||
<div class="detail-header">
|
||||
<div class="header-left">
|
||||
<el-image v-if="detailData.gift_icon" :src="detailData.gift_icon" fit="cover"
|
||||
style="width: 120px; height: 120px; border-radius: 8px" />
|
||||
<div v-else class="no-image">
|
||||
<el-icon :size="60">
|
||||
<Picture />
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="header-info">
|
||||
<h2>{{ detailData.type_name || "未命名" }}</h2>
|
||||
<div class="info-tags">
|
||||
<el-tag type="primary" size="large">
|
||||
倍率: {{ detailData.multiple }}x
|
||||
</el-tag>
|
||||
<el-tag type="success" size="large">
|
||||
概率: {{ detailData.probability }}%
|
||||
</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-divider />
|
||||
|
||||
<!-- 基本信息 -->
|
||||
<div class="info-section">
|
||||
<h3>基本信息</h3>
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item v-for="item in basicInfo" :key="item.prop" :label="item.label">
|
||||
<template v-if="item.prop === 'probability'">
|
||||
{{ detailData[item.prop] }}%
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ detailData[item.prop] || "-" }}
|
||||
</template>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
|
||||
<!-- 礼物信息 -->
|
||||
<div v-if="detailData.gift_name" class="info-section">
|
||||
<h3>礼物信息</h3>
|
||||
<el-card shadow="never">
|
||||
<div class="gift-info">
|
||||
<el-image v-if="detailData.gift_icon" :src="detailData.gift_icon" fit="cover"
|
||||
style="width: 80px; height: 80px; border-radius: 4px" />
|
||||
<div class="gift-details">
|
||||
<div class="gift-name">{{ detailData.gift_name }}</div>
|
||||
<div class="gift-count">数量: {{ detailData.num }}</div>
|
||||
<div v-if="detailData.gift_price" class="gift-price">
|
||||
价格: {{ detailData.gift_price }} 金币
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-empty v-else-if="!loading" description="暂无数据" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.detail-container {
|
||||
padding: 20px;
|
||||
min-height: 400px;
|
||||
|
||||
.detail-content {
|
||||
.detail-header {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 20px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.header-left {
|
||||
.no-image {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
border-radius: 8px;
|
||||
background-color: #f5f7fa;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #c0c4cc;
|
||||
}
|
||||
}
|
||||
|
||||
.header-info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.info-tags {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.info-section {
|
||||
margin-top: 30px;
|
||||
|
||||
h3 {
|
||||
margin-bottom: 15px;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.gift-info {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
align-items: center;
|
||||
|
||||
.gift-details {
|
||||
flex: 1;
|
||||
|
||||
.gift-name {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.gift-count,
|
||||
.gift-price {
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
36
src/views/LXlegend/multipleList/form.vue
Normal file
36
src/views/LXlegend/multipleList/form.vue
Normal file
@@ -0,0 +1,36 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
|
||||
defineProps(["formInline"]);
|
||||
|
||||
const ruleFormRef = ref();
|
||||
|
||||
const getRef = () => {
|
||||
return ruleFormRef.value;
|
||||
};
|
||||
|
||||
defineExpose({ getRef });
|
||||
|
||||
const rules = {
|
||||
multiple: [{ required: true, message: "请输入倍率", trigger: "blur" }]
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-form ref="ruleFormRef" :model="formInline" :rules="rules" label-width="100px">
|
||||
<el-form-item label="ID" prop="id">
|
||||
<el-input v-model="formInline.id" disabled />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="倍率" prop="multiple">
|
||||
<el-input-number v-model="formInline.multiple" :min="1" :max="10000" :step="0.1" :precision="1"
|
||||
controls-position="right" style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.el-form {
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
||||
138
src/views/LXlegend/multipleList/hook.tsx
Normal file
138
src/views/LXlegend/multipleList/hook.tsx
Normal file
@@ -0,0 +1,138 @@
|
||||
import { ref, h } from "vue";
|
||||
import {
|
||||
getMonsterMultipleList,
|
||||
editMonsterMultiple
|
||||
} from "@/api/modules/game";
|
||||
import { message } from "@/utils/message";
|
||||
import { addDialog } from "@/components/ReDialog";
|
||||
import detailView from "./detail.vue";
|
||||
import editFormView from "./form.vue";
|
||||
|
||||
export function useData() {
|
||||
const formRef = ref();
|
||||
const loading = ref(true);
|
||||
const tableList = ref([]);
|
||||
const isShow = ref(false);
|
||||
const pagination = ref({
|
||||
total: 0,
|
||||
pageSize: 10,
|
||||
pageSizes: [10, 20, 50, 100, 500, 1000, 2000],
|
||||
currentPage: 1,
|
||||
background: true
|
||||
});
|
||||
|
||||
const searchForm = ref({});
|
||||
|
||||
const tableLabel = ref([
|
||||
{
|
||||
label: "ID",
|
||||
prop: "id"
|
||||
},
|
||||
{
|
||||
label: "倍率",
|
||||
prop: "multiple"
|
||||
},
|
||||
{
|
||||
label: "更新时间",
|
||||
prop: "updatetime"
|
||||
},
|
||||
{
|
||||
label: "操作",
|
||||
fixed: "right",
|
||||
width: 200,
|
||||
slot: "operation"
|
||||
}
|
||||
]);
|
||||
|
||||
const onSearch = async formData => {
|
||||
loading.value = true;
|
||||
searchForm.value = { ...formData };
|
||||
const { data, code } = await getMonsterMultipleList({
|
||||
...formData,
|
||||
page: pagination.value.currentPage,
|
||||
limit: pagination.value.pageSize
|
||||
});
|
||||
if (code) {
|
||||
tableList.value = data.lists || data.data || [];
|
||||
pagination.value.total = data.count || data.total || 0;
|
||||
pagination.value.currentPage = data.page || pagination.value.currentPage;
|
||||
}
|
||||
loading.value = false;
|
||||
};
|
||||
|
||||
const handleSizeChange = (val: number) => {
|
||||
pagination.value.pageSize = val;
|
||||
onSearch(searchForm.value);
|
||||
};
|
||||
|
||||
const handleCurrentChange = (val: number) => {
|
||||
pagination.value.currentPage = val;
|
||||
onSearch(searchForm.value);
|
||||
};
|
||||
|
||||
// 查看详情
|
||||
const viewDetail = rowData => {
|
||||
addDialog({
|
||||
title: `倍数详情`,
|
||||
props: {
|
||||
id: rowData.id
|
||||
},
|
||||
width: "60%",
|
||||
closeOnClickModal: false,
|
||||
hideFooter: true,
|
||||
contentRenderer: () => h(detailView)
|
||||
});
|
||||
};
|
||||
|
||||
// 编辑倍数
|
||||
const openEditDialog = rowData => {
|
||||
addDialog({
|
||||
title: `编辑倍数`,
|
||||
props: {
|
||||
formInline: {
|
||||
id: rowData.id,
|
||||
multiple: rowData.multiple || 1
|
||||
}
|
||||
},
|
||||
width: "40%",
|
||||
closeOnClickModal: false,
|
||||
contentRenderer: () =>
|
||||
h(editFormView, { ref: formRef, formInline: null }),
|
||||
beforeSure: (done, { options }) => {
|
||||
const FormRef = formRef.value.getRef();
|
||||
const curData = options.props.formInline;
|
||||
|
||||
FormRef.validate(async valid => {
|
||||
if (!valid) return;
|
||||
|
||||
const { code, msg } = await editMonsterMultiple({
|
||||
id: curData.id,
|
||||
multiple: curData.multiple
|
||||
});
|
||||
|
||||
if (code) {
|
||||
message("编辑成功", { type: "success" });
|
||||
onSearch(searchForm.value);
|
||||
done();
|
||||
} else {
|
||||
message(msg || "编辑失败", { type: "error" });
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
searchForm,
|
||||
onSearch,
|
||||
isShow,
|
||||
tableList,
|
||||
tableLabel,
|
||||
pagination,
|
||||
handleSizeChange,
|
||||
handleCurrentChange,
|
||||
loading,
|
||||
viewDetail,
|
||||
openEditDialog
|
||||
};
|
||||
}
|
||||
61
src/views/LXlegend/multipleList/index.vue
Normal file
61
src/views/LXlegend/multipleList/index.vue
Normal file
@@ -0,0 +1,61 @@
|
||||
<script setup lang="ts">
|
||||
import { onBeforeMount } from "vue";
|
||||
import { useData } from "./hook";
|
||||
import { PureTableBar } from "@/components/RePureTableBar";
|
||||
import { deviceDetection } from "@pureadmin/utils";
|
||||
|
||||
const {
|
||||
searchForm,
|
||||
onSearch,
|
||||
isShow,
|
||||
tableList,
|
||||
pagination,
|
||||
tableLabel,
|
||||
handleSizeChange,
|
||||
handleCurrentChange,
|
||||
loading,
|
||||
viewDetail,
|
||||
openEditDialog
|
||||
} = useData();
|
||||
|
||||
onBeforeMount(() => {
|
||||
onSearch(searchForm.value);
|
||||
});
|
||||
|
||||
defineOptions({
|
||||
name: "multipleList"
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="main">
|
||||
<div ref="contentRef" :class="['flex', deviceDetection() ? 'flex-wrap' : '']">
|
||||
<PureTableBar v-if="!loading" title="倍数列表" :class="[isShow && !deviceDetection() ? '!w-[60vw]' : 'w-full']"
|
||||
:columns="tableLabel" @refresh="onSearch">
|
||||
<template v-slot="{ size, dynamicColumns }">
|
||||
<pure-table ref="tableRef" align-whole="center" showOverflowTooltip table-layout="auto" default-expand-all
|
||||
:loading="loading" :size="size" row-key="id" adaptive :adaptiveConfig="{ offsetBottom: 108 }"
|
||||
:data="tableList" :columns="dynamicColumns" :pagination="{ ...pagination, size }" :header-cell-style="{
|
||||
background: 'var(--el-fill-color-light)',
|
||||
color: 'var(--el-text-color-primary)'
|
||||
}" @page-current-change="handleCurrentChange" @page-size-change="handleSizeChange">
|
||||
<template #operation="{ row }">
|
||||
<!-- <el-button type="primary" size="small" link @click="viewDetail(row)">
|
||||
详情
|
||||
</el-button> -->
|
||||
<el-button type="primary" size="small" link @click="openEditDialog(row)">
|
||||
编辑
|
||||
</el-button>
|
||||
</template>
|
||||
</pure-table>
|
||||
</template>
|
||||
</PureTableBar>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- <style scoped lang="scss">
|
||||
.main {
|
||||
padding: 20px;
|
||||
}
|
||||
</style> -->
|
||||
132
src/views/LXlegend/periodsList/hook.tsx
Normal file
132
src/views/LXlegend/periodsList/hook.tsx
Normal file
@@ -0,0 +1,132 @@
|
||||
import { ref, h } from "vue";
|
||||
import { getMonsterLog } from "@/api/modules/game";
|
||||
import { message } from "@/utils/message";
|
||||
import { addDialog } from "@/components/ReDialog";
|
||||
import investRecordView from "./investRecord.vue";
|
||||
import winnerListView from "./winnerList.vue";
|
||||
|
||||
export function useData() {
|
||||
const loading = ref(true);
|
||||
const tableList = ref([]);
|
||||
const isShow = ref(false);
|
||||
const pagination = ref({
|
||||
total: 0,
|
||||
pageSize: 10,
|
||||
pageSizes: [10, 20, 50, 100, 500, 1000, 2000],
|
||||
currentPage: 1,
|
||||
background: true
|
||||
});
|
||||
|
||||
const searchForm = ref({});
|
||||
|
||||
const tableLabel = ref([
|
||||
{
|
||||
label: "期数ID",
|
||||
prop: "id"
|
||||
},
|
||||
{
|
||||
label: "游戏名称",
|
||||
prop: "type_name"
|
||||
},
|
||||
{
|
||||
label: "礼物名称",
|
||||
prop: "gift_name"
|
||||
},
|
||||
{
|
||||
label: "礼物价值",
|
||||
prop: "gift_price"
|
||||
},
|
||||
{
|
||||
label: "投入总数",
|
||||
prop: "out_amount"
|
||||
},
|
||||
{
|
||||
label: "支出总数",
|
||||
prop: "in_amount"
|
||||
},
|
||||
{
|
||||
label: "开始时间",
|
||||
prop: "createtime"
|
||||
},
|
||||
{
|
||||
label: "结束时间",
|
||||
prop: "end_time"
|
||||
},
|
||||
{
|
||||
label: "操作",
|
||||
fixed: "right",
|
||||
width: 220,
|
||||
slot: "operation"
|
||||
}
|
||||
]);
|
||||
|
||||
const onSearch = async formData => {
|
||||
loading.value = true;
|
||||
searchForm.value = { ...formData };
|
||||
const { data, code } = await getMonsterLog({
|
||||
...formData,
|
||||
page: pagination.value.currentPage,
|
||||
limit: pagination.value.pageSize
|
||||
});
|
||||
if (code) {
|
||||
tableList.value = data.lists || data.data || [];
|
||||
pagination.value.total = data.count || data.total || 0;
|
||||
pagination.value.currentPage = data.page || pagination.value.currentPage;
|
||||
}
|
||||
loading.value = false;
|
||||
};
|
||||
|
||||
const handleSizeChange = (val: number) => {
|
||||
pagination.value.pageSize = val;
|
||||
onSearch(searchForm.value);
|
||||
};
|
||||
|
||||
const handleCurrentChange = (val: number) => {
|
||||
pagination.value.currentPage = val;
|
||||
onSearch(searchForm.value);
|
||||
};
|
||||
|
||||
// 查看投入记录
|
||||
const viewInvestRecord = rowData => {
|
||||
addDialog({
|
||||
title: `投入记录 - 期数${rowData.period_no || rowData.id}`,
|
||||
props: {
|
||||
periodId: rowData.id,
|
||||
periodNo: rowData.period_no
|
||||
},
|
||||
width: "70%",
|
||||
closeOnClickModal: false,
|
||||
hideFooter: true,
|
||||
contentRenderer: () => h(investRecordView)
|
||||
});
|
||||
};
|
||||
|
||||
// 查看中奖人员
|
||||
const viewWinnerList = rowData => {
|
||||
addDialog({
|
||||
title: `中奖人员 - 期数${rowData.period_no || rowData.id}`,
|
||||
props: {
|
||||
periodId: rowData.id,
|
||||
periodNo: rowData.period_no
|
||||
},
|
||||
width: "70%",
|
||||
closeOnClickModal: false,
|
||||
hideFooter: true,
|
||||
contentRenderer: () => h(winnerListView)
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
searchForm,
|
||||
onSearch,
|
||||
isShow,
|
||||
tableList,
|
||||
tableLabel,
|
||||
pagination,
|
||||
handleSizeChange,
|
||||
handleCurrentChange,
|
||||
loading,
|
||||
viewInvestRecord,
|
||||
viewWinnerList
|
||||
};
|
||||
}
|
||||
61
src/views/LXlegend/periodsList/index.vue
Normal file
61
src/views/LXlegend/periodsList/index.vue
Normal file
@@ -0,0 +1,61 @@
|
||||
<script setup lang="ts">
|
||||
import { onBeforeMount } from "vue";
|
||||
import { useData } from "./hook";
|
||||
import { PureTableBar } from "@/components/RePureTableBar";
|
||||
import { deviceDetection } from "@pureadmin/utils";
|
||||
|
||||
const {
|
||||
searchForm,
|
||||
onSearch,
|
||||
isShow,
|
||||
tableList,
|
||||
pagination,
|
||||
tableLabel,
|
||||
handleSizeChange,
|
||||
handleCurrentChange,
|
||||
loading,
|
||||
viewInvestRecord,
|
||||
viewWinnerList
|
||||
} = useData();
|
||||
|
||||
onBeforeMount(() => {
|
||||
onSearch(searchForm.value);
|
||||
});
|
||||
|
||||
defineOptions({
|
||||
name: "periodsList"
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="main">
|
||||
<div ref="contentRef" :class="['flex', deviceDetection() ? 'flex-wrap' : '']">
|
||||
<PureTableBar v-if="!loading" title="期数列表" :class="[isShow && !deviceDetection() ? '!w-[60vw]' : 'w-full']"
|
||||
:columns="tableLabel" @refresh="onSearch">
|
||||
<template v-slot="{ size, dynamicColumns }">
|
||||
<pure-table ref="tableRef" align-whole="center" showOverflowTooltip table-layout="auto" default-expand-all
|
||||
:loading="loading" :size="size" row-key="id" adaptive :adaptiveConfig="{ offsetBottom: 108 }"
|
||||
:data="tableList" :columns="dynamicColumns" :pagination="{ ...pagination, size }" :header-cell-style="{
|
||||
background: 'var(--el-fill-color-light)',
|
||||
color: 'var(--el-text-color-primary)'
|
||||
}" @page-current-change="handleCurrentChange" @page-size-change="handleSizeChange">
|
||||
<template #operation="{ row }">
|
||||
<el-button type="primary" size="small" link @click="viewInvestRecord(row)">
|
||||
投入记录
|
||||
</el-button>
|
||||
<el-button type="success" size="small" link @click="viewWinnerList(row)">
|
||||
中奖人员
|
||||
</el-button>
|
||||
</template>
|
||||
</pure-table>
|
||||
</template>
|
||||
</PureTableBar>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<!--
|
||||
<style scoped lang="scss">
|
||||
.main {
|
||||
padding: 20px;
|
||||
}
|
||||
</style> -->
|
||||
107
src/views/LXlegend/periodsList/investRecord.vue
Normal file
107
src/views/LXlegend/periodsList/investRecord.vue
Normal file
@@ -0,0 +1,107 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from "vue";
|
||||
import { getUserMonsterLog } from "@/api/modules/game";
|
||||
|
||||
const props = defineProps(["periodId", "periodNo"]);
|
||||
const loading = ref(true);
|
||||
const tableList = ref([]);
|
||||
const pagination = ref({
|
||||
total: 0,
|
||||
pageSize: 10,
|
||||
currentPage: 1,
|
||||
background: true
|
||||
});
|
||||
|
||||
const tableColumns = ref([
|
||||
{
|
||||
label: "底数ID",
|
||||
prop: "id"
|
||||
},
|
||||
{
|
||||
label: "用户昵称",
|
||||
prop: "nickname"
|
||||
},
|
||||
{
|
||||
label: "头像",
|
||||
prop: "avatar",
|
||||
slot: "avatar"
|
||||
},
|
||||
{
|
||||
label: "投入类型",
|
||||
prop: "type_name"
|
||||
},
|
||||
{
|
||||
label: "总投入金额",
|
||||
prop: "price"
|
||||
},
|
||||
{
|
||||
label: "创建时间",
|
||||
prop: "createtime"
|
||||
}
|
||||
]);
|
||||
|
||||
// 获取投入记录
|
||||
const fetchInvestRecord = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const { data, code } = await getUserMonsterLog({
|
||||
mid: props.periodId,
|
||||
page: pagination.value.currentPage,
|
||||
limit: pagination.value.pageSize
|
||||
});
|
||||
if (code) {
|
||||
tableList.value = data.lists || data.data || [];
|
||||
pagination.value.total = data.count || data.total || 0;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("获取投入记录失败:", error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleSizeChange = (val: number) => {
|
||||
pagination.value.pageSize = val;
|
||||
fetchInvestRecord();
|
||||
};
|
||||
|
||||
const handleCurrentChange = (val: number) => {
|
||||
pagination.value.currentPage = val;
|
||||
fetchInvestRecord();
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
fetchInvestRecord();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="invest-record-container">
|
||||
<div class="info-bar">
|
||||
<el-alert :title="`期数:${periodNo || periodId}`" type="info" :closable="false" />
|
||||
</div>
|
||||
|
||||
<pure-table ref="tableRef" class="mt-5" align-whole="center" showOverflowTooltip table-layout="auto"
|
||||
:loading="loading" row-key="id" adaptive :adaptiveConfig="{ offsetBottom: 108 }" :data="tableList"
|
||||
:columns="tableColumns" :pagination="pagination" :header-cell-style="{
|
||||
background: 'var(--el-fill-color-light)',
|
||||
color: 'var(--el-text-color-primary)'
|
||||
}" @page-current-change="handleCurrentChange" @page-size-change="handleSizeChange">
|
||||
<template #avatar="{ row }">
|
||||
<el-image v-if="row.avatar" :src="row.avatar" fit="cover" preview-teleported :preview-src-list="[row.avatar]"
|
||||
style="width: 40px; height: 40px; border-radius: 50%" />
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</pure-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.invest-record-container {
|
||||
padding: 20px;
|
||||
|
||||
.info-bar {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
129
src/views/LXlegend/periodsList/winnerList.vue
Normal file
129
src/views/LXlegend/periodsList/winnerList.vue
Normal file
@@ -0,0 +1,129 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from "vue";
|
||||
import { getUserMonsterWinLog } from "@/api/modules/game";
|
||||
|
||||
const props = defineProps(["periodId", "periodNo"]);
|
||||
const loading = ref(true);
|
||||
const tableList = ref([]);
|
||||
const pagination = ref({
|
||||
total: 0,
|
||||
pageSize: 10,
|
||||
currentPage: 1,
|
||||
background: true
|
||||
});
|
||||
|
||||
const tableColumns = ref([
|
||||
{
|
||||
label: "期数ID",
|
||||
prop: "id"
|
||||
},
|
||||
{
|
||||
label: "用户昵称",
|
||||
prop: "nickname"
|
||||
},
|
||||
{
|
||||
label: "头像",
|
||||
prop: "avatar",
|
||||
slot: "avatar"
|
||||
},
|
||||
{
|
||||
label: "投入类型",
|
||||
prop: "nickname"
|
||||
},
|
||||
{
|
||||
label: "中奖礼物ID",
|
||||
prop: "win_gid"
|
||||
},
|
||||
{
|
||||
label: "中奖礼物名称",
|
||||
prop: "gift_name"
|
||||
},
|
||||
{
|
||||
label: "总投入金额",
|
||||
prop: "price"
|
||||
},
|
||||
{
|
||||
label: "获取礼物数量",
|
||||
prop: "num"
|
||||
},
|
||||
{
|
||||
label: "获取礼物价值",
|
||||
prop: "gift_price"
|
||||
},
|
||||
{
|
||||
label: "创建时间",
|
||||
prop: "createtime"
|
||||
}
|
||||
]);
|
||||
|
||||
// 获取中奖人员
|
||||
const fetchWinnerList = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const { data, code } = await getUserMonsterWinLog({
|
||||
mid: props.periodId,
|
||||
page: pagination.value.currentPage,
|
||||
limit: pagination.value.pageSize
|
||||
});
|
||||
if (code) {
|
||||
tableList.value = data.lists || data.data || [];
|
||||
pagination.value.total = data.count || data.total || 0;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("获取中奖人员失败:", error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleSizeChange = (val: number) => {
|
||||
pagination.value.pageSize = val;
|
||||
fetchWinnerList();
|
||||
};
|
||||
|
||||
const handleCurrentChange = (val: number) => {
|
||||
pagination.value.currentPage = val;
|
||||
fetchWinnerList();
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
fetchWinnerList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="winner-list-container">
|
||||
<div class="info-bar">
|
||||
<el-alert :title="`期数:${periodNo || periodId}`" type="success" :closable="false" />
|
||||
</div>
|
||||
|
||||
<pure-table ref="tableRef" class="mt-5" align-whole="center" showOverflowTooltip table-layout="auto"
|
||||
:loading="loading" row-key="id" adaptive :adaptiveConfig="{ offsetBottom: 108 }" :data="tableList"
|
||||
:columns="tableColumns" :pagination="pagination" :header-cell-style="{
|
||||
background: 'var(--el-fill-color-light)',
|
||||
color: 'var(--el-text-color-primary)'
|
||||
}" @page-current-change="handleCurrentChange" @page-size-change="handleSizeChange">
|
||||
<template #avatar="{ row }">
|
||||
<el-image v-if="row.avatar" :src="row.avatar" fit="cover" preview-teleported :preview-src-list="[row.avatar]"
|
||||
style="width: 40px; height: 40px; border-radius: 50%" />
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
|
||||
<template #giftIcon="{ row }">
|
||||
<el-image v-if="row.gift_icon" :src="row.gift_icon" fit="cover" preview-teleported
|
||||
:preview-src-list="[row.gift_icon]" style="width: 50px; height: 50px; border-radius: 4px" />
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</pure-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.winner-list-container {
|
||||
padding: 20px;
|
||||
|
||||
.info-bar {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
206
src/views/Statistical/luckycoinLottery/hook.tsx
Normal file
206
src/views/Statistical/luckycoinLottery/hook.tsx
Normal file
@@ -0,0 +1,206 @@
|
||||
import { ref, h } from "vue";
|
||||
import { getLotteryPoolFlow } from "@/api/modules/statistics";
|
||||
import { utils, writeFile } from "xlsx";
|
||||
import ExportForm from "@/components/exportDialog/index.vue";
|
||||
import { addDialog } from "@/components/ReDialog";
|
||||
import { message } from "@/utils/message";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
export function useData() {
|
||||
const loading = ref(true);
|
||||
const tableList = ref([]);
|
||||
const isShow = ref(false);
|
||||
const pagination = ref({
|
||||
total: 0,
|
||||
pageSize: 10,
|
||||
pageSizes: [10, 20, 50, 100, 500, 1000, 2000],
|
||||
currentPage: 1,
|
||||
background: true
|
||||
});
|
||||
|
||||
// 获取当月第一天 00:00:00 和当前时间
|
||||
const getDefaultTimeRange = () => {
|
||||
const now = dayjs();
|
||||
const startOfMonth = now.startOf("month").format("YYYY-MM-DD HH:mm:ss");
|
||||
const currentTime = now.format("YYYY-MM-DD HH:mm:ss");
|
||||
return { stime: startOfMonth, etime: currentTime };
|
||||
};
|
||||
|
||||
const defaultTime = getDefaultTimeRange();
|
||||
|
||||
const searchForm = ref({
|
||||
stime: defaultTime.stime,
|
||||
etime: defaultTime.etime,
|
||||
pool_type: 1,
|
||||
user_code: ""
|
||||
});
|
||||
|
||||
const searchLabel = ref([
|
||||
{ label: "开始时间", prop: "stime", type: "date" },
|
||||
{ label: "结束时间", prop: "etime", type: "date" },
|
||||
{ label: "用户ID", prop: "user_code", type: "input" },
|
||||
{
|
||||
label: "类型",
|
||||
prop: "pool_type",
|
||||
type: "select",
|
||||
optionList: [
|
||||
{ label: "初级", value: 1 },
|
||||
{ label: "中级", value: 3 },
|
||||
{ label: "高级", value: 4 }
|
||||
]
|
||||
}
|
||||
]);
|
||||
|
||||
const tableLabel = ref([
|
||||
{
|
||||
label: "ID",
|
||||
prop: "id"
|
||||
},
|
||||
{
|
||||
label: "抽奖用户(送礼用户)",
|
||||
prop: "send_nickname"
|
||||
},
|
||||
{
|
||||
label: "收礼用户",
|
||||
prop: "recv_nickname"
|
||||
},
|
||||
{
|
||||
label: "礼物信息",
|
||||
prop: "gift_name"
|
||||
},
|
||||
{
|
||||
label: "礼物价值",
|
||||
prop: "gift_gold"
|
||||
},
|
||||
{
|
||||
label: "收礼人收益",
|
||||
prop: "recv_gold"
|
||||
},
|
||||
{
|
||||
label: "划入奖池的金币",
|
||||
prop: "small_pool_add"
|
||||
},
|
||||
{
|
||||
label: "备注",
|
||||
prop: "remark"
|
||||
},
|
||||
{
|
||||
label: "时间",
|
||||
prop: "createtime"
|
||||
}
|
||||
]);
|
||||
|
||||
const onSearch = async formData => {
|
||||
loading.value = true;
|
||||
searchForm.value = { ...formData };
|
||||
const { data, code } = await getLotteryPoolFlow({
|
||||
...formData,
|
||||
page: pagination.value.currentPage,
|
||||
page_limit: pagination.value.pageSize
|
||||
});
|
||||
if (code) {
|
||||
tableList.value = data.lists.map(ele => {
|
||||
return {
|
||||
...ele,
|
||||
receive_income: parseFloat(ele.receive_income || 0),
|
||||
pool_amount: parseFloat(ele.pool_amount || 0)
|
||||
};
|
||||
});
|
||||
pagination.value.total = data.count;
|
||||
pagination.value.currentPage = parseFloat(data.page);
|
||||
}
|
||||
loading.value = false;
|
||||
};
|
||||
|
||||
const handleSizeChange = (val: number) => {
|
||||
pagination.value.pageSize = val;
|
||||
onSearch(searchForm.value);
|
||||
};
|
||||
|
||||
const handleCurrentChange = (val: number) => {
|
||||
pagination.value.currentPage = val;
|
||||
onSearch(searchForm.value);
|
||||
};
|
||||
|
||||
const exportFormRef = ref(null);
|
||||
const exportExcel = () => {
|
||||
let exportTableList = [];
|
||||
addDialog({
|
||||
title: `导出数据`,
|
||||
props: {
|
||||
formInline: {
|
||||
time: ""
|
||||
}
|
||||
},
|
||||
width: "40%",
|
||||
closeOnClickModal: false,
|
||||
contentRenderer: () =>
|
||||
h(ExportForm, { ref: exportFormRef, formInline: null }),
|
||||
beforeSure: (done, { options }) => {
|
||||
const FormRef = exportFormRef.value.getRef();
|
||||
const curData = options.props.formInline;
|
||||
const exportData = async formData => {
|
||||
const { data, code } = await getLotteryPoolFlow({
|
||||
...formData,
|
||||
page: 1,
|
||||
page_limit: 20000
|
||||
});
|
||||
if (code) {
|
||||
exportTableList = data.lists;
|
||||
const res = exportTableList.map(item => {
|
||||
const arr = [];
|
||||
tableLabel.value.forEach(column => {
|
||||
arr.push(item[column.prop as string]);
|
||||
});
|
||||
return arr;
|
||||
});
|
||||
const titleList = [];
|
||||
tableLabel.value.forEach(column => {
|
||||
titleList.push(column.label);
|
||||
});
|
||||
res.unshift(titleList);
|
||||
const workSheet = utils.aoa_to_sheet(res);
|
||||
const workBook = utils.book_new();
|
||||
utils.book_append_sheet(workBook, workSheet, "数据报表");
|
||||
writeFile(
|
||||
workBook,
|
||||
`幸运币抽奖统计${formData.start_time} - ${formData.end_time}.xlsx`
|
||||
);
|
||||
message("导出成功", {
|
||||
type: "success"
|
||||
});
|
||||
done();
|
||||
} else {
|
||||
message("获取数据失败,请重试!", {
|
||||
type: "error"
|
||||
});
|
||||
}
|
||||
};
|
||||
FormRef.validate(valid => {
|
||||
if (valid) {
|
||||
if (curData.time && curData.time.length) {
|
||||
exportData({
|
||||
start_time: curData.time[0] || "",
|
||||
end_time: curData.time[1] || ""
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
searchForm,
|
||||
searchLabel,
|
||||
onSearch,
|
||||
isShow,
|
||||
tableList,
|
||||
tableLabel,
|
||||
pagination,
|
||||
exportExcel,
|
||||
handleSizeChange,
|
||||
handleCurrentChange,
|
||||
loading
|
||||
};
|
||||
}
|
||||
63
src/views/Statistical/luckycoinLottery/index.vue
Normal file
63
src/views/Statistical/luckycoinLottery/index.vue
Normal file
@@ -0,0 +1,63 @@
|
||||
<script setup lang="ts">
|
||||
import { onBeforeMount } from "vue";
|
||||
import { useData } from "./hook";
|
||||
import SearchForm from "@/components/SearchForm/index.vue";
|
||||
import { PureTableBar } from "@/components/RePureTableBar";
|
||||
import { deviceDetection } from "@pureadmin/utils";
|
||||
|
||||
const {
|
||||
searchLabel,
|
||||
searchForm,
|
||||
onSearch,
|
||||
isShow,
|
||||
tableList,
|
||||
pagination,
|
||||
tableLabel,
|
||||
exportExcel,
|
||||
handleSizeChange,
|
||||
handleCurrentChange,
|
||||
loading
|
||||
} = useData();
|
||||
|
||||
onBeforeMount(() => {
|
||||
onSearch(searchForm.value);
|
||||
});
|
||||
|
||||
defineOptions({
|
||||
name: "luckycoinLottery"
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="main">
|
||||
<SearchForm class="pb-2" :LabelList="searchLabel" :formData="searchForm" @handleSearch="onSearch" />
|
||||
<div ref="contentRef" :class="['flex', deviceDetection() ? 'flex-wrap' : '']">
|
||||
<PureTableBar v-if="!loading" title="幸运币抽奖统计列表" :class="[isShow && !deviceDetection() ? '!w-[60vw]' : 'w-full']"
|
||||
:columns="tableLabel" @refresh="onSearch">
|
||||
<template #buttons>
|
||||
<el-button type="primary" @click="exportExcel"> 导出 </el-button>
|
||||
</template>
|
||||
<template v-slot="{ size, dynamicColumns }">
|
||||
<pure-table ref="tableRef" align-whole="center" showOverflowTooltip table-layout="auto" default-expand-all
|
||||
:loading="loading" :size="size" row-key="id" adaptive :adaptiveConfig="{ offsetBottom: 108 }"
|
||||
:data="tableList" :columns="dynamicColumns" :pagination="{ ...pagination, size }" :header-cell-style="{
|
||||
background: 'var(--el-fill-color-light)',
|
||||
color: 'var(--el-text-color-primary)'
|
||||
}" @page-current-change="handleCurrentChange" @page-size-change="handleSizeChange" />
|
||||
</template>
|
||||
</PureTableBar>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.content-flex {
|
||||
width: 100%;
|
||||
display: inline-flex;
|
||||
background-color: #fff;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user