首页/ mobileweb/ 小草问卷调查 H5 移动端功能演示/ 代码预览

💻 代码预览 · 小草问卷调查 H5 移动端功能演示

mw_service · 上传者 驰旭教育
← 返回详情
r104/app.js · 约 20271 字符
1/* 小草问卷调查 H5 —— 单页 hash 路由 + 底部 Tab */2(function () {3  'use strict';45  // ---------- 数据 ----------6  var USER = { name: '小草用户', phone: '138****6677', points: 1280, level: '黄金调研员', answers: 36, published: 5 };78  var CATS = [9    { ic: '📋', lb: '市场调研' }, { ic: '🎓', lb: '学术问卷' },10    { ic: '🎉', lb: '活动报名' }, { ic: '💡', lb: '产品反馈' },11    { ic: '🏢', lb: '员工测评' }, { ic: '🏥', lb: '健康调查' },12    { ic: '🛒', lb: '消费洞察' }, { ic: '❤️', lb: '满意度' }13  ];1415  var QS = [16    { id: 'q1', ti: '2026 新能源汽车消费意愿调研', de: '了解用户对新能源车的购买计划与关注因素', cat: '市场调研', thumb: '🚗', grad: 'linear-gradient(135deg,#15c39a,#1aa6e8)', qn: 12, join: 3820, rew: '+20 积分', tags: ['热门', '有奖'] },17    { id: 'q2', ti: '大学生线上学习习惯调查', de: '高校学习行为研究,匿名填写,结果公开', cat: '学术问卷', thumb: '🎓', grad: 'linear-gradient(135deg,#6c5ce7,#a05cff)', qn: 15, join: 1560, rew: '+15 积分', tags: ['匿名', '学术'] },18    { id: 'q3', ti: '城市马拉松志愿者报名', de: '2026 春季马拉松志愿者信息收集与岗位分配', cat: '活动报名', thumb: '🏃', grad: 'linear-gradient(135deg,#ff9a3c,#ff6a3c)', qn: 8, join: 890, rew: '纪念衫', tags: ['招募中'] },19    { id: 'q4', ti: 'APP 改版体验反馈收集', de: '新版首页与发布流程的满意度与改进建议', cat: '产品反馈', thumb: '📱', grad: 'linear-gradient(135deg,#1aa6e8,#15c39a)', qn: 10, join: 2410, rew: '+10 积分', tags: ['官方'] },20    { id: 'q5', ti: '员工敬业度年度测评', de: '企业内部匿名敬业度调研,助力组织健康', cat: '员工测评', thumb: '🏢', grad: 'linear-gradient(135deg,#3a7bd5,#15c39a)', qn: 20, join: 640, rew: '内部', tags: ['企业'] },21    { id: 'q6', ti: '社区养老服务需求调查', de: '倾听居民对社区养老服务的真实需求', cat: '健康调查', thumb: '🏥', grad: 'linear-gradient(135deg,#26c6a4,#1aa6e8)', qn: 14, join: 1120, rew: '+12 积分', tags: ['公益'] }22  ];2324  var MINE = [25    { ti: '门店顾客满意度回访', qn: 9, join: 326, status: '收集中', prog: 0.82 },26    { ti: '新品口味偏好测试', qn: 11, join: 158, status: '收集中', prog: 0.44 },27    { ti: '会员权益调研', qn: 7, join: 502, status: '已结束', prog: 1 },28    { ti: '节日活动意向调查', qn: 6, join: 211, status: '草稿', prog: 0.1 },29    { ti: '配送时效满意度', qn: 8, join: 433, status: '已结束', prog: 1 }30  ];3132  var ARTS = [33    { id: 'a1', cv: '问卷设计', ti: '写好一份问卷的 6 个基本原则', am: '阅读 3.2k · 收藏 480', de: '从目标到题目的结构化方法' },34    { id: 'a2', cv: '提高回收', ti: '如何让问卷回收率提升 3 倍', am: '阅读 2.1k · 收藏 312', de: '激励、渠道与节奏' },35    { id: 'a3', cv: '数据分析', ti: '问卷数据入门:从交叉分析到可视化', am: '阅读 1.8k · 收藏 276', de: '读懂你的受访者' },36    { id: 'a4', cv: '合规隐私', ti: '匿名与隐私:问卷合规必读', am: '阅读 1.5k · 收藏 198', de: '保护每一位填写者' }37  ];3839  var MSGS = [40    { md: '📊', mt: '问卷回收提醒', mx: '您发布的《门店顾客满意度回访》新增 12 份有效回答。', ti: '10 分钟前' },41    { md: '🎁', mt: '积分到账', mx: '完成《APP 改版体验反馈》获得 10 积分,当前 1280 分。', ti: '2 小时前' },42    { md: '✅', mt: '审核通过', mx: '您提交的《会员权益调研》已通过审核并公开发布。', ti: '昨天' },43    { md: '💡', mt: '小贴士', mx: '设置合理的答题时长(3 分钟内)可显著提升完成率。', ti: '3 天前' }44  ];4546  var Q_DEMO = [47    { t: '您最常使用问卷的场景是?', type: 'single', opts: ['工作调研', '学术研究', '活动报名', '产品反馈'] },48    { t: '您期望一份问卷的填写时长?', type: 'single', opts: ['1 分钟以内', '3 分钟以内', '5 分钟以上'] },49    { t: '您最关注问卷的哪些方面?(可多选)', type: 'multi', opts: ['题目设计', '匿名保护', '奖励回馈', '数据可信'] },50    { t: '对小草问卷调查的期待或建议', type: 'text' }51  ];5253  // ---------- 工具 ----------54  function go(route) { location.hash = route; }55  function goAttr(r) { return 'data-go="' + r + '"'; }56  function alertAttr(m) { return 'data-alert="' + m + '"'; }57  function esc(s) { return String(s).replace(/[&<>"]/g, function (c) { return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;' }[c]; }); }5859  function homeTop() {60    return '<div class="top"><div class="row"><div><h1>小草问卷调查</h1><div class="sub">轻松发布 · 高效回收</div></div>' +61      '<div class="iconbtn" ' + goAttr('message') + '>🔔</div></div>' +62      '<div class="search"><span>🔍</span><input placeholder="搜索问卷 / 话题" /></div></div>';63  }64  function innTop(t) {65    return '<div class="innTop"><span class="back" ' + goAttr('home') + '>‹</span><span class="t">' + esc(t) + '</span></div>';66  }6768  // ---------- 页面主体 ----------69  function homeBody() {70    var stats = '<div class="stats"><div class="st"><b>1.2w+</b><span>累计问卷</span></div>' +71      '<div class="st"><b>86w+</b><span>回收份数</span></div>' +72      '<div class="st"><b>98%</b><span>用户好评</span></div></div>';73    var cats = '<div class="section-t">问卷分类 <span class="more" ' + goAttr('list') + '>全部 ›</span></div><div class="cats">';74    CATS.forEach(function (c, i) { cats += '<div class="c" ' + goAttr('list?cat=' + i) + '><div class="ic">' + c.ic + '</div><div class="lb">' + c.lb + '</div></div>'; });75    cats += '</div>';76    var list = '<div class="section-t">热门问卷 <span class="more" ' + goAttr('list') + '>查看更多 ›</span></div>';77    QS.slice(0, 4).forEach(function (q) { list += qCard(q); });78    return stats + cats + list;79  }8081  function qCard(q) {82    return '<div class="card nb qcard" ' + goAttr('fill?id=' + q.id) + '>' +83      '<div class="thumb" style="background:' + q.grad + '">' + q.thumb + '</div>' +84      '<div class="info"><div class="ti">' + esc(q.ti) + '</div><div class="de">' + esc(q.de) + '</div>' +85      '<div class="tags">' + q.tags.map(function (t) { return '<span>' + esc(t) + '</span>'; }).join('') + '</div>' +86      '<div class="meta"><span>📝 ' + q.qn + ' 题</span><span>👥 ' + q.join + '</span><span class="rew">' + q.rew + '</span></div></div></div>';87  }8889  function listBody(q) {90    var title = '全部问卷';91    if (q && q.cat !== undefined && CATS[q.cat]) title = CATS[q.cat].lb;92    var body = '<div class="section-t" style="margin-top:14px">为你推荐</div>';93    QS.forEach(function (x) { body += qCard(x); });94    return innTop(title) + body;95  }9697  function fillBody(q) {98    var item = null;99    if (q && q.id) { for (var i = 0; i < QS.length; i++) if (QS[i].id === q.id) item = QS[i]; }100    item = item || QS[0];101    var h = innTop('填写问卷') +102      '<div class="card nb"><div style="font-weight:700;font-size:16px">' + esc(item.ti) + '</div>' +103      '<div class="tags" style="margin-top:8px"><span>' + esc(item.cat) + '</span><span>' + item.qn + ' 题</span><span class="rew" style="background:#fff3e8;color:#ff8a00">' + item.rew + '</span></div>' +104      '<div class="prog"><i style="width:0%"></i></div><div style="font-size:11px;color:#9aa3b0;margin-top:6px">预计 2 分钟 · 匿名保护</div></div>';105    Q_DEMO.forEach(function (qq, idx) {106      h += '<div class="q"><div class="qt"><span class="num">' + (idx + 1) + '.</span>' + esc(qq.t) + (qq.type !== 'text' ? '<span class="req">*</span>' : '') + '</div>';107      if (qq.type === 'text') {108        h += '<textarea class="field" style="margin:8px 0 0;width:100%;border:1px solid #e3e8f0;border-radius:10px;padding:11px;font-size:14px;outline:none" placeholder="请输入您的想法…"></textarea>';109      } else {110        qq.opts.forEach(function (o) {111          h += '<div class="opt" data-single="' + (qq.type === 'single' ? '1' : '0') + '"><span class="' + (qq.type === 'single' ? 'dot' : 'dot box') + '"></span>' + esc(o) + '</div>';112        });113      }114      h += '</div>';115    });116    h += '<div class="btn" data-fill-submit="1">提交问卷</div>';117    return h;118  }119120  function doneBody() {121    return '<div class="done"><div class="circle">✓</div><h2>提交成功,感谢参与!</h2>' +122      '<p>您获得 <b style="color:#ff8a00">+10 积分</b>,可在「我的」中查看</p>' +123      '<div class="btn ghost" ' + goAttr('home') + '>返回首页</div>' +124      '<div class="btn" ' + goAttr('knowledge') + '>读一篇问卷知识</div></div>';125  }126127  function publishBody() {128    var h = innTop('发布问卷') +129      '<div class="field"><label>问卷标题</label><input placeholder="例如:门店顾客满意度回访" /></div>' +130      '<div class="field"><label>问卷简介</label><textarea placeholder="一句话说明这份问卷的用途"></textarea></div>' +131      '<div class="field"><label>所属分类</label><select><option>市场调研</option><option>学术问卷</option><option>活动报名</option><option>产品反馈</option><option>员工测评</option><option>满意度</option></select></div>' +132      '<div class="section-t" style="margin:14px 16px 0">题目 <span class="more">已添加 2 题</span></div>';133    [['单选题','您对本次服务的整体满意度?'], ['多选题','您关注哪些方面?']].forEach(function (p) {134      h += '<div class="q"><div class="qt"><span class="num">●</span>' + p[0] + '</div><div class="opt"><span class="dot"></span>示例选项 A</div><div class="opt"><span class="dot"></span>示例选项 B</div></div>';135    });136    h += '<div class="qadd"><input placeholder="输入新题目后点击添加" /><div class="btn sm" ' + alertAttr('已添加题目') + '>添加</div></div>';137    h += '<div class="field" style="margin-top:0"><label>答题奖励</label><select><option>+10 积分</option><option>+20 积分</option><option>红包 1 元</option><option>无奖励</option></select></div>';138    h += '<div class="btn" data-publish="1">发布并公开</div>';139    return h;140  }141142  function mineBody() {143    var h = innTop('我的问卷') + '<div class="kpis"><div class="k"><b>' + USER.published + '</b><span>已发布</span></div>' +144      '<div class="k"><b>2.6k</b><span>总回收</span></div><div class="k"><b>92%</b><span>平均完成率</span></div></div>';145    MINE.forEach(function (m) {146      h += '<div class="card nb"><div style="display:flex;justify-content:space-between;align-items:center"><b>' + esc(m.ti) + '</b>' +147        '<span style="font-size:11px;color:#15a07e;background:#eafaf5;padding:2px 8px;border-radius:8px">' + m.status + '</span></div>' +148        '<div class="meta" style="display:flex;gap:12px;font-size:12px;color:#8a93a3;margin:8px 0 6px"><span>📝 ' + m.qn + ' 题</span><span>👥 ' + m.join + ' 份</span></div>' +149        '<div class="prog"><i style="width:' + Math.round(m.prog * 100) + '%"></i></div>' +150        '<div style="margin-top:10px"><span class="btn sm ghost" ' + goAttr('dash') + '>查看数据</span></div></div>';151    });152    return h;153  }154155  function dashBody() {156    var days = ['一', '二', '三', '四', '五', '六', '日'];157    var vals = [40, 62, 55, 80, 72, 95, 88];158    var max = 100;159    var bars = '<div class="bars">';160    vals.forEach(function (v, i) {161      var hh = Math.round(v / max * 120);162      bars += '<div class="b" style="height:' + hh + 'px"><i>' + v + '</i><em>周' + days[i] + '</em></div>';163    });164    bars += '</div>';165    return innTop('数据看板') +166      '<div class="kpis"><div class="k"><b>2,630</b><span>总回收</span></div><div class="k"><b>92%</b><span>完成率</span></div><div class="k"><b>4.7</b><span>平均分</span></div></div>' +167      '<div class="card nb"><div style="font-weight:700;margin-bottom:10px">近 7 天回收趋势</div>' + bars + '</div>' +168      '<div class="card nb"><div style="font-weight:700;margin-bottom:10px">满意度分布</div><div class="pie">' +169      '<div class="ring"></div><div class="lg"><div><b style="background:#15c39a"></b>非常满意 42%</div><div><b style="background:#1aa6e8"></b>满意 29%</div><div><b style="background:#ffb347"></b>一般 29%</div></div></div></div>' +170      '<div class="card nb" style="font-size:12px;color:#8a93a3">数据每小时更新,支持导出 Excel 与交叉分析。</div>';171  }172173  function knowledgeBody() {174    var h = innTop('问卷知识') + '<div class="section-t" style="margin-top:14px">精选阅读</div>';175    ARTS.forEach(function (a) {176      h += '<div class="card nb art" ' + goAttr('article?id=' + a.id) + '>' +177        '<div class="cv">' + a.cv + '</div><div style="flex:1;min-width:0"><div class="at">' + esc(a.ti) + '</div><div class="am">' + a.am + '</div></div></div>';178    });179    return h;180  }181182  function articleBody(q) {183    var a = ARTS[0];184    if (q && q.id) { for (var i = 0; i < ARTS.length; i++) if (ARTS[i].id === q.id) a = ARTS[i]; }185    return innTop('文章详情') +186      '<div class="card nb"><div style="font-weight:800;font-size:18px">' + esc(a.ti) + '</div>' +187      '<div class="am" style="font-size:12px;color:#9aa3b0;margin-top:6px">' + a.am + '</div></div>' +188      '<div class="card nb rich"><h3>一、先想清楚目标</h3><p>每一份好问卷都始于明确的目标:你想知道什么、决策依据是什么。目标越清晰,题目越聚焦。</p>' +189      '<div class="callout">💡 小技巧:用一句话写下「这份问卷要帮我决定什么」,它能筛掉 80% 的无效题目。</div>' +190      '<h3>二、题目要短而具体</h3><p>避免引导性、双重含义与专业术语。一道题只问一件事,选项互斥且覆盖全面。</p>' +191      '<h3>三、控制长度与节奏</h3><p>3 分钟以内、10 题左右是完成率最高的区间;开头放简单题,敏感题靠后。</p>' +192      '<h3>四、重视匿名与回馈</h3><p>明确告知匿名保护,并设置合理奖励,能显著提升回收质量与数量。</p></div>' +193      '<div class="btn ghost" ' + goAttr('knowledge') + '>返回知识列表</div>';194  }195196  function meBody() {197    return '<div class="profile"><div class="av">🌱</div><div><div class="pn">' + USER.name + '</div>' +198      '<div class="pp">' + USER.level + ' · ' + USER.phone + '</div></div></div>' +199      '<div class="kpis"><div class="k"><b>' + USER.points + '</b><span>我的积分</span></div><div class="k"><b>' + USER.answers + '</b><span>已答问卷</span></div><div class="k"><b>' + USER.published + '</b><span>已发布</span></div></div>' +200      '<div class="menu">' +201      '<div class="mi" ' + goAttr('mine') + '><span class="mi-ic">📋</span><span class="mi-t">我的问卷</span><span class="mi-r">›</span></div>' +202      '<div class="mi" ' + goAttr('dash') + '><span class="mi-ic">📊</span><span class="mi-t">数据看板</span><span class="mi-r">›</span></div>' +203      '<div class="mi" ' + goAttr('message') + '><span class="mi-ic">🔔</span><span class="mi-t">消息中心</span><span class="mi-r">›</span></div>' +204      '<div class="mi" ' + goAttr('publish') + '><span class="mi-ic">➕</span><span class="mi-t">发布问卷</span><span class="mi-r">›</span></div>' +205      '<div class="mi" ' + goAttr('about') + '><span class="mi-ic">ℹ️</span><span class="mi-t">关于小草</span><span class="mi-r">›</span></div></div>';206  }207208  function messageBody() {209    var h = innTop('消息中心');210    MSGS.forEach(function (m) {211      h += '<div class="card nb msg"><div class="md">' + m.md + '</div><div style="flex:1"><div class="mt">' + esc(m.mt) + '</div><div class="mx">' + esc(m.mx) + '</div><div class="mti">' + m.ti + '</div></div></div>';212    });213    return h;214  }215216  function aboutBody() {217    return '<div class="about"><div class="logo">🌱</div><h3>小草问卷调查</h3><p>轻松发布问卷,高效回收数据。<br>覆盖市场调研、学术问卷、活动报名、员工测评等场景,<br>让每一次提问都有价值。</p>' +218      '<div class="menu" style="text-align:left;margin-top:18px"><div class="mi"><span class="mi-ic">📞</span><span class="mi-t">商务合作</span><span class="mi-r">400-888-0666</span></div>' +219      '<div class="mi"><span class="mi-ic">🌐</span><span class="mi-t">官网</span><span class="mi-r">www.chixujiaoyu.com</span></div>' +220      '<div class="mi"><span class="mi-ic">⚖️</span><span class="mi-t">隐私与合规</span><span class="mi-r">›</span></div></div>' +221      '<p style="margin-top:18px;font-size:11px">版本 v2.6.0 · 西安小草网络 出品</p></div>';222  }223224  // ---------- 路由表 ----------225  var TAB = { home: 'home', list: 'home', fill: 'home', done: 'home', publish: 'publish', knowledge: 'knowledge', article: 'knowledge', me: 'me', message: 'me', mine: 'me', dash: 'me', about: 'me' };226  var ROUTES = {227    home: function () { return { top: homeTop(), body: homeBody(), tab: 'home' }; },228    list: function (q) { return { top: '', body: listBody(q), tab: 'home' }; },229    fill: function (q) { return { top: '', body: fillBody(q), tab: 'home' }; },230    done: function () { return { top: '', body: doneBody(), tab: 'home' }; },231    publish: function () { return { top: '', body: publishBody(), tab: 'publish' }; },232    knowledge: function () { return { top: '', body: knowledgeBody(), tab: 'knowledge' }; },233    article: function (q) { return { top: '', body: articleBody(q), tab: 'knowledge' }; },234    me: function () { return { top: '', body: meBody(), tab: 'me' }; },235    message: function () { return { top: '', body: messageBody(), tab: 'me' }; },236    mine: function () { return { top: '', body: mineBody(), tab: 'me' }; },237    dash: function () { return { top: '', body: dashBody(), tab: 'me' }; },238    about: function () { return { top: '', body: aboutBody(), tab: 'me' }; }239  };240241  function tabBar(active) {242    var items = [243      { k: 'home', ic: '🏠', lb: '广场' },244      { k: 'publish', ic: '➕', lb: '发布' },245      { k: 'knowledge', ic: '📚', lb: '知识' },246      { k: 'me', ic: '👤', lb: '我的' }247    ];248    var h = '<div class="tab">';249    items.forEach(function (it) {250      h += '<div class="ti ' + (it.k === active ? 'active' : '') + '" ' + goAttr(it.k) + '><span class="ti-ic">' + it.ic + '</span>' + it.lb + '</div>';251    });252    return h + '</div>';253  }254255  function render() {256    var h = location.hash.replace(/^#/, '') || 'home';257    var parts = h.split('?');258    var route = parts[0] || 'home';259    var q = {};260    if (parts[1]) parts[1].split('&').forEach(function (kv) { var a = kv.split('='); q[decodeURIComponent(a[0])] = decodeURIComponent(a[1] || ''); });261    var fn = ROUTES[route] || ROUTES.home;262    var r = fn(q);263    var tab = TAB[route] || 'home';264    var html = (r.top || '') + (r.body || '') + tabBar(tab);265    document.getElementById('app').innerHTML = html;266    window.scrollTo(0, 0);267  }268269  // ---------- 事件委托 ----------270  document.addEventListener('click', function (e) {271    var t = e.target;272    while (t && t !== document) {273      if (t.getAttribute && t.getAttribute('data-go')) { e.preventDefault(); go(t.getAttribute('data-go')); return; }274      if (t.getAttribute && t.getAttribute('data-alert')) { e.preventDefault(); alert(t.getAttribute('data-alert')); return; }275      if (t.getAttribute && t.getAttribute('data-fill-submit')) { e.preventDefault(); go('done'); return; }276      if (t.getAttribute && t.getAttribute('data-publish')) { e.preventDefault(); alert('问卷已提交审核,预计 1 小时内公开'); go('mine'); return; }277      if (t.classList && t.classList.contains('opt')) {278        var single = t.getAttribute('data-single');279        if (single === '1') {280          var sibs = t.parentNode.querySelectorAll('.opt');281          for (var i = 0; i < sibs.length; i++) sibs[i].classList.remove('sel');282          t.classList.add('sel');283        } else { t.classList.toggle('sel'); }284        return;285      }286      t = t.parentNode;287    }288  });289290  window.addEventListener('hashchange', render);291  render();292})();293