Browse Source

暂存

milestone-20251021-双11活动后台
maziyang 3 months ago
parent
commit
052a842171
  1. 2
      .env.development
  2. 7
      package-lock.json
  3. 18
      src/api/member.js
  4. 77
      src/views/admin/landingDetail.vue
  5. 520
      src/views/admin/landingManagement.vue

2
.env.development

@ -2,4 +2,4 @@
VITE_APP_ENV=development VITE_APP_ENV=development
# 测试环境 API # 测试环境 API
VITE_API_BASE_URL=https://hwjb.homilychart.com/dbqbApi
VITE_API_BASE_URL=https://dbqb.nfdxy.net/activityApi

7
package-lock.json

@ -2948,11 +2948,10 @@
} }
}, },
"node_modules/vite": { "node_modules/vite": {
"version": "7.1.10",
"resolved": "https://registry.npmmirror.com/vite/-/vite-7.1.10.tgz",
"integrity": "sha512-CmuvUBzVJ/e3HGxhg6cYk88NGgTnBoOo7ogtfJJ0fefUWAxN/WDSUa50o+oVBxuIhO8FoEZW0j2eW7sfjs5EtA==",
"version": "7.1.11",
"resolved": "https://registry.npmjs.org/vite/-/vite-7.1.11.tgz",
"integrity": "sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"esbuild": "^0.25.0", "esbuild": "^0.25.0",
"fdir": "^6.5.0", "fdir": "^6.5.0",

18
src/api/member.js

@ -8,7 +8,7 @@ const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
// 获取落地页活动列表 // 获取落地页活动列表
export function getLandingListApi(data) { export function getLandingListApi(data) {
return request({ return request({
url: `${API_BASE_URL}/admin/getLandingList`,
url: `${API_BASE_URL}/api/activity/get`,
method: "post", method: "post",
data: data, data: data,
}); });
@ -17,16 +17,7 @@ export function getLandingListApi(data) {
// 添加落地页活动 // 添加落地页活动
export function addLandingApi(data) { export function addLandingApi(data) {
return request({ return request({
url: `${API_BASE_URL}/admin/addLand`,
method: "post",
data: data,
});
}
// 修改落地页活动
export function editLandingtApi(data) {
return request({
url: `${API_BASE_URL}/admin/editLanding`,
url: `${API_BASE_URL}/admin/activity/add`,
method: "post", method: "post",
data: data, data: data,
}); });
@ -35,7 +26,7 @@ export function editLandingtApi(data) {
// 获取落地页活动列表 // 获取落地页活动列表
export function getLandingDetailApi(data) { export function getLandingDetailApi(data) {
return request({ return request({
url: `${API_BASE_URL}/admin/getLandingDetail`,
url: `${API_BASE_URL}/admin/activity/detail`,
method: "post", method: "post",
data: data, data: data,
}); });
@ -44,8 +35,9 @@ export function getLandingDetailApi(data) {
// 导出落地页活动列表 // 导出落地页活动列表
export function exportLandingDetailApi(data) { export function exportLandingDetailApi(data) {
return request({ return request({
url: `${API_BASE_URL}/admin/exportLandingDetail`,
url: `${API_BASE_URL}/admin/activity/export`,
method: "post", method: "post",
data: data, data: data,
responseType: 'arraybuffer'
}); });
} }

77
src/views/admin/landingDetail.vue

@ -48,7 +48,7 @@
/> />
</el-form-item> </el-form-item>
<el-form-item label="收下状态"> <el-form-item label="收下状态">
<el-select v-model="filterForm.status" placeholder="请选择状态" style="width: 150px;">
<el-select v-model="filterForm.status" placeholder="请选择状态" style="width: 150px;" clearable>
<el-option label="是" value="1"></el-option> <el-option label="是" value="1"></el-option>
<el-option label="否" value="0"></el-option> <el-option label="否" value="0"></el-option>
</el-select> </el-select>
@ -71,13 +71,13 @@
align="center" align="center"
></el-table-column> ></el-table-column>
<el-table-column <el-table-column
prop="userInfo"
prop="user_info"
label="用户信息" label="用户信息"
min-width="180" min-width="180"
align="center" align="center"
></el-table-column> ></el-table-column>
<el-table-column <el-table-column
prop="openTime"
prop="created_at"
label="打开网页时间" label="打开网页时间"
min-width="180" min-width="180"
align="center" align="center"
@ -88,7 +88,7 @@
align="center" align="center"
> >
<template v-slot:default="scope"> <template v-slot:default="scope">
{{ scope.row.status === 1 ? '是' : '否' }}
{{ scope.row.state === 1 ? '是' : '否' }}
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -125,33 +125,7 @@ export default {
status: '' status: ''
}, },
// //
tableData: [
{
userInfo: '张三(13800138000)',
openTime: '2025-10-20 09:15:30',
status: 1 //
},
{
userInfo: '李四(13900139000)',
openTime: '2025-10-20 10:22:15',
status: 0 //
},
{
userInfo: '王五(13700137000)',
openTime: '2025-10-20 14:05:40',
status: 1 //
},
{
userInfo: '赵六(13600136000)',
openTime: '2025-10-21 08:40:22',
status: 0 //
},
{
userInfo: '孙七(13500135000)',
openTime: '2025-10-21 11:30:10',
status: 1 //
},
],
tableData: [],
// //
currentPage: 1, currentPage: 1,
pageSize: 20, pageSize: 20,
@ -196,10 +170,10 @@ export default {
const res = await getLandingDetailApi({ const res = await getLandingDetailApi({
id: id, id: id,
page: this.currentPage, page: this.currentPage,
pageSize: this.pageSize,
startTime: this.formatDateTime(startTime),
endTime: this.formatDateTime(endTime),
status: status
page_size: this.pageSize,
start_time: this.formatDateTime(startTime),
end_time: this.formatDateTime(endTime),
state: status === '' || status == null ? -1 : status
}); });
if (res.code === 200) { if (res.code === 200) {
@ -228,23 +202,24 @@ export default {
const { startTime, endTime, status } = this.filterForm; const { startTime, endTime, status } = this.filterForm;
exportLandingDetailApi({ exportLandingDetailApi({
id: this.$route.params.id, id: this.$route.params.id,
startTime: this.formatDateTime(startTime),
endTime: this.formatDateTime(endTime),
status: status
page: this.currentPage,
page_size: this.pageSize,
start_time: this.formatDateTime(startTime),
end_time: this.formatDateTime(endTime),
state: status === '' || status == null ? -1 : status
}).then(res => { }).then(res => {
if (res.code === 200) {
ElMessage.success('导出成功');
// a
const blob = new Blob([res.data], { type: 'application/vnd.ms-excel' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `${'活动数据'}.xlsx`;
a.click();
URL.revokeObjectURL(url);
} else {
ElMessage.error(res.msg || '导出失败');
}
const data = res.data !== undefined ? res.data : res;
const blob = new Blob([data], { type: res.headers?.['content-type'] || 'application/octet-stream' });
let filename = `活动数据.xlsx`;
const blobUrl = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = blobUrl;
a.download = filename;
document.body.appendChild(a);
a.click();
a.remove();
URL.revokeObjectURL(blobUrl);
ElMessage.success('导出成功');
}); });
} catch (error) { } catch (error) {
ElMessage.error('导出失败,请重试'); ElMessage.error('导出失败,请重试');

520
src/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像素支持PNGJPGGIF格式图片需小于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像素支持PNGJPG格式图片需小于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>
Loading…
Cancel
Save