467 行
22 KiB
HTML
467 行
22 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>骑手奖励活动管理</title>
|
|
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
|
|
<script src="https://unpkg.com/vue@2/dist/vue.js"></script>
|
|
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
|
|
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
|
|
<style>
|
|
.page-container {
|
|
padding: 20px;
|
|
background-color: #f5f5f5;
|
|
min-height: 100vh;
|
|
}
|
|
.stats-cards {
|
|
display: flex;
|
|
gap: 20px;
|
|
margin-bottom: 20px;
|
|
}
|
|
.stats-card {
|
|
flex: 1;
|
|
background: white;
|
|
padding: 20px;
|
|
border-radius: 8px;
|
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
}
|
|
.stats-number {
|
|
font-size: 24px;
|
|
font-weight: bold;
|
|
color: #409EFF;
|
|
}
|
|
.stats-label {
|
|
color: #666;
|
|
margin-top: 5px;
|
|
}
|
|
.search-form {
|
|
background: white;
|
|
padding: 20px;
|
|
border-radius: 8px;
|
|
margin-bottom: 20px;
|
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
}
|
|
.table-container {
|
|
background: white;
|
|
border-radius: 8px;
|
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
}
|
|
.status-tag {
|
|
font-size: 12px;
|
|
}
|
|
.reward-type-tag {
|
|
font-size: 12px;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="app" class="page-container">
|
|
<div class="stats-cards">
|
|
<div class="stats-card">
|
|
<div class="stats-number">{{ stats.total_activities || 0 }}</div>
|
|
<div class="stats-label">总活动数</div>
|
|
</div>
|
|
<div class="stats-card">
|
|
<div class="stats-number">{{ stats.active_activities || 0 }}</div>
|
|
<div class="stats-label">进行中活动</div>
|
|
</div>
|
|
<div class="stats-card">
|
|
<div class="stats-number">{{ stats.total_participants || 0 }}</div>
|
|
<div class="stats-label">参与骑手数</div>
|
|
</div>
|
|
<div class="stats-card">
|
|
<div class="stats-number">¥{{ stats.total_rewards || 0 }}</div>
|
|
<div class="stats-label">累计奖励金额</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="search-form">
|
|
<el-form :inline="true" :model="searchForm" class="search-form">
|
|
<el-form-item label="关键词">
|
|
<el-input v-model="searchForm.keyword" placeholder="活动名称" clearable style="width: 200px;"></el-input>
|
|
</el-form-item>
|
|
<el-form-item label="活动类型">
|
|
<el-select v-model="searchForm.reward_type" placeholder="请选择" clearable style="width: 150px;">
|
|
<el-option label="全部" value=""></el-option>
|
|
<el-option label="高峰奖励" value="peak_hour"></el-option>
|
|
<el-option label="天气补贴" value="weather"></el-option>
|
|
<el-option label="满单奖励" value="order_count"></el-option>
|
|
<el-option label="距离奖励" value="distance"></el-option>
|
|
<el-option label="新手奖励" value="newbie"></el-option>
|
|
</el-select>
|
|
</el-form-item>
|
|
<el-form-item label="状态">
|
|
<el-select v-model="searchForm.status" placeholder="请选择" clearable style="width: 120px;">
|
|
<el-option label="全部" value=""></el-option>
|
|
<el-option label="进行中" value="1"></el-option>
|
|
<el-option label="已停止" value="0"></el-option>
|
|
</el-select>
|
|
</el-form-item>
|
|
<el-form-item label="时间范围">
|
|
<el-date-picker
|
|
v-model="searchForm.dateRange"
|
|
type="daterange"
|
|
range-separator="至"
|
|
start-placeholder="开始日期"
|
|
end-placeholder="结束日期"
|
|
format="yyyy-MM-dd"
|
|
value-format="yyyy-MM-dd">
|
|
</el-date-picker>
|
|
</el-form-item>
|
|
<el-form-item>
|
|
<el-button type="primary" @click="loadData">查询</el-button>
|
|
<el-button @click="resetSearch">重置</el-button>
|
|
<el-button type="success" @click="showAddDialog">新增活动</el-button>
|
|
</el-form-item>
|
|
</el-form>
|
|
</div>
|
|
|
|
<div class="table-container">
|
|
<el-table :data="tableData" v-loading="loading" style="width: 100%">
|
|
<el-table-column prop="id" label="ID" width="80"></el-table-column>
|
|
<el-table-column prop="activity_name" label="活动名称" min-width="150"></el-table-column>
|
|
<el-table-column prop="reward_type" label="活动类型" width="120">
|
|
<template slot-scope="scope">
|
|
<el-tag :type="getRewardTypeColor(scope.row.reward_type)" class="reward-type-tag">
|
|
{{ getRewardTypeText(scope.row.reward_type) }}
|
|
</el-tag>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column prop="reward_amount" label="奖励金额" width="100">
|
|
<template slot-scope="scope">
|
|
¥{{ scope.row.reward_amount }}
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column prop="condition_desc" label="触发条件" min-width="200"></el-table-column>
|
|
<el-table-column prop="start_time" label="开始时间" width="180">
|
|
<template slot-scope="scope">
|
|
{{ formatDateTime(scope.row.start_time) }}
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column prop="end_time" label="结束时间" width="180">
|
|
<template slot-scope="scope">
|
|
{{ formatDateTime(scope.row.end_time) }}
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column prop="participant_count" label="参与人数" width="100"></el-table-column>
|
|
<el-table-column prop="status" label="状态" width="80">
|
|
<template slot-scope="scope">
|
|
<el-tag :type="scope.row.status == 1 ? 'success' : 'danger'" class="status-tag">
|
|
{{ scope.row.status == 1 ? '进行中' : '已停止' }}
|
|
</el-tag>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="操作" width="200" fixed="right">
|
|
<template slot-scope="scope">
|
|
<el-button size="mini" @click="viewDetail(scope.row)">详情</el-button>
|
|
<el-button size="mini" type="primary" @click="editActivity(scope.row)">编辑</el-button>
|
|
<el-button
|
|
size="mini"
|
|
:type="scope.row.status == 1 ? 'warning' : 'success'"
|
|
@click="toggleStatus(scope.row)">
|
|
{{ scope.row.status == 1 ? '停止' : '启用' }}
|
|
</el-button>
|
|
<el-button size="mini" type="danger" @click="deleteActivity(scope.row)">删除</el-button>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
|
|
<div style="padding: 20px; text-align: right;">
|
|
<el-pagination
|
|
@size-change="handleSizeChange"
|
|
@current-change="handleCurrentChange"
|
|
:current-page="pagination.page"
|
|
:page-sizes="[10, 20, 50, 100]"
|
|
:page-size="pagination.pageSize"
|
|
layout="total, sizes, prev, pager, next, jumper"
|
|
:total="pagination.total">
|
|
</el-pagination>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 新增/编辑活动对话框 -->
|
|
<el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="600px">
|
|
<el-form :model="activityForm" :rules="activityRules" ref="activityForm" label-width="100px">
|
|
<el-form-item label="活动名称" prop="activity_name">
|
|
<el-input v-model="activityForm.activity_name" placeholder="请输入活动名称"></el-input>
|
|
</el-form-item>
|
|
<el-form-item label="活动类型" prop="reward_type">
|
|
<el-select v-model="activityForm.reward_type" placeholder="请选择活动类型" style="width: 100%;">
|
|
<el-option label="高峰奖励" value="peak_hour"></el-option>
|
|
<el-option label="天气补贴" value="weather"></el-option>
|
|
<el-option label="满单奖励" value="order_count"></el-option>
|
|
<el-option label="距离奖励" value="distance"></el-option>
|
|
<el-option label="新手奖励" value="newbie"></el-option>
|
|
</el-select>
|
|
</el-form-item>
|
|
<el-form-item label="奖励金额" prop="reward_amount">
|
|
<el-input-number v-model="activityForm.reward_amount" :min="0" :precision="2" style="width: 100%;"></el-input-number>
|
|
</el-form-item>
|
|
<el-form-item label="触发条件" prop="condition_desc">
|
|
<el-input type="textarea" v-model="activityForm.condition_desc" placeholder="请描述活动触发条件" :rows="3"></el-input>
|
|
</el-form-item>
|
|
<el-form-item label="活动时间" prop="dateRange">
|
|
<el-date-picker
|
|
v-model="activityForm.dateRange"
|
|
type="datetimerange"
|
|
range-separator="至"
|
|
start-placeholder="开始时间"
|
|
end-placeholder="结束时间"
|
|
format="yyyy-MM-dd HH:mm:ss"
|
|
value-format="yyyy-MM-dd HH:mm:ss"
|
|
style="width: 100%;">
|
|
</el-date-picker>
|
|
</el-form-item>
|
|
<el-form-item label="活动描述">
|
|
<el-input type="textarea" v-model="activityForm.description" placeholder="请输入活动描述" :rows="3"></el-input>
|
|
</el-form-item>
|
|
</el-form>
|
|
<div slot="footer" class="dialog-footer">
|
|
<el-button @click="dialogVisible = false">取消</el-button>
|
|
<el-button type="primary" @click="saveActivity">确定</el-button>
|
|
</div>
|
|
</el-dialog>
|
|
|
|
<!-- 活动详情对话框 -->
|
|
<el-dialog title="活动详情" :visible.sync="detailDialogVisible" width="800px">
|
|
<div v-if="currentActivity">
|
|
<el-descriptions :column="2" border>
|
|
<el-descriptions-item label="活动名称">{{ currentActivity.activity_name }}</el-descriptions-item>
|
|
<el-descriptions-item label="活动类型">{{ getRewardTypeText(currentActivity.reward_type) }}</el-descriptions-item>
|
|
<el-descriptions-item label="奖励金额">¥{{ currentActivity.reward_amount }}</el-descriptions-item>
|
|
<el-descriptions-item label="参与人数">{{ currentActivity.participant_count }}</el-descriptions-item>
|
|
<el-descriptions-item label="开始时间">{{ formatDateTime(currentActivity.start_time) }}</el-descriptions-item>
|
|
<el-descriptions-item label="结束时间">{{ formatDateTime(currentActivity.end_time) }}</el-descriptions-item>
|
|
<el-descriptions-item label="状态">
|
|
<el-tag :type="currentActivity.status == 1 ? 'success' : 'danger'">
|
|
{{ currentActivity.status == 1 ? '进行中' : '已停止' }}
|
|
</el-tag>
|
|
</el-descriptions-item>
|
|
<el-descriptions-item label="创建时间">{{ formatDateTime(currentActivity.create_time) }}</el-descriptions-item>
|
|
</el-descriptions>
|
|
<el-descriptions :column="1" border style="margin-top: 20px;">
|
|
<el-descriptions-item label="触发条件">{{ currentActivity.condition_desc }}</el-descriptions-item>
|
|
<el-descriptions-item label="活动描述">{{ currentActivity.description || '暂无描述' }}</el-descriptions-item>
|
|
</el-descriptions>
|
|
</div>
|
|
</el-dialog>
|
|
</div>
|
|
|
|
<script>
|
|
new Vue({
|
|
el: '#app',
|
|
data() {
|
|
return {
|
|
loading: false,
|
|
tableData: [],
|
|
stats: {},
|
|
searchForm: {
|
|
keyword: '',
|
|
reward_type: '',
|
|
status: '',
|
|
dateRange: []
|
|
},
|
|
pagination: {
|
|
page: 1,
|
|
pageSize: 20,
|
|
total: 0
|
|
},
|
|
dialogVisible: false,
|
|
detailDialogVisible: false,
|
|
dialogTitle: '新增活动',
|
|
currentActivity: null,
|
|
activityForm: {
|
|
id: null,
|
|
activity_name: '',
|
|
reward_type: '',
|
|
reward_amount: 0,
|
|
condition_desc: '',
|
|
description: '',
|
|
dateRange: []
|
|
},
|
|
activityRules: {
|
|
activity_name: [
|
|
{ required: true, message: '请输入活动名称', trigger: 'blur' }
|
|
],
|
|
reward_type: [
|
|
{ required: true, message: '请选择活动类型', trigger: 'change' }
|
|
],
|
|
reward_amount: [
|
|
{ required: true, message: '请输入奖励金额', trigger: 'blur' }
|
|
],
|
|
condition_desc: [
|
|
{ required: true, message: '请输入触发条件', trigger: 'blur' }
|
|
],
|
|
dateRange: [
|
|
{ required: true, message: '请选择活动时间', trigger: 'change' }
|
|
]
|
|
}
|
|
}
|
|
},
|
|
mounted() {
|
|
this.loadData();
|
|
this.loadStats();
|
|
},
|
|
methods: {
|
|
loadData() {
|
|
this.loading = true;
|
|
const params = {
|
|
page: this.pagination.page,
|
|
pageSize: this.pagination.pageSize,
|
|
...this.searchForm
|
|
};
|
|
|
|
// 模拟API调用
|
|
setTimeout(() => {
|
|
this.tableData = [
|
|
{
|
|
id: 1,
|
|
activity_name: '午高峰奖励活动',
|
|
reward_type: 'peak_hour',
|
|
reward_amount: 5.00,
|
|
condition_desc: '11:00-14:00时段完成订单',
|
|
start_time: '2024-01-01 00:00:00',
|
|
end_time: '2024-12-31 23:59:59',
|
|
participant_count: 156,
|
|
status: 1,
|
|
create_time: '2024-01-01 10:00:00',
|
|
description: '午餐高峰期配送奖励'
|
|
},
|
|
{
|
|
id: 2,
|
|
activity_name: '雨天补贴',
|
|
reward_type: 'weather',
|
|
reward_amount: 3.00,
|
|
condition_desc: '雨天配送订单',
|
|
start_time: '2024-01-01 00:00:00',
|
|
end_time: '2024-12-31 23:59:59',
|
|
participant_count: 89,
|
|
status: 1,
|
|
create_time: '2024-01-01 10:00:00',
|
|
description: '恶劣天气配送补贴'
|
|
}
|
|
];
|
|
this.pagination.total = 2;
|
|
this.loading = false;
|
|
}, 500);
|
|
},
|
|
loadStats() {
|
|
// 模拟统计数据
|
|
this.stats = {
|
|
total_activities: 8,
|
|
active_activities: 5,
|
|
total_participants: 245,
|
|
total_rewards: 12580.50
|
|
};
|
|
},
|
|
handleSizeChange(val) {
|
|
this.pagination.pageSize = val;
|
|
this.loadData();
|
|
},
|
|
handleCurrentChange(val) {
|
|
this.pagination.page = val;
|
|
this.loadData();
|
|
},
|
|
resetSearch() {
|
|
this.searchForm = {
|
|
keyword: '',
|
|
reward_type: '',
|
|
status: '',
|
|
dateRange: []
|
|
};
|
|
this.pagination.page = 1;
|
|
this.loadData();
|
|
},
|
|
showAddDialog() {
|
|
this.dialogTitle = '新增活动';
|
|
this.activityForm = {
|
|
id: null,
|
|
activity_name: '',
|
|
reward_type: '',
|
|
reward_amount: 0,
|
|
condition_desc: '',
|
|
description: '',
|
|
dateRange: []
|
|
};
|
|
this.dialogVisible = true;
|
|
},
|
|
editActivity(row) {
|
|
this.dialogTitle = '编辑活动';
|
|
this.activityForm = {
|
|
id: row.id,
|
|
activity_name: row.activity_name,
|
|
reward_type: row.reward_type,
|
|
reward_amount: row.reward_amount,
|
|
condition_desc: row.condition_desc,
|
|
description: row.description || '',
|
|
dateRange: [row.start_time, row.end_time]
|
|
};
|
|
this.dialogVisible = true;
|
|
},
|
|
saveActivity() {
|
|
this.$refs.activityForm.validate((valid) => {
|
|
if (valid) {
|
|
// 模拟保存操作
|
|
this.$message.success('保存成功');
|
|
this.dialogVisible = false;
|
|
this.loadData();
|
|
}
|
|
});
|
|
},
|
|
viewDetail(row) {
|
|
this.currentActivity = row;
|
|
this.detailDialogVisible = true;
|
|
},
|
|
toggleStatus(row) {
|
|
const action = row.status == 1 ? '停止' : '启用';
|
|
this.$confirm(`确定要${action}该活动吗?`, '提示', {
|
|
confirmButtonText: '确定',
|
|
cancelButtonText: '取消',
|
|
type: 'warning'
|
|
}).then(() => {
|
|
// 模拟状态切换
|
|
this.$message.success(`${action}成功`);
|
|
this.loadData();
|
|
});
|
|
},
|
|
deleteActivity(row) {
|
|
this.$confirm('确定要删除该活动吗?', '提示', {
|
|
confirmButtonText: '确定',
|
|
cancelButtonText: '取消',
|
|
type: 'warning'
|
|
}).then(() => {
|
|
// 模拟删除操作
|
|
this.$message.success('删除成功');
|
|
this.loadData();
|
|
});
|
|
},
|
|
getRewardTypeText(type) {
|
|
const typeMap = {
|
|
'peak_hour': '高峰奖励',
|
|
'weather': '天气补贴',
|
|
'order_count': '满单奖励',
|
|
'distance': '距离奖励',
|
|
'newbie': '新手奖励'
|
|
};
|
|
return typeMap[type] || type;
|
|
},
|
|
getRewardTypeColor(type) {
|
|
const colorMap = {
|
|
'peak_hour': 'warning',
|
|
'weather': 'info',
|
|
'order_count': 'success',
|
|
'distance': 'primary',
|
|
'newbie': 'danger'
|
|
};
|
|
return colorMap[type] || '';
|
|
},
|
|
formatDateTime(timestamp) {
|
|
if (!timestamp) return '';
|
|
return new Date(timestamp).toLocaleString('zh-CN');
|
|
}
|
|
}
|
|
});
|
|
</script>
|
|
</body>
|
|
</html> |