查看: 26|回复: 0

哈哈哈

[复制链接]

6

主题

13

回帖

854

积分

管理员

站长

积分
854

荣誉管理论坛元老

QQ
发表于 2026-9-15 13:19:37 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册  

×
  1. <?php
  2. /**
  3. * 每日签到插件 - 核心函数库
  4. */
  5. if(!defined('IN_DISCUZ')) {
  6.         exit('Access Denied');
  7. }

  8. /* ---------------- 设置 ---------------- */

  9. function bbgn_set_default() {
  10.         return array(
  11.                 'open' => '1',            // 启用开关
  12.                 'btntext' => '',          // 签到按钮文字
  13.                 'retro_open' => '1',      // 允许补签
  14.                 'retro_credit' => 'extcredits2', // 补签消耗积分类型
  15.                 'retro_num' => '10',      // 补签消耗数值 0=免费
  16.                 'retro_max' => '3',       // 周期(自然月)内补签次数上限 0=禁用
  17.                 'remind_open' => '0',     // 定时提醒开关
  18.                 'remind_hour' => '20',    // 提醒触发时段 0-23
  19.                 'rank_cache' => '3600',   // 榜单缓存时长(秒)
  20.                 'notice_open' => '1',     // 签到成功站内通知
  21.                 'base_credit' => 'extcredits2', // 奖励积分类型
  22.                 'base_num' => '2',        // 基础奖励数值
  23.                 'random_open' => '0',     // 随机积分奖励开关
  24.                 'random_min' => '1',
  25.                 'random_max' => '5',
  26.                 'rank_limit' => '20',     // 榜单上榜人数
  27.         );
  28. }

  29. function bbgn_set_all($refresh = false) {
  30.         static $set = null;
  31.         if($set === null || $refresh) {
  32.                 $set = array();
  33.                 $query = DB::query("SELECT skey, svalue FROM ".DB::table('lymsouqd_bbgn_set'));
  34.                 while($row = DB::fetch($query)) {
  35.                         $set[$row['skey']] = $row['svalue'];
  36.                 }
  37.                 $set = array_merge(bbgn_set_default(), $set);
  38.         }
  39.         return $set;
  40. }

  41. function bbgn_set_save($key, $value) {
  42.         DB::insert('lymsouqd_bbgn_set', array('skey' => $key, 'svalue' => $value), false, true);
  43. }

  44. /* ---------------- 工具 ---------------- */

  45. function bbgn_today() {
  46.         return dgmdate(TIMESTAMP, 'Y-m-d');
  47. }

  48. function bbgn_creditname($credittype) {
  49.         global $_G;
  50.         $id = intval(str_replace('extcredits', '', $credittype));
  51.         if($id >= 1 && $id <= 8 && !empty($_G['setting']['extcredits'][$id]['title'])) {
  52.                 return $_G['setting']['extcredits'][$id]['title'];
  53.         }
  54.         return $credittype;
  55. }

  56. /* 站点已启用的扩展积分列表 */
  57. function bbgn_creditlist() {
  58.         global $_G;
  59.         $list = array();
  60.         for($i = 1; $i <= 8; $i++) {
  61.                 if(!empty($_G['setting']['extcredits'][$i]['title'])) {
  62.                         $list['extcredits'.$i] = $_G['setting']['extcredits'][$i]['title'];
  63.                 }
  64.         }
  65.         return $list;
  66. }

  67. function bbgn_json($data) {
  68.         header('Content-Type: application/json; charset=utf-8');
  69.         echo json_encode($data, JSON_UNESCAPED_UNICODE);
  70.         exit;
  71. }

  72. /* ---------------- 用户统计 ---------------- */

  73. function bbgn_user_get($uid) {
  74.         global $_G;
  75.         $user = DB::fetch_first("SELECT * FROM ".DB::table('lymsouqd_bbgn_user')." WHERE uid=%d", array($uid));
  76.         if(!$user) {
  77.                 $username = ($_G['uid'] == $uid) ? $_G['username'] : DB::result_first("SELECT username FROM ".DB::table('common_member')." WHERE uid=%d", array($uid));
  78.                 $data = array(
  79.                         'uid' => $uid,
  80.                         'username' => $username,
  81.                         'totaldays' => 0,
  82.                         'contin' => 0,
  83.                         'maxcontin' => 0,
  84.                         'reward_total' => 0,
  85.                         'lastday' => '',
  86.                         'lasttime' => 0,
  87.                         'retro_num' => 0,
  88.                         'retro_month' => '',
  89.                         'updatetime' => TIMESTAMP,
  90.                 );
  91.                 DB::insert('lymsouqd_bbgn_user', $data, false, true);
  92.                 $user = $data;
  93.         }
  94.         return $user;
  95. }

  96. function bbgn_signed_today($uid) {
  97.         return DB::result_first("SELECT COUNT(*) FROM ".DB::table('lymsouqd_bbgn_log')." WHERE uid=%d AND qdday=%s AND status=1", array($uid, bbgn_today()));
  98. }

  99. /* 重新计算连续签到天数(从今天或昨天向前追溯) */
  100. function bbgn_recalc_contin($uid) {
  101.         $map = array();
  102.         $query = DB::query("SELECT DISTINCT qdday FROM ".DB::table('lymsouqd_bbgn_log')." WHERE uid=%d AND status=1", array($uid));
  103.         while($row = DB::fetch($query)) {
  104.                 $map[$row['qdday']] = 1;
  105.         }
  106.         $today = bbgn_today();
  107.         $cursor = isset($map[$today]) ? $today : dgmdate(TIMESTAMP - 86400, 'Y-m-d');
  108.         $contin = 0;
  109.         while(isset($map[$cursor])) {
  110.                 $contin++;
  111.                 $cursor = dgmdate(strtotime($cursor) - 86400, 'Y-m-d');
  112.         }
  113.         return $contin;
  114. }

  115. /* 全量重算用户统计(撤销记录后调用) */
  116. function bbgn_recalc_user($uid) {
  117.         $totaldays = DB::result_first("SELECT COUNT(DISTINCT qdday) FROM ".DB::table('lymsouqd_bbgn_log')." WHERE uid=%d AND status=1", array($uid));
  118.         $reward_total = DB::result_first("SELECT IFNULL(SUM(reward),0) FROM ".DB::table('lymsouqd_bbgn_log')." WHERE uid=%d AND status=1", array($uid));
  119.         $lastday = DB::result_first("SELECT IFNULL(MAX(qdday),'') FROM ".DB::table('lymsouqd_bbgn_log')." WHERE uid=%d AND status=1", array($uid));
  120.         $contin = bbgn_recalc_contin($uid);
  121.         $user = bbgn_user_get($uid);
  122.         $maxcontin = max($user['maxcontin'], $contin);
  123.         DB::update('lymsouqd_bbgn_user', array(
  124.                 'totaldays' => $totaldays,
  125.                 'reward_total' => $reward_total,
  126.                 'lastday' => $lastday,
  127.                 'contin' => $contin,
  128.                 'maxcontin' => $maxcontin,
  129.                 'updatetime' => TIMESTAMP,
  130.         ), "uid='".intval($uid)."'");
  131. }

  132. /* 当月已用补签次数 */
  133. function bbgn_retro_count($uid) {
  134.         $user = bbgn_user_get($uid);
  135.         $month = dgmdate(TIMESTAMP, 'Y-m');
  136.         if($user['retro_month'] != $month) {
  137.                 return 0;
  138.         }
  139.         return intval($user['retro_num']);
  140. }

  141. /* ---------------- 奖励 ---------------- */

  142. /* 计算签到奖励:基础 + 随机 + 连签区间 + 阶段 */
  143. function bbgn_reward_calc($contin, $set) {
  144.         $total = 0;
  145.         $detail = array();
  146.         $base = intval($set['base_num']);
  147.         if($base > 0) {
  148.                 $total += $base;
  149.                 $detail[] = '基础奖励 +'.$base;
  150.         }
  151.         if($set['random_open']) {
  152.                 $min = max(0, intval($set['random_min']));
  153.                 $max = max($min, intval($set['random_max']));
  154.                 $r = mt_rand($min, $max);
  155.                 if($r > 0) {
  156.                         $total += $r;
  157.                         $detail[] = '随机奖励 +'.$r;
  158.                 }
  159.         }
  160.         $query = DB::query("SELECT * FROM ".DB::table('lymsouqd_bbgn_reward')." WHERE status=1 ORDER BY sort, id");
  161.         while($rule = DB::fetch($query)) {
  162.                 $num = intval($rule['num']);
  163.                 if($num <= 0) continue;
  164.                 if($rule['rtype'] == 'contin' && $contin >= intval($rule['daymin']) && $contin <= intval($rule['daymax'])) {
  165.                         $total += $num;
  166.                         $detail[] = '连签'.$rule['daymin'].'-'.$rule['daymax'].'天奖励 +'.$num;
  167.                 } elseif($rule['rtype'] == 'stage' && $contin == intval($rule['day'])) {
  168.                         $total += $num;
  169.                         $detail[] = '连签'.$rule['day'].'天阶段奖励 +'.$num;
  170.                 }
  171.         }
  172.         return array($total, $detail);
  173. }

  174. /* 下一阶段奖励进度 */
  175. function bbgn_nextstage($contin) {
  176.         $stage = DB::fetch_first("SELECT day, num FROM ".DB::table('lymsouqd_bbgn_reward')." WHERE rtype='stage' AND status=1 AND day>%d ORDER BY day ASC LIMIT 1", array($contin));
  177.         if(!$stage) {
  178.                 return null;
  179.         }
  180.         $prev = DB::result_first("SELECT IFNULL(MAX(day),0) FROM ".DB::table('lymsouqd_bbgn_reward')." WHERE rtype='stage' AND status=1 AND day<=%d", array($contin));
  181.         $span = max(1, $stage['day'] - $prev);
  182.         $done = max(0, $contin - $prev);
  183.         return array(
  184.                 'day' => $stage['day'],
  185.                 'num' => $stage['num'],
  186.                 'need' => $stage['day'] - $contin,
  187.                 'progress' => min(100, round($done / $span * 100)),
  188.         );
  189. }

  190. /* ---------------- 签到 / 补签 ---------------- */

  191. /* 执行签到,返回 array(code, msg, data) */
  192. function bbgn_dosign($uid) {
  193.         global $_G;
  194.         $set = bbgn_set_all();
  195.         if(!$set['open']) {
  196.                 return array(1, '签到功能已关闭');
  197.         }
  198.         if(bbgn_signed_today($uid)) {
  199.                 return array(1, '今日已完成签到,请勿重复操作');
  200.         }
  201.         $user = bbgn_user_get($uid);
  202.         $today = bbgn_today();
  203.         $yesterday = dgmdate(TIMESTAMP - 86400, 'Y-m-d');
  204.         $contin = ($user['lastday'] == $yesterday) ? $user['contin'] + 1 : 1;

  205.         list($total, $detail) = bbgn_reward_calc($contin, $set);
  206.         $credit = $set['base_credit'];
  207.         if($total > 0) {
  208.                 updatemembercount($uid, array($credit => $total), 1, 'BGN', 0, '', '每日签到奖励');
  209.         }
  210.         DB::insert('lymsouqd_bbgn_log', array(
  211.                 'uid' => $uid,
  212.                 'username' => $user['username'],
  213.                 'qdday' => $today,
  214.                 'dateline' => TIMESTAMP,
  215.                 'qtype' => 1,
  216.                 'credit' => $credit,
  217.                 'reward' => $total,
  218.                 'detail' => implode(',', $detail),
  219.                 'status' => 1,
  220.         ));
  221.         DB::update('lymsouqd_bbgn_user', array(
  222.                 'totaldays' => $user['totaldays'] + 1,
  223.                 'contin' => $contin,
  224.                 'maxcontin' => max($user['maxcontin'], $contin),
  225.                 'reward_total' => $user['reward_total'] + $total,
  226.                 'lastday' => $today,
  227.                 'lasttime' => TIMESTAMP,
  228.                 'updatetime' => TIMESTAMP,
  229.         ), "uid='".intval($uid)."'");

  230.         if($set['notice_open']) {
  231.                 $msg = '签到成功!连续签到 '.$contin.' 天';
  232.                 if($total > 0) {
  233.                         $msg .= ',获得 '.bbgn_creditname($credit).' +'.$total.'('.implode(',', $detail).')';
  234.                 }
  235.                 notification_add($uid, 'system', $msg, array(), 1);
  236.         }
  237.         return array(0, '签到成功', array(
  238.                 'contin' => $contin,
  239.                 'totaldays' => $user['totaldays'] + 1,
  240.                 'reward' => $total,
  241.                 'reward_total' => $user['reward_total'] + $total,
  242.                 'detail' => $detail,
  243.                 'nextstage' => bbgn_nextstage($contin),
  244.         ));
  245. }

  246. /* 执行补签($isadmin=true 时跳过开关/次数/积分校验),返回 array(code, msg, data) */
  247. function bbgn_doretro($uid, $date, $isadmin = false) {
  248.         global $_G;
  249.         $set = bbgn_set_all();
  250.         if(!$set['open']) {
  251.                 return array(1, '签到功能已关闭');
  252.         }
  253.         if(!$isadmin && !$set['retro_open']) {
  254.                 return array(1, '补签功能已关闭');
  255.         }
  256.         if(!preg_match('/^\d{4}-\d{2}-\d{2}$/', $date) || !strtotime($date)) {
  257.                 return array(1, '补签日期无效');
  258.         }
  259.         $today = bbgn_today();
  260.         if($date >= $today) {
  261.                 return array(1, '只能补签今天之前的日期');
  262.         }
  263.         if(!$isadmin && dgmdate(TIMESTAMP, 'Y-m') != substr($date, 0, 7)) {
  264.                 return array(1, '仅支持补签本月漏签日期');
  265.         }
  266.         $exists = DB::result_first("SELECT COUNT(*) FROM ".DB::table('lymsouqd_bbgn_log')." WHERE uid=%d AND qdday=%s AND status=1", array($uid, $date));
  267.         if($exists) {
  268.                 return array(1, '该日期已有签到记录');
  269.         }
  270.         if(!$isadmin) {
  271.                 $max = intval($set['retro_max']);
  272.                 if($max <= 0) {
  273.                         return array(1, '补签功能已关闭');
  274.                 }
  275.                 if(bbgn_retro_count($uid) >= $max) {
  276.                         return array(1, '本周期补签次数已达上限');
  277.                 }
  278.                 $cost = intval($set['retro_num']);
  279.                 $credit = $set['retro_credit'];
  280.                 if($cost > 0) {
  281.                         $cid = intval(str_replace('extcredits', '', $credit));
  282.                         $field = ($cid >= 1 && $cid <= 8) ? 'extcredits'.$cid : 'extcredits2';
  283.                         $balance = DB::result_first("SELECT `".$field."` FROM ".DB::table('common_member_count')." WHERE uid=%d", array($uid));
  284.                         if($balance < $cost) {
  285.                                 return array(1, bbgn_creditname($credit).'不足,无法完成补签');
  286.                         }
  287.                         updatemembercount($uid, array($credit => -$cost), 1, 'BGR', 0, '', '签到补签消耗');
  288.                 }
  289.                 /* 更新本月补签计数 */
  290.                 $user = bbgn_user_get($uid);
  291.                 $month = dgmdate(TIMESTAMP, 'Y-m');
  292.                 $num = ($user['retro_month'] == $month) ? $user['retro_num'] + 1 : 1;
  293.                 DB::update('lymsouqd_bbgn_user', array('retro_num' => $num, 'retro_month' => $month), "uid='".intval($uid)."'");
  294.         }
  295.         $user = bbgn_user_get($uid);
  296.         DB::insert('lymsouqd_bbgn_log', array(
  297.                 'uid' => $uid,
  298.                 'username' => $user['username'],
  299.                 'qdday' => $date,
  300.                 'dateline' => TIMESTAMP,
  301.                 'qtype' => $isadmin ? 3 : 2,
  302.                 'credit' => '',
  303.                 'reward' => 0,
  304.                 'detail' => $isadmin ? '管理员补签' : '积分补签',
  305.                 'status' => 1,
  306.         ));
  307.         /* 连签天数自动接续:重算统计 */
  308.         bbgn_recalc_user($uid);
  309.         $user = bbgn_user_get($uid);
  310.         return array(0, '补签成功', array(
  311.                 'contin' => $user['contin'],
  312.                 'totaldays' => $user['totaldays'],
  313.                 'nextstage' => bbgn_nextstage($user['contin']),
  314.         ));
  315. }

  316. /* ---------------- 榜单 ---------------- */

  317. function bbgn_rank($type) {
  318.         $set = bbgn_set_all();
  319.         $cache = bbgn_set_all();
  320.         $key = 'rankcache_'.$type;
  321.         $now = TIMESTAMP;
  322.         $cached = isset($cache[$key]) ? json_decode($cache[$key], true) : null;
  323.         if($cached && !empty($cached['list']) && $now - intval($cached['time']) < max(60, intval($set['rank_cache']))) {
  324.                 return $cached['list'];
  325.         }
  326.         $limit = max(1, intval($set['rank_limit']));
  327.         $list = array();
  328.         if($type == 'total') {
  329.                 $query = DB::query("SELECT uid, username, totaldays AS score FROM ".DB::table('lymsouqd_bbgn_user')." WHERE totaldays>0 ORDER BY totaldays DESC, updatetime ASC LIMIT ".$limit);
  330.         } elseif($type == 'contin') {
  331.                 $query = DB::query("SELECT uid, username, contin AS score FROM ".DB::table('lymsouqd_bbgn_user')." WHERE contin>0 ORDER BY contin DESC, updatetime ASC LIMIT ".$limit);
  332.         } else {
  333.                 $month = dgmdate(TIMESTAMP, 'Y-m');
  334.                 $query = DB::query("SELECT uid, username, COUNT(DISTINCT qdday) AS score FROM ".DB::table('lymsouqd_bbgn_log')." WHERE status=1 AND qdday LIKE %s GROUP BY uid ORDER BY score DESC, uid ASC LIMIT ".$limit, array($month.'%'));
  335.         }
  336.         while($row = DB::fetch($query)) {
  337.                 $list[] = $row;
  338.         }
  339.         bbgn_set_save($key, json_encode(array('time' => $now, 'list' => $list)));
  340.         return $list;
  341. }

  342. /* 当前用户名次 */
  343. function bbgn_rank_self($uid, $type) {
  344.         if($type == 'total') {
  345.                 $my = bbgn_user_get($uid);
  346.                 $score = $my['totaldays'];
  347.                 if($score <= 0) return 0;
  348.                 return DB::result_first("SELECT COUNT(*) FROM ".DB::table('lymsouqd_bbgn_user')." WHERE totaldays>%d", array($score)) + 1;
  349.         } elseif($type == 'contin') {
  350.                 $my = bbgn_user_get($uid);
  351.                 $score = $my['contin'];
  352.                 if($score <= 0) return 0;
  353.                 return DB::result_first("SELECT COUNT(*) FROM ".DB::table('lymsouqd_bbgn_user')." WHERE contin>%d", array($score)) + 1;
  354.         } else {
  355.                 $month = dgmdate(TIMESTAMP, 'Y-m');
  356.                 $score = DB::result_first("SELECT COUNT(DISTINCT qdday) FROM ".DB::table('lymsouqd_bbgn_log')." WHERE uid=%d AND status=1 AND qdday LIKE %s", array($uid, $month.'%'));
  357.                 if($score <= 0) return 0;
  358.                 return DB::result_first("SELECT COUNT(*) FROM (SELECT uid FROM ".DB::table('lymsouqd_bbgn_log')." WHERE status=1 AND qdday LIKE %s GROUP BY uid HAVING COUNT(DISTINCT qdday)>%d) t", array($month.'%', $score)) + 1;
  359.         }
  360. }

  361. /* 清空榜单缓存 */
  362. function bbgn_rank_clear() {
  363.         DB::query("DELETE FROM ".DB::table('lymsouqd_bbgn_set')." WHERE skey LIKE 'rankcache_%'");
  364. }
复制代码

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册  

本版积分规则

关注公众号

相关侵权、举报、投诉及建议等,请发 E-mail:admin@discuz.vip

Powered by Discuz! X5.0 © 2001-2026 Discuz! Team.|闽ICP备:2024080050号|闽公网安备:35082302000245号

在本版发帖
关注公众号
QQ客服返回顶部