Commit 1ef1a1fa authored by lijin's avatar lijin

增加计划投放任务管理

parent 2f7301db
import request from '@/utils/request'
export function getCampaignTaskList(params) {
return request({
url: process.env.PUTIN_API + '/campaign-tasks',
method: 'get',
params
})
}
export function getCampaignTaskById(id) {
return request({
url: process.env.PUTIN_API + `/campaign-tasks/${id}`,
method: 'get'
})
}
export function createCampaignTask(data) {
return request({
url: process.env.PUTIN_API + '/campaign-tasks',
method: 'post',
data
})
}
export function updateCampaignTask(data) {
return request({
url: process.env.PUTIN_API + '/campaign-tasks',
method: 'put',
data
})
}
export function deleteCampaignTask(id) {
return request({
url: process.env.PUTIN_API + `/campaign-tasks/${id}`,
method: 'delete'
})
}
<template>
<el-select
v-model="selectedValues"
filterable
clearable
placeholder="请选择计划模板"
@change="handleChange"
>
<el-option
v-for="item in options"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</template>
<script>
import axios from 'axios'
export default {
name: 'CampaignTemplateSelector',
props: {
value: {
type: [Number, String, null],
default: null
}
},
data() {
return {
options: [],
selectedValues: []
}
},
watch: {
value: {
handler(newVal) {
this.selectedValues = newVal
},
immediate: true
}
},
created() {
this.fetchOptions()
},
methods: {
async fetchOptions() {
try {
const response = await axios.get(process.env.PUTIN_API + '/campaign-templates')
if (response.data && response.data.result && response.data.result.data) {
this.options = response.data.result.data.value || []
}
} catch (error) {
console.error('Failed to fetch campaign templates:', error)
}
},
handleChange(values) {
this.$emit('input', values)
this.$emit('change', values)
}
}
}
</script>
...@@ -70,6 +70,13 @@ export const constantRouterMap = [ ...@@ -70,6 +70,13 @@ export const constantRouterMap = [
meta: { title: "创意投放", icon: "chart" } meta: { title: "创意投放", icon: "chart" }
}, },
{
path: '/intelligentDelivery/campaign-task',
name: "intelligentDelivery.campaign-task",
component: () => import('@/views/campaignTask/CampaignTaskManage'),
meta: { title: '计划投放' }
},
{ {
path: '/intelligentDelivery/campaign-template', path: '/intelligentDelivery/campaign-template',
name: "intelligentDelivery.campaign-template", name: "intelligentDelivery.campaign-template",
......
<template>
<div class="campaign-task-container">
<!-- Filter section -->
<div class="filter-section">
<el-form :inline="true" :model="condition" class="filter-form">
<el-form-item label="计划模板">
<campaign-template-selector
v-model="condition.campaignTemplateId"
@change="handleTemplateChange"
/>
</el-form-item>
<el-form-item label="状态">
<el-select
v-model="condition.status"
placeholder="请选择状态"
clearable
@change="handleStatusChange">
<el-option label="未执行" :value="1"></el-option>
<el-option label="执行中" :value="2"></el-option>
<el-option label="执行成功" :value="3"></el-option>
<el-option label="执行失败" :value="4"></el-option>
</el-select>
</el-form-item>
<el-form-item label="日期范围">
<el-date-picker
v-model="dateRange"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="yyyy-MM-dd"
@change="handleDateChange">
</el-date-picker>
</el-form-item>
</el-form>
</div>
<el-divider></el-divider>
<!-- Table Header actions -->
<div class="header-actions">
<el-button type="primary" @click="showAddDialog">创建任务</el-button>
<div class="header-right">
<el-button icon="el-icon-refresh" @click="fetchData">刷新</el-button>
</div>
</div>
<!-- Main table -->
<el-table
:data="tableData"
border
style="width: 100%"
v-loading="loading">
<el-table-column prop="id" label="ID" width="80"></el-table-column>
<el-table-column prop="campaignTemplateId" label="计划模板" width="250">
<template slot-scope="scope">
{{ getTemplateName(scope.row.campaignTemplateId) }}
</template>
</el-table-column>
<el-table-column prop="status" label="状态" width="120">
<template slot-scope="scope">
<el-tag :type="getStatusType(scope.row.status)">
{{ getStatusText(scope.row.status) }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="start_time" label="开始时间" width="180">
<template slot-scope="scope">
{{ scope.row.start_time }}
</template>
</el-table-column>
<el-table-column prop="finish_time" label="结束时间" width="180">
<template slot-scope="scope">
{{ scope.row.finish_time }}
</template>
</el-table-column>
<el-table-column label="执行时间" width="150">
<template slot-scope="scope">
{{ calculateDuration(scope.row) }}
</template>
</el-table-column>
<el-table-column label="操作" align="center">
<template slot-scope="scope">
<el-button
size="mini"
type="primary"
@click="handleEdit(scope.row)">编辑</el-button>
<el-button
size="mini"
type="info"
@click="handleDetail(scope.row)">详情</el-button>
<el-button
v-if="scope.row.status === 1"
size="mini"
type="success"
@click="handleStart(scope.row)">开始</el-button>
<el-button
v-if="scope.row.status === 4"
size="mini"
type="warning"
@click="handleRetry(scope.row)">重试</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, 100]"
:page-size="pageSize"
:total="total"
layout="total, prev, pager, next, sizes">
</el-pagination>
</div>
<!-- Add/Edit Dialog -->
<el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="50%">
<el-form :model="form" :rules="rules" ref="form" label-width="120px">
<el-form-item label="计划模板" prop="campaignTemplateId">
<campaign-template-selector
v-model="form.campaignTemplateId"
/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="submitForm">确 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import CampaignTemplateSelector from '@/components/GroupSelectors/CampaignTemplateSelector'
import { getCampaignTaskList, createCampaignTask, updateCampaignTask } from '@/api/campaignTask'
import axios from 'axios'
import dayjs from 'dayjs'
import duration from 'dayjs/plugin/duration'
dayjs.extend(duration)
export default {
name: 'CampaignTaskManage',
components: {
CampaignTemplateSelector
},
data() {
const end = dayjs()
const start = end.subtract(7, 'day')
return {
loading: false,
condition: {
templateId: null,
status: null,
},
dateRange: [start.format('YYYY-MM-DD'), end.format('YYYY-MM-DD')],
tableData: [],
currentPage: 1,
pageSize: 10,
total: 0,
dialogVisible: false,
dialogTitle: '',
form: {
campaignTemplateId: null
},
rules: {
campaignTemplateId: [
{ required: true, message: '请选择计划模板', trigger: 'change' }
]
},
templateMap: new Map()
}
},
created() {
this.fetchTemplates()
this.fetchData()
},
methods: {
async fetchData() {
this.loading = true
try {
const [startDate, endDate] = this.dateRange || []
const response = await getCampaignTaskList({
page: this.currentPage,
size: this.pageSize,
...this.condition,
startDate,
endDate
})
if (response.status === 200) {
this.tableData = response.result.data.value
this.total = response.result.count
} else {
this.$message.error(response.msg || '获取数据失败')
}
} catch (error) {
console.error('获取数据失败:', error)
this.$message.error('获取数据失败')
}
this.loading = false
},
getStatusText(status) {
const statusMap = {
1: '未执行',
2: '执行中',
3: '执行成功',
4: '执行失败'
}
return statusMap[status] || status
},
getStatusType(status) {
const typeMap = {
1: 'info',
2: 'warning',
3: 'success',
4: 'danger'
}
return typeMap[status] || ''
},
calculateDuration(row) {
const startTime = dayjs(row.start_time)
const endTime = row.finish_time ? dayjs(row.finish_time) : dayjs()
const diff = endTime.diff(startTime)
const duration = dayjs.duration(diff)
if (duration.asHours() >= 1) {
return Math.floor(duration.asHours()) + '小时'
} else if (duration.asMinutes() >= 1) {
return Math.floor(duration.asMinutes()) + '分钟'
} else {
return Math.floor(duration.asSeconds()) + '秒'
}
},
async fetchTemplates() {
try {
const response = await axios.get(process.env.PUTIN_API + '/campaign-templates')
if (response.data && response.data.result && response.data.result.data) {
const templates = response.data.result.data.value || []
this.templateMap = new Map(templates.map(t => [t.id, t.name]))
}
} catch (error) {
console.error('Failed to fetch templates:', error)
}
},
getTemplateName(id) {
return this.templateMap.get(id) || id
},
handleTemplateChange() {
this.fetchData()
},
handleStatusChange() {
this.fetchData()
},
handleDateChange() {
this.fetchData()
},
handleSizeChange(val) {
this.pageSize = val
this.currentPage = 1
this.fetchData()
},
handleCurrentChange(val) {
this.currentPage = val
this.fetchData()
},
showAddDialog() {
this.dialogTitle = '创建任务'
this.form = {
campaignTemplateId: null
}
this.dialogVisible = true
},
handleEdit(row) {
this.dialogTitle = '编辑任务'
this.form = { ...row }
this.dialogVisible = true
},
handleDetail(row) {
// TODO: 实现详情查看功能
console.log('查看详情:', row)
},
async handleStart(row) {
try {
const response = await axios.post(process.env.PUTIN_API + `/campaign-tasks/start?campaignTaskId=${row.id}`)
if (response.status == 200 &&response.data && response.data.result && response.data.result.data) {
this.$message.success('任务开始成功')
}
} catch (error) {
console.error('Failed to start task:', error)
this.$message.success('任务开始失败:' + error.message)
}
},
handleRetry(row) {
// TODO: 实现重试功能
console.log('重试任务:', row)
},
async submitForm() {
this.$refs.form.validate(async (valid) => {
if (valid) {
try {
let response
if (this.form.id) {
response = await updateCampaignTask(this.form)
} else {
response = await createCampaignTask(this.form)
}
if (response.status === 200) {
this.$message.success(this.form.id ? '更新成功' : '创建成功')
this.dialogVisible = false
this.fetchData()
} else {
this.$message.error(response.msg || (this.form.id ? '更新失败' : '创建失败'))
}
} catch (error) {
console.error(this.form.id ? '更新失败:' : '创建失败:', error)
this.$message.error(this.form.id ? '更新失败' : '创建失败')
}
}
})
}
}
}
</script>
<style scoped>
.campaign-task-container {
padding: 20px;
}
.filter-section {
background-color: #fff;
padding: 20px;
border-radius: 4px;
}
.filter-form {
display: flex;
flex-wrap: wrap;
}
.filter-input {
width: 200px;
}
.header-actions {
margin: 20px 0;
display: flex;
justify-content: space-between;
}
.header-right {
display: flex;
gap: 10px;
}
.el-tag {
margin-right: 5px;
margin-bottom: 5px;
}
.el-table--enable-row-hover .el-table__body tr:hover > td {
background-color: #f5f7fa;
}
.el-button--primary {
background-color: #1890ff;
border-color: #1890ff;
}
.el-button--primary:hover,
.el-button--primary:focus {
background-color: #40a9ff;
border-color: #40a9ff;
}
.el-link {
color: #1890ff;
}
.el-link:hover {
color: #40a9ff;
}
.el-select .el-input__inner,
.el-input__inner {
border-radius: 2px;
}
.pagination-container {
margin-top: 20px;
display: flex;
justify-content: flex-end;
padding: 10px 0;
}
.el-pagination {
font-weight: normal;
}
.el-pagination .el-select .el-input {
width: 110px;
}
.el-pagination .el-select .el-input__inner {
padding-right: 25px;
}
.el-pagination .btn-prev,
.el-pagination .btn-next {
background: transparent;
}
.el-pagination .el-pager li {
background: transparent;
border: none;
}
.el-pagination .el-pager li.active {
color: #1890ff;
background-color: #e6f7ff;
border-radius: 2px;
}
.el-pagination__total {
margin-right: 10px;
}
.el-pagination__sizes {
margin-left: 10px;
}
</style>
...@@ -19,9 +19,20 @@ ...@@ -19,9 +19,20 @@
<el-submenu index="2"> <el-submenu index="2">
<template slot="title">推广管理</template> <template slot="title">推广管理</template>
<el-menu-item index="/intelligentDelivery/createDelivery">创建计划</el-menu-item> <el-menu-item index="/intelligentDelivery/createDelivery">创建计划</el-menu-item>
<el-menu-item index="/intelligentDelivery/campaign-task">计划投放</el-menu-item>
<el-menu-item index="/intelligentDelivery/campaign-template">计划模板</el-menu-item> <el-menu-item index="/intelligentDelivery/campaign-template">计划模板</el-menu-item>
</el-submenu> </el-submenu>
<!-- 带子菜单的导航项 -->
<el-submenu index="4">
<template slot="title">资产管理</template>
<el-menu-item index="/intelligentDelivery/campaign-template">产品组</el-menu-item>
<el-menu-item index="/intelligentDelivery/createDelivery">地域组</el-menu-item>
<el-menu-item index="/intelligentDelivery/createDelivery">素材组</el-menu-item>
<el-menu-item index="/intelligentDelivery/createDelivery">标题组</el-menu-item>
<el-menu-item index="/intelligentDelivery/createDelivery">描述组</el-menu-item>
</el-submenu>
<el-submenu index="3"> <el-submenu index="3">
<template slot="title">工具</template> <template slot="title">工具</template>
<el-menu-item index="/assetManagement/googleOauthYoutube">Youtube账号管理</el-menu-item> <el-menu-item index="/assetManagement/googleOauthYoutube">Youtube账号管理</el-menu-item>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment