|
@@ -3,77 +3,340 @@
|
|
|
<el-card>
|
|
<el-card>
|
|
|
<div slot="header">
|
|
<div slot="header">
|
|
|
<span>奖励管理</span>
|
|
<span>奖励管理</span>
|
|
|
- <el-button type="primary" size="small" style="float: right">添加奖励模板</el-button>
|
|
|
|
|
|
|
+ <el-button
|
|
|
|
|
+ type="primary"
|
|
|
|
|
+ size="small"
|
|
|
|
|
+ style="float: right"
|
|
|
|
|
+ @click="handleRefresh"
|
|
|
|
|
+ :loading="loading"
|
|
|
|
|
+ >
|
|
|
|
|
+ 刷新
|
|
|
|
|
+ </el-button>
|
|
|
</div>
|
|
</div>
|
|
|
- <el-tabs v-model="activeTab">
|
|
|
|
|
|
|
+
|
|
|
|
|
+ <el-tabs v-model="activeTab" @tab-click="handleTabClick">
|
|
|
|
|
+ <!-- 奖励列表 -->
|
|
|
<el-tab-pane label="奖励列表" name="list">
|
|
<el-tab-pane label="奖励列表" name="list">
|
|
|
- <el-table :data="tableData" border>
|
|
|
|
|
- <el-table-column prop="id" label="ID" width="60"></el-table-column>
|
|
|
|
|
- <el-table-column prop="title" label="奖励名称"></el-table-column>
|
|
|
|
|
- <el-table-column prop="pointsRequired" label="所需积分"></el-table-column>
|
|
|
|
|
- <el-table-column prop="category" label="分类"></el-table-column>
|
|
|
|
|
- <el-table-column prop="status" label="状态">
|
|
|
|
|
|
|
+ <!-- 搜索筛选 -->
|
|
|
|
|
+ <el-form :inline="true" :model="searchForm" style="margin-bottom: 20px">
|
|
|
|
|
+ <el-form-item label="状态">
|
|
|
|
|
+ <el-select v-model="searchForm.status" placeholder="全部状态" clearable @change="handleSearch">
|
|
|
|
|
+ <el-option label="可用" value="available"></el-option>
|
|
|
|
|
+ <el-option label="待审批" value="pending"></el-option>
|
|
|
|
|
+ <el-option label="已兑换" value="exchanged"></el-option>
|
|
|
|
|
+ <el-option label="已拒绝" value="rejected"></el-option>
|
|
|
|
|
+ </el-select>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item>
|
|
|
|
|
+ <el-button type="primary" @click="handleSearch">搜索</el-button>
|
|
|
|
|
+ <el-button @click="handleReset">重置</el-button>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-form>
|
|
|
|
|
+
|
|
|
|
|
+ <el-table :data="tableData" border v-loading="loading" style="width: 100%">
|
|
|
|
|
+ <el-table-column prop="id" label="ID" width="80"></el-table-column>
|
|
|
|
|
+ <el-table-column prop="title" label="奖励名称" min-width="200"></el-table-column>
|
|
|
|
|
+ <el-table-column prop="pointsRequired" label="所需积分" width="120">
|
|
|
|
|
+ <template slot-scope="scope">
|
|
|
|
|
+ <el-tag type="warning">{{ scope.row.pointsRequired }}</el-tag>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column prop="category" label="分类" width="100"></el-table-column>
|
|
|
|
|
+ <el-table-column prop="childId" label="孩子ID" width="80"></el-table-column>
|
|
|
|
|
+ <el-table-column prop="status" label="状态" width="100">
|
|
|
<template slot-scope="scope">
|
|
<template slot-scope="scope">
|
|
|
<el-tag :type="getStatusType(scope.row.status)" size="small">
|
|
<el-tag :type="getStatusType(scope.row.status)" size="small">
|
|
|
{{ getStatusText(scope.row.status) }}
|
|
{{ getStatusText(scope.row.status) }}
|
|
|
</el-tag>
|
|
</el-tag>
|
|
|
</template>
|
|
</template>
|
|
|
</el-table-column>
|
|
</el-table-column>
|
|
|
- <el-table-column label="操作" width="200">
|
|
|
|
|
|
|
+ <el-table-column prop="createdAt" label="创建时间" width="180">
|
|
|
<template slot-scope="scope">
|
|
<template slot-scope="scope">
|
|
|
- <el-button v-if="scope.row.status === 'pending'" type="text" size="small" @click="handleApprove(scope.row, true)">通过</el-button>
|
|
|
|
|
- <el-button v-if="scope.row.status === 'pending'" type="text" size="small" style="color: #F56C6C" @click="handleApprove(scope.row, false)">拒绝</el-button>
|
|
|
|
|
- <el-button type="text" size="small">编辑</el-button>
|
|
|
|
|
|
|
+ {{ formatDate(scope.row.createdAt) }}
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="操作" width="200" fixed="right">
|
|
|
|
|
+ <template slot-scope="scope">
|
|
|
|
|
+ <el-button
|
|
|
|
|
+ v-if="scope.row.status === 'pending'"
|
|
|
|
|
+ type="text"
|
|
|
|
|
+ size="small"
|
|
|
|
|
+ @click="handleApprove(scope.row, true)"
|
|
|
|
|
+ >
|
|
|
|
|
+ 通过
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ <el-button
|
|
|
|
|
+ v-if="scope.row.status === 'pending'"
|
|
|
|
|
+ type="text"
|
|
|
|
|
+ size="small"
|
|
|
|
|
+ style="color: #F56C6C"
|
|
|
|
|
+ @click="handleApprove(scope.row, false)"
|
|
|
|
|
+ >
|
|
|
|
|
+ 拒绝
|
|
|
|
|
+ </el-button>
|
|
|
</template>
|
|
</template>
|
|
|
</el-table-column>
|
|
</el-table-column>
|
|
|
</el-table>
|
|
</el-table>
|
|
|
|
|
+
|
|
|
|
|
+ <el-pagination
|
|
|
|
|
+ style="margin-top: 20px; text-align: right"
|
|
|
|
|
+ @size-change="handleSizeChange"
|
|
|
|
|
+ @current-change="handleCurrentChange"
|
|
|
|
|
+ :current-page="pagination.current"
|
|
|
|
|
+ :page-sizes="[10, 20, 50, 100]"
|
|
|
|
|
+ :page-size="pagination.size"
|
|
|
|
|
+ :total="pagination.total"
|
|
|
|
|
+ layout="total, sizes, prev, pager, next, jumper"
|
|
|
|
|
+ ></el-pagination>
|
|
|
</el-tab-pane>
|
|
</el-tab-pane>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 奖励模板 -->
|
|
|
<el-tab-pane label="奖励模板" name="templates">
|
|
<el-tab-pane label="奖励模板" name="templates">
|
|
|
- <el-table :data="templates" border>
|
|
|
|
|
- <el-table-column prop="id" label="ID" width="60"></el-table-column>
|
|
|
|
|
- <el-table-column prop="title" label="模板名称"></el-table-column>
|
|
|
|
|
- <el-table-column prop="pointsRequired" label="所需积分"></el-table-column>
|
|
|
|
|
- <el-table-column prop="category" label="分类"></el-table-column>
|
|
|
|
|
- <el-table-column label="操作" width="120">
|
|
|
|
|
|
|
+ <el-button type="primary" size="small" style="margin-bottom: 15px" @click="showCreateTemplate">
|
|
|
|
|
+ 新建模板
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ <el-table :data="templates" border v-loading="loadingTemplates" style="width: 100%">
|
|
|
|
|
+ <el-table-column prop="id" label="ID" width="80"></el-table-column>
|
|
|
|
|
+ <el-table-column prop="title" label="模板名称" min-width="200"></el-table-column>
|
|
|
|
|
+ <el-table-column prop="pointsRequired" label="所需积分" width="120">
|
|
|
|
|
+ <template slot-scope="scope">
|
|
|
|
|
+ <el-tag type="warning">{{ scope.row.pointsRequired }}</el-tag>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column prop="category" label="分类" width="100"></el-table-column>
|
|
|
|
|
+ <el-table-column prop="createdAt" label="创建时间" width="180">
|
|
|
<template slot-scope="scope">
|
|
<template slot-scope="scope">
|
|
|
- <el-button type="text" size="small">编辑</el-button>
|
|
|
|
|
- <el-button type="text" size="small" style="color: #F56C6C">删除</el-button>
|
|
|
|
|
|
|
+ {{ formatDate(scope.row.createdAt) }}
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="操作" width="150" fixed="right">
|
|
|
|
|
+ <template slot-scope="scope">
|
|
|
|
|
+ <el-button
|
|
|
|
|
+ type="text"
|
|
|
|
|
+ size="small"
|
|
|
|
|
+ style="color: #F56C6C"
|
|
|
|
|
+ @click="handleDeleteTemplate(scope.row)"
|
|
|
|
|
+ >
|
|
|
|
|
+ 删除
|
|
|
|
|
+ </el-button>
|
|
|
</template>
|
|
</template>
|
|
|
</el-table-column>
|
|
</el-table-column>
|
|
|
</el-table>
|
|
</el-table>
|
|
|
</el-tab-pane>
|
|
</el-tab-pane>
|
|
|
</el-tabs>
|
|
</el-tabs>
|
|
|
</el-card>
|
|
</el-card>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 创建奖励模板对话框 -->
|
|
|
|
|
+ <el-dialog title="新建奖励模板" :visible.sync="dialogVisible" width="500px">
|
|
|
|
|
+ <el-form :model="templateForm" label-width="100px">
|
|
|
|
|
+ <el-form-item label="奖励名称">
|
|
|
|
|
+ <el-input v-model="templateForm.title" placeholder="请输入奖励名称"></el-input>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="所需积分">
|
|
|
|
|
+ <el-input-number v-model="templateForm.pointsRequired" :min="1" :max="10000"></el-input-number>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="分类">
|
|
|
|
|
+ <el-select v-model="templateForm.category" placeholder="请选择分类">
|
|
|
|
|
+ <el-option label="玩具" value="玩具"></el-option>
|
|
|
|
|
+ <el-option label="图书" value="图书"></el-option>
|
|
|
|
|
+ <el-option label="美食" value="美食"></el-option>
|
|
|
|
|
+ <el-option label="娱乐" value="娱乐"></el-option>
|
|
|
|
|
+ <el-option label="其他" value="其他"></el-option>
|
|
|
|
|
+ </el-select>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-form>
|
|
|
|
|
+ <div slot="footer">
|
|
|
|
|
+ <el-button @click="dialogVisible = false">取消</el-button>
|
|
|
|
|
+ <el-button type="primary" @click="handleCreateTemplate" :loading="creating">确定</el-button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-dialog>
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
<script>
|
|
|
|
|
+import { getRewardsList, getRewardTemplates, createRewardTemplate, deleteRewardTemplate, approveReward } from '@/api/admin'
|
|
|
|
|
+
|
|
|
export default {
|
|
export default {
|
|
|
|
|
+ name: 'Rewards',
|
|
|
data() {
|
|
data() {
|
|
|
return {
|
|
return {
|
|
|
activeTab: 'list',
|
|
activeTab: 'list',
|
|
|
- tableData: [
|
|
|
|
|
- { id: 1, title: '看动画片30分钟', pointsRequired: 30, category: '精神类', status: 'pending' },
|
|
|
|
|
- { id: 2, title: '去游乐场', pointsRequired: 100, category: '物质类', status: 'exchanged' }
|
|
|
|
|
- ],
|
|
|
|
|
- templates: [
|
|
|
|
|
- { id: 1, title: '看动画片30分钟', pointsRequired: 30, category: '精神类' },
|
|
|
|
|
- { id: 2, title: '玩平板游戏30分钟', pointsRequired: 40, category: '特权类' }
|
|
|
|
|
- ]
|
|
|
|
|
|
|
+ loading: false,
|
|
|
|
|
+ loadingTemplates: false,
|
|
|
|
|
+ tableData: [],
|
|
|
|
|
+ templates: [],
|
|
|
|
|
+ searchForm: {
|
|
|
|
|
+ status: ''
|
|
|
|
|
+ },
|
|
|
|
|
+ pagination: {
|
|
|
|
|
+ current: 1,
|
|
|
|
|
+ size: 10,
|
|
|
|
|
+ total: 0
|
|
|
|
|
+ },
|
|
|
|
|
+ // 创建模板对话框
|
|
|
|
|
+ dialogVisible: false,
|
|
|
|
|
+ creating: false,
|
|
|
|
|
+ templateForm: {
|
|
|
|
|
+ title: '',
|
|
|
|
|
+ pointsRequired: 100,
|
|
|
|
|
+ category: ''
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
|
|
+ mounted() {
|
|
|
|
|
+ this.loadRewards()
|
|
|
|
|
+ },
|
|
|
methods: {
|
|
methods: {
|
|
|
|
|
+ async loadRewards() {
|
|
|
|
|
+ this.loading = true
|
|
|
|
|
+ try {
|
|
|
|
|
+ const params = {
|
|
|
|
|
+ page: this.pagination.current,
|
|
|
|
|
+ size: this.pagination.size,
|
|
|
|
|
+ ...this.searchForm
|
|
|
|
|
+ }
|
|
|
|
|
+ const res = await getRewardsList(params)
|
|
|
|
|
+ this.tableData = res.data.records || res.data || []
|
|
|
|
|
+ this.pagination.total = res.data.total || this.tableData.length
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ this.$message.error(error.message || '加载奖励列表失败')
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ this.loading = false
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ async loadTemplates() {
|
|
|
|
|
+ this.loadingTemplates = true
|
|
|
|
|
+ try {
|
|
|
|
|
+ const res = await getRewardTemplates()
|
|
|
|
|
+ this.templates = res.data || []
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ this.$message.error(error.message || '加载模板失败')
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ this.loadingTemplates = false
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ handleTabClick(tab) {
|
|
|
|
|
+ if (tab.name === 'templates' && this.templates.length === 0) {
|
|
|
|
|
+ this.loadTemplates()
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ handleSearch() {
|
|
|
|
|
+ this.pagination.current = 1
|
|
|
|
|
+ this.loadRewards()
|
|
|
|
|
+ },
|
|
|
|
|
+ handleReset() {
|
|
|
|
|
+ this.searchForm = {
|
|
|
|
|
+ status: ''
|
|
|
|
|
+ }
|
|
|
|
|
+ this.handleSearch()
|
|
|
|
|
+ },
|
|
|
|
|
+ handleRefresh() {
|
|
|
|
|
+ if (this.activeTab === 'list') {
|
|
|
|
|
+ this.loadRewards()
|
|
|
|
|
+ } else {
|
|
|
|
|
+ this.loadTemplates()
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ handleSizeChange(val) {
|
|
|
|
|
+ this.pagination.size = val
|
|
|
|
|
+ this.loadRewards()
|
|
|
|
|
+ },
|
|
|
|
|
+ handleCurrentChange(val) {
|
|
|
|
|
+ this.pagination.current = val
|
|
|
|
|
+ this.loadRewards()
|
|
|
|
|
+ },
|
|
|
|
|
+ async handleApprove(row, approved) {
|
|
|
|
|
+ this.$confirm(
|
|
|
|
|
+ approved ? `确定通过 "${row.title}" 的兑换申请吗?` : `确定拒绝 "${row.title}" 的兑换申请吗?`,
|
|
|
|
|
+ '提示',
|
|
|
|
|
+ {
|
|
|
|
|
+ confirmButtonText: '确定',
|
|
|
|
|
+ cancelButtonText: '取消',
|
|
|
|
|
+ type: 'warning'
|
|
|
|
|
+ }
|
|
|
|
|
+ ).then(async () => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ await approveReward(row.id, { approved })
|
|
|
|
|
+ this.$message.success(approved ? '已通过' : '已拒绝')
|
|
|
|
|
+ this.loadRewards()
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ this.$message.error(error.message || '操作失败')
|
|
|
|
|
+ }
|
|
|
|
|
+ }).catch(() => {})
|
|
|
|
|
+ },
|
|
|
getStatusType(status) {
|
|
getStatusType(status) {
|
|
|
- const types = { available: 'success', pending: 'warning', exchanged: 'info', rejected: 'danger' }
|
|
|
|
|
|
|
+ const types = {
|
|
|
|
|
+ available: 'success',
|
|
|
|
|
+ pending: 'warning',
|
|
|
|
|
+ exchanged: 'info',
|
|
|
|
|
+ rejected: 'danger'
|
|
|
|
|
+ }
|
|
|
return types[status] || 'info'
|
|
return types[status] || 'info'
|
|
|
},
|
|
},
|
|
|
getStatusText(status) {
|
|
getStatusText(status) {
|
|
|
- const texts = { available: '可用', pending: '待审批', exchanged: '已兑换', rejected: '已拒绝' }
|
|
|
|
|
|
|
+ const texts = {
|
|
|
|
|
+ available: '可用',
|
|
|
|
|
+ pending: '待审批',
|
|
|
|
|
+ exchanged: '已兑换',
|
|
|
|
|
+ rejected: '已拒绝'
|
|
|
|
|
+ }
|
|
|
return texts[status] || status
|
|
return texts[status] || status
|
|
|
},
|
|
},
|
|
|
- handleApprove(row, approved) {
|
|
|
|
|
- this.$message.success(approved ? '已通过' : '已拒绝')
|
|
|
|
|
|
|
+ showCreateTemplate() {
|
|
|
|
|
+ this.templateForm = {
|
|
|
|
|
+ title: '',
|
|
|
|
|
+ pointsRequired: 100,
|
|
|
|
|
+ category: ''
|
|
|
|
|
+ }
|
|
|
|
|
+ this.dialogVisible = true
|
|
|
|
|
+ },
|
|
|
|
|
+ async handleCreateTemplate() {
|
|
|
|
|
+ if (!this.templateForm.title) {
|
|
|
|
|
+ this.$message.warning('请输入奖励名称')
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!this.templateForm.category) {
|
|
|
|
|
+ this.$message.warning('请选择分类')
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ this.creating = true
|
|
|
|
|
+ try {
|
|
|
|
|
+ await createRewardTemplate(this.templateForm)
|
|
|
|
|
+ this.$message.success('创建成功')
|
|
|
|
|
+ this.dialogVisible = false
|
|
|
|
|
+ this.loadTemplates()
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ this.$message.error(error.message || '创建失败')
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ this.creating = false
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ handleDeleteTemplate(row) {
|
|
|
|
|
+ this.$confirm('确定要删除该模板吗?', '提示', {
|
|
|
|
|
+ confirmButtonText: '确定',
|
|
|
|
|
+ cancelButtonText: '取消',
|
|
|
|
|
+ type: 'warning'
|
|
|
|
|
+ }).then(async () => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ await deleteRewardTemplate(row.id)
|
|
|
|
|
+ this.$message.success('删除成功')
|
|
|
|
|
+ this.loadTemplates()
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ this.$message.error(error.message || '删除失败')
|
|
|
|
|
+ }
|
|
|
|
|
+ }).catch(() => {})
|
|
|
|
|
+ },
|
|
|
|
|
+ formatDate(dateStr) {
|
|
|
|
|
+ if (!dateStr) return '-'
|
|
|
|
|
+ const date = new Date(dateStr)
|
|
|
|
|
+ return date.toLocaleString('zh-CN')
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
</script>
|
|
</script>
|
|
|
|
|
+
|
|
|
|
|
+<style scoped>
|
|
|
|
|
+.page-container {
|
|
|
|
|
+ padding: 20px;
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|