feat(广告): 添加广告模块

dev
zhangjiabao 11 months ago
parent d4e4460fdf
commit 299defd48e

@ -0,0 +1,81 @@
/*
* @Description:
* @version: v1
* @Author: zhangjiabao
* @Date: 2024-02-24 23:38:16
*/
import request from "@/utils/request";
export default {
getList(data, page, size) {
return request({
url: `/luoo-music/cms/ad/search/${page}/${size}`,
method: "post",
data: data
});
},
getDetail(id) {
return request({
url: `/luoo-music/cms/ad/${id}`,
method: "get"
});
},
/**
* 删除
* @param {*} id
* @returns
*/
delete(id) {
return request({
url: `/luoo-music/cms/ad/${id}`,
method: "delete"
});
},
/**
* 发布
* @param {*} id
* @returns
*/
publish(id, type, time) {
return request({
url: `/luoo-music/cms/ad/publish/${id}`,
method: "put",
data: {
isScheduled: type,
pubTime: time
}
});
},
/**
* 更新状态
* @param {*} id
* @param {*} state
* @returns
*/
updateStatus(id, state) {
return request({
url: `/luoo-music/cms/ad/update/state/${id}`,
method: "put",
data: state
});
},
/**
* 更新
* @param {*} id
* @param {*} data
* @returns
*/
update(id, data) {
return request({
url: `/luoo-music/cms/ad/${id}`,
method: "put",
data: data
});
},
add(data) {
return request({
url: `/luoo-music/cms/ad/add`,
method: "post",
data: data
});
}
};

@ -2,7 +2,7 @@
* @Author: zhangjiabao
* @Date: 2024-01-25 11:05:17
* @LastEditors: zhangjiabao
* @LastEditTime: 2024-02-24 20:59:42
* @LastEditTime: 2024-02-25 11:12:29
* @FilePath: /luoo_manage_fe/src/router/index.js
*/
import Vue from "vue";
@ -197,8 +197,15 @@ export const constantRouterMap = [
{
path: "ad",
name: "Ad",
component: () => import("@/views/common/unfinished"),
component: () => import("@/views/ad/index"),
meta: { title: "广告管理" }
},
{
path: "adModify",
name: "AdDetail",
hidden: true,
component: () => import("@/views/ad/adModifyPage"),
meta: { title: "文章详情" }
}
]
},

@ -0,0 +1,230 @@
<!--
* @Description:
* @version: v1
* @Author: zhangjiabao
* @Date: 2024-01-20 02:11:55
-->
<template>
<div>
<el-form
ref="modifyDialogForm"
:model="data"
:rules="rules"
style="width: 800px;margin: 0 auto;"
label-position="left"
label-suffix=":"
label-width="100px"
>
<el-form-item prop="name" label="广告名称">
<el-input
v-model="data.name"
size="small"
style="width:187px"
placeholder="请输入广告名称"
></el-input>
</el-form-item>
<el-form-item prop="location" label="广告位置">
<el-select
placeholder="选择广告位置"
size="small"
v-model="data.location"
>
<el-option
v-for="item in ['首页banner', '我的banne']"
:label="item"
:value="item"
:key="item + ''"
></el-option>
</el-select>
</el-form-item>
<el-form-item prop="type" label="跳转类型">
<el-select placeholder="选择跳转类型" size="small" v-model="data.type">
<el-option
v-for="item in ['站内文章', '外部链接', '跳转期刊']"
:label="item"
:value="item"
:key="item + ''"
></el-option>
</el-select>
</el-form-item>
<el-form-item prop="url" label="跳转地址">
<el-input
v-model="data.url"
size="small"
style="width:187px"
placeholder="请输入跳转地址"
></el-input>
</el-form-item>
<el-form-item size="small" prop="userId" label="发布人">
<el-select placeholder="发布人" size="small" v-model="data.userId">
<el-option
v-for="item in publisher"
:label="item.name"
:value="item.id"
:key="item.id"
></el-option>
</el-select>
</el-form-item>
<el-form-item prop="startTime" label="开始时间">
<el-date-picker
type="datetime"
v-model="data.startTime"
size="small"
value-format="yyyy-MM-dd HH:mm:ss"
style="width:200px"
></el-date-picker>
</el-form-item>
<el-form-item prop="endTime" label="结束时间">
<el-date-picker
type="datetime"
v-model="data.endTime"
size="small"
value-format="yyyy-MM-dd HH:mm:ss"
style="width:200px"
></el-date-picker>
</el-form-item>
<el-form-item prop="isDisplay" label="是否显示">
<el-checkbox
v-model="data.isDisplay"
size="small"
:true-label="'1'"
:false-label="'0'"
>是否显示</el-checkbox
>
</el-form-item>
<el-form-item prop="image" label="广告封面">
<img style="width: 170px;height: 120px;" :src="data.image" />
<el-upload
:action="`${uploadBase}/luoo-music/cms/ad/upload/image`"
:headers="uploadHeader"
:on-preview="handlePreview"
:on-remove="handleRemove"
:before-remove="beforeRemove"
:on-change="handleUploadadImageSuccess"
multiple
:limit="1"
:on-exceed="handleExceed"
:file-list="coverUploadFileList"
>
<el-button size="small" type="primary" icon="el-icon-receiving"
>上传图片</el-button
>
<div
slot="tip"
style="font-family: '微软雅黑', sans-serif; font-weight: 400; font-style: normal; color: #999999;"
>
支持格式.jpg, .png 单个文件不能超过5MB 建议图片分辨率640*520
</div>
</el-upload>
</el-form-item>
</el-form>
<el-form
label-suffix=":"
style="width: calc(50% + 400px); margin: 15px 0 auto auto;"
label-position="left"
label-width="100px"
>
<el-form-item prop="content" label="广告详情">
<el-input
type="textarea"
rows="8"
v-model="data.content"
style="height: 500px;"
/>
</el-form-item>
</el-form>
</div>
</template>
<script>
import { getToken } from "@/utils/auth";
export default {
name: "adModify",
props: {
data: {
type: Object,
default: {
content: "",
id: null,
endTime: "",
image: "",
isDisplay: "",
location: "",
name: "",
startTime: "",
type: "",
url: "",
userId: ""
}
},
publisher: {
type: Array,
default: []
}
},
data() {
return {
uploadHeader: {
"Admin-Token": getToken(),
"X-Token": getToken(),
Authorization: getToken()
},
uploadBase: process.env.BASE_API,
coverUploadFileList: [],
rules: {
name: [{ required: true, message: "请输入广告标题", trigger: "blur" }],
url: [{ required: true, message: "请输入跳转地址", trigger: "blur" }],
location: [
{ required: true, message: "请选择广告位置", trigger: "change" }
],
type: [
{ required: true, message: "请选择跳转类型", trigger: "change" }
],
startTime: [
{ required: true, message: "请选择开始时间", trigger: "change" }
],
endTime: [
{ required: true, message: "请选择结束时间", trigger: "change" }
],
isDisplay: [
{ required: true, message: "请选择是否显示", trigger: "change" }
],
userId: [
{ required: true, message: "请选择广告作者", trigger: "blur" }
],
image: [{ required: true, message: "请上传封面", trigger: "change" }]
}
};
},
filters: {},
created() {},
components: {},
mounted() {},
methods: {
// ************************* *************************
handleRemove(file, fileList) {
console.log(file, fileList);
},
handlePreview(file) {
console.log(file);
},
handleExceed(files, fileList) {
this.$message.warning(
`当前限制选择 1 个文件,本次选择了 ${
files.length
} 个文件共选择了 ${files.length + fileList.length} 个文件`
);
},
beforeRemove(file, fileList) {
return this.$confirm(`确定移除 ${file.name}`);
},
handleUploadadImageSuccess(response, file, fileList) {
if (response.status === "success") {
this.$message.success("上传成功");
this.data.image = response.response.data["fullUrl"];
this.coverUploadFileList = [];
}
}
}
};
</script>

@ -0,0 +1,271 @@
<!--
* @Description: 广告
* @version: v1
* @Author: zhangjiabao
* @Date: 2024-01-19 23:29:58
-->
<template>
<div class="app-container">
<el-card class="box-card">
<div slot="header" class="card-header clearfix">
<span class="card-header-text">{{
["广告发布", "广告编辑"][type]
}}</span>
<div style="float: right; margin-top: -5px;">
<el-button
icon="el-icon-s-fold"
size="small"
@click="handleBackToList"
>返回列表</el-button
>
<el-button
type="primary"
icon="el-icon-circle-check"
size="small"
@click="save"
:loading="saveLoading"
:disabled="saveLoading"
>保存广告</el-button
>
</div>
</div>
<el-result v-if="resultShow" icon="success" title="保存成功">
<template slot="extra">
<el-button
@click="handleBackToList"
plain
type="primary"
size="medium"
>返回广告列表</el-button
>
<el-button @click="handleNew" plain type="default" size="medium"
>新建广告</el-button
>
</template>
</el-result>
<adModify
style="margin-left: -200px;"
ref="modifyDialog"
v-if="contentShow"
:data="data"
:remoteTagList="remoteData.tags"
:publisher="remoteData.publisher"
></adModify>
</el-card>
</div>
</template>
<script>
import adApi from "@/api/ad";
import tagApi from "@/api/tag";
import adModify from "./adModify.vue";
export default {
name: "adPublish",
data() {
return {
type: 0,
remoteData: { publisher: [] },
contentShow: false,
resultShow: false,
saveLoading: false,
data: {
content: "",
id: null,
endTime: "",
image: "",
isDisplay: "",
location: "",
name: "",
startTime: "",
type: "",
url: "",
userId: ""
}
};
},
components: {
adModify
},
filters: {},
created() {
if (this.$route.query.type && this.$route.query.type === "modify") {
if (this.$route.query.id) {
this.fetchDetail(this.$route.query.id);
}
} else {
this.contentShow = true;
}
this.fetchCreaterList();
},
methods: {
fetchDetail(id) {
adApi.getDetail(id).then(res => {
if (res.code === 200) {
this.data = JSON.parse(JSON.stringify(res.data));
this.type = 1;
this.contentShow = true;
} else {
this.type = 0;
this.$message.error(res.message);
}
});
},
/**
* 创建人下拉框
*/
fetchCreaterList() {
tagApi.createrList().then(res => {
if (res.code === 200) {
this.remoteData.publisher = res.data;
} else {
this.remoteData.publisher = [];
}
});
},
handleBackToList() {
this.$router.push("/contentManage/ad");
},
handleNew() {
this.data = {
content: "",
id: null,
endTime: "",
image: "",
isDisplay: "",
location: "",
name: "",
startTime: "",
type: "",
url: "",
userId: ""
};
this.type = 0;
this.resultShow = false;
this.contentShow = true;
this.$refs.modifyDialog.selectTag = [];
},
/**
* 保存
*/
save() {
this.saveLoading = true;
this.$refs.modifyDialog.$refs.modifyDialogForm.validate(valid => {
if (valid) {
let orgData = this.$refs.modifyDialog.data;
let param = orgData;
if (param.content === "" || param.content === null) {
this.$message.error("请填入内容");
this.saveLoading = false;
return;
}
console.log(param);
//
if (this.type === 0) {
adApi.add(param).then(res => {
if (res.code === 200) {
this.data = {
id: null,
allowCommit: "0",
autoPush: "0",
content: "",
image: "",
isScheduled: "0",
pubTime: "",
title: "",
type: "",
userId: ""
};
this.$refs.modifyDialog.selectTag = [];
this.saveLoading = false;
this.contentShow = false;
this.resultShow = true;
this.$message.success(res.message);
} else {
this.saveLoading = false;
this.$message.error(res.message);
}
});
return;
}
if (this.type === 1) {
adApi.update(param.id, param).then(res => {
if (res.code === 200) {
this.data = {
id: null,
allowCommit: "0",
autoPush: "0",
content: "",
image: "",
isScheduled: "0",
pubTime: "",
title: "",
type: "",
userId: ""
};
this.$refs.modifyDialog.selectTag = [];
this.saveLoading = false;
this.contentShow = false;
this.resultShow = true;
this.$message.success(res.message);
} else {
this.saveLoading = false;
this.$message.error(res.message);
}
});
return;
}
} else {
this.$message.error("请完善表单相关信息!");
this.saveLoading = false;
return false;
}
});
}
}
};
</script>
<style scoped>
.clearfix:before,
.clearfix:after {
display: table;
content: "";
}
.clearfix:after {
clear: both;
}
.card-header {
height: 23px;
}
.app-container {
font-family: "Microsoft YaHei Bold", "Microsoft YaHei Regular",
"Microsoft YaHei", sans-serif;
}
.card-header-text {
font-family: "Microsoft YaHei Bold", "Microsoft YaHei Regular",
"Microsoft YaHei", sans-serif;
font-weight: 700;
font-style: normal;
font-size: 16px;
text-align: left;
line-height: 20px;
letter-spacing: normal;
color: #333333;
}
.box-card {
min-height: 300px;
height: calc(100vh - 140px);
border-radius: 10px;
padding-bottom: 30px;
.el-card__header {
background-color: rgba(249, 249, 249, 1);
}
.el-card__body {
overflow: auto;
height: calc(100% - 50px);
padding-bottom: 80px;
}
}
</style>

@ -0,0 +1,526 @@
<!--
* @Description: 广告
* @version: v1
* @Author: zhangjiabao
* @Date: 2024-01-19 23:29:58
-->
<template>
<div class="app-container">
<!-- card -->
<el-card class="box-card">
<div slot="header" class="card-header clearfix">
<span class="card-header-text">广告管理</span>
</div>
<!-- 查询条件 -->
<el-form :inline="true" class="in-card-form" label-suffix=":">
<el-form-item>
<el-input
placeholder="广告名称"
size="medium"
disabled
v-model="queryForm.data.name"
></el-input>
</el-form-item>
<el-form-item>
<el-select
placeholder="广告位置"
size="medium"
disabled
v-model="queryForm.data.type"
>
<el-option
v-for="item in ['首页banner', '我的banner']"
:label="item"
:value="item"
:key="item + ''"
></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-select
placeholder="发布人"
size="medium"
disabled
v-model="queryForm.data.creatorId"
>
<el-option
v-for="item in queryForm.remoteData.publisher"
:label="item.name"
:value="item.id"
:key="item.id"
></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-date-picker
placeholder="更新时间"
disabled
v-model="queryForm.data.timeRange"
type="daterange"
:range-separator="
queryForm.data.timeRange.length === 0 ? null : '~'
"
:editable="false"
:clearable="false"
value-format="yyyy-MM-dd"
start-placeholder="选择时间范围"
size="medium"
style="width: 280px;"
>
</el-date-picker>
</el-form-item>
<el-form-item>
<el-button
icon="el-icon-search"
type="primary"
size="medium"
@click="handleQueryClick"
>查询</el-button
>
</el-form-item>
<el-form-item>
<el-button
icon="el-icon-refresh-left"
size="medium"
@click="handleResetClick"
>重置</el-button
>
</el-form-item>
</el-form>
<el-form :inline="true" class="in-card-form">
<el-form-item>
<el-button
type="primary"
icon="el-icon-plus"
size="medium"
@click="handleAddClick"
>新增广告</el-button
>
</el-form-item>
</el-form>
<!-- 表格 -->
<el-table
stripe
:data="table.data"
height="calc(100vh - 400px)"
v-loading="table.loading"
v-if="table.show"
element-loading-text="加载中"
:header-cell-style="{ background: '#f5f7fa', color: '#606266' }"
border
fit
>
<el-table-column align="center" label="序号" width="95">
<template slot-scope="scope">
{{ scope.$index + 1 }}
</template>
</el-table-column>
<el-table-column label="编号" prop="id"></el-table-column>
<el-table-column label="广告名称" prop="name"></el-table-column>
<el-table-column label="广告分类" prop="type"></el-table-column>
<el-table-column label="广告图">
<template slot-scope="scope">
<img style="height: 50px;" :src="scope.row.image" />
</template>
</el-table-column>
<el-table-column label="广告位置" prop="location"></el-table-column>
<el-table-column label="上架时间" prop="date"></el-table-column>
<el-table-column label="添加人员" prop="userName"></el-table-column>
<el-table-column fixed="right" label="操作" width="200px">
<template slot-scope="scope">
<el-button
plain
icon="el-icon-edit"
@click="handleModifyClick(scope.row)"
type="primary"
size="mini"
>编辑</el-button
>
<el-popconfirm
confirm-button-text="确定"
cancel-button-text="取消"
icon="el-icon-info"
icon-color="red"
title="是否确认删除广告?"
style="margin-left: 10px;"
@confirm="handleDeleteClick(scope.row)"
>
<el-button
slot="reference"
plain
icon="el-icon-delete"
type="danger"
size="mini"
>删除</el-button
>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
class="pagination-right"
background
v-if="table.show"
layout="total, prev, pager, next, sizes"
:current-page.sync="table.page.current"
:page-size="table.page.size"
:total="table.page.total"
@size-change="handlePageSizeChange"
@current-change="handlePageCurrentChange"
>
</el-pagination>
</el-card>
</div>
</template>
<script>
import adApi from "@/api/ad";
import tagApi from "@/api/tag";
export default {
name: "ad",
data() {
return {
//
queryForm: {
remoteData: {
publisher: [],
type: []
},
lastQuery: {},
superFilterDialog: {
visible: false
},
data: {
name: null,
type: null,
creatorId: null,
timeRange: []
}
},
//
table: {
show: true,
loading: true,
data: [],
page: {
current: 1,
size: 10,
total: 0
}
},
//
modifyDialog: {
visible: false,
loading: true,
type: 0, // 0for 1for 2for
data: {} //
}
};
},
components: {},
filters: {},
created() {
this.fetchCreaterList();
this.fetchTypeList();
this.fetchData(this.queryForm.data);
},
methods: {
log(e) {
this.$message.success(e);
},
// ************************* *************************
/**
* 查询表格数据
*/
fetchData(param) {
//
this.queryForm.lastQuery = param;
let queryParam = {
end: "",
keyword: param.name,
start: "",
tags: param.tags,
userId: param.creatorId,
type: param.type
};
if (param.timeRange) {
if (param.timeRange[0]) {
queryParam.start = param.timeRange[0];
}
if (param.timeRange[1]) {
queryParam.end = param.timeRange[1];
}
}
this.table.loading = true;
this.table.data = [];
adApi
.getList(queryParam, this.table.page.current, this.table.page.size)
.then(res => {
if (res.code === 200) {
this.table.data = res.data.rows;
this.table.page.total = res.data.total;
} else {
this.$message.error(res.message);
}
this.table.loading = false;
});
},
/**
* 创建人下拉框
*/
fetchCreaterList() {
tagApi.createrList().then(res => {
if (res.code === 200) {
this.queryForm.remoteData.publisher = res.data;
} else {
this.queryForm.remoteData.publisher = [];
}
});
},
/**
* 类型下拉框
*/
fetchTypeList() {
this.queryForm.remoteData.type = [];
// tagApi.typeList().then(res => {
// if (res.code === 200) {
// this.queryForm.remoteData.type = res.data;
// } else {
// this.queryForm.remoteData.type = [];
// }
// });
},
// ************************* *************************
/**
* 匹配发布者
*/
getAuthorNameById(userId) {
for (let index in this.queryForm.remoteData.publisher) {
let item = this.queryForm.remoteData.publisher[index];
if (item.id === userId) {
return item.name;
}
return "";
}
},
/**
* 匹配广告分类
*/
getTagNameById(type) {
for (let index in this.queryForm.remoteData.type) {
let item = this.queryForm.remoteData.type[index];
if (item.id === type) {
return item.name;
}
return "";
}
},
// ************************* *************************
/**
* 查询按扭点击事件
*/
handleQueryClick() {
this.table.page.current = 1;
this.table.page.total = 0;
this.fetchData(this.queryForm.data);
},
/**
* 重置点击事件
*/
handleResetClick() {
this.queryForm.data = {
parentId: null,
name: null,
type: null,
creatorId: null,
timeRange: []
};
},
/**
* 新建标签点击事件
*/
handleAddClick() {
this.$router.push(`/contentManage/adModify?type=add`);
},
/**
* 编辑标签点击事件
*/
handleModifyClick(row) {
this.$router.push(`/contentManage/adModify?id=${row.id}&type=modify`);
},
handleDeleteClick(row) {
adApi.delete(row.id).then(res => {
if (res.code === 200) {
this.$message.success(res.message);
this.fetchData(this.queryForm.lastQuery);
} else {
this.$message.error(res.message);
}
});
},
/**
* 弹窗取消按扭点击事件
*/
handleDialogCancel() {
this.modifyDialog.visible = false;
},
/**
* 弹窗取消按扭点击事件
*/
handlePublishDialogCancel() {
this.publishDialog.visible = false;
},
/**
* 发布弹窗确认按扭
*/
handlePublishDialogSubmit() {
adApi
.publish(
this.publishDialog.id,
this.publishDialog.type,
this.publishDialog.time
)
.then(res => {
if (res.code === 200) {
this.$message.success(res.message);
this.fetchData(this.queryForm.lastQuery);
this.publishDialog.visible = false;
return;
} else {
this.$message.error(res.message);
}
});
},
/**
* 弹窗重置
*/
handleDialogReset() {
this.$message.success("重置");
},
/**
* 弹窗关闭按扭点击事件
*/
handleModifyDialogBeforeClose(done) {
this.modifyDialog.visible = false;
done();
},
/**
* 弹窗关闭按扭点击事件
*/
handleTagsDialogBeforeClose(done) {
this.queryForm.superFilterDialog.visible = false;
done();
},
/**
* 弹窗关闭按扭点击事件
*/
handlePublishDialogBeforeClose(done) {
this.publishDialog.visible = false;
done();
},
/**
* 分页组件页数变化事件
*/
handlePageCurrentChange(val) {
this.table.page.current = val;
this.fetchData(this.queryForm.lastQuery);
},
/**
* 分页组件大小变化事件
*/
handlePageSizeChange(val) {
this.table.page.size = val;
this.fetchData(this.queryForm.lastQuery);
},
/**
* 切换标签事件
*/
handleChangeActivateTab(tab) {
this.activateTab = tab;
//
this.handleResetClick();
//
this.table.data = [];
this.table.page.current = 1;
this.table.page.size = 10;
this.table.show = false;
this.$nextTick(() => {
this.table.show = true;
});
this.fetchData(this.queryForm.data);
}
}
};
</script>
<style scoped>
.pagination-right {
text-align: right;
margin-top: 10px;
}
.box-card {
min-height: 300px;
height: calc(100vh - 140px);
border-radius: 10px;
.el-card__header {
background-color: rgba(249, 249, 249, 1);
}
}
/deep/ .el-dialog {
border-radius: 5px;
}
.popup-dialog {
.el-dialog__header {
border-top-left-radius: 5px;
border-top-right-radius: 5px;
height: 50px;
background-color: #f5f5f5f5;
}
.el-dialog__title {
font-size: 15px;
font-weight: bolder;
}
.el-dialog__footer {
border-top: solid;
border-top-width: thin;
border-top-color: rgb(233, 233, 233);
padding: 10px 20px 10px;
}
}
.in-card-form {
height: 60px;
display: flex;
}
.clearfix:before,
.clearfix:after {
display: table;
content: "";
}
.clearfix:after {
clear: both;
}
.card-header {
height: 23px;
}
.app-container {
font-family: "Microsoft YaHei Bold", "Microsoft YaHei Regular",
"Microsoft YaHei", sans-serif;
}
.card-header-text {
font-family: "Microsoft YaHei Bold", "Microsoft YaHei Regular",
"Microsoft YaHei", sans-serif;
font-weight: 700;
font-style: normal;
font-size: 16px;
text-align: left;
line-height: 20px;
letter-spacing: normal;
color: #333333;
}
</style>
Loading…
Cancel
Save