Browse Source
Merge branch 'milestone-20260107-用户画像记录' of http://39.101.133.168:8807/qimaohong/deepChartBack into songjie/feature-20260204135046-用户活跃度统计
milestone-20260107-用户画像记录
Merge branch 'milestone-20260107-用户画像记录' of http://39.101.133.168:8807/qimaohong/deepChartBack into songjie/feature-20260204135046-用户活跃度统计
milestone-20260107-用户画像记录
7 changed files with 1144 additions and 14 deletions
-
1.env.development
-
1.env.production
-
56src/api/eventManagement.js
-
76src/layout/Layout.vue
-
26src/router/index.js
-
568src/views/EventManagement/ContentConfiguration.vue
-
426src/views/EventManagement/WinningRecords.vue
@ -1,2 +1,3 @@ |
|||||
VITE_API_BASE_URL = "https://dbqb.legu168.cn/adminApi" |
VITE_API_BASE_URL = "https://dbqb.legu168.cn/adminApi" |
||||
VITE_API_BASE_URL_LINK = "https://dbqb.legu168.cn/hljw/api/haiwai/user/login_jwcode" |
VITE_API_BASE_URL_LINK = "https://dbqb.legu168.cn/hljw/api/haiwai/user/login_jwcode" |
||||
|
VITE_API_BASE_URLXXCG=https://api.homilychart.com/ |
||||
@ -1,2 +1,3 @@ |
|||||
VITE_API_BASE_URL = "https://dcapi.homilychart.com/prod/deepchart" |
VITE_API_BASE_URL = "https://dcapi.homilychart.com/prod/deepchart" |
||||
VITE_API_BASE_URL_LINK = "https://api.homilychart.com/hljw/api/haiwai/user/login_jwcode" |
VITE_API_BASE_URL_LINK = "https://api.homilychart.com/hljw/api/haiwai/user/login_jwcode" |
||||
|
VITE_API_BASE_URLXXCG=https://api.homilychart.com/ |
||||
@ -0,0 +1,56 @@ |
|||||
|
import request from '../utils/myAxios'; |
||||
|
var base_url = import.meta.env.VITE_API_BASE_URL |
||||
|
|
||||
|
// 获取用户抽奖记录
|
||||
|
export function userLuckyDrawListApi(params) { |
||||
|
return request({ |
||||
|
url: base_url + "/admin/luckyDraw/list", |
||||
|
method: "post", |
||||
|
data: params, |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
// 导出用户抽奖记录
|
||||
|
export function exportUserLuckyDrawListApi(params) { |
||||
|
return request({ |
||||
|
url: base_url + "/admin/luckyDraw/export/create", |
||||
|
method: "post", |
||||
|
data: params, |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
// 获取配置列表
|
||||
|
export function getContentListApi(params) { |
||||
|
return request({ |
||||
|
url: base_url + "/admin/luckyDraw/getContentList", |
||||
|
method: "post", |
||||
|
data: params, |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
// 添加奖品
|
||||
|
export function addDrawConfigApi(params) { |
||||
|
return request({ |
||||
|
url: base_url + "/admin/luckyDraw/addDrawConfig", |
||||
|
method: "post", |
||||
|
data: params, |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
// 删除奖品
|
||||
|
export function deleteDrawApi(params) { |
||||
|
return request({ |
||||
|
url: base_url + "/admin/luckyDraw/deleteDraw", |
||||
|
method: "post", |
||||
|
data: params, |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
// 修改奖品状态
|
||||
|
export function changeStatusApi(params) { |
||||
|
return request({ |
||||
|
url: base_url + "/admin/luckyDraw/changeStatus", |
||||
|
method: "post", |
||||
|
data: params, |
||||
|
}); |
||||
|
} |
||||
@ -0,0 +1,568 @@ |
|||||
|
<template> |
||||
|
<div class="page-container"> |
||||
|
<div class="search-container"> |
||||
|
<el-button type="danger" @click="add">添加</el-button> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 数据 --> |
||||
|
<el-table |
||||
|
:data="tableData" |
||||
|
style="width: 100%; margin-top: 20px" |
||||
|
header-cell-class-name="table-header" |
||||
|
@sort-change="handleSortChange" |
||||
|
:default-sort="{ prop: null, order: null }" |
||||
|
class="table-rounded" |
||||
|
:loading="tableLoading" |
||||
|
> |
||||
|
<el-table-column |
||||
|
prop="id" |
||||
|
label="序号" |
||||
|
align="center" |
||||
|
header-align="center" |
||||
|
width="80" |
||||
|
> |
||||
|
<template #default="scope"> |
||||
|
{{ (currentPage - 1) * pageSize + scope.$index + 1 }} |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column |
||||
|
prop="prize_type" |
||||
|
label="类型" |
||||
|
align="center" |
||||
|
header-align="center" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
prop="prize_name" |
||||
|
label="物品名称" |
||||
|
align="center" |
||||
|
header-align="center" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
prop="stick_type" |
||||
|
label="福签" |
||||
|
align="center" |
||||
|
header-align="center" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
prop="probability" |
||||
|
label="概率" |
||||
|
align="center" |
||||
|
header-align="center" |
||||
|
/> |
||||
|
<el-table-column label="状态" prop="status"> |
||||
|
<template #default="scope"> |
||||
|
<el-switch |
||||
|
v-model="scope.row.status" |
||||
|
:active-value="1" |
||||
|
:inactive-value="0" |
||||
|
inline-prompt |
||||
|
style=" |
||||
|
--el-switch-on-color: #13ce66; |
||||
|
--el-switch-off-color: #ff4949; |
||||
|
" |
||||
|
active-text="ON" |
||||
|
inactive-text="OFF" |
||||
|
:before-change="() => beforeChangeState(scope.row)" |
||||
|
> |
||||
|
</el-switch> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column |
||||
|
prop="time" |
||||
|
label="时间" |
||||
|
align="center" |
||||
|
header-align="center" |
||||
|
/> |
||||
|
<el-table-column label="操作" align="center" header-align="center"> |
||||
|
<template #default="scope"> |
||||
|
<el-button type="text" @click="deleteDraw(scope.row)">删除</el-button> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
</el-table> |
||||
|
|
||||
|
<!-- 分页组件 --> |
||||
|
<div class="demo-pagination-block"> |
||||
|
<el-pagination |
||||
|
@size-change="handleSizeChange" |
||||
|
@current-change="handleCurrentChange" |
||||
|
:current-page="currentPage" |
||||
|
:page-sizes="[10, 15, 20, 50, 100]" |
||||
|
:page-size="pageSize" |
||||
|
layout="total, sizes, prev, pager, next, jumper" |
||||
|
:total="datatotal" |
||||
|
/> |
||||
|
</div> |
||||
|
<el-dialog v-model="dialogFormVisible" width="500" :show-close="false"> |
||||
|
<el-form |
||||
|
:model="form" |
||||
|
style="width: 400px; margin: 0 auto" |
||||
|
:rules="rules" |
||||
|
ref="formRef" |
||||
|
> |
||||
|
<el-form-item label="类型" prop="type"> |
||||
|
<el-select v-model="form.type" placeholder="请选择类型" clearable> |
||||
|
<el-option |
||||
|
v-for="item in prizeTypeOptions" |
||||
|
:key="item.value" |
||||
|
:label="item.label" |
||||
|
:value="item.value" |
||||
|
/> |
||||
|
</el-select> |
||||
|
</el-form-item> |
||||
|
<el-form-item :label="nameConfig.label" :prop="nameConfig.prop"> |
||||
|
<el-input |
||||
|
v-model="form[nameConfig.prop]" |
||||
|
:type="nameConfig.type" |
||||
|
autocomplete="off" |
||||
|
:placeholder="nameConfig.placeholder" |
||||
|
clearable |
||||
|
/> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="概率" prop="probability"> |
||||
|
<el-input |
||||
|
v-model.number="form.probability" |
||||
|
type="number" |
||||
|
autocomplete="off" |
||||
|
placeholder="请输入概率" |
||||
|
clearable |
||||
|
> |
||||
|
<template #append>%</template> |
||||
|
</el-input> |
||||
|
<div class="tip">(小于等于100%)</div> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="福签" prop="stick_type"> |
||||
|
<el-select |
||||
|
v-model="form.stick_type" |
||||
|
placeholder="请选择类型" |
||||
|
clearable |
||||
|
> |
||||
|
<el-option |
||||
|
v-for="item in typeOptions" |
||||
|
:key="item.value" |
||||
|
:label="item.label" |
||||
|
:value="item.value" |
||||
|
/> |
||||
|
</el-select> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="图片" prop="img"> |
||||
|
<el-upload |
||||
|
ref="uploadRef" |
||||
|
v-model:file-list="fileList" |
||||
|
class="avatar-uploader" |
||||
|
:action="uploadUrl" |
||||
|
:limit="1" |
||||
|
list-type="picture-card" |
||||
|
:on-success="handleSuccess" |
||||
|
:before-upload="beforeUpload" |
||||
|
:on-remove="handleRemove" |
||||
|
:on-exceed="handleExceed" |
||||
|
> |
||||
|
<el-icon><Plus /></el-icon> |
||||
|
</el-upload> |
||||
|
<div class="tip"> |
||||
|
大小180*180像素,支持PNG、JPG格式,图片需小于500K |
||||
|
</div> |
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
|
<template #footer> |
||||
|
<div class="dialog-footer"> |
||||
|
<el-button @click="dialogFormVisible = false">取消</el-button> |
||||
|
<el-button type="danger" @click="submitForm(formRef)"> |
||||
|
提交 |
||||
|
</el-button> |
||||
|
</div> |
||||
|
</template> |
||||
|
</el-dialog> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import { ref, reactive, onMounted, computed, watch } from "vue"; |
||||
|
import { ElMessage, genFileId, ElMessageBox } from "element-plus"; |
||||
|
import router from "../../router"; |
||||
|
import { |
||||
|
getContentListApi, |
||||
|
addDrawConfigApi, |
||||
|
deleteDrawApi, |
||||
|
changeStatusApi, |
||||
|
} from "../../api/eventManagement"; |
||||
|
const uploadUrl = import.meta.env.VITE_API_BASE_URLXXCG + "hljw/api/aws/upload"; |
||||
|
const uploadRef = ref(); |
||||
|
const fileList = ref([]); |
||||
|
const formRef = ref(); |
||||
|
const form = reactive({ |
||||
|
stick_type: "", |
||||
|
type: "", |
||||
|
item_name: "", |
||||
|
num: null, |
||||
|
probability: null, |
||||
|
img: "", |
||||
|
}); |
||||
|
const typeOptions = ref([ |
||||
|
{ label: "好运签", value: 1 }, |
||||
|
{ label: "福气签", value: 2 }, |
||||
|
{ label: "富贵签", value: 3 }, |
||||
|
{ label: "财神签", value: 4 }, |
||||
|
{ label: "上上签", value: 5 }, |
||||
|
{ label: "锦鲤签", value: 6 }, |
||||
|
]); |
||||
|
const prizeTypeOptions = ref([ |
||||
|
{ label: "金币", value: 2 }, |
||||
|
{ label: "金豆", value: 3 }, |
||||
|
{ label: "Token", value: 1 }, |
||||
|
{ label: "实物", value: 4 }, |
||||
|
]); |
||||
|
const nameConfig = computed(() => { |
||||
|
switch (form.type) { |
||||
|
case 1: // Token |
||||
|
return { label: "数量", placeholder: "请输入Token数量", prop: "num", type: "number" }; |
||||
|
case 2: // 金币 |
||||
|
return { label: "数量", placeholder: "请输入金币数量", prop: "num", type: "number" }; |
||||
|
case 3: // 金豆 |
||||
|
return { label: "数量", placeholder: "请输入金豆数量", prop: "num", type: "number" }; |
||||
|
default: // 默认情况(未选择或实物) |
||||
|
return { label: "名称", placeholder: "请输入物品名称", prop: "item_name", type: "text" }; |
||||
|
} |
||||
|
}); |
||||
|
const handleSuccess = (response, uploadFile) => { |
||||
|
form.img = response.data.url; |
||||
|
}; |
||||
|
|
||||
|
const beforeUpload = (rawFile) => { |
||||
|
if (!rawFile.type.startsWith("image/")) { |
||||
|
ElMessage.error("请上传图片文件!"); |
||||
|
return false; |
||||
|
} else if (rawFile.size / 1024 > 500) { |
||||
|
ElMessage.error("图片大小必须小于500K!"); |
||||
|
return false; |
||||
|
} |
||||
|
return true; |
||||
|
}; |
||||
|
|
||||
|
const handleRemove = (file, fileList) => { |
||||
|
form.img = ""; |
||||
|
}; |
||||
|
|
||||
|
const handleExceed = (files) => { |
||||
|
// 1. 清空当前文件列表 |
||||
|
uploadRef.value.clearFiles(); |
||||
|
const file = files[0]; |
||||
|
// 2. 必须生成新的 uid,否则可能导致 key 冲突无法上传 |
||||
|
file.uid = genFileId(); |
||||
|
// 3. 手动选择文件 |
||||
|
uploadRef.value.handleStart(file); |
||||
|
// 4. 手动触发上传 |
||||
|
uploadRef.value.submit(); |
||||
|
}; |
||||
|
|
||||
|
// token |
||||
|
const token = localStorage.getItem("token"); |
||||
|
|
||||
|
const dialogFormVisible = ref(false); |
||||
|
|
||||
|
const rules = computed(() => { |
||||
|
const baseRules = { |
||||
|
stick_type: [{ required: true, message: "请选择类型", trigger: "change" }], |
||||
|
type: [{ required: true, message: "请选择类型", trigger: "change" }], |
||||
|
probability: [ |
||||
|
{ required: true, message: "请输入概率", trigger: "blur" }, |
||||
|
// 为负数时提示 |
||||
|
{ validator: validateNum, trigger: "blur" }, |
||||
|
], |
||||
|
img: [{ required: true, message: "请上传图片", trigger: "change" }], // 上传通常用 change |
||||
|
}; |
||||
|
if ([1, 2, 3].includes(form.type)) { |
||||
|
return { |
||||
|
...baseRules, |
||||
|
num: [ |
||||
|
{ required: true, message: "请输入数量", trigger: "blur" }, |
||||
|
// 为负数时提示 |
||||
|
{ validator: validateNum, trigger: "blur" }, |
||||
|
], |
||||
|
}; |
||||
|
} else { |
||||
|
return { |
||||
|
...baseRules, |
||||
|
item_name: [ |
||||
|
{ required: true, message: "请输入物品名称", trigger: "blur" }, |
||||
|
], |
||||
|
}; |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
watch( |
||||
|
() => form.type, |
||||
|
() => { |
||||
|
// 切换类型时,清除之前的输入值,避免校验报错或数据混乱 |
||||
|
form.item_name = ""; |
||||
|
form.num = null; |
||||
|
// 也可以清除校验状态 |
||||
|
if (formRef.value) { |
||||
|
formRef.value.clearValidate(["item_name", "num"]); |
||||
|
} |
||||
|
} |
||||
|
); |
||||
|
|
||||
|
const validateNum = (rule, value, callback) => { |
||||
|
// 如果值为空,交给 required 规则处理 |
||||
|
if (value === "" || value === null || value === undefined) { |
||||
|
callback(); |
||||
|
return; |
||||
|
} |
||||
|
// 转换为数字进行判断 |
||||
|
if (Number(value) < 0) { |
||||
|
callback(new Error("不能为负数")); |
||||
|
} else { |
||||
|
callback(); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
// 表格数据 |
||||
|
const tableData = ref([]); |
||||
|
const tableLoading = ref(false); |
||||
|
const datatotal = ref(0); |
||||
|
|
||||
|
// 分页参数 |
||||
|
const currentPage = ref(1); |
||||
|
const pageSize = ref(15); |
||||
|
|
||||
|
const beforeChangeState = (row) => { |
||||
|
return new Promise(async (resolve, reject) => { |
||||
|
try { |
||||
|
const targetStatus = row.status === 1 ? 0 : 1; |
||||
|
await changeStatusApi({ |
||||
|
token: token, |
||||
|
id: row.id, |
||||
|
status: targetStatus, |
||||
|
}); |
||||
|
ElMessage.success("状态更新成功"); |
||||
|
resolve(true); |
||||
|
// fetchTableData(); |
||||
|
} catch (error) { |
||||
|
// reject()拒绝操作,switch 组件会自动回滚状态 |
||||
|
reject(new Error("状态更新失败")); |
||||
|
} |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
// 重置表单数据 |
||||
|
const resetForm = () => { |
||||
|
form.stick_type = ""; |
||||
|
form.type = ""; |
||||
|
form.item_name = ""; |
||||
|
form.num = null; |
||||
|
form.probability = null; |
||||
|
form.img = ""; |
||||
|
fileList.value = []; |
||||
|
}; |
||||
|
|
||||
|
// 添加按钮 |
||||
|
const add = () => { |
||||
|
resetForm(); |
||||
|
dialogFormVisible.value = true; |
||||
|
}; |
||||
|
|
||||
|
const submitForm = async () => { |
||||
|
try { |
||||
|
await formRef.value.validate(); |
||||
|
const requestParams = { |
||||
|
token: token, |
||||
|
stick_type: form.stick_type, |
||||
|
type: form.type, |
||||
|
probability: form.probability, |
||||
|
img: form.img, |
||||
|
}; |
||||
|
if ([1, 2, 3].includes(form.type)) { |
||||
|
requestParams.num = Number(form.num); |
||||
|
} else { |
||||
|
requestParams.item_name = form.item_name; |
||||
|
} |
||||
|
const data = await addDrawConfigApi(requestParams); |
||||
|
ElMessage.success("添加成功"); |
||||
|
dialogFormVisible.value = false; |
||||
|
fetchTableData(); |
||||
|
} catch (error) {} |
||||
|
}; |
||||
|
|
||||
|
const deleteDraw = async (row) => { |
||||
|
try { |
||||
|
await ElMessageBox.confirm("确定要删除吗?", "确认删除", { |
||||
|
confirmButtonText: "确定", |
||||
|
cancelButtonText: "取消", |
||||
|
type: "warning", |
||||
|
confirmButtonClass: "custom-confirm-btn", |
||||
|
}); |
||||
|
const requestParams = { |
||||
|
token: token, |
||||
|
id: row.id, |
||||
|
}; |
||||
|
const data = await deleteDrawApi(requestParams); |
||||
|
ElMessage.success("删除成功"); |
||||
|
fetchTableData(); |
||||
|
} catch (error) { |
||||
|
if (error === "cancel") { |
||||
|
// 用户点击取消 |
||||
|
ElMessage.info("已取消删除"); |
||||
|
} else { |
||||
|
// 删除操作失败 |
||||
|
ElMessage.error("删除失败"); |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
// 获取表格数据 |
||||
|
const fetchTableData = async () => { |
||||
|
try { |
||||
|
tableLoading.value = true; |
||||
|
const requestParams = { |
||||
|
token: token, |
||||
|
page: currentPage.value, |
||||
|
page_size: pageSize.value, |
||||
|
}; |
||||
|
const data = await getContentListApi(requestParams); |
||||
|
tableData.value = data.list; |
||||
|
datatotal.value = data.total; |
||||
|
} catch (error) { |
||||
|
console.error("获取表格数据失败:", error); |
||||
|
tableData.value = []; |
||||
|
datatotal.value = 0; |
||||
|
} finally { |
||||
|
tableLoading.value = false; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
// 组件挂载时:获取地区列表 + 初始化表格数据 |
||||
|
onMounted(() => { |
||||
|
fetchTableData(); |
||||
|
}); |
||||
|
|
||||
|
// 分页方法 |
||||
|
const handleSizeChange = (val) => { |
||||
|
pageSize.value = val; |
||||
|
fetchTableData(); |
||||
|
console.log(`每页 ${val} 条`); |
||||
|
}; |
||||
|
|
||||
|
const handleCurrentChange = (val) => { |
||||
|
currentPage.value = val; |
||||
|
fetchTableData(); |
||||
|
console.log(`当前页: ${val}`); |
||||
|
}; |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
/* 父容器 */ |
||||
|
.page-container { |
||||
|
position: relative; |
||||
|
min-height: 600px; |
||||
|
} |
||||
|
|
||||
|
/* 搜索区域 */ |
||||
|
.search-container { |
||||
|
display: flex; |
||||
|
height: auto; |
||||
|
flex-direction: column; |
||||
|
justify-content: center; |
||||
|
align-items: flex-start; |
||||
|
gap: 12px; |
||||
|
align-self: stretch; |
||||
|
border-radius: 8px; |
||||
|
background: #fefaf9; |
||||
|
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.25); |
||||
|
padding: 15px; |
||||
|
margin-bottom: 20px; |
||||
|
} |
||||
|
|
||||
|
/* 表格样式 */ |
||||
|
.table-rounded { |
||||
|
border-radius: 12px !important; |
||||
|
overflow: hidden !important; |
||||
|
border: 1px solid #e4e7ed !important; |
||||
|
height: 750px; |
||||
|
} |
||||
|
|
||||
|
.table-header { |
||||
|
text-align: center !important; |
||||
|
font-weight: 800 !important; |
||||
|
font-size: 15px !important; |
||||
|
color: #333 !important; |
||||
|
background-color: #f8f9fa !important; |
||||
|
} |
||||
|
|
||||
|
.el-table__cell { |
||||
|
border-right: none !important; |
||||
|
border-bottom: 1px solid #e4e7ed !important; |
||||
|
} |
||||
|
|
||||
|
.el-table__header th.el-table__cell { |
||||
|
border-right: none !important; |
||||
|
border-bottom: 1px solid #e4e7ed !important; |
||||
|
} |
||||
|
|
||||
|
.el-table__row:hover .el-table__cell { |
||||
|
background-color: #fafafa !important; |
||||
|
} |
||||
|
|
||||
|
/* 分页组件样式 */ |
||||
|
.demo-pagination-block { |
||||
|
display: flex; |
||||
|
width: 100%; |
||||
|
height: 44px; |
||||
|
padding: 0 16px; |
||||
|
align-items: center; |
||||
|
gap: 16px; |
||||
|
position: absolute; |
||||
|
margin-top: 10px; |
||||
|
border-radius: 0 0 3px 3px; |
||||
|
border-top: 1px solid #eaeaea; |
||||
|
background: #fefbfb; |
||||
|
box-sizing: border-box; |
||||
|
} |
||||
|
|
||||
|
.tip { |
||||
|
font-size: 12px; |
||||
|
color: #8c939d; |
||||
|
} |
||||
|
|
||||
|
.avatar-uploader .avatar { |
||||
|
width: 120px; |
||||
|
height: 120px; |
||||
|
display: block; |
||||
|
} |
||||
|
</style> |
||||
|
|
||||
|
<style> |
||||
|
.custom-confirm-btn { |
||||
|
background: #e13d52; |
||||
|
border-color: #e13d52; |
||||
|
color: white !important; |
||||
|
border-radius: 6px !important; |
||||
|
padding: 8px 16px !important; |
||||
|
} |
||||
|
|
||||
|
.custom-confirm-btn:hover { |
||||
|
background: #d88b95; |
||||
|
border-color: #d88b95; |
||||
|
} |
||||
|
|
||||
|
.avatar-uploader .el-upload { |
||||
|
border: 1px dashed var(--el-border-color); |
||||
|
border-radius: 6px; |
||||
|
cursor: pointer; |
||||
|
position: relative; |
||||
|
overflow: hidden; |
||||
|
transition: var(--el-transition-duration-fast); |
||||
|
} |
||||
|
|
||||
|
.avatar-uploader .el-upload:hover { |
||||
|
border-color: var(--el-color-primary); |
||||
|
} |
||||
|
|
||||
|
.el-icon.avatar-uploader-icon { |
||||
|
font-size: 28px; |
||||
|
color: #8c939d; |
||||
|
width: 120px; |
||||
|
height: 120px; |
||||
|
text-align: center; |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,426 @@ |
|||||
|
<template> |
||||
|
<div class="page-container"> |
||||
|
<!-- 搜索区域 --> |
||||
|
<div class="search-container"> |
||||
|
<div class="search-group"> |
||||
|
<span class="form-label">账号</span> |
||||
|
<el-input |
||||
|
v-model="searchForm.dccode" |
||||
|
placeholder="请输入账号" |
||||
|
clearable |
||||
|
style="height: 36px; width: 140px" |
||||
|
/> |
||||
|
<span class="form-label">地区</span> |
||||
|
<el-select |
||||
|
v-model="searchForm.country" |
||||
|
placeholder="请选择地区" |
||||
|
clearable |
||||
|
filterable |
||||
|
style="height: 36px; width: 160px" |
||||
|
:loading="isRegionLoading" |
||||
|
> |
||||
|
<el-option |
||||
|
v-for="region in regionList" |
||||
|
:key="region.ID" |
||||
|
:label="region.Name" |
||||
|
:value="region.ID" |
||||
|
/> |
||||
|
</el-select> |
||||
|
<span class="form-label">物品类型</span> |
||||
|
<el-select |
||||
|
v-model="searchForm.prize_type" |
||||
|
placeholder="请选择类型" |
||||
|
style="height: 36px; width: 160px" |
||||
|
clearable |
||||
|
> |
||||
|
<el-option |
||||
|
v-for="item in typeOptions" |
||||
|
:key="item.value" |
||||
|
:label="item.label" |
||||
|
:value="item.value" |
||||
|
/> |
||||
|
</el-select> |
||||
|
</div> |
||||
|
<div class="button-group"> |
||||
|
<el-button type="primary" @click="search">搜索</el-button> |
||||
|
<el-button type="success" @click="exportExcel">导出Excel列表</el-button> |
||||
|
<el-button color="#626aef" @click="exportList">查看导出列表</el-button> |
||||
|
<el-button type="primary" @click="resetBn">重置</el-button> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 数据 --> |
||||
|
<el-table |
||||
|
:data="tableData" |
||||
|
style="width: 100%; margin-top: 20px" |
||||
|
header-cell-class-name="table-header" |
||||
|
@sort-change="handleSortChange" |
||||
|
:default-sort="{ prop: null, order: null }" |
||||
|
class="table-rounded" |
||||
|
:loading="tableLoading" |
||||
|
> |
||||
|
<el-table-column |
||||
|
prop="id" |
||||
|
label="序号" |
||||
|
align="center" |
||||
|
header-align="center" |
||||
|
width="80" |
||||
|
> |
||||
|
<template #default="scope"> |
||||
|
{{ (currentPage - 1) * pageSize + scope.$index + 1 }} |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column |
||||
|
prop="dccode" |
||||
|
label="账号" |
||||
|
align="center" |
||||
|
header-align="center" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
prop="name" |
||||
|
label="姓名" |
||||
|
align="center" |
||||
|
header-align="center" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
prop="market" |
||||
|
label="地区" |
||||
|
align="center" |
||||
|
header-align="center" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
prop="prize_name" |
||||
|
label="物品名称" |
||||
|
align="center" |
||||
|
header-align="center" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
prop="stick_type" |
||||
|
label="福签" |
||||
|
align="center" |
||||
|
header-align="center" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
prop="prize_count" |
||||
|
label="数量" |
||||
|
align="center" |
||||
|
header-align="center" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
prop="created_at" |
||||
|
label="时间" |
||||
|
align="center" |
||||
|
header-align="center" |
||||
|
/> |
||||
|
</el-table> |
||||
|
|
||||
|
<!-- 分页组件 --> |
||||
|
<div class="demo-pagination-block"> |
||||
|
<el-pagination |
||||
|
@size-change="handleSizeChange" |
||||
|
@current-change="handleCurrentChange" |
||||
|
:current-page="currentPage" |
||||
|
:page-sizes="[10, 15, 20, 50, 100]" |
||||
|
:page-size="pageSize" |
||||
|
layout="total, sizes, prev, pager, next, jumper" |
||||
|
:total="datatotal" |
||||
|
/> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import { ref, reactive, onMounted } from "vue"; |
||||
|
import { ElMessage } from "element-plus"; |
||||
|
import { marketListApi } from "../../api/userPermissions"; |
||||
|
import { userLuckyDrawListApi, exportUserLuckyDrawListApi } from "../../api/eventManagement"; |
||||
|
import router from "../../router"; |
||||
|
|
||||
|
// token |
||||
|
const token = localStorage.getItem("token"); |
||||
|
const typeOptions = ref([ |
||||
|
{ label: "金币", value: 2 }, |
||||
|
{ label: "金豆", value: 3 }, |
||||
|
{ label: "Token", value: 1 }, |
||||
|
{ label: "实物", value: 4 }, |
||||
|
]); |
||||
|
// 搜索表单 |
||||
|
const searchForm = reactive({ |
||||
|
dccode: "", |
||||
|
country: "", |
||||
|
prize_type: "", |
||||
|
}); |
||||
|
|
||||
|
// 排序参数 |
||||
|
const sortProp = ref(null); |
||||
|
const sortOrder = ref(null); |
||||
|
|
||||
|
// 表格数据 |
||||
|
const tableData = ref([]); |
||||
|
const tableLoading = ref(false); |
||||
|
const datatotal = ref(0); |
||||
|
|
||||
|
// 分页参数 |
||||
|
const currentPage = ref(1); |
||||
|
const pageSize = ref(15); |
||||
|
|
||||
|
// 地区下拉框 |
||||
|
const regionList = ref([]); |
||||
|
const isRegionLoading = ref(false); |
||||
|
|
||||
|
// 来源下拉框 |
||||
|
const originList = ref([]); |
||||
|
const isOriginLoading = ref(false); |
||||
|
|
||||
|
// 禁用当前日期之前的日期(当天0点之前的时间) |
||||
|
const disabledDate = (time) => { |
||||
|
return time.getTime() < new Date().getTime() - 8.64e7; |
||||
|
}; |
||||
|
|
||||
|
// 格式化日期 |
||||
|
const formatDate = (date) => { |
||||
|
if (!date) return ""; |
||||
|
const year = date.getFullYear(); |
||||
|
const month = String(date.getMonth() + 1).padStart(2, "0"); |
||||
|
const day = String(date.getDate()).padStart(2, "0"); |
||||
|
return `${year}/${month}/${day}`; |
||||
|
}; |
||||
|
|
||||
|
// 校验HLid |
||||
|
const checkHlids = () => { |
||||
|
// 非空 |
||||
|
if (!hlidsInput.value.trim()) { |
||||
|
ElMessage.error("请输入HLid"); |
||||
|
return false; |
||||
|
} |
||||
|
// 处理输入:去空、去重,转数组 |
||||
|
const hlidList = hlidsInput.value |
||||
|
.split("\n") |
||||
|
.map((item) => item.trim()) |
||||
|
.filter((item) => item) |
||||
|
.filter((item, index, self) => self.indexOf(item) === index); // 去重 |
||||
|
// 数量校验(最多1000个) |
||||
|
if (hlidList.length > 1000) { |
||||
|
ElMessage.error("HLid数量不能超过1000个"); |
||||
|
return false; |
||||
|
} |
||||
|
// 格式校验(8位数字) |
||||
|
const hlidReg = /^\d{8}$/; |
||||
|
for (const hlid of hlidList) { |
||||
|
if (!hlidReg.test(hlid)) { |
||||
|
ElMessage.error(`有HLid格式错误:${hlid},请重新输入`); |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
return true; |
||||
|
}; |
||||
|
|
||||
|
// 重置表单数据 |
||||
|
const resetForm = () => { |
||||
|
hlidsInput.value = ""; |
||||
|
timeType.value = ""; |
||||
|
expireTime.value = ""; |
||||
|
delayValue.value = ""; |
||||
|
delayUnit.value = ""; |
||||
|
remark.value = ""; |
||||
|
operator.value = ""; |
||||
|
}; |
||||
|
|
||||
|
// 获取地区列表 |
||||
|
const fetchRegionList = async () => { |
||||
|
try { |
||||
|
isRegionLoading.value = true; |
||||
|
const data = await marketListApi({ |
||||
|
token: token, |
||||
|
app_form: "en", |
||||
|
}); |
||||
|
regionList.value = data.list; |
||||
|
} catch (error) { |
||||
|
console.error("获取地区列表失败:", error); |
||||
|
regionList.value = []; |
||||
|
} finally { |
||||
|
isRegionLoading.value = false; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
// 获取表格数据 |
||||
|
const fetchTableData = async () => { |
||||
|
try { |
||||
|
tableLoading.value = true; |
||||
|
const requestParams = { |
||||
|
token: token, |
||||
|
dccode: searchForm.dccode, |
||||
|
country: searchForm.country, |
||||
|
prize_type: searchForm.prize_type, |
||||
|
page: currentPage.value, |
||||
|
page_size: pageSize.value, |
||||
|
}; |
||||
|
const data = await userLuckyDrawListApi(requestParams); |
||||
|
tableData.value = data.list; |
||||
|
datatotal.value = data.total; |
||||
|
} catch (error) { |
||||
|
console.error("获取表格数据失败:", error); |
||||
|
tableData.value = []; |
||||
|
datatotal.value = 0; |
||||
|
} finally { |
||||
|
tableLoading.value = false; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
// 组件挂载时:获取地区列表 + 初始化表格数据 |
||||
|
onMounted(() => { |
||||
|
fetchRegionList(); |
||||
|
fetchTableData(); |
||||
|
}); |
||||
|
|
||||
|
// 搜索按钮 |
||||
|
const search = () => { |
||||
|
currentPage.value = 1; |
||||
|
fetchTableData(); |
||||
|
}; |
||||
|
|
||||
|
// 导出Excel列表按钮 |
||||
|
const exportExcel = async () => { |
||||
|
const requestParams = { |
||||
|
token: token, |
||||
|
dccode: searchForm.dccode, |
||||
|
country: searchForm.country, |
||||
|
prize_type: searchForm.prize_type, |
||||
|
}; |
||||
|
const data = await exportUserLuckyDrawListApi(requestParams); |
||||
|
console.log(data); |
||||
|
if (data != "") { |
||||
|
ElMessage.success("已导出"); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
// 查看导出列表按钮 |
||||
|
const exportList = () => { |
||||
|
router.push({ |
||||
|
path: '/userPermissions/export' |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
// 重置按钮 |
||||
|
const resetBn = () => { |
||||
|
searchForm.dccode = ""; |
||||
|
searchForm.country = ""; |
||||
|
searchForm.prize_type = ""; |
||||
|
currentPage.value = 1; |
||||
|
pageSize.value = 15; |
||||
|
fetchTableData(); |
||||
|
}; |
||||
|
|
||||
|
// 分页方法 |
||||
|
const handleSizeChange = (val) => { |
||||
|
pageSize.value = val; |
||||
|
fetchTableData(); |
||||
|
console.log(`每页 ${val} 条`); |
||||
|
}; |
||||
|
|
||||
|
const handleCurrentChange = (val) => { |
||||
|
currentPage.value = val; |
||||
|
fetchTableData(); |
||||
|
console.log(`当前页: ${val}`); |
||||
|
}; |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
/* 父容器 */ |
||||
|
.page-container { |
||||
|
position: relative; |
||||
|
min-height: 600px; |
||||
|
} |
||||
|
|
||||
|
/* 搜索区域 */ |
||||
|
.search-container { |
||||
|
display: flex; |
||||
|
height: auto; |
||||
|
justify-content: center; |
||||
|
align-items: flex-start; |
||||
|
gap: 12px; |
||||
|
align-self: stretch; |
||||
|
border-radius: 8px; |
||||
|
background: #fefaf9; |
||||
|
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.25); |
||||
|
padding: 15px; |
||||
|
margin-bottom: 20px; |
||||
|
flex-wrap: wrap; |
||||
|
} |
||||
|
|
||||
|
.search-group { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
gap: 15px; |
||||
|
} |
||||
|
|
||||
|
/* 搜索标签文字 */ |
||||
|
.form-label { |
||||
|
font-weight: 800 !important; |
||||
|
font-size: 15px; |
||||
|
color: #333; |
||||
|
font-family: "SimHei", "Heiti SC", "Microsoft YaHei", sans-serif !important; |
||||
|
font-weight: 500; |
||||
|
} |
||||
|
|
||||
|
/* 按钮组 */ |
||||
|
.button-group { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
gap: 0px !important; |
||||
|
margin-left: auto; |
||||
|
} |
||||
|
|
||||
|
/* 按钮样式 */ |
||||
|
.button-group .el-button { |
||||
|
padding: 6px 10px !important; |
||||
|
font-size: 14px !important; |
||||
|
height: 36px !important; |
||||
|
} |
||||
|
|
||||
|
/* 表格样式 */ |
||||
|
.table-rounded { |
||||
|
border-radius: 12px !important; |
||||
|
overflow: hidden !important; |
||||
|
border: 1px solid #e4e7ed !important; |
||||
|
height: 750px; |
||||
|
} |
||||
|
|
||||
|
.table-header { |
||||
|
text-align: center !important; |
||||
|
font-weight: 800 !important; |
||||
|
font-size: 15px !important; |
||||
|
color: #333 !important; |
||||
|
background-color: #f8f9fa !important; |
||||
|
} |
||||
|
|
||||
|
.el-table__cell { |
||||
|
border-right: none !important; |
||||
|
border-bottom: 1px solid #e4e7ed !important; |
||||
|
} |
||||
|
|
||||
|
.el-table__header th.el-table__cell { |
||||
|
border-right: none !important; |
||||
|
border-bottom: 1px solid #e4e7ed !important; |
||||
|
} |
||||
|
|
||||
|
.el-table__row:hover .el-table__cell { |
||||
|
background-color: #fafafa !important; |
||||
|
} |
||||
|
|
||||
|
/* 分页组件样式 */ |
||||
|
.demo-pagination-block { |
||||
|
display: flex; |
||||
|
width: 100%; |
||||
|
height: 44px; |
||||
|
padding: 0 16px; |
||||
|
align-items: center; |
||||
|
gap: 16px; |
||||
|
position: absolute; |
||||
|
margin-top: 10px; |
||||
|
border-radius: 0 0 3px 3px; |
||||
|
border-top: 1px solid #eaeaea; |
||||
|
background: #fefbfb; |
||||
|
box-sizing: border-box; |
||||
|
} |
||||
|
</style> |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue