5 changed files with 555 additions and 69 deletions
-
2.env.development
-
7package-lock.json
-
18src/api/member.js
-
77src/views/admin/landingDetail.vue
-
520src/views/admin/landingManagement.vue
@ -0,0 +1,520 @@ |
|||||
|
<template> |
||||
|
<div class="page-container"> |
||||
|
<!-- 顶栏容器 --> |
||||
|
<div class="top-bar"> |
||||
|
<span>落地页管理</span> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 主体容器(包含侧边栏和主内容) --> |
||||
|
<div class="main-container"> |
||||
|
<!-- 侧边栏容器(目录) --> |
||||
|
<div class="sidebar"> |
||||
|
<el-menu |
||||
|
default-active="1" |
||||
|
class="sidebar-menu" |
||||
|
background-color="#f5f7fa" |
||||
|
text-color="#333" |
||||
|
active-text-color="#1890ff" |
||||
|
> |
||||
|
<el-menu-item index="1"> |
||||
|
<i class="el-icon-document"></i> |
||||
|
<span slot="title">落地页管理</span> |
||||
|
</el-menu-item> |
||||
|
</el-menu> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 主要区域容器(表格内容) --> |
||||
|
<div class="content-area"> |
||||
|
<!-- 内容头部 --> |
||||
|
<div class="content-header"> |
||||
|
<el-button type="primary" icon="el-icon-plus" @click="openAddDialog">+新增落地页</el-button> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 表格区域 --> |
||||
|
<el-table :data="tableData" stripe v-loading="loading" style="width: 100%; margin-bottom: 20px; border-top: 1px solid #e8e8e8;" > |
||||
|
<el-table-column |
||||
|
type="index" |
||||
|
label="序号" |
||||
|
width="80" |
||||
|
align="center" |
||||
|
></el-table-column> |
||||
|
<el-table-column |
||||
|
prop="name" |
||||
|
label="活动名称" |
||||
|
min-width="100" |
||||
|
align="center" |
||||
|
></el-table-column> |
||||
|
<el-table-column |
||||
|
prop="introduction" |
||||
|
label="活动简介" |
||||
|
min-width="220" |
||||
|
align="center" |
||||
|
></el-table-column> |
||||
|
<el-table-column label="活动时间" min-width="220" align="center"> |
||||
|
<template #default="{ row }"> |
||||
|
{{row.start_time}} - {{ row.end_time }} |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
|
||||
|
<el-table-column |
||||
|
prop="updated_at" |
||||
|
label="编辑时间" |
||||
|
min-width="180" |
||||
|
align="center" |
||||
|
></el-table-column> |
||||
|
<el-table-column |
||||
|
label="操作" |
||||
|
width="280" |
||||
|
align="center" |
||||
|
> |
||||
|
<template v-slot:default="scope"> |
||||
|
<el-button type="text" size="small" :icon="Edit" @click="openEditDialog(scope.row)">编辑</el-button> |
||||
|
<el-button type="text" size="small" :icon="View" @click="detail(scope.row.id)">详情</el-button> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
</el-table> |
||||
|
|
||||
|
<!-- 分页区域 --> |
||||
|
<div class="pagination-container"> |
||||
|
<el-pagination |
||||
|
@size-change="handleSizeChange" |
||||
|
@current-change="handleCurrentChange" |
||||
|
:current-page="currentPage" |
||||
|
:page-sizes="[10, 20, 50]" |
||||
|
:page-size="pageSize" |
||||
|
layout="total, sizes, prev, pager, next, jumper" |
||||
|
:total="totalCount" |
||||
|
></el-pagination> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 新增:添加/编辑活动弹窗 --> |
||||
|
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="600px" :before-close="handleDialogClose"> |
||||
|
<el-form ref="formRef" :model="form" :rules="formRules" label-width="100px"> |
||||
|
<!-- 活动名称 --> |
||||
|
<el-form-item label="活动名称" prop="name"> |
||||
|
<el-input v-model="form.name" placeholder="请输入活动名称" /> |
||||
|
</el-form-item> |
||||
|
|
||||
|
<!-- 活动简介 --> |
||||
|
<el-form-item label="活动简介" prop="introduction"> |
||||
|
<el-input |
||||
|
v-model="form.introduction" |
||||
|
type="textarea" |
||||
|
placeholder="请输入活动简介" |
||||
|
:maxlength="80" |
||||
|
show-word-limit |
||||
|
/> |
||||
|
<div class="intro-tip">活动简介会给分享后客户展示,请注意填写内容</div> |
||||
|
</el-form-item> |
||||
|
|
||||
|
<!-- 活动时间 --> |
||||
|
<el-form-item label="活动时间" prop="time"> |
||||
|
<el-date-picker |
||||
|
v-model="form.startTime" |
||||
|
type="datetime" |
||||
|
placeholder="请选择开始时间" |
||||
|
style="width: 200px" |
||||
|
/> |
||||
|
<span class="time-separator">至</span> |
||||
|
<el-date-picker |
||||
|
v-model="form.endTime" |
||||
|
type="datetime" |
||||
|
placeholder="请选择结束时间" |
||||
|
style="width: 200px" |
||||
|
/> |
||||
|
</el-form-item> |
||||
|
|
||||
|
<!-- 活动落地页(宽度≤375px) --> |
||||
|
<el-form-item label="活动落地页" prop="landingPage"> |
||||
|
<el-upload |
||||
|
class="upload-demo" |
||||
|
action="#" |
||||
|
:on-change="handleLandingPageUpload" |
||||
|
:show-file-list="false" |
||||
|
> |
||||
|
<el-button type="primary" icon="Plus">上传</el-button> |
||||
|
<template #tip> |
||||
|
<div class="upload-tip"> |
||||
|
宽度≤375像素,支持PNG、JPG、GIF格式,图片需小于2M |
||||
|
</div> |
||||
|
</template> |
||||
|
</el-upload> |
||||
|
</el-form-item> |
||||
|
|
||||
|
<!-- 落地页弹窗(宽度≤375px) --> |
||||
|
<el-form-item label="落地页弹窗" prop="popup"> |
||||
|
<el-upload |
||||
|
class="upload-demo" |
||||
|
action="#" |
||||
|
:limit="1" |
||||
|
:on-change="handlePopupUpload" |
||||
|
list-type="picture" |
||||
|
:file-list="form.popupFiles" |
||||
|
> |
||||
|
<el-button type="primary" icon="Plus">上传</el-button> |
||||
|
<template #tip> |
||||
|
<div class="upload-tip"> |
||||
|
宽度≤375像素,支持PNG、JPG格式,图片需小于2M |
||||
|
</div> |
||||
|
</template> |
||||
|
</el-upload> |
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
|
|
||||
|
<template #footer> |
||||
|
<div class="dialog-footer"> |
||||
|
<el-button @click="dialogVisible = false">取消</el-button> |
||||
|
<el-button type="primary" @click="submitForm">确定</el-button> |
||||
|
</div> |
||||
|
</template> |
||||
|
</el-dialog> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import { getLandingListApi, addLandingApi } from '../../api/member.js'; |
||||
|
import { ElMessage } from 'element-plus'; |
||||
|
import axios from 'axios'; |
||||
|
export default { |
||||
|
name: 'LandingList', |
||||
|
data() { |
||||
|
return { |
||||
|
// 表格数据 |
||||
|
tableData: [], |
||||
|
// 分页参数 |
||||
|
currentPage: 1, |
||||
|
pageSize: 10, |
||||
|
// 总数据量 |
||||
|
totalCount: 0, |
||||
|
// 加载状态 |
||||
|
loading: false, |
||||
|
// 弹窗显示状态 |
||||
|
dialogVisible: false, |
||||
|
// 弹窗标题 |
||||
|
dialogTitle: '', |
||||
|
// 表单数据 |
||||
|
form: { |
||||
|
id: '', |
||||
|
name: '', |
||||
|
introduction: '', |
||||
|
startTime: '', |
||||
|
endTime: '', |
||||
|
landingPage: '', |
||||
|
popup: '', |
||||
|
landingPageFiles: [], // 存储已上传的落地页图片 |
||||
|
popupFiles: [] // 存储已上传的弹窗图片 |
||||
|
}, |
||||
|
// 表单校验规则 |
||||
|
formRules: { |
||||
|
name: [{ required: true, message: '请输入活动名称', trigger: 'blur' }], |
||||
|
introduction: [{ required: true, message: '请输入活动简介', trigger: 'blur' }], |
||||
|
startTime: [{ required: true, message: '请选择开始时间', trigger: 'change' }], |
||||
|
endTime: [{ required: true, message: '请选择结束时间', trigger: 'change' }], |
||||
|
landingPage: [{ required: true, message: '请上传活动落地页', trigger: 'change' }], |
||||
|
popup: [{ required: true, message: '请上传落地页弹窗', trigger: 'change' }] |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
mounted() { |
||||
|
this.getLandingList(); |
||||
|
}, |
||||
|
methods: { |
||||
|
// 获取落地页管理列表数据 |
||||
|
async getLandingList() { |
||||
|
// 显示加载状态 |
||||
|
this.loading = true; |
||||
|
try { |
||||
|
// 调用接口,传递分页参数(当前页、每页条数) |
||||
|
const res = await getLandingListApi({ |
||||
|
page: this.currentPage, |
||||
|
pageSize: this.pageSize |
||||
|
}); |
||||
|
if (res.code === 200) { |
||||
|
// 更新表格数据 |
||||
|
this.tableData = res.data.list; |
||||
|
// 更新总条数 |
||||
|
this.totalCount = res.data.total; |
||||
|
} else { |
||||
|
// 接口返回错误信息 |
||||
|
ElMessage.error('获取数据失败'); |
||||
|
} |
||||
|
} catch (error) { |
||||
|
// 捕获网络错误 |
||||
|
ElMessage.error('网络异常,请稍后重试'); |
||||
|
} finally { |
||||
|
// 无论成功失败,都关闭加载状态 |
||||
|
this.loading = false; |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// 分页大小改变时重新获取数据 |
||||
|
handleSizeChange(val) { |
||||
|
this.pageSize = val; |
||||
|
this.currentPage = 1; |
||||
|
this.getLandingList(); |
||||
|
}, |
||||
|
|
||||
|
// 当前页改变时重新获取数据 |
||||
|
handleCurrentChange(val) { |
||||
|
this.currentPage = val; |
||||
|
this.getLandingList(); |
||||
|
}, |
||||
|
|
||||
|
// 详情按钮 |
||||
|
detail(id){ |
||||
|
this.$router.push({ |
||||
|
path: `/admin/landingDetail/${id}`, |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// 打开新增弹窗 |
||||
|
openAddDialog() { |
||||
|
this.dialogTitle = '添加活动'; |
||||
|
this.form = { |
||||
|
id: '', |
||||
|
name: '', |
||||
|
introduction: '', |
||||
|
startTime: '', |
||||
|
endTime: '', |
||||
|
landingPage: '', |
||||
|
popup: '', |
||||
|
}; |
||||
|
this.dialogVisible = true; |
||||
|
}, |
||||
|
// 打开编辑弹窗 |
||||
|
openEditDialog(row) { |
||||
|
this.dialogTitle = '编辑活动'; |
||||
|
console.log(row) |
||||
|
this.form = { |
||||
|
id: row.id, |
||||
|
name: row.name, |
||||
|
introduction: row.introduction, |
||||
|
startTime: row.start_time, |
||||
|
endTime: row.end_time, |
||||
|
landingPage: row.landing_page, |
||||
|
popup: row.landing_page_popup, |
||||
|
}; |
||||
|
console.log(row.landing_page) |
||||
|
this.form.landingPageFiles = [ |
||||
|
{ |
||||
|
name: row.landing_page.split('/').pop(), |
||||
|
url: row.landing_page |
||||
|
} |
||||
|
] |
||||
|
this.form.popupFiles = [ |
||||
|
{ |
||||
|
name: row.landing_page_popup.split('/').pop(), |
||||
|
url: row.landing_page_popup |
||||
|
} |
||||
|
] |
||||
|
this.dialogVisible = true; |
||||
|
}, |
||||
|
|
||||
|
// 处理落地页上传(宽度校验≤375px) |
||||
|
handleLandingPageUpload(file) { |
||||
|
const reader = new FileReader(); |
||||
|
reader.onload = (e) => { |
||||
|
const img = new Image(); |
||||
|
img.onload = () => { |
||||
|
if (img.width > 375) { |
||||
|
ElMessage.error('图片宽度不能超过375px'); |
||||
|
this.form.landingPageFiles = []; |
||||
|
} else { |
||||
|
this.form.landingPage = file.raw; |
||||
|
this.form.landingPageFiles = [file]; |
||||
|
} |
||||
|
}; |
||||
|
img.src = e.target.result; |
||||
|
}; |
||||
|
reader.readAsDataURL(file.raw); |
||||
|
}, |
||||
|
|
||||
|
// 处理弹窗上传(宽度校验≤375px) |
||||
|
handlePopupUpload(file) { |
||||
|
const reader = new FileReader(); |
||||
|
reader.onload = (e) => { |
||||
|
const img = new Image(); |
||||
|
img.onload = () => { |
||||
|
if (img.width > 375) { |
||||
|
ElMessage.error('图片宽度不能超过375px'); |
||||
|
this.form.popupFiles = []; |
||||
|
} else { |
||||
|
this.form.popup = file.raw; |
||||
|
this.form.popupFiles = [file]; |
||||
|
} |
||||
|
}; |
||||
|
img.src = e.target.result; |
||||
|
}; |
||||
|
reader.readAsDataURL(file.raw); |
||||
|
}, |
||||
|
|
||||
|
// 提交表单(新增/编辑) |
||||
|
async submitForm() { |
||||
|
this.$refs.formRef.validate( async (valid) => { |
||||
|
if (valid) { |
||||
|
let landingPageFlag = false |
||||
|
const formData = new FormData(); |
||||
|
formData.append('file', this.form.landingPageFiles[0].raw); |
||||
|
formData.append("type", "image"); |
||||
|
formData.append("app_from", "toujiao"); |
||||
|
const landingPageRes = await axios.post( |
||||
|
'http://39.101.133.168:8828/hljwgo/api/file/upload', |
||||
|
formData, |
||||
|
{ |
||||
|
headers: { "Content-Type": "multipart/form-data" } |
||||
|
} |
||||
|
); |
||||
|
if(landingPageRes.data.code === 200){ |
||||
|
this.form.landingPage = landingPageRes.data.data.url |
||||
|
// this.form.popup = resp.data.file_name |
||||
|
landingPageFlag = true |
||||
|
} |
||||
|
let popupFlag = false |
||||
|
const popupFormData = new FormData(); |
||||
|
popupFormData.append('file', this.form.popupFiles[0].raw); |
||||
|
popupFormData.append("type", "image"); |
||||
|
popupFormData.append("app_from", "toujiao"); |
||||
|
const popupRes =await axios.post( |
||||
|
'http://39.101.133.168:8828/hljwgo/api/file/upload', |
||||
|
popupFormData, |
||||
|
{ |
||||
|
headers: { "Content-Type": "multipart/form-data" } |
||||
|
} |
||||
|
); |
||||
|
if(popupRes.data.code === 200){ |
||||
|
this.form.popup = popupRes.data.data.url |
||||
|
// this.form.popup = popupRes.data.file_name |
||||
|
popupFlag = true |
||||
|
} |
||||
|
if(!landingPageFlag || !popupFlag){ |
||||
|
ElMessage.error('图片上传失败'); |
||||
|
return |
||||
|
} |
||||
|
// const api = this.form.id ? editLandingtApi : addLandingApi; |
||||
|
addLandingApi({ |
||||
|
id: this.form.id, |
||||
|
name: this.form.name, |
||||
|
introduction: this.form.introduction, |
||||
|
start_time: this.form.startTime, |
||||
|
end_time: this.form.endTime, |
||||
|
landing_page: this.form.landingPage, |
||||
|
landing_page_popup: this.form.popup |
||||
|
}).then(res => { |
||||
|
if (res.code === 200) { |
||||
|
ElMessage.success('操作成功'); |
||||
|
this.dialogVisible = false; |
||||
|
this.getLandingList(); |
||||
|
} else { |
||||
|
ElMessage.error(res.msg || '操作失败'); |
||||
|
} |
||||
|
}).catch(err => { |
||||
|
ElMessage.error('网络异常'); |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// 关闭弹窗 |
||||
|
handleDialogClose() { |
||||
|
this.dialogVisible = false; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
.page-container { |
||||
|
width: 100%; |
||||
|
height: 100vh; |
||||
|
overflow: hidden; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
} |
||||
|
|
||||
|
/* 顶栏样式 */ |
||||
|
.top-bar { |
||||
|
height: 60px; |
||||
|
background-color: #1890ff; |
||||
|
color: #fff; |
||||
|
padding: 0 20px; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
font-size: 18px; |
||||
|
font-weight: 500; |
||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); |
||||
|
z-index: 10; |
||||
|
} |
||||
|
|
||||
|
/* 主体容器样式 */ |
||||
|
.main-container { |
||||
|
display: flex; |
||||
|
flex: 1; |
||||
|
overflow: hidden; |
||||
|
} |
||||
|
|
||||
|
/* 侧边栏样式 */ |
||||
|
.sidebar { |
||||
|
width: 220px; |
||||
|
background-color: #f5f7fa; |
||||
|
border-right: 1px solid #e8e8e8; |
||||
|
overflow-y: auto; |
||||
|
} |
||||
|
|
||||
|
.sidebar-menu { |
||||
|
border-right: none; |
||||
|
height: 100%; |
||||
|
} |
||||
|
|
||||
|
/* 主内容区域样式 */ |
||||
|
.content-area { |
||||
|
flex: 1; |
||||
|
padding: 20px; |
||||
|
overflow-y: auto; |
||||
|
background-color: #fff; |
||||
|
} |
||||
|
|
||||
|
/* 内容头部样式 */ |
||||
|
.content-header { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
margin-bottom: 20px; |
||||
|
padding-bottom: 10px; |
||||
|
border-bottom: 1px solid #e8e8e8; |
||||
|
} |
||||
|
|
||||
|
.content-header h2 { |
||||
|
margin: 0; |
||||
|
font-size: 18px; |
||||
|
color: #333; |
||||
|
} |
||||
|
|
||||
|
/* 分页容器样式 */ |
||||
|
.pagination-container { |
||||
|
display: flex; |
||||
|
justify-content: flex-end; |
||||
|
align-items: center; |
||||
|
margin-top: 10px; |
||||
|
} |
||||
|
|
||||
|
/* 弹窗样式 */ |
||||
|
.intro-tip { |
||||
|
font-size: 12px; |
||||
|
color: #999; |
||||
|
margin-top: 5px; |
||||
|
} |
||||
|
.time-separator { |
||||
|
margin: 0 10px; |
||||
|
} |
||||
|
.upload-tip { |
||||
|
font-size: 12px; |
||||
|
color: #999; |
||||
|
margin-top: 5px; |
||||
|
} |
||||
|
.dialog-footer { |
||||
|
display: flex; |
||||
|
justify-content: flex-end; |
||||
|
} |
||||
|
</style> |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue