AI取名大师 | 做一个简单的免费积分试用功能

63 阅读3分钟

关于 AI 取名大师

借助豆包通义千问DeepSeek 等 AI 大模型,为您的宝宝、宠物、店铺、网名、笔名、项目、产品、服务、文章等取一个专业、有意义的名字😄。


开源地址:👉GitCode(国内友好)👈、👉GitHub👈 技术组合:Bun.jsElysia.jsuni-app 体验地址:AI取名大师(H5版)

特别注明:本系列文章仅为实战经验分享,并记录开发过程中碰到的问题😄,如有不足之处欢迎随时留言提出。


📣 需求简介

想给取名大师加一个免费试用功能,零成本试用核心功能,降低使用门槛。另外希望通过试用,提升新用户活跃度,为后续付费转化铺垫,同时通过唯一标识控制成本😄。

核心需求

  • 可配置化发放:支持通过配置文件自定义试用积分(默认 5 积分),无需修改代码即可调整福利力度;​
  • 资格精准判断:基于客户端唯一标识(指纹),确保 “同一设备 / 客户端仅能领取一次”,避免羊毛党重复领取;​
  • 场景化交互:用户访问首页后,若未持有积分券且符合试用资格,自动触发弹窗提示,引导领取;​
  • 权益绑定闭环:用户点击领取后,系统自动创建积分券并与当前客户端绑定,支持后续服务使用抵扣。

🤔 实施思路

  1. 首先我们设计一个数据表(trial)用于存放试用情况,记录客户端ID(指纹)、IP地址、录入时间等;
  2. 用户进入首页,若已有积分券则终止;
  3. 前端使用FingerprintJS (动态加载)计算客户端指纹,调用后端接口判断是否具备试用资格;
    • 情况一:未启用试用(配置文件中trialSize未设置大于0
    • 情况二:该客户端已经试用过(trial 表中已有记录)
    • 情况三:当日试用名额已用完(配置文件中trialPreDay
  4. 若后端返回正整数,则表示可以试用该值的积分,此时弹窗提示用户;
  5. 用户点击立即领取后自动创建积分券并绑定。

👨‍💻 代码实现

数据字典

表名: trial

字段名中文名类型必填默认值说明
id指纹String客户端唯一值
cid积分券String
ipIP地址String
region地区String
platform平台String
sys系统信息String
addOn录入时间Long13 位时间戳

后端服务

/**
 * 判断是否具备试用资格
 * @param {String} uuid
 * @returns {Number} 试用积分数,-1=未开启,0=无可用,-2=免费额度已用完
 */
const checkTril = uuid=>{
    let { trialSize, trialPreDay } = config.app
    if(trialSize<=0)
        return -1

    // 如果已经存在过,则不能再试用
    if(count(TRIAL, "id=?", uuid)>0)
        return 0

    // 判断是否超过试用每日限额
    if(trialPreDay > 0){
        let now = new Date()
        now.setHours(0, 0, 0, 0)

        if(count(TRIAL, "addOn>=?", now.getTime())>=trialPreDay)
            throw -2
    }
    return trialSize
}


/**
 * @param {Elysia} app
 */
export default app=>{
    app.post("/trial/check", ({ body:{ uuid }})=> ok(checkTril(uuid)) )
    app.post("/trial/:uuid", async ({ server, request, headers, params:{ uuid } })=>{
        const trialSign = checkTril(uuid)

        if(trialSign == -1)     throw `未开放试用`
        if(trialSign == -2)     throw `今日试用名额已用完`
        if(trialSign <= 0)      throw `客户端已试用`

        let ip = server?.requestIP(request).address
        let platform = headers['platform']
        let sys = headers['system']

        logger.info(`客户端 ${ip}(${platform}/${sys}) 尝试生产试用积分券 coupon=${trialSign}`)

        let cid = createUUID(config.app.couponLen)
        //创建积分券
        createCoupon({ id: cid, quota: trialSign })

        logger.info(`试用积分券 ${cid} 已生成...`)

        let region = await ipToRegion(ip)

        insertNew(TRIAL, Trial.parse({ id: uuid, cid, region, platform, sys, ip, addOn: Date.now() }))
        logger.info(`保存试用信息 ${uuid} (region=${region} platform=${platform}) sys=${sys}`)

        return ok(cid)
    })
}

组件实现

<!-- 免费试用 -->
<template>
    <wd-transition :show="showTrial" name="fade-down" :duration="600">
        <view class="card card-success">
            <view class="pt-1">现在能免费领 {{ trial }} 积分试用啦!不用注册,手机号、邮箱都不用填,到手就能用🎉</view>
            <view class="text-right mt-3">
                <wd-button size="small" type="info" style="margin-right: 10px;" @click="showTrial=false">暂不需要</wd-button>
                <wd-button size="small" type="success" @click="getTrial">立即领取</wd-button>
            </view>
        </view>
    </wd-transition>

    <wd-toast />
</template>

<script setup>
    import { RESULT } from '@U'
    import { useDataStore } from '@/store'

    const dataStore = useDataStore()
    const toast = useToast()

    let uuid = ""
    const trial = ref(5)
    const showTrial = ref(false)

    const tryTrial = ()=>{
        //如果已经有积分券,则跳过
        if(dataStore.coupon)
            return

        // Initialize the agent at application startup.
        const fpPromise = import('https://openfpcdn.io/fingerprintjs/v5')
            .then(FingerprintJS => FingerprintJS.load())

        // Get the visitor identifier when you need it.
        fpPromise
            .then(fp => fp.get())
            .then(result => {
                uuid = result.visitorId
                console.debug(`获取到客户端指纹`, uuid)

                RESULT("/trial/check", { uuid }, d=>{
                    if(!isNaN(d.data) && d.data>0){
                        trial.value = d.data
                        showTrial.value = true
                    }
                })
            })
    }

    const getTrial = ()=> {
        if(!uuid)   return toast.warning(`无效指纹数据`)

        RESULT(`/trial/${uuid}`, {}, d=>{
            dataStore.setCoupon(d.data)
            toast.success(`免费积分券已领取`)

            showTrial.value = false
        })
    }

    const check = () => {
        nextTick( tryTrial )
        // setTimeout(()=> showTrial.value = true, 2000)
    }

    defineExpose({ check })

</script>

👁️ 效果展示