feat(fe): 评论改小红书式展开输入面板;FAB 统一暖橘;顶部去冗余入口

- 评论:底部平时一条细「说点什么」,点开才展开大写评论面板
  (大输入框+工具栏+发送,浮在键盘上方)。失焦时有草稿保持展开,
  避免点发送因面板收起而丢点击
- FAB 主题色统一:社区发帖 FAB 从深色改成和首页肉垫一致的暖橘圆钮
- 报告页顶部筛选去掉「添加」(报告页不需要建档入口)
- 社区去掉顶部「发布」按钮,发帖统一走右下角悬浮按钮

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Blizzard
2026-07-30 18:13:41 +08:00
parent 4f52a7d3a1
commit c48e241fe1
6 changed files with 71 additions and 46 deletions
@@ -80,6 +80,7 @@ Component({
commentImages: [], commentImages: [],
replyTo: {}, replyTo: {},
cmFocus: false, cmFocus: false,
composing: false, // 评论输入面板是否展开(收起时只是一条细条)
kbHeight: 0, kbHeight: 0,
total: 0, total: 0,
}, },
@@ -117,6 +118,7 @@ Component({
patch.commentImages = []; patch.commentImages = [];
patch.replyTo = {}; patch.replyTo = {};
patch.cmFocus = false; patch.cmFocus = false;
patch.composing = false;
patch.kbHeight = 0; patch.kbHeight = 0;
patch.saving = false; patch.saving = false;
} }
@@ -635,7 +637,7 @@ Component({
this.data.commentImages.map((i) => i.url), this.data.commentImages.map((i) => i.url),
this.data.replyTo.id || '', this.data.replyTo.id || '',
); );
this.setData({ commentText: '', commentImages: [], replyTo: {} }); this.setData({ commentText: '', commentImages: [], replyTo: {}, composing: false, cmFocus: false });
this.loadComments(); this.loadComments();
this.triggerEvent('commented'); this.triggerEvent('commented');
} catch (e) { } catch (e) {
@@ -661,7 +663,16 @@ Component({
onReplyTo(e) { onReplyTo(e) {
const { id, name } = e.currentTarget.dataset; const { id, name } = e.currentTarget.dataset;
if (!id) return; if (!id) return;
this.setData({ replyTo: { id, name }, cmFocus: true }); // 点任意评论直接展开面板并预填回复对象
this.setData({ replyTo: { id, name }, composing: true, cmFocus: true });
},
// 点细条:展开大输入面板并聚焦(拉起键盘)
onStartCompose() {
this.setData({ composing: true, cmFocus: true });
},
// 收起面板,草稿(文字/图片)留着,下次点开接着写
onCloseCompose() {
this.setData({ composing: false, cmFocus: false, kbHeight: 0 });
}, },
onCommentFocus(e) { onCommentFocus(e) {
// adjust-position=false,键盘高度自己接管:弹层是 fixed 定位, // adjust-position=false,键盘高度自己接管:弹层是 fixed 定位,
@@ -669,7 +680,10 @@ Component({
this.setData({ kbHeight: (e.detail && e.detail.height) || 0 }); this.setData({ kbHeight: (e.detail && e.detail.height) || 0 });
}, },
onCommentBlur() { onCommentBlur() {
this.setData({ kbHeight: 0, cmFocus: false }); // 失焦先放下键盘。有草稿就保持展开(否则点「发送」会因面板收起而丢掉这一下点击);
// 空内容才收回细条
const empty = !(this.data.commentText || '').trim() && !this.data.commentImages.length;
this.setData({ kbHeight: 0, cmFocus: false, composing: empty ? false : this.data.composing });
}, },
onCancelReply() { onCancelReply() {
this.setData({ replyTo: {} }); this.setData({ replyTo: {} });
@@ -68,29 +68,34 @@ module.exports.sel = function (map, key, index, def) {
</view> </view>
</scroll-view> </scroll-view>
<view class="cmp-dock" style="padding-bottom:{{kbHeight ? kbHeight + 'px' : 'calc(20rpx + env(safe-area-inset-bottom))'}}"> <!-- 收起态:一条细条,点了才展开成大写评论面板(小红书那套) -->
<view wx:if="{{replyTo.name}}" class="cm-replying"> <view wx:if="{{!composing}}" class="cm-collapsed" catchtap="onStartCompose">
<text>回复 {{replyTo.name}}</text> <view class="cm-collapsed-pill {{commentText ? 'has' : ''}}">{{commentText || '说点什么…'}}</view>
<view class="cm-cancel" catchtap="onCancelReply"><pt-icon name="close" size="{{24}}"></pt-icon></view> <view class="cm-collapsed-ic"><pt-icon name="photo" size="{{40}}"></pt-icon></view>
</view>
<!-- 展开态:大输入面板,浮在键盘上方 -->
<view wx:else class="cmp-dock" style="padding-bottom:{{kbHeight ? kbHeight + 'px' : 'calc(20rpx + env(safe-area-inset-bottom))'}}">
<view class="cm-dock-head">
<text class="cm-dock-title">{{replyTo.name ? '回复 ' + replyTo.name : '写评论'}}</text>
<view class="cm-dock-close" catchtap="onCloseCompose"><pt-icon name="close" size="{{30}}"></pt-icon></view>
</view> </view>
<view wx:if="{{commentImages.length}}" class="img-picker" style="margin-bottom:12rpx"> <textarea class="cm-ta" placeholder="{{replyTo.name ? '回复 @' + replyTo.name + '…' : '有爱评论,说点好听的~'}}"
placeholder-class="placeholder" value="{{commentText}}" bindinput="onCommentInput"
focus="{{cmFocus}}" bindfocus="onCommentFocus" bindblur="onCommentBlur"
maxlength="500" auto-height="{{true}}" show-confirm-bar="{{false}}"
adjust-position="{{false}}" cursor-spacing="12"></textarea>
<view wx:if="{{commentImages.length}}" class="img-picker" style="margin-top:12rpx">
<view wx:for="{{commentImages}}" wx:key="id" class="img-thumb"> <view wx:for="{{commentImages}}" wx:key="id" class="img-thumb">
<image src="{{item.url}}" mode="aspectFill"></image> <image src="{{item.url}}" mode="aspectFill"></image>
<view class="img-del" catchtap="onRemoveCommentImage" data-index="{{index}}"><pt-icon name="close" size="{{24}}"></pt-icon></view> <view class="img-del" catchtap="onRemoveCommentImage" data-index="{{index}}"><pt-icon name="close" size="{{24}}"></pt-icon></view>
</view> </view>
</view> </view>
<view class="cm-inputrow"> <view class="cm-toolbar">
<view class="cm-pic" catchtap="onPickCommentImages"> <view class="cm-pic" catchtap="onPickCommentImages"><pt-icon name="photo" size="{{44}}"></pt-icon></view>
<pt-icon name="photo" size="{{40}}"></pt-icon> <text class="cm-count">{{commentText.length}}/500</text>
</view>
<textarea class="cm-ta" placeholder="{{replyTo.name ? '回复 @' + replyTo.name : '有话要说,快来评论'}}"
placeholder-class="placeholder" value="{{commentText}}" bindinput="onCommentInput"
focus="{{cmFocus}}" bindfocus="onCommentFocus" bindblur="onCommentBlur"
maxlength="500" auto-height="{{true}}" show-confirm-bar="{{false}}"
adjust-position="{{false}}" cursor-spacing="12"></textarea>
<view class="cm-send {{commentText ? 'on' : ''}}" catchtap="onSendComment">发送</view> <view class="cm-send {{commentText ? 'on' : ''}}" catchtap="onSendComment">发送</view>
</view> </view>
<text wx:if="{{commentText.length}}" class="cm-count">{{commentText.length}}/500</text>
</view> </view>
</block> </block>
@@ -136,22 +136,35 @@
background:var(--primary-soft);color:var(--primary-ink);font-size:var(--fs-cap); background:var(--primary-soft);color:var(--primary-ink);font-size:var(--fs-cap);
} }
.cm-cancel{display:flex;align-items:center} .cm-cancel{display:flex;align-items:center}
/* 相机 + 输入框 + 发送 合成一条圆角输入栏,像聊天输入条; /* 收起态:底部一条细条,点了才展开成大面板(小红书那套) */
textarea 撑开时相机和发送贴着底部 */ .cm-collapsed{
.cm-inputrow{ flex:none;display:flex;align-items:center;gap:var(--sp-3);
display:flex;align-items:flex-end;gap:var(--sp-2); background:#fff;border-top:1rpx solid var(--line);
background:var(--surface-2);border:1rpx solid var(--line); padding:var(--sp-3) var(--sp-5) calc(20rpx + env(safe-area-inset-bottom));
border-radius:32rpx;padding:10rpx var(--sp-2) 10rpx var(--sp-3);
} }
.cm-pic{flex:none;display:flex;align-items:center;height:64rpx;color:var(--muted)} .cm-collapsed-pill{
flex:1;min-width:0;height:76rpx;line-height:76rpx;padding:0 var(--sp-5);
border-radius:var(--r-full);background:var(--surface-2);color:var(--muted2);
font-size:var(--fs-md);overflow:hidden;white-space:nowrap;text-overflow:ellipsis;
}
.cm-collapsed-pill.has{color:var(--text)}
.cm-collapsed-ic{flex:none;display:flex;align-items:center;color:var(--muted)}
/* 展开态:大写评论面板 */
.cm-dock-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--sp-2)}
.cm-dock-title{font-size:var(--fs-md);font-weight:var(--fw-b);color:var(--text)}
.cm-dock-close{display:flex;align-items:center;color:var(--muted);padding:var(--sp-1)}
.cm-ta{ .cm-ta{
flex:1;min-width:0;min-height:64rpx;max-height:280rpx;height:auto; width:100%;box-sizing:border-box;min-height:200rpx;max-height:520rpx;height:auto;
padding:16rpx 0;background:transparent;font-size:var(--fs-md);line-height:1.4; padding:var(--sp-4);background:var(--surface-2);border-radius:var(--r-md);
font-size:var(--fs-lg);line-height:1.5;
} }
.cm-toolbar{display:flex;align-items:center;gap:var(--sp-3);margin-top:var(--sp-3)}
.cm-pic{flex:none;display:flex;align-items:center;color:var(--muted)}
.cm-count{margin-left:auto;color:var(--muted2);font-size:var(--fs-cap)}
.cm-send{ .cm-send{
flex:none;height:64rpx;padding:0 var(--sp-4);border-radius:var(--r-full); flex:none;height:76rpx;padding:0 var(--sp-6);border-radius:var(--r-full);
display:flex;align-items:center;justify-content:center; display:flex;align-items:center;justify-content:center;
background:var(--line);color:#fff;font-size:var(--fs-sm);font-weight:var(--fw-b);transition:.16s ease; background:var(--line);color:#fff;font-size:var(--fs-md);font-weight:var(--fw-b);transition:.16s ease;
} }
.cm-send.on{background:var(--cta)} .cm-send.on{background:var(--cta)}
.cm-count{display:block;text-align:right;margin-top:6rpx;color:var(--muted2);font-size:var(--fs-cap)}
+7 -12
View File
@@ -1,22 +1,17 @@
/* 统一暖橘圆钮:首页肉垫和社区发帖用同一套主题色 */
.fab{ .fab{
position:fixed;right:36rpx;bottom:calc(190rpx + env(safe-area-inset-bottom)); position:fixed;right:36rpx;bottom:calc(190rpx + env(safe-area-inset-bottom));
width:108rpx;height:108rpx;border-radius:var(--r-md); width:112rpx;height:112rpx;border-radius:50%;
background:var(--cta); background:linear-gradient(150deg,#FFB865,#F5943E);
color:#fff; color:#fff;
display:flex;align-items:center;justify-content:center; display:flex;align-items:center;justify-content:center;
box-shadow:var(--sd-2); box-shadow:0 12rpx 28rpx rgba(214,138,52,.42),0 2rpx 6rpx rgba(214,138,52,.3);
z-index:60; z-index:60;
} }
.fab:active{transform:scale(.96)} .fab:active{transform:scale(.94)}
/* 肉垫造型:暖橘圆钮,中间一只奶白肉垫。圆形更像脚印落下的样子, /* 肉垫造型:和基础一致的暖橘圆钮,中间一只奶白肉垫 */
阴影带橘调让它从奶白背景上浮起来 */ .fab-paw{width:116rpx;height:116rpx}
.fab-paw{
width:116rpx;height:116rpx;border-radius:50%;
background:linear-gradient(150deg,#FFB865,#F5943E);
box-shadow:0 12rpx 28rpx rgba(214,138,52,.42),0 2rpx 6rpx rgba(214,138,52,.3);
}
.fab-paw:active{transform:scale(.94)}
.paw{position:relative;width:66rpx;height:60rpx} .paw{position:relative;width:66rpx;height:60rpx}
/* 掌垫:上窄下宽的圆角心形块,坐在下方 */ /* 掌垫:上窄下宽的圆角心形块,坐在下方 */
+1 -3
View File
@@ -3,11 +3,9 @@ module.exports.isUrl = function (s) { return s && s.indexOf('http') === 0; }
</wxs> </wxs>
<nav-bar title="宠友圈"></nav-bar> <nav-bar title="宠友圈"></nav-bar>
<!-- 发帖统一走右下角悬浮按钮,顶部不再放发布按钮 -->
<view class="top-bar feed-bar"> <view class="top-bar feed-bar">
<seg-tabs items="{{feedTabs}}" current="{{feedIdx}}" bind:change="switchFeedTab"></seg-tabs> <seg-tabs items="{{feedTabs}}" current="{{feedIdx}}" bind:change="switchFeedTab"></seg-tabs>
<view class="feed-post" bindtap="openSheet" data-type="createPost">
<pt-icon name="plus" size="{{28}}"></pt-icon>发布
</view>
</view> </view>
<scroll-view class="page-scroll" scroll-y="{{true}}" scroll-into-view="{{intoView}}" bindscroll="onFeedScroll" enhanced="{{true}}" show-scrollbar="{{false}}"> <scroll-view class="page-scroll" scroll-y="{{true}}" scroll-into-view="{{intoView}}" bindscroll="onFeedScroll" enhanced="{{true}}" show-scrollbar="{{false}}">
+1 -1
View File
@@ -1,6 +1,6 @@
<nav-bar title="成长报告"></nav-bar> <nav-bar title="成长报告"></nav-bar>
<view class="top-bar"><pet-switch bind:add="onAddPet"></pet-switch></view> <view class="top-bar"><pet-switch show-add="{{false}}"></pet-switch></view>
<scroll-view class="page-scroll" scroll-y="{{true}}" enhanced="{{true}}" show-scrollbar="{{false}}"> <scroll-view class="page-scroll" scroll-y="{{true}}" enhanced="{{true}}" show-scrollbar="{{false}}">
<view class="page-body tab-nofab"> <view class="page-body tab-nofab">