|
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
1、问题缘起及探讨过程中提出的所有新问题汇总
原始需求: 在 Discuz 论坛中实现一套完整的新手引导流程,确保新注册用户依次完成"打卡签到"和"新人报到回帖"两个任务后才能正常使用论坛。
任务 ID 从 10 变更为 14,是因为论坛后台重新创建了“新人报到”任务(原任务可能被删除或停用)。
探讨过程中提出的独立问题:
| 序号 | 问题描述 | 状态 | | 1 | 新手任务弹窗遮挡 Discuz 本身的头像设置提示页面 | 已解决 | | 2 | 发帖后任务状态未更新,仍被强制跳转回目标帖子 | 已解决 | | 3 | 任务 ID 从 10 变更为 14,需同步更新代码 | 已解决 | | 4 | Discuz 原生任务插件 task_post 的 threadid 功能失效(与 forumid 优先级冲突) | 已解决 | | 5 | 注册完成后直接跳转打卡页面,缺少中间引导弹窗 | 已解决 | | 6 | 打卡成功后无弹窗直接跳转任务页,用户体验断裂 | 已解决 | | 7 | 老用户自动打卡出现 showWindow loading 转圈卡住 | 已解决 | | 8 | 打卡页面已打卡后未触发跳转,用户被留在打卡页 | 已解决 |
2、解决方案
(1)简要技术分析
通过 Discuz 插件钩子 global_footer 拦截页面输出,根据用户组(groupid=10 新手)、打卡状态、任务状态三层条件分支,动态注入 showDialog 弹窗和 window.location.href 跳转脚本,实现新手引导流程的闭环控制;同时修复原生任务插件 task_post 的 csc() 和 view() 方法中 threadid 与 forumid 的优先级冲突。
(2)修改、新增文件列表
| 文件路径 | 操作 | | source/plugin/zqlj_sign/hook.class.php | 修改(核心逻辑) | | source/class/task/task_post.php | 修改(任务插件) | | source/class/task/lang/lang_post.php | 修改(语言包) |
(3)关键作用代码段全文
文件一:source/plugin/zqlj_sign/hook.class.php — 核心主控逻辑
- function _ajax_and_go(){
- global $_G,$_sign_init;
- if($_G['uid']){
- $ajax=$gojs='';
- $newbie_redirect = '';
- $sign_completed = false;
-
- // ============================================================
- // 第一步:自动打卡(区分新手/老用户)
- // ============================================================
- if(in_array($_G['groupid'],$_sign_init['groups'])){
- if($_sign_init['open']&&!zqlj_sign_status($_G['uid'])){
- if(in_array($_G['groupid'],$_sign_init['ajaxgroups'])){
- if($_sign_init['mobile']){
- $ajax='<!-- auto sign -->';
- $result=zqlj_sign($_G['uid']);
- if($result==2){
- if($_G['groupid'] == 10){
- // 新手:打卡后引导去任务页
- $sign_completed = true;
- $ajax.='<script>
- showDialog(\'打卡成功!接下来去完成新手任务吧。\', \'notice\', \'提示\', function(){
- window.location.href="' . $_G['siteurl'] . 'home.php?mod=task";
- });
- </script>';
- } else {
- // 老用户:静默打卡
- $ajax.='<script>showDialog(\'打卡成功!\', \'notice\', \'提示\');</script>';
- }
- }
- }else{
- if($_G['groupid'] == 10){
- // 新手:打卡窗口带回调跳转
- $ajax=zqlj_sign_url('<script type="text/javascript">
- showWindow(\'zqlj_sign\', \'plugin.php?id=zqlj_sign&sign='.$_sign_init['formhash'].'&ajax=yes\', function(){
- showDialog(\'打卡成功!接下来去完成新手任务吧。\', \'notice\', \'提示\', function(){
- window.location.href="' . $_G['siteurl'] . 'home.php?mod=task";
- });
- });
- </script>');
- } else {
- // 老用户:打卡窗口无回调,避免loading卡住
- $ajax=zqlj_sign_url('<script type="text/javascript">
- showWindow(\'zqlj_sign\', \'plugin.php?id=zqlj_sign&sign='.$_sign_init['formhash'].'&ajax=yes\');
- </script>');
- }
- }
- }
- if(!$ajax&&in_array($_G['groupid'],$_sign_init['gogroups'])&&$_GET['id']!='zqlj_sign'){
- if($_G['groupid'] == 10){
- // 新手:中间引导弹窗
- $gojs='<script>
- showDialog(\'接下来花几分钟时间完成两个新手任务,有积分拿哦!<br><br>在此之前,先一键打卡!\', \'notice\', \'新手引导\', function(){
- window.location.href=\'' . $_G['siteurl'] . 'plugin.php?id=zqlj_sign\';
- });
- </script>';
- } else {
- // 老用户:直接跳转
- $gojs=zqlj_sign_url('<script>window.location.href=\'plugin.php?id=zqlj_sign\';</script>');
- }
- }
- if(CURSCRIPT=='home'&&CURMODULE=='spacecp'&&($_GET['ac']=='profile'||$_GET['ac']=='avatar')) {
- $ajax='';
- $gojs='';
- $sign_completed = false;
- }
- }
- }
-
- // ============================================================
- // 第二步:检查任务 14 状态(新人报到任务)
- // ============================================================
- $task_10_status = false;
- $task_10_completed = false;
- if ($_G['uid']) {
- $task_info = DB::fetch_first("SELECT status FROM ".DB::table('common_mytask')." WHERE uid='$_G[uid]' AND taskid=14");
- if ($task_info) {
- $task_10_status = true;
- if ($task_info['status'] == 1 || $task_info['status'] == 2) {
- $task_10_completed = true;
- }
- }
- }
-
- // ============================================================
- // 第三步:根据任务状态决定跳转
- // ============================================================
- if(empty($gojs) && !$sign_completed){
-
- // 情况1:任务已完成 → 放行
- if ($task_10_completed) {
- // 放行
- }
-
- // 情况2:已领取但未完成 → 跳转到目标帖子
- else if ($task_10_status && getuserprofile('posts') == 0 && strpos($_SERVER['REQUEST_URI'], 'thread-95959-1-1.html') === false) {
- $is_fastpost = (CURSCRIPT=='forum' && $_GET['mod']=='post' && $_GET['action']=='reply' && $_GET['replysubmit']=='yes' && $_GET['infloat']=='yes' && $_GET['handlekey']=='fastpost');
- if (strpos($_SERVER['REQUEST_URI'], 'thread-95959-1-1.html') === false &&
- !(CURSCRIPT=='home'&&CURMODULE=='spacecp'&&in_array($_GET['ac'], array('profile', 'avatar'))) &&
- !$is_fastpost) {
- $newbie_redirect = '<script>
- showDialog(\'您已领取新手任务,请前往新人报到帖完成回帖,才能正式成为会员。\', \'notice\', \'提示\', function(){
- window.location.href="' . $_G['siteurl'] . 'thread-95959-1-1.html";
- });
- </script>';
- }
- }
-
- // 情况3:未领取任务 → 跳转到任务列表
- else if ($_G['groupid'] == 10 && getuserprofile('posts') == 0 &&
- strpos($_SERVER['REQUEST_URI'], 'home.php?mod=task') === false &&
- strpos($_SERVER['REQUEST_URI'], 'thread-95959-1-1.html') === false) {
- $is_fastpost_float = (CURSCRIPT=='forum' && $_GET['mod']=='post' && $_GET['action']=='reply' && $_GET['replysubmit']=='yes' && $_GET['infloat']=='yes' && $_GET['handlekey']=='fastpost');
- $is_signed = zqlj_sign_status($_G['uid']);
- if (!(CURSCRIPT=='home'&&CURMODULE=='spacecp'&&in_array($_GET['ac'], array('profile', 'avatar'))) && !$is_fastpost_float && ($_GET['id'] != 'zqlj_sign' || $is_signed)) {
- $newbie_redirect = '<script>
- showDialog(\'接下来去完成新手任务吧。\', \'notice\', \'提示\', function(){
- window.location.href="' . $_G['siteurl'] . 'home.php?mod=task";
- });
- </script>';
- }
- }
- }
-
- return $ajax.$gojs.$newbie_redirect;
- }
- return '';
- }
复制代码
文件二:source/class/task/task_post.php — csc() 方法修复(调整 threadid 优先级)
- $tbladd = $sqladd = '';
- if($taskvars['act'] == 'newreply' && $taskvars['threadid']) {
- $threadid = intval($taskvars['threadid']);
- }
- if($taskvars['forumid']) {
- $forumid = intval($taskvars['forumid']);
- }
- if($taskvars['author']) {
- return TRUE;
- }
复制代码
文件三:source/class/task/task_post.php — view() 方法修复(调换 threadid 与 forumid 优先级)
- function view($task, $taskvars) {
- global $_G;
- $return = $value = '';
- if(!empty($taskvars['complete']['threadid'])) {
- $value = intval($taskvars['complete']['threadid']['value']);
- $thread = C::t('forum_thread')->fetch_thread($value);
- $value = '<a href="forum.php?mod=viewthread&tid='.$value.'"><strong>'.($thread['subject'] ? $thread['subject'] : 'TID '.$value).'</strong></a>';
- } elseif(!empty($taskvars['complete']['forumid'])) {
- $value = intval($taskvars['complete']['forumid']['value']);
- loadcache('forums');
- $value = '<a href="forum.php?mod=forumdisplay&fid='.$value.'"><strong>'.$_G['cache']['forums'][$value]['name'].'</strong></a>';
- } elseif(!empty($taskvars['complete']['author'])) {
复制代码
文件四:source/class/task/lang/lang_post.php — 语言包修改(明确引导目标)
- 'task_complete_act_newreply_thread' => '在主题帖"{value}"中回复 {num} 次',
复制代码
修改语言包的目的:将“新人报到”任务的完成提示从泛泛的“在指定版块回复”改为包含具体帖子(thread-95959-1-1.html)的引导,使新手用户明确知道需要去哪个帖子回帖。
3、最终实现效果
| 用户类型 | 访问场景 | 行为 | | 新注册用户(groupid=10) | 首次访问论坛 | 弹窗"接下来花几分钟时间完成两个新手任务..." → 点击跳转打卡页面 | | 打卡页面手动打卡 | 弹窗"打卡成功!接下来去完成新手任务吧" → 点击跳转任务列表 | | 任务列表领取任务后访问其他页面 | 弹窗"您已领取新手任务,请前往新人报到帖..." → 点击跳转目标帖子 | | 目标帖子回帖完成 | 任务完成,后续访问放行 | | 资料编辑/头像上传页 | 放行,不拦截 | | 快速回复浮层页 | 放行,不遮挡 Discuz 原生提示 | | 老用户(groupid≠10) | 访问论坛 | 自动打卡浮层,打卡成功显示"打卡成功!",无强制跳转 | | 打卡页面 | 正常打卡,无新手引导弹窗 |
引导链流程图:
- 新用户注册
- │
- ├── 引导弹窗 → 打卡页面
- │
- ├── 打卡成功 → 任务列表页
- │
- ├── 领取任务14 → 目标帖子(thread-95959-1-1.html)
- │
- └── 完成回帖 → 任务完成 ✅ → 放行
复制代码
4、重要技术沉淀 / 踩坑点
| 踩坑点 | 正确做法 | | showWindow 回调函数在窗口打开时即执行,而非打卡成功后 | 老用户去掉回调,避免 loading 转圈卡住 | | task_post 的 view() 中 forumid 优先级高于 threadid,同时设置时后者被跳过 | 调换判断顺序,让 threadid 优先匹配 | | 新手引导弹窗遮挡头像设置、快速回复等 Discuz 原生提示页面 | 在放行条件中增加 profile、avatar、fastpost 白名单 | | 打卡页面已打卡后用户被留在打卡页,无法跳转 | 情况3去掉 $_GET['id'] != 'zqlj_sign' 硬排除,改为 $_GET['id'] != 'zqlj_sign' | $is_signed | | 任务 ID 硬编码在代码中,变更时需要同步修改 | 当前任务 ID 14 和目标帖子 ID 95959 已硬编码,后续可考虑后台配置化 |
涉及插件版本: 天天打卡签到 v7.5.0(已修改,无官方更新)
5、进一步优化可能性
- 当前任务 ID(14)和目标帖子 ID(95959)硬编码在 hook 中,未来可考虑后台配置化。
- 新手引导流程可扩展为更多步骤(如完善资料、上传头像),当前仅覆盖打卡+回帖两步。
- 可考虑使用 Cookie 或 Session 记录引导进度,避免用户刷新页面重复弹窗。
|
|