feat(我的): 意见反馈——功能问题/建议/其他 + 截图 + 联系方式,我提交过的 (v26100423)
后端 box_app 新增 /api/mp/public/mama-box/feedback(POST/GET)与管理端 /api/mama-box/feedbacks Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
35
index.html
35
index.html
@@ -7,7 +7,7 @@
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<title>兜爸心选 · 孕育陪伴</title>
|
||||
<!-- V:26100422 缓存版本标记:改 css/js 时同步 bump 该值(与 js/app.js 的 VER 同源),静态资源按 mtime 走 ETag 自动刷新 -->
|
||||
<!-- V:26100423 缓存版本标记:改 css/js 时同步 bump 该值(与 js/app.js 的 VER 同源),静态资源按 mtime 走 ETag 自动刷新 -->
|
||||
<link rel="stylesheet" href="mama-box.css">
|
||||
<script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
|
||||
<!-- 共享助手:授权/跳商城/位置上报(分享卡片同步,见 docs/h5-auth-standard.md 第四节) -->
|
||||
@@ -1174,6 +1174,8 @@
|
||||
<button class="svc ripple hide" id="meBoxCard"><span class="sv-ico o"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true"><rect x="4.5" y="10.5" width="15" height="9.5" rx="2" fill="none" stroke="currentColor" stroke-width="1.8"/><rect x="3.3" y="7.2" width="17.4" height="3.6" rx="1.3" fill="none" stroke="currentColor" stroke-width="1.8"/><path d="M12 7.2V20M12 7.2C10.4 3.8 7 4.3 8 6.4c.6 1 2.4.9 4 .8zM12 7.2c1.6-3.4 5-2.9 4-.8-.6 1-2.4.9-4 .8z" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linejoin="round"/></svg></span><span class="sv-t">孕期卡册</span><span class="sv-badge" id="meBoxV"></span></button>
|
||||
<button class="svc ripple" data-open="detailSetting" data-set="privacy"><span class="sv-ico p"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true"><rect x="4.5" y="10" width="15" height="10.5" rx="3" fill="none" stroke="currentColor" stroke-width="1.8"/><path d="M8.2 10V7.6a3.8 3.8 0 0 1 7.6 0V10" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/><circle cx="12" cy="15.2" r="1.5" fill="currentColor"/></svg></span><span class="sv-t">隐私权限</span></button>
|
||||
<button class="svc ripple" data-open="detailSetting" data-set="help"><span class="sv-ico o"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true"><path d="M12 4.2c4.5 0 7.8 2.8 7.8 6.4s-3.3 6.4-7.8 6.4c-.7 0-1.3-.06-1.9-.18l-3.6 2.3a.4.4 0 0 1-.6-.45l.8-2.9c-1.5-1.16-2.3-2.7-2.3-4.4 0-3.6 3.1-6.4 7.6-6.4z" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round"/><path d="M9.9 9.4a2.2 2.2 0 0 1 4.2.8c0 1.5-2.1 1.6-2.1 3" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg></span><span class="sv-t">帮助反馈</span></button>
|
||||
<!-- 2026-10-04 意见反馈(用户:「我的页面里加一个客服反馈,功能上的反馈、功能上的建议」)→ #modalFeedback,提交到 box_app /api/mp/public/mama-box/feedback -->
|
||||
<button class="svc ripple" id="meFeedback"><span class="sv-ico g"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true"><path d="M5.5 4.8h13a1.7 1.7 0 0 1 1.7 1.7v8.6a1.7 1.7 0 0 1-1.7 1.7H11l-4.1 3a.4.4 0 0 1-.64-.32V16.8H5.5a1.7 1.7 0 0 1-1.7-1.7V6.5a1.7 1.7 0 0 1 1.7-1.7z" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round"/><path d="M8.2 9.3h7.6M8.2 12.5h4.8" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg></span><span class="sv-t">意见反馈</span></button>
|
||||
<button class="svc ripple" data-open="detailSetting" data-set="about"><span class="sv-ico b"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true"><circle cx="12" cy="12" r="8.2" fill="none" stroke="currentColor" stroke-width="1.8"/><path d="M12 11v5.4" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round"/><circle cx="12" cy="7.9" r="1.15" fill="currentColor"/></svg></span><span class="sv-t">关于我们</span></button>
|
||||
</div>
|
||||
<!-- 退出授权登录:仅已授权时显示(applyRemoteProfile 控制 style.display)。
|
||||
@@ -1766,6 +1768,37 @@
|
||||
<div class="modal-foot"><button class="dl-btn main" id="bxAddrSave">提交</button></div>
|
||||
</section>
|
||||
|
||||
<!-- 意见反馈(2026-10-04)。类型 → 描述 → 截图(选填,最多 3 张,走 /api/upload)→ 联系方式(选填)→ 提交。
|
||||
底部「我提交过的」列出最近几条和处理状态 / 回复(运营在管理端 PUT /api/mama-box/feedbacks/{id} 标记)。 -->
|
||||
<section class="modal fb-modal" id="modalFeedback" data-autofocus="off" role="dialog" aria-modal="true" aria-labelledby="fbTitle">
|
||||
<div class="modal-head">
|
||||
<h3 id="fbTitle">意见反馈</h3>
|
||||
<button class="modal-x" data-modal="close" aria-label="关闭">
|
||||
<svg viewBox="0 0 24 24" width="15" height="15" aria-hidden="true"><path d="M6 6l12 12M18 6L6 18" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
<p class="fb-lead">哪里不好用、想要什么新功能,都可以告诉我们,每一条都会认真看。</p>
|
||||
<div class="fb-kinds" id="fbKinds" role="radiogroup" aria-label="反馈类型">
|
||||
<button type="button" class="fb-kind" data-kind="bug" role="radio" aria-checked="false">功能问题</button>
|
||||
<button type="button" class="fb-kind on" data-kind="idea" role="radio" aria-checked="true">功能建议</button>
|
||||
<button type="button" class="fb-kind" data-kind="other" role="radio" aria-checked="false">其他</button>
|
||||
</div>
|
||||
<div class="fb-ta-wrap">
|
||||
<textarea class="fb-ta" id="fbText" maxlength="500" placeholder="说说你遇到的问题或想法…"></textarea>
|
||||
<span class="fb-count" id="fbCount">0/500</span>
|
||||
</div>
|
||||
<div class="fb-imgs" id="fbImgs">
|
||||
<label class="fb-add" id="fbAdd"><input type="file" accept="image/*" id="fbFile" hidden><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true"><path d="M12 6v12M6 12h12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg><span>截图</span></label>
|
||||
<span class="fb-imgs-tip">选填,最多 3 张</span>
|
||||
</div>
|
||||
<label class="fld fb-contact"><span>联系方式(选填)</span><input id="fbContact" type="text" maxlength="40" placeholder="手机号或微信号,方便我们回复你"></label>
|
||||
<div class="modal-foot"><button class="dl-btn main" id="fbSubmit">提交</button></div>
|
||||
<div class="fb-mine" id="fbMine" hidden>
|
||||
<h4>我提交过的</h4>
|
||||
<div id="fbMineList"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 同周悄悄话 · 全屏页(2026-10-02 二改)。「深夜星河」:深靛紫夜空 + 星点,悄悄话是一盏盏漂浮的玻璃泡,
|
||||
抱抱越多越亮越大;最上面是今晚抱抱最多的一句,大字。底部一颗发光的「说一句悄悄话」。
|
||||
层级 z 110:盖住 tabbar(60),低于说一句弹窗(modal 120+),所以在这页里点「说一句」弹窗能盖在上面。 -->
|
||||
|
||||
92
js/app.js
92
js/app.js
@@ -3,7 +3,7 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
/* 页面版本号(YYMMDD+序号):显示在「关于兜爸心选」页底部;bump 时同步 head 注释与 ?v= */
|
||||
var VER = '26100422';
|
||||
var VER = '26100423';
|
||||
const $ = (s, c) => (c || document).querySelector(s);
|
||||
const $$ = (s, c) => Array.from((c || document).querySelectorAll(s));
|
||||
|
||||
@@ -839,6 +839,91 @@
|
||||
}));
|
||||
modalScrim.addEventListener('click', closeModal);
|
||||
|
||||
/* ================= 意见反馈(2026-10-04) =================
|
||||
用户:「在我的页面里加一个客服反馈,功能上的反馈、功能上的建议」。
|
||||
入口:「我的」常用服务 #meFeedback;「帮助与反馈」里的「提交反馈或建议」行(data-fb)。
|
||||
提交:POST /api/mp/public/mama-box/feedback?openid=&unionid= {kind,text,images,contact,ctx}
|
||||
服务端规则(box_app FeedbackService):5~500 字、截图只认本站 /api/upload 地址、每人每天 10 条。
|
||||
截图:前端先压到长边 1600 的 JPEG 再传(手机原图动辄 5MB+),最多 3 张。 */
|
||||
(function () {
|
||||
const M = $('#modalFeedback'); if (!M) return;
|
||||
const ta = $('#fbText'), cnt = $('#fbCount'), add = $('#fbAdd'), file = $('#fbFile'), box = $('#fbImgs'), btn = $('#fbSubmit');
|
||||
let kind = 'idea', imgs = [], busy = 0; // imgs: [{el, url|null}]
|
||||
const API = '/api/mp/public/mama-box/feedback';
|
||||
const ident = () => { const o = hashParam('openid'), u = hashParam('unionid');
|
||||
return o ? 'openid=' + encodeURIComponent(o) + (u ? '&unionid=' + encodeURIComponent(u) : '') : ''; };
|
||||
$$('.fb-kind', M).forEach(b => b.addEventListener('click', () => {
|
||||
kind = b.dataset.kind;
|
||||
$$('.fb-kind', M).forEach(x => { x.classList.toggle('on', x === b); x.setAttribute('aria-checked', x === b ? 'true' : 'false'); });
|
||||
ta.placeholder = kind === 'bug' ? '哪个功能、怎么操作的时候出了问题?截个图会更快定位哦' : kind === 'idea' ? '想要什么新功能,或者哪里可以做得更好?' : '想对我们说的话…';
|
||||
}));
|
||||
ta.addEventListener('input', () => { cnt.textContent = ta.value.length + '/500'; });
|
||||
const syncAdd = () => add.classList.toggle('hide', imgs.length >= 3);
|
||||
function shrink(f) {
|
||||
return new Promise(res => {
|
||||
const u = URL.createObjectURL(f), im = new Image();
|
||||
im.onload = () => {
|
||||
const k = Math.min(1, 1600 / Math.max(im.width, im.height)), c = document.createElement('canvas');
|
||||
c.width = Math.round(im.width * k); c.height = Math.round(im.height * k);
|
||||
c.getContext('2d').drawImage(im, 0, 0, c.width, c.height); URL.revokeObjectURL(u);
|
||||
c.toBlob(b => res(b || f), 'image/jpeg', .85);
|
||||
};
|
||||
im.onerror = () => { URL.revokeObjectURL(u); res(f); };
|
||||
im.src = u;
|
||||
});
|
||||
}
|
||||
file.addEventListener('change', () => {
|
||||
const f = file.files && file.files[0]; file.value = '';
|
||||
if (!f || imgs.length >= 3) return;
|
||||
const it = { url: null, el: el('span', 'fb-thumb up') };
|
||||
const pv = document.createElement('img'); pv.alt = ''; pv.src = URL.createObjectURL(f); it.el.appendChild(pv);
|
||||
const x = el('button', '', '×'); x.type = 'button'; x.setAttribute('aria-label', '删除这张');
|
||||
x.addEventListener('click', () => { imgs = imgs.filter(i => i !== it); it.el.remove(); syncAdd(); });
|
||||
it.el.appendChild(x); box.insertBefore(it.el, add); imgs.push(it); syncAdd(); busy++;
|
||||
shrink(f).then(b => { const fd = new FormData(); fd.append('file', b, 'feedback.jpg'); return fetch('/api/upload', { method: 'POST', body: fd }); })
|
||||
.then(r => r.json()).then(j => { it.url = j && j.result && j.result.url || null; if (!it.url) throw 0; it.el.classList.remove('up'); })
|
||||
.catch(() => { toast('截图上传失败,可以删掉重新选'); it.el.classList.remove('up'); it.el.classList.add('bad'); })
|
||||
.finally(() => { busy--; });
|
||||
});
|
||||
function renderMine(list) {
|
||||
const wrap = $('#fbMine'), L = $('#fbMineList');
|
||||
if (!list || !list.length) { wrap.hidden = true; return; }
|
||||
wrap.hidden = false; L.innerHTML = '';
|
||||
list.slice(0, 5).forEach(f => {
|
||||
const d = el('div', 'fb-item'), h = el('div', 'fb-item-h');
|
||||
h.appendChild(el('b', '', f.kindName)); h.appendChild(el('span', '', fmtWhen(f.at)));
|
||||
h.appendChild(el('span', 'fb-st' + (f.status === 'done' ? ' done' : ''), f.status === 'done' ? '已处理' : '已收到'));
|
||||
d.appendChild(h); d.appendChild(el('div', '', f.text));
|
||||
if (f.reply) d.appendChild(el('div', 'fb-reply', '兜爸心选回复:' + f.reply));
|
||||
L.appendChild(d);
|
||||
});
|
||||
}
|
||||
function loadMine() { const q = ident(); if (!q) return;
|
||||
fetch(API + '?' + q).then(r => r.json()).then(j => renderMine(j && j.result && j.result.list)).catch(() => {}); }
|
||||
function open() { openModal('modalFeedback'); loadMine(); }
|
||||
const entry = $('#meFeedback'); if (entry) entry.addEventListener('click', open);
|
||||
document.addEventListener('click', e => { const r = e.target.closest && e.target.closest('[data-fb]'); if (r) { e.preventDefault(); open(); } });
|
||||
btn.addEventListener('click', () => {
|
||||
const text = ta.value.trim();
|
||||
if (text.length < 5) { toast('再多写几个字吧(至少 5 个字)'); ta.focus(); return; }
|
||||
if (busy) { toast('截图还在上传,稍等一下'); return; }
|
||||
const q = ident(); if (!q) { toast('请从小程序里打开后再提交'); return; }
|
||||
btn.disabled = true; btn.textContent = '提交中…';
|
||||
fetch(API + '?' + q, { method: 'POST', headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ kind, text, images: imgs.map(i => i.url).filter(Boolean), contact: $('#fbContact').value.trim(),
|
||||
ctx: { ver: VER, ua: navigator.userAgent.slice(0, 300), from: 'me' } }) })
|
||||
.then(r => r.json()).then(j => {
|
||||
if (!j || j.code !== 200) { toast((j && j.message) || '提交失败,请稍后再试'); return; }
|
||||
toast('收到啦,谢谢你的反馈 💛');
|
||||
ta.value = ''; cnt.textContent = '0/500'; $('#fbContact').value = '';
|
||||
imgs.forEach(i => i.el.remove()); imgs = []; syncAdd();
|
||||
loadMine();
|
||||
})
|
||||
.catch(() => toast('网络不太好,请稍后再试'))
|
||||
.finally(() => { btn.disabled = false; btn.textContent = '提交'; });
|
||||
});
|
||||
})();
|
||||
|
||||
/* ================= 孕期信息 =================
|
||||
预产期是唯一的「源」:填了它就按今天倒推出孕周 + 额外天数;
|
||||
没填时那两格 disabled(置灰不可编辑)。算出来之后用户可以微调,
|
||||
@@ -1569,7 +1654,7 @@
|
||||
groups: [
|
||||
{ t: '联系我们', rows: [
|
||||
['row', '在线客服', '9:00 – 21:00'],
|
||||
['row', '提交反馈或建议', '截图一起发给我们'],
|
||||
['row', '提交反馈或建议', '功能问题、建议都可以', 'fb'], // 2026-10-04 真能提交了 → 打开 #modalFeedback
|
||||
['row', '加入内测群', '抢先体验新功能']
|
||||
] }
|
||||
],
|
||||
@@ -1616,6 +1701,9 @@
|
||||
const rows = g.rows.map(r => {
|
||||
/* .st-para 而不是 .st-txt:后者是首页成长脚印在用的类名 */
|
||||
if (r[0] === 'txt') return '<p class="st-para">' + r[1] + '</p>';
|
||||
if (r[0] === 'row' && r[3] === 'fb')
|
||||
return '<button class="st-row ripple" data-fb="1"><span class="st-rt">' + r[1] + '</span>' +
|
||||
'<span class="st-rv">' + r[2] + '</span><i class="chev">›</i></button>';
|
||||
if (r[0] === 'row')
|
||||
return '<button class="st-row ripple" data-toast="' + r[1] + (r[2] ? ' · ' + r[2] : '') + '">' +
|
||||
'<span class="st-rt">' + r[1] + '</span>' +
|
||||
|
||||
31
mama-box.css
31
mama-box.css
@@ -4498,3 +4498,34 @@ a.skip:focus{left:16px;top:16px}
|
||||
/* 2026-10-04 羊水深度层:在宝宝下面(z1),正常混合,能压暗也能提亮;画满后盖住 CSS 背景(CSS 背景留作降级/首帧) */
|
||||
.hero-water{position:absolute;z-index:1;left:0;top:0;width:100%;height:100%;pointer-events:none;opacity:0;transition:opacity 1s ease}
|
||||
.hero-water.is-on{opacity:1}
|
||||
|
||||
/* ============ 2026-10-04 意见反馈(「我的」常用服务 → #modalFeedback) ============ */
|
||||
.sv-ico.g{background:#E6F5EE;color:#2F9A6A}
|
||||
.fb-modal{max-height:88vh;overflow-y:auto;-webkit-overflow-scrolling:touch}
|
||||
.fb-lead{margin:6px 0 14px;font-size:13px;line-height:1.6;color:var(--muted)}
|
||||
.fb-kinds{display:flex;gap:8px}
|
||||
.fb-kind{flex:1;display:flex;align-items:center;justify-content:center;height:36px;border-radius:12px;border:1.5px solid #EFE3DA;background:#fff;color:var(--ink-2);font-size:13.5px;font-weight:700}
|
||||
.fb-kind.on{border-color:var(--brand);background:#FFF1EC;color:var(--brand)}
|
||||
.fb-ta-wrap{position:relative;margin-top:12px}
|
||||
.fb-ta{display:block;width:100%;box-sizing:border-box;height:128px;resize:none;padding:13px 15px 26px;border-radius:14px;border:1.5px solid #EFE3DA;
|
||||
background:#fff;font:inherit;font-size:14.5px;line-height:1.6;color:var(--ink)}
|
||||
.fb-ta:focus{outline:none;border-color:var(--brand);box-shadow:0 0 0 3px rgba(244,89,60,.12)}
|
||||
.fb-count{position:absolute;right:12px;bottom:8px;font-size:11.5px;color:#B9AAA0}
|
||||
.fb-imgs{display:flex;align-items:center;gap:8px;margin-top:12px;flex-wrap:wrap}
|
||||
.fb-add{width:64px;height:64px;border-radius:12px;border:1.5px dashed #E2CFC2;background:#fff;color:#B49A8A;
|
||||
display:flex;flex-direction:column;align-items:center;justify-content:center;gap:1px;font-size:11px}
|
||||
.fb-add.hide{display:none}
|
||||
.fb-thumb{position:relative;width:64px;height:64px;border-radius:12px;overflow:hidden;background:#F2E8E1}
|
||||
.fb-thumb img{width:100%;height:100%;object-fit:cover;display:block}
|
||||
.fb-thumb.up::after{content:"上传中";position:absolute;inset:0;display:grid;place-items:center;background:rgba(0,0,0,.35);color:#fff;font-size:11px}
|
||||
.fb-thumb button{position:absolute;top:3px;right:3px;width:18px;height:18px;border-radius:50%;border:0;background:rgba(0,0,0,.5);color:#fff;font-size:12px;line-height:18px;padding:0}
|
||||
.fb-imgs-tip{font-size:12px;color:#B9AAA0}
|
||||
.fb-contact{margin-top:12px}
|
||||
.fb-mine{margin-top:18px;padding-top:14px;border-top:1px solid #EFE3DA}
|
||||
.fb-mine h4{margin:0 0 8px;font-size:13.5px;color:var(--ink-2)}
|
||||
.fb-item{padding:10px 12px;border-radius:12px;background:#fff;margin-top:8px;font-size:13px;line-height:1.55;color:var(--ink)}
|
||||
.fb-item-h{display:flex;align-items:center;gap:6px;margin-bottom:3px;font-size:11.5px;color:var(--muted)}
|
||||
.fb-item-h b{font-weight:700;color:var(--ink-2)}
|
||||
.fb-st{margin-left:auto;padding:1px 7px;border-radius:999px;background:#F3ECE6;color:#A08D80;font-size:11px}
|
||||
.fb-st.done{background:#E6F5EE;color:#2F9A6A}
|
||||
.fb-reply{margin-top:6px;padding:7px 9px;border-radius:9px;background:#FFF6EF;color:#9A5A3C;font-size:12.5px}
|
||||
|
||||
Reference in New Issue
Block a user