188 lines
7.1 KiB
Vue
188 lines
7.1 KiB
Vue
<template>
|
||
<div class="jio-page-container">
|
||
<h2 class="jio-page-title">积分配置</h2>
|
||
<p class="jio-page-desc">
|
||
配置积分规则与发放策略。可自定义货币名称(如”金币”、”魔石”等)。用户余额与手工调整在 WordPress 原生”用户”菜单中管理。
|
||
</p>
|
||
|
||
<n-card class="jio-section-card">
|
||
<div class="jio-section-header"><h3>主开关 + 基础设置</h3></div>
|
||
<n-form :model="cfg" label-placement="left" label-width="200" class="jio-form">
|
||
<n-form-item label="启用积分系统">
|
||
<n-switch v-model:value="cfg.enabled" />
|
||
</n-form-item>
|
||
<n-form-item label="自定义货币名称">
|
||
<n-input v-model:value="cfg.currency_name" placeholder="积分" maxlength="20" />
|
||
<template #feedback>
|
||
<span class="jio-hint-text">自定义货币显示名称,如"金币"、"魔石"等。留空则使用默认名称"积分"。</span>
|
||
</template>
|
||
</n-form-item>
|
||
<n-form-item label="注册赠送积分">
|
||
<n-input-number v-model:value="cfg.register_bonus" :min="0" :max="10000" />
|
||
</n-form-item>
|
||
</n-form>
|
||
</n-card>
|
||
|
||
<n-card class="jio-section-card">
|
||
<div class="jio-section-header"><h3>每日签到</h3></div>
|
||
<n-form :model="cfg.daily_signin" label-placement="left" label-width="200" class="jio-form">
|
||
<n-form-item label="启用">
|
||
<n-switch v-model:value="cfg.daily_signin.enabled" />
|
||
</n-form-item>
|
||
<n-form-item label="基础奖励">
|
||
<n-input-number v-model:value="cfg.daily_signin.base" :min="0" :max="10000" />
|
||
</n-form-item>
|
||
<n-form-item label="连续奖励(JSON)">
|
||
<n-input
|
||
type="textarea"
|
||
v-model:value="streakJson"
|
||
placeholder='{"3":2,"7":5,"30":20}'
|
||
:autosize="{ minRows: 2 }"
|
||
/>
|
||
<template #feedback>
|
||
<span class="jio-hint-text">连续 N 天时额外发放的积分。</span>
|
||
</template>
|
||
</n-form-item>
|
||
</n-form>
|
||
</n-card>
|
||
|
||
<n-card class="jio-section-card">
|
||
<div class="jio-section-header"><h3>评论奖励</h3></div>
|
||
<n-form :model="cfg.comment_reward" label-placement="left" label-width="200" class="jio-form">
|
||
<n-form-item label="启用">
|
||
<n-switch v-model:value="cfg.comment_reward.enabled" />
|
||
</n-form-item>
|
||
<n-form-item label="单次奖励">
|
||
<n-input-number v-model:value="cfg.comment_reward.amount" :min="0" :max="10000" />
|
||
</n-form-item>
|
||
<n-form-item label="每日上限">
|
||
<n-input-number v-model:value="cfg.comment_reward.daily_cap" :min="0" :max="100" />
|
||
</n-form-item>
|
||
<n-form-item label="最少字符数">
|
||
<n-input-number v-model:value="cfg.comment_reward.min_length" :min="0" :max="500" />
|
||
</n-form-item>
|
||
<n-form-item label="审核通过后发放">
|
||
<n-switch v-model:value="cfg.comment_reward.on_approved" />
|
||
</n-form-item>
|
||
</n-form>
|
||
</n-card>
|
||
|
||
<n-card class="jio-section-card">
|
||
<div class="jio-section-header"><h3>Ref 推广奖励</h3></div>
|
||
<n-form :model="cfg.referral_reward" label-placement="left" label-width="200" class="jio-form">
|
||
<n-form-item label="启用">
|
||
<n-switch v-model:value="cfg.referral_reward.enabled" />
|
||
</n-form-item>
|
||
<n-form-item label="推广人奖励">
|
||
<n-input-number v-model:value="cfg.referral_reward.promoter_amount" :min="0" :max="10000" />
|
||
</n-form-item>
|
||
<n-form-item label="新用户奖励">
|
||
<n-input-number v-model:value="cfg.referral_reward.referred_amount" :min="0" :max="10000" />
|
||
</n-form-item>
|
||
<n-form-item label="推广等级积分">
|
||
<n-input-number v-model:value="cfg.referral_reward.level_points" :min="0" :max="10000" />
|
||
</n-form-item>
|
||
<n-form-item label="需邮箱验证后发放">
|
||
<n-switch v-model:value="cfg.referral_reward.require_verify" />
|
||
</n-form-item>
|
||
<n-form-item label="同 IP 当日上限">
|
||
<n-input-number v-model:value="cfg.referral_reward.ip_daily_cap" :min="0" :max="100" />
|
||
</n-form-item>
|
||
</n-form>
|
||
</n-card>
|
||
|
||
<n-card class="jio-section-card">
|
||
<div class="jio-section-header"><h3>下载消费(参考)</h3></div>
|
||
<n-form :model="cfg" label-placement="left" label-width="200" class="jio-form">
|
||
<n-form-item :label="`默认积分价参考(${cfg.currency_name || '积分'})`">
|
||
<n-input-number v-model:value="cfg.download_default_cost" :min="0" :max="100000" />
|
||
<template #feedback>
|
||
<span class="jio-hint-text">实际价格以文章「付费内容设置」的积分价或现金价为准;下载解锁走收银台订单,不按次扣费。</span>
|
||
</template>
|
||
</n-form-item>
|
||
</n-form>
|
||
</n-card>
|
||
|
||
<JioSaveBar :dirty="dirty" :saving="saving" @save="saveCfg" @reload="loadCfg" />
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { computed, ref, reactive, onMounted } from 'vue'
|
||
import { useMessage } from 'naive-ui'
|
||
import api from '@/api'
|
||
import JioSaveBar from '@/components/form/JioSaveBar.vue'
|
||
|
||
const message = useMessage()
|
||
|
||
function defaultCfg() {
|
||
return {
|
||
enabled: true,
|
||
currency_name: '',
|
||
register_bonus: 10,
|
||
daily_signin: { enabled: true, base: 1, streak: { 3: 2, 7: 5, 30: 20 } },
|
||
comment_reward: { enabled: true, amount: 1, daily_cap: 5, min_length: 10, on_approved: true },
|
||
referral_reward: {
|
||
enabled: true,
|
||
promoter_amount: 5,
|
||
referred_amount: 2,
|
||
level_points: 0,
|
||
require_verify: true,
|
||
ip_daily_cap: 3,
|
||
},
|
||
download_default_cost: 0,
|
||
}
|
||
}
|
||
const cfg = reactive(defaultCfg())
|
||
const streakJson = ref('{}')
|
||
const loading = ref(true)
|
||
const saving = ref(false)
|
||
const initial = ref('')
|
||
const snapshot = computed(() => JSON.stringify({ cfg, streakJson: streakJson.value }))
|
||
const dirty = computed(() => !loading.value && initial.value !== '' && snapshot.value !== initial.value)
|
||
|
||
async function loadCfg() {
|
||
loading.value = true
|
||
try {
|
||
const response = await api.getCreditSettings()
|
||
const data = response?.data || response || {}
|
||
Object.assign(cfg, defaultCfg(), data)
|
||
streakJson.value = JSON.stringify(cfg.daily_signin?.streak || {}, null, 0)
|
||
initial.value = snapshot.value
|
||
} catch (e) {
|
||
message.error(e.message || '加载失败')
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
async function saveCfg() {
|
||
let streak
|
||
try {
|
||
streak = JSON.parse(streakJson.value || '{}')
|
||
} catch (error) {
|
||
message.error('连续奖励 JSON 格式错误')
|
||
return
|
||
}
|
||
if (!streak || typeof streak !== 'object' || Array.isArray(streak)) {
|
||
message.error('连续奖励必须是 JSON 对象')
|
||
return
|
||
}
|
||
saving.value = true
|
||
try {
|
||
await api.saveCreditSettings({ ...cfg, daily_signin: { ...cfg.daily_signin, streak } })
|
||
cfg.daily_signin.streak = streak
|
||
initial.value = snapshot.value
|
||
message.success('已保存')
|
||
} catch (e) {
|
||
message.error(e.message || '保存失败')
|
||
} finally {
|
||
saving.value = false
|
||
}
|
||
}
|
||
|
||
onMounted(() => {
|
||
loadCfg()
|
||
})
|
||
</script>
|