| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250 |
- <template>
- <div class="promotion-management admin-page">
- <el-card>
- <el-tabs v-model="activeTab" @tab-click="handleTabChange">
- <el-tab-pane label="邀请里程碑" name="milestone">
- <div style="margin-bottom: 16px">
- <el-input v-model="milestoneKeyword" placeholder="搜索里程碑..." prefix-icon="el-icon-search" style="width:200px" clearable @keyup.enter.native="handleMilestoneSearch" @clear="handleMilestoneSearch" />
- </div>
- <el-table :data="filteredMilestones" v-loading="milestoneLoading" border stripe :max-height="tableHeight">
- <el-table-column prop="milestone" label="里程碑" min-width="180" show-overflow-tooltip />
- <el-table-column prop="rewardPoints" label="奖励积分" width="120" />
- <el-table-column prop="rewardEnergy" label="奖励能量" width="120" />
- <el-table-column label="操作" width="140" fixed="right">
- <template slot-scope="{ row }">
- <el-button size="mini" @click="handleEditMilestone(row)" :disabled="row.claimed">
- {{ row.claimed ? '已达成' : '编辑' }}
- </el-button>
- </template>
- </el-table-column>
- </el-table>
- </el-tab-pane>
- <el-tab-pane label="排行榜" name="leaderboard">
- <div style="margin-bottom: 16px; display: flex; gap: 16px; align-items: center; flex-wrap: wrap">
- <el-date-picker
- v-model="weekStart"
- type="date"
- placeholder="选择周起始日"
- value-format="yyyy-MM-dd"
- @change="handleWeekChange"
- style="width: 180px"
- />
- <el-input
- v-model="searchKeyword"
- placeholder="搜索用户昵称"
- style="width: 200px"
- clearable
- @keyup.enter.native="handleSearch"
- />
- <el-button type="primary" @click="handleSearch">搜索</el-button>
- <el-button @click="resetLeaderboard">重置</el-button>
- </div>
- <el-table :data="leaderboardList" v-loading="leaderboardLoading" border stripe :max-height="tableHeight">
- <el-table-column label="排名" width="80" type="index" :index="leaderboardIndex" />
- <el-table-column label="头像" width="80">
- <template slot-scope="{ row }">
- <el-avatar :src="row.avatar" size="small" />
- </template>
- </el-table-column>
- <el-table-column prop="nickname" label="昵称" min-width="140" show-overflow-tooltip />
- <el-table-column prop="referralCount" label="邀请数" width="100" />
- </el-table>
- <el-pagination
- v-if="leaderboardTotal > leaderboardSize"
- @current-change="onLeaderboardPageChange"
- :current-page="leaderboardPage"
- :page-size="leaderboardSize"
- :total="leaderboardTotal"
- layout="total, prev, pager, next"
- style="margin-top: 20px; text-align: right"
- />
- </el-tab-pane>
- </el-tabs>
- </el-card>
- <el-dialog title="编辑里程碑" :visible.sync="milestoneDialogVisible" width="450px">
- <el-form :model="milestoneForm" label-width="120px">
- <el-form-item label="里程碑" required>
- <el-input v-model="milestoneForm.milestone" disabled />
- </el-form-item>
- <el-form-item label="奖励积分" required>
- <el-input-number v-model="milestoneForm.rewardPoints" :min="0" style="width: 200px" />
- </el-form-item>
- <el-form-item label="奖励能量" required>
- <el-input-number v-model="milestoneForm.rewardEnergy" :min="0" style="width: 200px" />
- </el-form-item>
- </el-form>
- <div slot="footer">
- <el-button @click="milestoneDialogVisible = false">取消</el-button>
- <el-button type="primary" @click="handleMilestoneSubmit" :loading="milestoneSubmitting">保存</el-button>
- </div>
- </el-dialog>
- </div>
- </template>
- <script>
- import { getMilestoneConfig, updateMilestoneConfig, getLeaderboardTop, getLeaderboardByUser } from '@/api/promotion'
- export default {
- name: 'PromotionManagement',
- data() {
- return {
- activeTab: 'milestone',
- milestoneList: [],
- milestoneKeyword: '',
- milestoneLoading: false,
- milestoneDialogVisible: false,
- milestoneSubmitting: false,
- milestoneForm: {
- milestone: '',
- rewardPoints: 0,
- rewardEnergy: 0
- },
- leaderboardList: [],
- leaderboardLoading: false,
- weekStart: this.getCurrentWeekStart(),
- searchKeyword: '',
- leaderboardPage: 1,
- leaderboardSize: 20,
- leaderboardTotal: 0,
- searchMode: false
- }
- },
- created() {
- this.loadMilestones()
- },
- computed: {
- tableHeight() {
- return window.innerHeight - 300
- },
- filteredMilestones() {
- if (!this.milestoneKeyword) return this.milestoneList
- var kw = this.milestoneKeyword.toLowerCase()
- return this.milestoneList.filter(function(item) {
- return item.milestone && item.milestone.toLowerCase().indexOf(kw) !== -1
- })
- }
- },
- methods: {
- getCurrentWeekStart() {
- const now = new Date()
- const day = now.getDay()
- const diff = now.getDate() - day + (day === 0 ? -6 : 1)
- const monday = new Date(now.setDate(diff))
- return monday.toISOString().split('T')[0]
- },
- leaderboardIndex(index) {
- return (this.leaderboardPage - 1) * this.leaderboardSize + index + 1
- },
- handleMilestoneSearch() {},
- handleTabChange() {
- if (this.activeTab === 'leaderboard') {
- this.loadLeaderboard()
- } else {
- this.loadMilestones()
- }
- },
- async loadMilestones() {
- this.milestoneLoading = true
- try {
- const res = await getMilestoneConfig()
- if (res.data) {
- this.milestoneList = res.data.records || res.data.list || res.data
- }
- } catch (e) {
- console.error(e)
- this.$message.error('加载里程碑配置失败')
- } finally {
- this.milestoneLoading = false
- }
- },
- handleEditMilestone(row) {
- if (row.claimed) return
- this.milestoneForm = {
- milestone: row.milestone,
- rewardPoints: row.rewardPoints,
- rewardEnergy: row.rewardEnergy
- }
- this.milestoneDialogVisible = true
- },
- async handleMilestoneSubmit() {
- this.milestoneSubmitting = true
- try {
- await updateMilestoneConfig({
- milestone: this.milestoneForm.milestone,
- rewardPoints: this.milestoneForm.rewardPoints,
- rewardEnergy: this.milestoneForm.rewardEnergy
- })
- this.$message.success('保存成功')
- this.milestoneDialogVisible = false
- this.loadMilestones()
- } catch (e) {
- this.$message.error('保存失败')
- } finally {
- this.milestoneSubmitting = false
- }
- },
- async loadLeaderboard() {
- this.leaderboardLoading = true
- this.searchMode = false
- try {
- const params = { page: this.leaderboardPage, size: this.leaderboardSize }
- if (this.weekStart) {
- params.weekStart = this.weekStart
- }
- const res = await getLeaderboardTop(params)
- if (res.data) {
- this.leaderboardList = res.data.records || res.data.list || res.data
- this.leaderboardTotal = res.data.total || this.leaderboardList.length
- }
- } catch (e) {
- console.error(e)
- this.$message.error('加载排行榜失败')
- } finally {
- this.leaderboardLoading = false
- }
- },
- handleWeekChange() {
- if (this.activeTab === 'leaderboard') {
- this.leaderboardPage = 1
- this.loadLeaderboard()
- }
- },
- async handleSearch() {
- if (!this.searchKeyword.trim()) {
- this.resetLeaderboard()
- return
- }
- this.leaderboardLoading = true
- this.searchMode = true
- try {
- const res = await getLeaderboardByUser({ keyword: this.searchKeyword.trim() })
- if (res.data) {
- this.leaderboardList = res.data.records || res.data.list || res.data
- this.leaderboardTotal = this.leaderboardList.length
- }
- } catch (e) {
- console.error(e)
- this.$message.error('搜索失败')
- } finally {
- this.leaderboardLoading = false
- }
- },
- resetLeaderboard() {
- this.searchKeyword = ''
- this.leaderboardPage = 1
- this.loadLeaderboard()
- },
- onLeaderboardPageChange(p) {
- this.leaderboardPage = p
- this.loadLeaderboard()
- }
- }
- }
- </script>
- <style scoped>
- .promotion-management {
- padding: 20px;
- }
- </style>
|