4 changed files with 451 additions and 12 deletions
-
18src/api/advertisingManagement.js
-
6src/router/index.js
-
14src/views/AdvertisingManagement/FloatingWindow.vue
-
419src/views/AdvertisingManagement/PushManagement.vue
@ -0,0 +1,419 @@ |
|||||
|
<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" |
||||
|
: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="title" |
||||
|
label="浮窗标题" |
||||
|
align="center" |
||||
|
header-align="center" |
||||
|
width="240" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
prop="content" |
||||
|
label="浮窗正文" |
||||
|
align="center" |
||||
|
header-align="center" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
label="客户权限" |
||||
|
align="center" |
||||
|
header-align="center" |
||||
|
width="120" |
||||
|
> |
||||
|
<template #default="scope"> |
||||
|
{{ formatUserRole(scope.row.user_role) }} |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column |
||||
|
prop="push_time" |
||||
|
label="推送时间" |
||||
|
align="center" |
||||
|
header-align="center" |
||||
|
width="180" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
label="推送状态" |
||||
|
prop="status_str" |
||||
|
align="center" |
||||
|
header-align="center" |
||||
|
width="120" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
label="操作" |
||||
|
align="center" |
||||
|
header-align="center" |
||||
|
width="120" |
||||
|
> |
||||
|
<template #default="scope"> |
||||
|
<el-button |
||||
|
type="text" |
||||
|
:disabled="scope.row.push_status !== 1" |
||||
|
@click="handleEdit(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="[5, 10, 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" |
||||
|
title="推送配置" |
||||
|
> |
||||
|
<el-form |
||||
|
:model="form" |
||||
|
style="width: 450px; margin: 0 auto" |
||||
|
:rules="rules" |
||||
|
ref="formRef" |
||||
|
> |
||||
|
<el-form-item label="浮窗标题" prop="title"> |
||||
|
<el-input v-model="form.title" placeholder="请输入" clearable> |
||||
|
</el-input> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="浮窗正文" prop="content"> |
||||
|
<el-input |
||||
|
v-model="form.content" |
||||
|
placeholder="请输入" |
||||
|
clearable |
||||
|
type="textarea" |
||||
|
> |
||||
|
</el-input> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="跳转链接" prop="jump_url"> |
||||
|
<el-input v-model="form.jump_url" placeholder="请输入" clearable> |
||||
|
</el-input> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="客户权限" prop="user_role"> |
||||
|
<el-checkbox-group v-model="userRoleArray"> |
||||
|
<el-checkbox label="网员" value="1" /> |
||||
|
<el-checkbox label="非网" value="2" /> |
||||
|
<el-checkbox label="游客" value="3" /> |
||||
|
</el-checkbox-group> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="推送时间" prop="push_time"> |
||||
|
<el-date-picker |
||||
|
v-model="form.push_time" |
||||
|
type="datetime" |
||||
|
placeholder="请选择推送时间" |
||||
|
value-format="YYYY-MM-DD HH:mm:ss" |
||||
|
:disabled-date="disabledDate" |
||||
|
:default-time="defaultTime" |
||||
|
/> |
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
|
<template #footer> |
||||
|
<div class="dialog-footer"> |
||||
|
<el-button @click="dialogFormVisible = false">取消</el-button> |
||||
|
<el-button type="danger" @click="submitForm"> 提交 </el-button> |
||||
|
</div> |
||||
|
</template> |
||||
|
</el-dialog> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import { ref, reactive, onMounted, computed, nextTick } from "vue"; |
||||
|
import { ElMessage } from "element-plus"; |
||||
|
import { |
||||
|
pushManagementListApi, |
||||
|
pushManagementSaveApi, |
||||
|
} from "../../api/advertisingManagement"; |
||||
|
|
||||
|
const formRef = ref(); |
||||
|
const isEdit = ref(false); |
||||
|
const token = localStorage.getItem("token"); |
||||
|
const dialogFormVisible = ref(false); |
||||
|
const tableData = ref([]); |
||||
|
const tableLoading = ref(false); |
||||
|
const datatotal = ref(0); |
||||
|
const currentPage = ref(1); |
||||
|
const pageSize = ref(5); |
||||
|
|
||||
|
const roleMap = { |
||||
|
1: "会员", |
||||
|
2: "非网", |
||||
|
3: "游客", |
||||
|
}; |
||||
|
|
||||
|
const formatUserRole = (userRole) => { |
||||
|
if (!userRole) return "-"; |
||||
|
const roles = userRole.split(",").map((role) => { |
||||
|
return roleMap[role.trim()] || role.trim(); |
||||
|
}); |
||||
|
return roles.join(","); |
||||
|
}; |
||||
|
|
||||
|
const form = reactive({ |
||||
|
id: undefined, // 建议加上 id 预设,防止响应式丢失 |
||||
|
title: "", |
||||
|
content: "", |
||||
|
jump_url: "", |
||||
|
user_role: "", |
||||
|
push_time: "", |
||||
|
}); |
||||
|
|
||||
|
const resetForm = () => { |
||||
|
form.id = undefined; |
||||
|
form.title = ""; |
||||
|
form.content = ""; |
||||
|
form.jump_url = ""; |
||||
|
form.user_role = ""; |
||||
|
form.push_time = ""; |
||||
|
}; |
||||
|
|
||||
|
// 赋值后手动清除权限校验报错 |
||||
|
const userRoleArray = computed({ |
||||
|
get() { |
||||
|
if (form.user_role) { |
||||
|
return form.user_role.split(","); |
||||
|
} |
||||
|
return []; |
||||
|
}, |
||||
|
set(val) { |
||||
|
if (val && val.length > 0) { |
||||
|
form.user_role = val.join(","); |
||||
|
// 手动清除客户权限校验报错 |
||||
|
if (formRef.value) formRef.value.clearValidate("user_role"); |
||||
|
} else { |
||||
|
form.user_role = ""; |
||||
|
} |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
const rules = { |
||||
|
title: [ |
||||
|
{ required: true, message: "请输入浮窗标题", trigger: "blur" }, |
||||
|
{ min: 1, max: 20, message: "浮窗标题字数在20字以内", trigger: "blur" }, |
||||
|
], |
||||
|
content: [ |
||||
|
{ required: true, message: "请输入浮窗正文", trigger: "blur" }, |
||||
|
{ min: 1, max: 100, message: "浮窗正文字数在100字以内", trigger: "blur" }, // 提示文案修复为100字 |
||||
|
], |
||||
|
jump_url: [{ required: true, message: "请输入跳转链接", trigger: "blur" }], |
||||
|
user_role: [{ required: true, message: "请选择客户权限", trigger: "change" }], |
||||
|
push_time: [ |
||||
|
{ |
||||
|
validator: (rule, value, callback) => { |
||||
|
// 如果没有填值,直接通过校验(非必填) |
||||
|
if (!value) { |
||||
|
callback(); |
||||
|
return; |
||||
|
} |
||||
|
// 如果填写值,则将选择的值转换为时间戳 |
||||
|
const selectedTime = new Date(value).getTime(); |
||||
|
const currentTime = Date.now(); |
||||
|
|
||||
|
// 如果选择的时间早于当前时间,报错 |
||||
|
if (selectedTime < currentTime) { |
||||
|
callback(new Error("推送时间不能早于当前时间")); |
||||
|
} else { |
||||
|
callback(); |
||||
|
} |
||||
|
}, |
||||
|
trigger: "change", |
||||
|
}, |
||||
|
], |
||||
|
}; |
||||
|
|
||||
|
const disabledDate = (time) => { |
||||
|
// 获取今天的凌晨 00:00:00 时间戳 |
||||
|
const today = new Date(); |
||||
|
today.setHours(0, 0, 0, 0); |
||||
|
// time.getTime() 是面板上每个格子的时间,小于今天凌晨的全部禁用 |
||||
|
return time.getTime() < today.getTime(); |
||||
|
}; |
||||
|
|
||||
|
// 限制:点击日期面板时,默认时间填充为当前时间,而不是 00:00:00 |
||||
|
const defaultTime = ref(new Date()); |
||||
|
|
||||
|
const add = () => { |
||||
|
isEdit.value = false; |
||||
|
resetForm(); |
||||
|
dialogFormVisible.value = true; |
||||
|
nextTick(() => { |
||||
|
if (formRef.value) { |
||||
|
formRef.value.clearValidate(); |
||||
|
} |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
const submitForm = async () => { |
||||
|
if (!formRef.value) return; |
||||
|
|
||||
|
await formRef.value.validate(async (valid) => { |
||||
|
if (valid) { |
||||
|
const params = { |
||||
|
...form, |
||||
|
token: token, |
||||
|
}; |
||||
|
// 提交表单数据 |
||||
|
await pushManagementSaveApi(params); |
||||
|
ElMessage.success("提交成功"); |
||||
|
dialogFormVisible.value = false; |
||||
|
fetchTableData(); |
||||
|
} |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
const handleEdit = (row) => { |
||||
|
isEdit.value = true; |
||||
|
resetForm(); |
||||
|
form.id = row.id; |
||||
|
form.title = row.title; |
||||
|
form.content = row.content; |
||||
|
form.jump_url = row.jump_url; |
||||
|
form.user_role = row.user_role; |
||||
|
form.push_time = row.push_time; |
||||
|
|
||||
|
dialogFormVisible.value = true; |
||||
|
|
||||
|
nextTick(() => { |
||||
|
isEdit.value = false; |
||||
|
if (formRef.value) { |
||||
|
formRef.value.clearValidate(); |
||||
|
} |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
const fetchTableData = async () => { |
||||
|
try { |
||||
|
tableLoading.value = true; |
||||
|
const requestParams = { |
||||
|
token: token, |
||||
|
page: currentPage.value, |
||||
|
page_size: pageSize.value, |
||||
|
}; |
||||
|
const data = await pushManagementListApi(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(); |
||||
|
}; |
||||
|
|
||||
|
const handleCurrentChange = (val) => { |
||||
|
currentPage.value = val; |
||||
|
fetchTableData(); |
||||
|
}; |
||||
|
</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; |
||||
|
} |
||||
|
</style> |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue