| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- <template>
- <div class="energy-behavior-config admin-page">
- <div class="header">
- <h2>能量行为配置</h2>
- <div class="filters">
- <el-input v-model="keyword" placeholder="搜索行为名称/编码..." prefix-icon="el-icon-search" style="width:260px" clearable @keyup.enter.native="loadList" @clear="loadList" />
- <el-select v-model="enabledFilter" placeholder="状态筛选" @change="loadList" style="width: 140px;" clearable>
- <el-option label="全部" value="" />
- <el-option label="已启用" value="1" />
- <el-option label="已禁用" value="0" />
- </el-select>
- </div>
- </div>
- <el-table :data="list" v-loading="loading" border stripe highlight-current-row>
- <el-table-column prop="behaviorCode" label="行为编码" width="160" />
- <el-table-column prop="behaviorName" label="行为名称" width="130" />
- <el-table-column prop="description" label="描述" min-width="160" show-overflow-tooltip />
- <el-table-column label="默认值" width="80">
- <template slot-scope="{ row }">
- <el-tag size="mini" type="info">{{ row.defaultAmount }}</el-tag>
- </template>
- </el-table-column>
- <el-table-column prop="amountSource" label="值来源" width="120">
- <template slot-scope="{ row }">
- <el-tag size="mini" :type="sourceTypeTag(row.amountSource)">{{ sourceTypeLabel(row.amountSource) }}</el-tag>
- </template>
- </el-table-column>
- <el-table-column label="维度分配" min-width="200">
- <template slot-scope="{ row }">
- <span v-if="!row.dimensionAssign" style="color:#999">未配置</span>
- <el-tag v-for="d in parseDimAssign(row.dimensionAssign)" :key="d.dim" size="mini" :style="{ background: dimColor(d.dim), color: '#fff', marginRight: '4px' }">
- {{ dimLabel(d.dim) }} {{ d.ratio }}%
- </el-tag>
- </template>
- </el-table-column>
- <el-table-column label="每日上限" width="80">
- <template slot-scope="{ row }">
- <span>{{ row.dailyLimit || '不限' }}</span>
- </template>
- </el-table-column>
- <el-table-column label="过期天数" width="80">
- <template slot-scope="{ row }">
- <span>{{ row.expireDays || '永久' }}</span>
- </template>
- </el-table-column>
- <el-table-column label="状态" width="80">
- <template slot-scope="{ row }">
- <el-switch :value="row.enabled === 1" @change="toggleStatus(row)" />
- </template>
- </el-table-column>
- <el-table-column label="操作" width="120" fixed="right">
- <template slot-scope="{ row }">
- <el-button size="mini" type="primary" @click="showEdit(row)">编辑</el-button>
- </template>
- </el-table-column>
- </el-table>
- <el-dialog title="编辑能量行为配置" :visible.sync="dialogVisible" width="700px" :close-on-click-modal="false">
- <el-form :model="form" label-width="110px" size="small">
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="行为编码">
- <el-input v-model="form.behaviorCode" disabled />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="行为名称">
- <el-input v-model="form.behaviorName" disabled />
- </el-form-item>
- </el-col>
- </el-row>
- <el-form-item label="描述">
- <el-input v-model="form.description" disabled />
- </el-form-item>
- <el-row :gutter="20">
- <el-col :span="8">
- <el-form-item label="默认能量值">
- <el-input-number v-model="form.defaultAmount" :min="0" :max="9999" />
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="值来源">
- <el-select v-model="form.amountSource" style="width:100%">
- <el-option label="固定值" value="fixed" />
- <el-option label="跟随积分" value="points" />
- <el-option label="跟随金额" value="order_amount" />
- <el-option label="从配置表读取" value="config" />
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="过期天数">
- <el-input-number v-model="form.expireDays" :min="0" :max="3650" />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="每日上限">
- <el-input-number v-model="form.dailyLimit" :min="0" :max="9999" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="冷却时间(秒)">
- <el-input-number v-model="form.cooldownSeconds" :min="0" :max="86400" />
- </el-form-item>
- </el-col>
- </el-row>
- <el-form-item label="维度分配">
- <div v-for="(d, i) in dimAssignList" :key="i" style="display:flex;align-items:center;margin-bottom:8px;gap:8px">
- <el-select v-model="d.dim" style="width:120px" @change="normalizeDimRatio">
- <el-option v-for="dim in dimensions" :key="dim.code" :label="dim.name" :value="dim.code" />
- </el-select>
- <el-slider v-model="d.ratio" :min="0" :max="100" style="flex:1" />
- <span style="width:40px;text-align:right">{{ d.ratio }}%</span>
- <el-button type="danger" size="mini" icon="el-icon-delete" circle @click="removeDim(i)" v-if="dimAssignList.length > 1" />
- </div>
- <el-button size="mini" @click="addDim" v-if="dimAssignList.length < 5">+ 添加维度</el-button>
- </el-form-item>
- </el-form>
- <span slot="footer">
- <el-button @click="dialogVisible = false">取消</el-button>
- <el-button type="primary" @click="saveConfig">保存</el-button>
- </span>
- </el-dialog>
- </div>
- </template>
- <script>
- import { getEnergyBehaviorList, updateEnergyBehavior, toggleEnergyBehavior } from '@/api/energy'
- const DIMENSION_MAP = {
- body: { name: '身', color: '#FF8C42' },
- mind: { name: '心', color: '#FF6B9D' },
- wisdom: { name: '智', color: '#6366F1' },
- action: { name: '行', color: '#10B981' },
- wealth: { name: '富', color: '#F59E0B' }
- }
- export default {
- name: 'EnergyBehaviorConfig',
- data() {
- return {
- keyword: '',
- enabledFilter: '',
- loading: false,
- list: [],
- dialogVisible: false,
- form: {},
- dimAssignList: [],
- dimensions: Object.entries(DIMENSION_MAP).map(([code, v]) => ({ code, name: v.name }))
- }
- },
- mounted() {
- this.loadList()
- },
- methods: {
- async loadList() {
- this.loading = true
- try {
- const res = await getEnergyBehaviorList()
- if (res.code === 200) {
- this.list = (res.data || []).filter(r => {
- if (this.keyword) {
- const kw = this.keyword.toLowerCase()
- if (!r.behaviorCode.toLowerCase().includes(kw) && !r.behaviorName.toLowerCase().includes(kw)) return false
- }
- if (this.enabledFilter !== '') {
- if (r.enabled !== parseInt(this.enabledFilter)) return false
- }
- return true
- })
- }
- } finally {
- this.loading = false
- }
- },
- showEdit(row) {
- this.form = { ...row }
- this.dimAssignList = this.parseDimAssign(row.dimensionAssign)
- if (this.dimAssignList.length === 0) {
- this.dimAssignList = [{ dim: 'action', ratio: 100 }]
- }
- this.dialogVisible = true
- },
- parseDimAssign(json) {
- if (!json) return []
- try { return JSON.parse(json) } catch { return [] }
- },
- async saveConfig() {
- const dimensionAssign = JSON.stringify(this.dimAssignList.filter(d => d.ratio > 0))
- const payload = { ...this.form, dimensionAssign }
- const res = await updateEnergyBehavior(payload)
- if (res.code === 200) {
- this.$message.success('保存成功')
- this.dialogVisible = false
- this.loadList()
- } else {
- this.$message.error(res.message || '保存失败')
- }
- },
- async toggleStatus(row) {
- const res = await toggleEnergyBehavior(row.id)
- if (res.code === 200) {
- this.$message.success(res.message)
- this.loadList()
- }
- },
- addDim() {
- const used = this.dimAssignList.map(d => d.dim)
- const next = this.dimensions.find(d => !used.includes(d.code))
- if (next) this.dimAssignList.push({ dim: next.code, ratio: 0 })
- },
- removeDim(i) {
- this.dimAssignList.splice(i, 1)
- this.normalizeDimRatio()
- },
- normalizeDimRatio() {
- // 自动调整,确保总和为100
- },
- sourceTypeLabel(v) {
- return { fixed: '固定值', points: '跟随积分', order_amount: '跟随金额', config: '配置表读取' }[v] || v
- },
- sourceTypeTag(v) {
- return { fixed: '', points: 'warning', order_amount: 'danger', config: 'info' }[v] || ''
- },
- dimLabel(code) { return (DIMENSION_MAP[code] || {}).name || code },
- dimColor(code) { return (DIMENSION_MAP[code] || {}).color || '#999' }
- }
- }
- </script>
- <style scoped>
- .header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; }
- .filters { display: flex; gap: 10px; align-items: center; }
- </style>
|