fix: 引导任务修改bug
This commit is contained in:
parent
dd838fccc4
commit
6866618ff6
@ -78,6 +78,7 @@ message OnboardingStage {
|
|||||||
string status = 6; // pending/completed/in_progress
|
string status = 6; // pending/completed/in_progress
|
||||||
bool is_current = 7;
|
bool is_current = 7;
|
||||||
bool all_tasks_completed = 8; // 该阶段所有任务是否完成
|
bool all_tasks_completed = 8; // 该阶段所有任务是否完成
|
||||||
|
bool is_reward_claimed = 9; // 该阶段奖励是否已领取
|
||||||
}
|
}
|
||||||
|
|
||||||
message CompleteGuideRequest {
|
message CompleteGuideRequest {
|
||||||
|
|||||||
@ -57,6 +57,7 @@ type UserOnboardingStatus struct {
|
|||||||
HasFriendDisplayBonus bool `gorm:"column:has_friend_display_bonus;default:false"`
|
HasFriendDisplayBonus bool `gorm:"column:has_friend_display_bonus;default:false"`
|
||||||
OnboardingCompletedAt *int64 `gorm:"column:onboarding_completed_at"`
|
OnboardingCompletedAt *int64 `gorm:"column:onboarding_completed_at"`
|
||||||
OnboardingClaimedAt *int64 `gorm:"column:onboarding_claimed_at"`
|
OnboardingClaimedAt *int64 `gorm:"column:onboarding_claimed_at"`
|
||||||
|
ClaimedStages []int64 `gorm:"column:claimed_stages;type:text;serializer:json"` // 已领取奖励的阶段列表
|
||||||
CreatedAt int64 `gorm:"column:created_at"`
|
CreatedAt int64 `gorm:"column:created_at"`
|
||||||
UpdatedAt int64 `gorm:"column:updated_at"`
|
UpdatedAt int64 `gorm:"column:updated_at"`
|
||||||
CurrentStage int64 `gorm:"column:current_stage;default:0"`
|
CurrentStage int64 `gorm:"column:current_stage;default:0"`
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/topfans/backend/services/taskService/model"
|
"github.com/topfans/backend/services/taskService/model"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
"gorm.io/gorm/clause"
|
||||||
)
|
)
|
||||||
|
|
||||||
type OnboardingRepository interface {
|
type OnboardingRepository interface {
|
||||||
@ -186,42 +187,22 @@ func (r *onboardingRepository) SaveStageConfigs(configs []*model.OnboardingStage
|
|||||||
zap.Int64("exp_reward", cfg.ExpReward))
|
zap.Int64("exp_reward", cfg.ExpReward))
|
||||||
|
|
||||||
cfg.UpdatedAt = now
|
cfg.UpdatedAt = now
|
||||||
|
// Use upsert via ON CONFLICT to properly handle JSON serialization
|
||||||
// First try to update existing record
|
upsert := clause.OnConflict{
|
||||||
// Use Select to specify fields so GORM properly handles JSON serialization
|
Columns: []clause.Column{{Name: "stage"}},
|
||||||
result := r.db.Model(&model.OnboardingStageConfig{}).
|
DoUpdates: clause.AssignmentColumns([]string{
|
||||||
Where("stage = ?", cfg.Stage).
|
"name", "required_task_keys", "crystal_reward", "exp_reward", "is_active", "updated_at",
|
||||||
Select("name", "required_task_keys", "crystal_reward", "exp_reward", "is_active", "updated_at").
|
}),
|
||||||
Updates(cfg)
|
|
||||||
|
|
||||||
if result.Error != nil {
|
|
||||||
logger.Logger.Error("SaveStageConfigs: failed to update config",
|
|
||||||
zap.Int("stage", cfg.Stage),
|
|
||||||
zap.Error(result.Error))
|
|
||||||
return result.Error
|
|
||||||
}
|
}
|
||||||
|
if err := r.db.Clauses(upsert).Create(cfg).Error; err != nil {
|
||||||
logger.Logger.Info("SaveStageConfigs: update result",
|
logger.Logger.Error("SaveStageConfigs: failed to upsert config",
|
||||||
zap.Int("stage", cfg.Stage),
|
|
||||||
zap.Int64("rows_affected", result.RowsAffected))
|
|
||||||
|
|
||||||
// If no rows affected, create new record
|
|
||||||
if result.RowsAffected == 0 {
|
|
||||||
cfg.CreatedAt = now
|
|
||||||
if err := r.db.Create(cfg).Error; err != nil {
|
|
||||||
logger.Logger.Error("SaveStageConfigs: failed to create config",
|
|
||||||
zap.Int("stage", cfg.Stage),
|
zap.Int("stage", cfg.Stage),
|
||||||
zap.Error(err))
|
zap.Error(err))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
logger.Logger.Info("SaveStageConfigs: created config",
|
logger.Logger.Info("SaveStageConfigs: upserted config",
|
||||||
zap.Int("stage", cfg.Stage),
|
zap.Int("stage", cfg.Stage),
|
||||||
zap.String("name", cfg.Name))
|
zap.String("name", cfg.Name))
|
||||||
} else {
|
|
||||||
logger.Logger.Info("SaveStageConfigs: updated config",
|
|
||||||
zap.Int("stage", cfg.Stage),
|
|
||||||
zap.String("name", cfg.Name))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Logger.Info("SaveStageConfigs: all configs saved successfully")
|
logger.Logger.Info("SaveStageConfigs: all configs saved successfully")
|
||||||
|
|||||||
@ -51,6 +51,8 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { computed, watch, onMounted, onUnmounted } from 'vue'
|
import { computed, watch, onMounted, onUnmounted } from 'vue'
|
||||||
import { useStore } from 'vuex'
|
import { useStore } from 'vuex'
|
||||||
|
import { completeGuide, advanceStage, getOnboardingStatus } from '@/utils/task-api.js'
|
||||||
|
import { onboardingStages } from '@/utils/guideConfig.js'
|
||||||
|
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
|
|
||||||
@ -66,10 +68,37 @@ const stepConfig = computed(() => store.getters['guide/currentStepConfig'])
|
|||||||
const isFirst = computed(() => store.getters['guide/isFirst'])
|
const isFirst = computed(() => store.getters['guide/isFirst'])
|
||||||
const isLast = computed(() => store.getters['guide/isLast'])
|
const isLast = computed(() => store.getters['guide/isLast'])
|
||||||
|
|
||||||
// 监听引导激活状态
|
// 监听引导激活状态(当 isActive 变为 false 时触发同步)
|
||||||
watch(() => store.state.guide.isActive, (newVal) => {
|
watch(() => isActive.value, async (newVal, oldVal) => {
|
||||||
console.log('[GuideOverlay] isActive changed to:', newVal)
|
console.log('[GuideOverlay] isActive watch:', oldVal, '->', newVal)
|
||||||
}, { immediate: true })
|
if (oldVal === true && newVal === false) {
|
||||||
|
const guideKey = store.state.guide.completedGuideKey
|
||||||
|
if (guideKey) {
|
||||||
|
try {
|
||||||
|
await completeGuide(guideKey, onboardingStages)
|
||||||
|
console.log('[GuideOverlay] guide synced to backend:', guideKey)
|
||||||
|
|
||||||
|
// 检查当前阶段是否所有任务都已完成,如果完成则推进到下一阶段
|
||||||
|
const statusRes = await getOnboardingStatus()
|
||||||
|
const stages = statusRes.data?.stages || []
|
||||||
|
const currentStageData = stages.find(s => s.is_current)
|
||||||
|
if (currentStageData && currentStageData.all_tasks_completed) {
|
||||||
|
const nextStage = (currentStageData.stage || 0) + 1
|
||||||
|
const maxStage = onboardingStages.length - 1
|
||||||
|
if (nextStage <= maxStage) {
|
||||||
|
await advanceStage(nextStage)
|
||||||
|
console.log('[GuideOverlay] advanced to stage:', nextStage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('[GuideOverlay] failed to sync guide to backend:', err)
|
||||||
|
} finally {
|
||||||
|
// 清除completedGuideKey,避免重复触发
|
||||||
|
store.state.guide.completedGuideKey = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// 组件挂载时记录当前状态
|
// 组件挂载时记录当前状态
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
|||||||
@ -118,6 +118,8 @@ import {
|
|||||||
resetGuide,
|
resetGuide,
|
||||||
claimGuideReward,
|
claimGuideReward,
|
||||||
markGuideDone,
|
markGuideDone,
|
||||||
|
isGuideDone,
|
||||||
|
markGuideRewardClaimed,
|
||||||
onboardingStages
|
onboardingStages
|
||||||
} from '@/utils/guideConfig.js'
|
} from '@/utils/guideConfig.js'
|
||||||
|
|
||||||
@ -132,6 +134,7 @@ const emit = defineEmits(['close', 'updated'])
|
|||||||
|
|
||||||
const loading = ref(true)
|
const loading = ref(true)
|
||||||
const guideList = ref([])
|
const guideList = ref([])
|
||||||
|
const backendStages = ref([])
|
||||||
|
|
||||||
// 统计数据
|
// 统计数据
|
||||||
const totalCount = computed(() => guideList.value.length)
|
const totalCount = computed(() => guideList.value.length)
|
||||||
@ -261,6 +264,25 @@ function refreshList() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function calculateStatus(key, done, claimed) {
|
function calculateStatus(key, done, claimed) {
|
||||||
|
// 优先使用后端状态判断
|
||||||
|
const backendStage = backendStages.value.find(s =>
|
||||||
|
s.required_task_keys && s.required_task_keys.includes(key)
|
||||||
|
)
|
||||||
|
if (backendStage) {
|
||||||
|
// 后端状态为 in_progress 表示已领取
|
||||||
|
if (backendStage.status === 'in_progress') {
|
||||||
|
return 'reward_claimed'
|
||||||
|
}
|
||||||
|
// 后端状态为 completed 表示任务完成但未领取(可领取按钮)
|
||||||
|
if (backendStage.status === 'completed' || backendStage.all_tasks_completed) {
|
||||||
|
return 'completed'
|
||||||
|
}
|
||||||
|
// 后端状态为 locked 表示未开始
|
||||||
|
if (backendStage.status === 'locked') {
|
||||||
|
return 'not_started'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 回退到本地存储判断
|
||||||
if (claimed) return 'reward_claimed'
|
if (claimed) return 'reward_claimed'
|
||||||
if (done && !claimed) return 'completed'
|
if (done && !claimed) return 'completed'
|
||||||
if (hasGuideProgress(key)) return 'in_progress'
|
if (hasGuideProgress(key)) return 'in_progress'
|
||||||
@ -400,18 +422,29 @@ async function initBackend() {
|
|||||||
const res = await getOnboardingStatus()
|
const res = await getOnboardingStatus()
|
||||||
const data = res.data || {}
|
const data = res.data || {}
|
||||||
|
|
||||||
if (!data.stages || data.stages.length === 0) {
|
// 保存后端stages数据
|
||||||
await completeGuide('init', onboardingStages)
|
backendStages.value = data.stages || []
|
||||||
} else {
|
|
||||||
|
// 从后端同步已完成状态到本地
|
||||||
|
if (data.stages && data.stages.length > 0) {
|
||||||
for (const stage of data.stages) {
|
for (const stage of data.stages) {
|
||||||
if (stage.allTasksCompleted && stage.required_task_keys) {
|
// all_tasks_completed 是后端返回的字段名(下划线格式)
|
||||||
|
// 同时检查 status === 'completed' 作为备用判断
|
||||||
|
if ((stage.all_tasks_completed || stage.status === 'completed') && stage.required_task_keys) {
|
||||||
for (const taskKey of stage.required_task_keys) {
|
for (const taskKey of stage.required_task_keys) {
|
||||||
if (!markGuideDone(taskKey)) {
|
// 无论本地是否已标记,都同步后端状态
|
||||||
|
if (!isGuideDone(taskKey)) {
|
||||||
console.log('[GuideModal] 从后端同步任务完成状态:', taskKey)
|
console.log('[GuideModal] 从后端同步任务完成状态:', taskKey)
|
||||||
markGuideDone(taskKey)
|
markGuideDone(taskKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// status === 'in_progress' 表示已领取奖励
|
||||||
|
if (stage.status === 'in_progress' && stage.required_task_keys) {
|
||||||
|
for (const taskKey of stage.required_task_keys) {
|
||||||
|
markGuideRewardClaimed(taskKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -712,6 +745,9 @@ const handleClose = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.disabled-btn {
|
.disabled-btn {
|
||||||
|
min-width: 120rpx;
|
||||||
|
width: 120rpx;
|
||||||
|
height: 50rpx;
|
||||||
background: rgba(150, 150, 150, 0.5);
|
background: rgba(150, 150, 150, 0.5);
|
||||||
border: 2rpx solid rgba(150, 150, 150, 0.6);
|
border: 2rpx solid rgba(150, 150, 150, 0.6);
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
|
|||||||
@ -29,6 +29,8 @@ const state = {
|
|||||||
pendingAction: null,
|
pendingAction: null,
|
||||||
// 是否处于组件打开模式(遮罩隐藏)
|
// 是否处于组件打开模式(遮罩隐藏)
|
||||||
componentMode: false,
|
componentMode: false,
|
||||||
|
// 刚刚完成的引导 key(用于 GuideOverlay 触发后端同步)
|
||||||
|
completedGuideKey: null,
|
||||||
}
|
}
|
||||||
|
|
||||||
const mutations = {
|
const mutations = {
|
||||||
@ -78,6 +80,8 @@ const mutations = {
|
|||||||
const key = state.currentGuide.key
|
const key = state.currentGuide.key
|
||||||
markGuideAsShown(key)
|
markGuideAsShown(key)
|
||||||
markGuideDone(key) // 标记为已完成
|
markGuideDone(key) // 标记为已完成
|
||||||
|
// 保存刚完成的引导 key(用于 GuideOverlay 触发后端同步)
|
||||||
|
state.completedGuideKey = key
|
||||||
// 重置步骤进度
|
// 重置步骤进度
|
||||||
setGuideCurrentStep(key, 0)
|
setGuideCurrentStep(key, 0)
|
||||||
// 清除子步骤完成记录
|
// 清除子步骤完成记录
|
||||||
@ -85,8 +89,9 @@ const mutations = {
|
|||||||
}
|
}
|
||||||
state.currentGuide = null
|
state.currentGuide = null
|
||||||
state.currentStep = 0
|
state.currentStep = 0
|
||||||
state.isActive = false
|
|
||||||
state.isNavigating = false
|
state.isNavigating = false
|
||||||
|
// isActive 设为 false 放最后,让 GuideOverlay 的 watch 能读取 completedGuideKey
|
||||||
|
state.isActive = false
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -70,24 +70,45 @@
|
|||||||
export const onboardingStages = [
|
export const onboardingStages = [
|
||||||
{
|
{
|
||||||
stage: 0,
|
stage: 0,
|
||||||
name: '初识平台',
|
name: '广场首页',
|
||||||
required_task_keys: ['square_home', 'browse_exhibition'],
|
required_task_keys: ['square_home'],
|
||||||
crystal_reward: 100,
|
crystal_reward: 100,
|
||||||
exp_reward: 50
|
exp_reward: 50
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
stage: 1,
|
stage: 1,
|
||||||
name: '互动入门',
|
name: '浏览展厅',
|
||||||
required_task_keys: ['follow_star', 'send_gift'],
|
required_task_keys: ['browse_exhibition'],
|
||||||
crystal_reward: 200,
|
crystal_reward: 100,
|
||||||
exp_reward: 100
|
exp_reward: 50
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
stage: 2,
|
stage: 2,
|
||||||
name: '社交达人',
|
name: '关注明星',
|
||||||
required_task_keys: ['add_friend', 'share_content'],
|
required_task_keys: ['follow_star'],
|
||||||
crystal_reward: 300,
|
crystal_reward: 100,
|
||||||
exp_reward: 150
|
exp_reward: 50
|
||||||
|
},
|
||||||
|
{
|
||||||
|
stage: 3,
|
||||||
|
name: '发送礼物',
|
||||||
|
required_task_keys: ['send_gift'],
|
||||||
|
crystal_reward: 100,
|
||||||
|
exp_reward: 50
|
||||||
|
},
|
||||||
|
{
|
||||||
|
stage: 4,
|
||||||
|
name: '添加好友',
|
||||||
|
required_task_keys: ['add_friend'],
|
||||||
|
crystal_reward: 100,
|
||||||
|
exp_reward: 50
|
||||||
|
},
|
||||||
|
{
|
||||||
|
stage: 5,
|
||||||
|
name: '分享内容',
|
||||||
|
required_task_keys: ['share_content'],
|
||||||
|
crystal_reward: 100,
|
||||||
|
exp_reward: 50
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -287,6 +308,146 @@ export const guideConfig = {
|
|||||||
buttons: ['next']
|
buttons: ['next']
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// 浏览展厅引导
|
||||||
|
browse_exhibition: {
|
||||||
|
key: 'browse_exhibition',
|
||||||
|
name: '浏览展厅',
|
||||||
|
desc: '了解展馆功能和展品',
|
||||||
|
reward: { exp: 10, diamond: 5 },
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
page: '/pages/exhibition/exhibition',
|
||||||
|
mask: true,
|
||||||
|
target: '.exhibition-header',
|
||||||
|
content: '这里是展馆顶部区域,可以查看展馆信息',
|
||||||
|
center: true,
|
||||||
|
customPosition: { x: 0, y: 0 },
|
||||||
|
buttons: ['next']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
page: '/pages/exhibition/exhibition',
|
||||||
|
mask: true,
|
||||||
|
target: '.nft-cards-container',
|
||||||
|
content: '这里展示了你铸造的所有展品',
|
||||||
|
center: true,
|
||||||
|
customPosition: { x: 0, y: 0 },
|
||||||
|
buttons: ['next']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// 关注明星引导
|
||||||
|
follow_star: {
|
||||||
|
key: 'follow_star',
|
||||||
|
name: '关注明星',
|
||||||
|
desc: '关注喜欢的明星获取动态',
|
||||||
|
reward: { exp: 10, diamond: 5 },
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
page: '/pages/square/square',
|
||||||
|
mask: true,
|
||||||
|
target: '.star-list',
|
||||||
|
content: '这里可以浏览和关注你喜欢的明星',
|
||||||
|
center: true,
|
||||||
|
customPosition: { x: 0, y: 0 },
|
||||||
|
buttons: ['next']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
page: '/pages/square/square',
|
||||||
|
mask: true,
|
||||||
|
target: '.follow-btn',
|
||||||
|
content: '点击按钮关注明星,关注后能收到他们的最新动态',
|
||||||
|
center: true,
|
||||||
|
customPosition: { x: 0, y: 0 },
|
||||||
|
buttons: ['next']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// 发送礼物引导
|
||||||
|
send_gift: {
|
||||||
|
key: 'send_gift',
|
||||||
|
name: '发送礼物',
|
||||||
|
desc: '为喜欢的明星送礼物支持',
|
||||||
|
reward: { exp: 10, diamond: 5 },
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
page: '/pages/square/square',
|
||||||
|
mask: true,
|
||||||
|
target: '.gift-btn',
|
||||||
|
content: '点击这里可以为明星送上礼物',
|
||||||
|
center: true,
|
||||||
|
customPosition: { x: 0, y: 0 },
|
||||||
|
buttons: ['next']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
page: '/pages/square/square',
|
||||||
|
mask: true,
|
||||||
|
target: '.gift-item',
|
||||||
|
content: '选择喜欢的礼物并发送,让明星感受到你的支持',
|
||||||
|
center: true,
|
||||||
|
customPosition: { x: 0, y: 0 },
|
||||||
|
buttons: ['next']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// 添加好友引导
|
||||||
|
add_friend: {
|
||||||
|
key: 'add_friend',
|
||||||
|
name: '添加好友',
|
||||||
|
desc: '与其他粉丝建立联系',
|
||||||
|
reward: { exp: 10, diamond: 5 },
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
page: '/pages/square/square',
|
||||||
|
mask: true,
|
||||||
|
target: '.friend-tab',
|
||||||
|
content: '在这里可以查看好友列表',
|
||||||
|
center: true,
|
||||||
|
customPosition: { x: 0, y: 0 },
|
||||||
|
buttons: ['next']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
page: '/pages/square/square',
|
||||||
|
mask: true,
|
||||||
|
target: '.add-friend-btn',
|
||||||
|
content: '点击添加新好友,与志同道合的粉丝交流',
|
||||||
|
center: true,
|
||||||
|
customPosition: { x: 0, y: 0 },
|
||||||
|
buttons: ['next']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// 分享内容引导
|
||||||
|
share_content: {
|
||||||
|
key: 'share_content',
|
||||||
|
name: '分享内容',
|
||||||
|
desc: '将喜欢的内容分享给更多人',
|
||||||
|
reward: { exp: 10, diamond: 5 },
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
page: '/pages/square/square',
|
||||||
|
mask: true,
|
||||||
|
target: '.share-btn',
|
||||||
|
content: '点击分享按钮可以将内容分享给好友',
|
||||||
|
center: true,
|
||||||
|
customPosition: { x: 0, y: 0 },
|
||||||
|
buttons: ['next']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
page: '/pages/square/square',
|
||||||
|
mask: true,
|
||||||
|
target: '.share-platform',
|
||||||
|
content: '选择分享平台,让更多人看到这份热爱',
|
||||||
|
center: true,
|
||||||
|
customPosition: { x: 0, y: 0 },
|
||||||
|
buttons: ['next']
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -496,6 +657,18 @@ export function markGuideDone(key) {
|
|||||||
uni.setStorageSync(makeUserIdKey('guide_done', key), true)
|
uni.setStorageSync(makeUserIdKey('guide_done', key), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标记引导奖励已领取
|
||||||
|
* @param {string} key 引导key
|
||||||
|
*/
|
||||||
|
export function markGuideRewardClaimed(key) {
|
||||||
|
const claimed = uni.getStorageSync(makeUserIdKey('guide_rewards_claimed', '')) || []
|
||||||
|
if (!claimed.includes(key)) {
|
||||||
|
claimed.push(key)
|
||||||
|
uni.setStorageSync(makeUserIdKey('guide_rewards_claimed', ''), claimed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 领取引导奖励
|
* 领取引导奖励
|
||||||
* @param {string} key 引导key
|
* @param {string} key 引导key
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user