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