Browse Source

Merge branch 'milestone-20260405-新增推送和浮窗' into dev

dev
zhaowenkang 1 week ago
parent
commit
432747b1a5
  1. 20
      src/api/advertisingManagement.js
  2. 15
      src/router/index.js
  3. 494
      src/views/AdvertisingManagement/FloatingWindow.vue

20
src/api/advertisingManagement.js

@ -0,0 +1,20 @@
import request from '../utils/myAxios';
var base_url = import.meta.env.VITE_API_BASE_URL
// 广告管理--首页浮窗活动--获取首页浮窗活动列表
export function floatingActivityListApi(params) {
return request({
url: base_url + "/admin/advertising/floating/activity/list",
method: "post",
data: params,
});
}
// 广告管理--首页浮窗活动--保存/修改首页浮窗活动
export function floatingActivitySaveApi(params) {
return request({
url: base_url + "/admin/advertising/floating/activity/save",
method: "post",
data: params,
});
}

15
src/router/index.js

@ -170,7 +170,20 @@ const routes = [
] ]
}, },
] ]
}
},
{
path: 'AdvertisingManagement',
name: 'AdvertisingManagement',
meta: { title: '广告管理', icon: "Management", showSidebar: true, isParentNav: true },
children: [
{
path: 'FloatingWindow',
name: 'FloatingWindow',
component: () => import('../views/AdvertisingManagement/FloatingWindow.vue'),
meta: { title: '首页浮窗活动', showSidebar: true },
},
]
},
] ]
} }
] ]

494
src/views/AdvertisingManagement/FloatingWindow.vue

@ -0,0 +1,494 @@
<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 label="入口图" align="center" header-align="center">
<template #default="scope">
<el-image
:src="scope.row.image"
style="width: 100px; height: 100px"
fit="cover"
/>
</template>
</el-table-column>
<el-table-column
prop="name"
label="活动名称"
align="center"
header-align="center"
/>
<el-table-column label="客户权限" align="center" header-align="center">
<template #default="scope">
{{ formatUserRole(scope.row.user_role) }}
</template>
</el-table-column>
<el-table-column label="活动时间" align="center" header-align="center">
<template #default="scope">
{{ scope.row.start_time }} {{ scope.row.end_time }}
</template>
</el-table-column>
<el-table-column
prop="created_at"
label="创建时间"
align="center"
header-align="center"
/>
<el-table-column
label="状态"
prop="status_str"
align="center"
header-align="center"
/>
<el-table-column label="操作" align="center" header-align="center">
<template #default="scope">
<el-button type="text" @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="[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="name">
<el-input v-model="form.name" placeholder="请输入" clearable>
</el-input>
</el-form-item>
<el-form-item label="活动图标" prop="image">
<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">建议上传图片大小750*1200像素支持PNGJPG格式</div>
</el-form-item>
<el-form-item label="活动时间" prop="timeRange">
<el-date-picker
v-model="timeRange"
type="datetimerange"
range-separator="至"
start-placeholder="开始时间"
end-placeholder="结束时间"
value-format="YYYY-MM-DD HH:mm:ss"
/>
</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>
<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, watch, nextTick } from "vue";
import { ElMessage, genFileId, ElMessageBox } from "element-plus";
import { Plus } from "@element-plus/icons-vue"; // <Plus />
import router from "../../router";
import {
floatingActivityListApi,
floatingActivitySaveApi,
} from "../../api/advertisingManagement";
const uploadUrl = import.meta.env.VITE_API_BASE_URLXXCG + "hljw/api/aws/upload";
const uploadRef = ref();
const fileList = ref([]);
const formRef = ref();
const isEdit = ref(false);
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({
name: "",
image: "",
jump_url: "",
user_role: "",
start_time: "",
end_time: "",
});
//
const timeRange = computed({
get() {
if (form.start_time && form.end_time) {
return [form.start_time, form.end_time];
}
return [];
},
set(val) {
if (val && val.length === 2) {
form.start_time = val[0];
form.end_time = val[1];
//
if (formRef.value) formRef.value.clearValidate("start_time");
} else {
form.start_time = "";
form.end_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 = {
name: [{ required: true, message: "请输入活动名称", trigger: "blur" }],
image: [{ required: true, message: "请上传活动图片", trigger: "change" }],
jump_url: [{ required: true, message: "请输入活动地址", trigger: "blur" }],
timeRange: [
{
required: true,
validator: (rule, value, callback) => {
if (!form.start_time || !form.end_time) {
callback(new Error("请选择活动时间"));
} else {
callback();
}
},
trigger: "change",
},
],
user_role: [{ required: true, message: "请选择客户权限", trigger: "change" }],
};
const handleSuccess = (response, uploadFile) => {
form.image = response.data.url; // form.img
if (formRef.value) {
formRef.value.clearValidate("image"); //
}
};
const beforeUpload = (rawFile) => {
if (!rawFile.type.startsWith("image/")) {
ElMessage.error("请上传图片文件!");
return false;
} else if (rawFile.size / 1024 > 100) {
ElMessage.error("图片大小必须小于100K!");
return false;
}
return true;
};
//
const handleRemove = (file, fileList) => {
form.image = ""; // form.img
if (formRef.value) {
formRef.value.validateField("image"); //
}
};
const handleExceed = (files) => {
uploadRef.value.clearFiles();
const file = files[0];
file.uid = genFileId();
uploadRef.value.handleStart(file);
uploadRef.value.submit();
};
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(10);
const resetForm = () => {
form.id = undefined;
form.name = "";
form.image = "";
form.jump_url = "";
form.user_role = "";
form.start_time = "";
form.end_time = "";
fileList.value = [];
};
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,
};
console.log(params);
//
await floatingActivitySaveApi(params);
ElMessage.success("提交成功");
dialogFormVisible.value = false;
fetchTableData();
}
});
};
const handleEdit = (row) => {
isEdit.value = true;
resetForm();
form.id = row.id;
form.name = row.name;
form.image = row.image;
form.jump_url = row.jump_url;
form.user_role = row.user_role;
form.start_time = row.start_time;
form.end_time = row.end_time;
if (row.image) {
fileList.value = [{ name: "图片", url: row.image }];
}
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 floatingActivityListApi(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;
}
.tip {
font-size: 12px;
color: #8c939d;
}
.avatar-uploader .avatar {
width: 120px;
height: 120px;
display: block;
}
</style>
<style>
.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>
Loading…
Cancel
Save