Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 57 additions & 14 deletions packages/pro-components/chat/chat-actionbar/chat-actionbar.less
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,18 @@
@chat-actionbar: ~'@{prefix}-chat-actionbar';

@chat-actionbar-padding: var(--chat-actionbar-padding, 0);
@chat-actionbar-item-padding: var(--chat-actionbar-item-padding, 16rpx 28rpx);
@chat-actionbar-item-padding: var(--chat-actionbar-item-padding, 4rpx 28rpx);
@chat-actionbar-item-margin: 12rpx 0;
@chat-actionbar-item-color: @text-color-primary;
@chat-actionbar-item-active: @brand-color;

// TODO: 长按弹出层样式
@chat-actionbar-popover-background: @mask-active;
@chat-actionbar-popover-radius: 32rpx;
@chat-actionbar-popover-padding: 45rpx;
@chat-actionbar-popover-background: rgba(0, 0, 0, 0.9);
@chat-actionbar-popover-radius: 6rpx;
@chat-actionbar-popover-padding: 40rpx 16rpx;
@chat-actionbar-popover-padding-tri-width: 24rpx;
@chat-actionbar-popover-padding-tri-height: 10rpx;
@chat-actionbar-popover-item-color: @font-white-1;

.@{chat-actionbar} {
display: flex;
Expand All @@ -25,6 +29,53 @@
justify-content: flex-end;
}

// 弹出层
&--popover {
position: fixed;
display: none;
padding: @chat-actionbar-popover-padding;
color: @font-white-1;
background-color: @chat-actionbar-popover-background;
border-radius: @chat-actionbar-popover-radius;

// 顶部三角形
&::before {
content: '';
position: absolute;
top: calc(@chat-actionbar-popover-padding-tri-height * -2);
left: 50%;
transform: translateX(-50%);
width: 0;
height: 0;
border-left: @chat-actionbar-popover-padding-tri-width solid transparent;
border-right: @chat-actionbar-popover-padding-tri-width solid transparent;
border-bottom: calc(@chat-actionbar-popover-padding-tri-height * 2) solid @chat-actionbar-popover-background;
}

&.popover-visible {
display: block;
}

.@{chat-actionbar}__inner {
background-color: unset;
border: none;

&--column {
gap: 8rpx;
}
}

.@{chat-actionbar}__item--popover {
color: #fff;
background-color: unset;
padding: 0;
font-size: 28rpx;
line-height: 42rpx;
width: 128rpx;
text-align: center;
}
}

// 内部容器
&__inner {
background-color: @bg-color-secondarycontainer;
Expand All @@ -42,14 +93,6 @@
align-items: center;
justify-content: space-between;
}

// 弹出层
&--popover {
padding: @chat-actionbar-popover-padding;
background-color: @chat-actionbar-popover-background;
border-radius: @chat-actionbar-popover-radius;
color: @font-white-1;
}
}

// 左侧内容
Expand All @@ -62,8 +105,8 @@
// 操作项
&__item {
color: @chat-actionbar-item-color;
margin: 12rpx 0;
padding: 4rpx 28rpx;
margin: @chat-actionbar-item-margin;
padding: @chat-actionbar-item-padding;
border-right: 2rpx solid @component-stroke;
background-color: unset;
outline: none;
Expand Down
32 changes: 29 additions & 3 deletions packages/pro-components/chat/chat-actionbar/chat-actionbar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export default class ChatActionbar extends SuperComponent {
actions: [],
classPrefix: name,
pComment: '',
computedPlacement: '',
iconMap: {
good: 'thumb-up',
bad: 'thumb-down',
Expand All @@ -28,13 +29,12 @@ export default class ChatActionbar extends SuperComponent {
good: 'thumb-up-filled',
bad: 'thumb-down-filled',
},
popoverPosition: '',
};

observers = {
comment(newVal) {
this.setData({
pComment: newVal || '',
});
this.setPComment(newVal);
},
'actionBar, pComment'() {
this.setActions();
Expand Down Expand Up @@ -122,6 +122,12 @@ export default class ChatActionbar extends SuperComponent {
});
},

setComputedPlacement() {
this.setData({
computedPlacement: this.properties.placement || 'start',
});
},

setActions() {
const baseActions = [];
if (Array.isArray(this.properties.actionBar)) {
Expand All @@ -143,13 +149,33 @@ export default class ChatActionbar extends SuperComponent {
actions: baseActions,
});
},

setPComment(newVal) {
this.setData({
pComment: newVal || '',
});
},

showPopover(str) {
const width = (this.data.actions.length * 128 + (this.data.actions.length - 1) * 8 + 16 * 2) / 2;
this.setData({
popoverPosition: `${str};margin-left:-${width}rpx`,
});
},

hidePopover() {
this.setData({ popoverPosition: '' });
},
};

lifetimes = {
created() {
this.data.filterSpecialChars = this.filterSpecialChars.bind(this);
this.data.handleActionClick = this.handleActionClick.bind(this);
this.data.handleCopy = this.handleCopy.bind(this);
this.data.showPopover = this.showPopover.bind(this);
this.data.hidePopover = this.hidePopover.bind(this);
this.data.setPComment = this.setPComment.bind(this);
},

attached() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,38 @@
<wxs src="../../../components/common/utils.wxs" module="_" />
<!-- TODO: api 可选项 longpress 下个版本迭代发布长按气泡样式 -->
<view
class="class {{[classPrefix, placement==='longpress' ? classPrefix+'__inner--popover' : '', computedPlacement]}}"
style="{{_._style([style, customStyle])}}"
class="{{[classPrefix, placement==='longpress' ? classPrefix+'--popover' : '', computedPlacement, popoverPosition ? 'popover-visible' : '']}}"
style="{{_._style([style, customStyle, popoverPosition])}}"
>
<view class="{{classPrefix}}__inner {{classPrefix}}__inner--column">
<view class="{{classPrefix}}__item {{classPrefix}}__left">
<view
class="{{classPrefix}}__left {{placement==='longpress' ? classPrefix+'__item--popover' : classPrefix+'__item'}}"
>
<slot name="prefix" />
</view>
<block wx:for="{{actions}}" wx:for-item="item" wx:for-index="index" wx:key="index">
<!-- 分享按钮使用 button 标签 -->
<button
wx:if="{{item.name === 'share'}}"
data-name="{{item.name}}"
class="{{_.cls(classPrefix + '__item', [['active', item.isActive]])}}"
class="{{_.cls(placement==='longpress' ? classPrefix+'__item--popover' : classPrefix+'__item', [['active', item.isActive]])}}"
open-type="{{content ? 'share' : 'none'}}"
data-chat-id="{{chatId}}"
bindtap="handleActionClick"
>
<t-icon name="{{item.isActive ? iconActiveMap[item.name] : iconMap[item.name]}}" size="40rpx" />
<view wx:if="{{placement==='longpress'}}" class="{{classPrefix}}__item__text">{{item.name}}</view>
</button>

<!-- 其他按钮使用 view 标签 -->
<view
wx:else
data-name="{{item.name}}"
class="{{_.cls(classPrefix + '__item', [['active', item.isActive]])}}"
class="{{_.cls(placement==='longpress' ? classPrefix+'__item--popover' : classPrefix+'__item', [['active', item.isActive]])}}"
bindtap="handleActionClick"
>
<t-icon name="{{item.isActive ? iconActiveMap[item.name] : iconMap[item.name]}}" size="40rpx" />
<view wx:if="{{placement==='longpress'}}" class="{{classPrefix}}__item__text">{{item.name}}</view>
</view>
</block>
</view>
Expand Down
2 changes: 1 addition & 1 deletion packages/pro-components/chat/chat-actionbar/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,6 @@ export interface TdChatActionbarProps {
*/
placement?: {
type: StringConstructor;
value?: 'start' | 'end' | 'space-around' | 'space-between';
value?: 'start' | 'end' | 'space-around' | 'space-between' | 'longpress';
};
}
73 changes: 51 additions & 22 deletions packages/pro-components/chat/chat-list/_example/base/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,20 @@ Component({
role: 'assistant',
status: 'complete',
content: [
{
type: 'text',
data: '它叫 McMurdo Station ATM,是美国富国银行安装在南极洲最大科学中心麦克默多站的一台自动提款机。',
},
],
{
type: 'text',
data: '它叫 McMurdo Station ATM,是美国富国银行安装在南极洲最大科学中心麦克默多站的一台自动提款机。',
},
],
},
{
role: 'user',
content: [
{
type: 'text',
data: '牛顿第一定律是否适用于所有参考系?',
},
],
role: 'user',
content: [
{
type: 'text',
data: '牛顿第一定律是否适用于所有参考系?',
},
],
},
],
value: '', // 输入框的值
Expand All @@ -62,6 +62,7 @@ Component({
inputStyle: '', // 输入框样式
contentHeight: '100vh', // 内容高度
animation: 'dots',
activePopover: '',
},

methods: {
Expand Down Expand Up @@ -122,7 +123,7 @@ Component({

// 模拟助手回复
simulateAssistantReply() {
this.setData({ loading: true});
this.setData({ loading: true });
// 请求中
const assistantMessage = {
role: 'assistant',
Expand All @@ -141,15 +142,15 @@ Component({
const that = this;
wx.nextTick(() => {
fetchStream(mockData, {
success(result) {
// 生文中
that.data.chatList[0].status = 'streaming';
if (!that.data.loading) return;
that.data.chatList[0].content[0].data += result;
that.setData({
chatList: that.data.chatList,
});
},
success(result) {
// 生文中
that.data.chatList[0].status = 'streaming';
if (!that.data.loading) return;
that.data.chatList[0].content[0].data += result;
that.setData({
chatList: that.data.chatList,
});
},
complete() {
that.data.chatList[0].status = 'complete';
that.setData({
Expand Down Expand Up @@ -194,6 +195,34 @@ Component({
theme: 'success',
});
},
showPopover(e) {
const { e: event, id } = e.detail;
const child = this.selectComponent('.popover-actionbar');
const actionbar = this.selectComponent(`#actionbar-${id}`);
if (child) {
this.setData({
activePopover: id,
});
child.__data__.setPComment(actionbar.__data__.pComment);
child.__data__.showPopover(`top:${event.detail.y}px;left:${event.detail.x}px`);
}
},
hidePopover() {
const child = this.selectComponent('.popover-actionbar');
if (child) {
child.__data__.hidePopover();
}
},
handlePopoverAction(e) {
const { name } = e.detail;

this.handleAction(e);
if (name === 'good' || name === 'bad') {
const actionbar = this.selectComponent(`#actionbar-${this.data.activePopover}`);
const child = this.selectComponent('.popover-actionbar');
actionbar.__data__.setPComment(child.__data__.pComment);
}
},
},
lifetimes: {
attached: function () {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
<view class="chat-box" style="height: {{contentHeight}};">
<view class="chat-box" style="height: {{contentHeight}};" bind:tap="hidePopover">
<t-chat id="chatList" bindscroll="onScroll">
<block wx:for="{{chatList}}" wx:key="index">
<t-chat-message
chatId="{{index}}"
avatar="{{item.avatar || ''}}"
name="{{item.name || ''}}"
datetime="{{item.datetime || ''}}"
content="{{item.content}}"
role="{{item.role}}"
placement="{{item.role === 'user' ? 'right' : 'left'}}"
status="{{item.status || ''}}"
bind:message-longpress="showPopover"
>
<t-chat-actionbar
wx:if="{{chatIndex !== chatList.length - 1 && item.status === 'complete' && item.role === 'assistant'}}"
wx:if="{{index !== chatList.length - 1 && item.status === 'complete' && item.role === 'assistant'}}"
id="{{'actionbar-'+index}}"
slot="actionbar"
placement="end"
bind:actions="handleAction"
Expand All @@ -31,6 +34,7 @@
/>
</view>
</t-chat>
<t-chat-actionbar class="popover-actionbar" placement="longpress" bind:actions="handlePopoverAction" />
<!-- 内置虚拟列表优化性能仅在data属性中使用 -->
<!-- <t-chat id="chatList" bindscroll="onScroll" data="{{chatList}}"></t-chat> -->
</view>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export default class ChatMessage extends SuperComponent {

methods = {
handleLongPress(e) {
this.triggerEvent('longpress', {
this.triggerEvent('message-longpress', {
e,
id: this.data.chatId,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@
>
<view slot="footer-prefix" class="demo-footer-prefix">
<view class="deep-think-block {{deepThinkActive ? 'active' : ''}}" bind:tap="onDeepThinkTap">
<t-icon name="system-sum" size="40rpx" />
<t-icon name="system-sum" size="36rpx" />
<text class="deep-think-text">深度思考</text>
</view>
<view class="net-search-block {{ netSearchActive ? 'active' : '' }}" bind:tap="onNetSearchTap">
<t-icon name="internet" size="40rpx" />
<t-icon name="internet" size="36rpx" />
</view>
</view>
</t-chat-sender>
Expand Down
Loading
Loading