diff --git a/packages/common b/packages/common index 484a04e43..8b565d28d 160000 --- a/packages/common +++ b/packages/common @@ -1 +1 @@ -Subproject commit 484a04e4317f3ed559f0f7e6d0ae17ea530c3073 +Subproject commit 8b565d28da2a7e99e9a9e2d03784b2670c3bd402 diff --git a/packages/pro-components/chat/chat-actionbar/README.md b/packages/pro-components/chat/chat-actionbar/README.md index 8b8e0fe4a..4c2f58267 100644 --- a/packages/pro-components/chat/chat-actionbar/README.md +++ b/packages/pro-components/chat/chat-actionbar/README.md @@ -52,10 +52,11 @@ comment | String | - | 评价内容 | N content | String | - | 被复制的内容 | N copy-mode | String | markdown | 【实验】复制内容的模式,可选 'markdown'(复制markdown原文)或 'text'(复制纯文本)。可选项:markdown/text | N disabled | Boolean | false | 【讨论中】操作按钮是否可点击 | N -placement | String | start | 【实验】操作栏位置。可选项:start/end/space-around/space-between | N +long-press-position | Object | - | 【实验】长按触发点的位置信息,用于定位 popover。TS 类型:`{pageX: number; pageY: number; clientX: number; clientY: number; x: number; y: number}` | N +placement | String | start | 【实验】操作栏位置。可选项:start/end/space-around/space-between/longpress | N ### ChatActionbar Events 名称 | 参数 | 描述 -- | -- | -- -actions | `(detail: {name: string, active: boolean})` | 点击点赞,点踩,复制,分享,重新生成按钮时触发发 +actions | `(detail: {name: string, active: boolean, chatId: string})` | 点击点赞,点踩,复制,分享,重新生成按钮时触发发 diff --git a/packages/pro-components/chat/chat-actionbar/chat-actionbar.less b/packages/pro-components/chat/chat-actionbar/chat-actionbar.less index 05d6960a2..073727bc4 100644 --- a/packages/pro-components/chat/chat-actionbar/chat-actionbar.less +++ b/packages/pro-components/chat/chat-actionbar/chat-actionbar.less @@ -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: 8rpx 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; @@ -25,6 +29,63 @@ 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; + max-width: 544rpx; + + // 顶部三角形 + &::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; + display: flex; + flex-wrap: wrap; + gap: 4rpx; + + &--column { + gap: 8rpx; + } + } + + .@{chat-actionbar}__item--popover { + color: #fff; + background-color: unset; + padding: 0; + margin: 0; + font-size: 28rpx; + line-height: 42rpx; + width: 128rpx; + height: 156rpx; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 8rpx; + } + } + // 内部容器 &__inner { background-color: @bg-color-secondarycontainer; @@ -42,14 +103,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; - } } // 左侧内容 @@ -62,8 +115,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; diff --git a/packages/pro-components/chat/chat-actionbar/chat-actionbar.ts b/packages/pro-components/chat/chat-actionbar/chat-actionbar.ts index 2a8a560eb..43a5aad14 100644 --- a/packages/pro-components/chat/chat-actionbar/chat-actionbar.ts +++ b/packages/pro-components/chat/chat-actionbar/chat-actionbar.ts @@ -17,6 +17,7 @@ export default class ChatActionbar extends SuperComponent { actions: [], classPrefix: name, pComment: '', + computedPlacement: '', iconMap: { good: 'thumb-up', bad: 'thumb-down', @@ -28,17 +29,25 @@ 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(); }, + longPressPosition(newVal) { + if (this.properties.placement === 'longpress') { + if (newVal) { + this.showPopover(newVal); + } else { + this.hidePopover(); + } + } + }, }; methods = { @@ -95,6 +104,7 @@ export default class ChatActionbar extends SuperComponent { this.triggerEvent('actions', { name, active: !isActive, + chatId: this.properties.chatId, }); } else if (name === 'bad') { const isActive = this.data.pComment === 'bad'; @@ -104,10 +114,12 @@ export default class ChatActionbar extends SuperComponent { this.triggerEvent('actions', { name, active: !isActive, + chatId: this.properties.chatId, }); } else { this.triggerEvent('actions', { name, + chatId: this.properties.chatId, }); } }, @@ -122,6 +134,12 @@ export default class ChatActionbar extends SuperComponent { }); }, + setComputedPlacement() { + this.setData({ + computedPlacement: this.properties.placement || 'start', + }); + }, + setActions() { const baseActions = []; if (Array.isArray(this.properties.actionBar)) { @@ -143,6 +161,24 @@ export default class ChatActionbar extends SuperComponent { actions: baseActions, }); }, + + setPComment(newVal) { + this.setData({ + pComment: newVal || '', + }); + }, + + showPopover(pos) { + const lineNumber = Math.min(this.data.actions.length, 4); + const width = (lineNumber * 128 + (lineNumber - 1) * 8 + 16 * 2) / 2; + this.setData({ + popoverPosition: `top:${pos.y}px;left:${pos.x}px;margin-left:-${width}rpx`, + }); + }, + + hidePopover() { + this.setData({ popoverPosition: '' }); + }, }; lifetimes = { @@ -150,6 +186,9 @@ export default class ChatActionbar extends SuperComponent { 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() { diff --git a/packages/pro-components/chat/chat-actionbar/chat-actionbar.wxml b/packages/pro-components/chat/chat-actionbar/chat-actionbar.wxml index af86db22b..84ab8158e 100644 --- a/packages/pro-components/chat/chat-actionbar/chat-actionbar.wxml +++ b/packages/pro-components/chat/chat-actionbar/chat-actionbar.wxml @@ -1,11 +1,13 @@ - + @@ -13,22 +15,24 @@ + {{item.name}} diff --git a/packages/pro-components/chat/chat-actionbar/props.ts b/packages/pro-components/chat/chat-actionbar/props.ts index f75f62193..4df0e18b4 100644 --- a/packages/pro-components/chat/chat-actionbar/props.ts +++ b/packages/pro-components/chat/chat-actionbar/props.ts @@ -41,6 +41,11 @@ const props: TdChatActionbarProps = { type: String, value: 'start', }, + /** 【实验】长按触发点的位置信息,用于定位 popover */ + longPressPosition: { + type: Object, + value: null, + }, }; export default props; diff --git a/packages/pro-components/chat/chat-actionbar/type.ts b/packages/pro-components/chat/chat-actionbar/type.ts index f600f0d52..5a6d1a920 100644 --- a/packages/pro-components/chat/chat-actionbar/type.ts +++ b/packages/pro-components/chat/chat-actionbar/type.ts @@ -59,6 +59,20 @@ export interface TdChatActionbarProps { */ placement?: { type: StringConstructor; - value?: 'start' | 'end' | 'space-around' | 'space-between'; + value?: 'start' | 'end' | 'space-around' | 'space-between' | 'longpress'; + }; + /** + * 【实验】长按触发点的位置信息,用于定位 popover + */ + longPressPosition?: { + type: ObjectConstructor; + value?: { + pageX: number; + pageY: number; + clientX: number; + clientY: number; + x: number; + y: number; + }; }; } diff --git a/packages/pro-components/chat/chat-list/_example/base/index.js b/packages/pro-components/chat/chat-list/_example/base/index.js index 0ee1a13b1..fbbc33fe3 100644 --- a/packages/pro-components/chat/chat-list/_example/base/index.js +++ b/packages/pro-components/chat/chat-list/_example/base/index.js @@ -1,6 +1,12 @@ import Toast from 'tdesign-miniprogram/toast'; import { getNavigationBarHeight } from '../../../utils/utils'; +let uniqueId = 0; +const getUniqueKey = () => { + uniqueId += 1; + return `key-${uniqueId}`; +}; + const mockData = `南极的自动提款机并没有一个特定的专属名称,但历史上确实有一台ATM机曾短暂存在于南极的**麦克默多站**(McMurdo Station)。这台ATM由美国**富兰克林国家银行**(Wells Fargo)于1998年安装,主要供驻扎在该站的科研人员使用。不过,由于南极的极端环境和极低的人口密度,这台ATM机并未长期运行,最终被移除。 **背景补充:** @@ -40,20 +46,23 @@ Component({ role: 'assistant', status: 'complete', content: [ - { - type: 'text', - data: '它叫 McMurdo Station ATM,是美国富国银行安装在南极洲最大科学中心麦克默多站的一台自动提款机。', - }, - ], + { + type: 'text', + data: '它叫 McMurdo Station ATM,是美国富国银行安装在南极洲最大科学中心麦克默多站的一台自动提款机。', + }, + ], + chatId: getUniqueKey(), + comment: '', }, { - role: 'user', - content: [ - { - type: 'text', - data: '牛顿第一定律是否适用于所有参考系?', - }, - ], + role: 'user', + content: [ + { + type: 'text', + data: '牛顿第一定律是否适用于所有参考系?', + }, + ], + chatId: getUniqueKey(), }, ], value: '', // 输入框的值 @@ -62,6 +71,9 @@ Component({ inputStyle: '', // 输入框样式 contentHeight: '100vh', // 内容高度 animation: 'dots', + activePopoverId: '', // 当前打开悬浮actionbar的chatId + activePopoverComment: '', // 当前打开悬浮actionbar的comment + longPressPosition: null, // 长按位置对象 }, methods: { @@ -89,6 +101,7 @@ Component({ data: value.trim(), }, ], + chatId: getUniqueKey(), }; // 将用户消息插入到chatList的开头(因为reverse为true,所以用unshift) @@ -122,7 +135,7 @@ Component({ // 模拟助手回复 simulateAssistantReply() { - this.setData({ loading: true}); + this.setData({ loading: true }); // 请求中 const assistantMessage = { role: 'assistant', @@ -134,6 +147,8 @@ Component({ ], avatar: 'https://tdesign.gtimg.com/site/chat-avatar.png', status: 'pending', + chatId: getUniqueKey(), + comment: '', }; this.setData({ chatList: [assistantMessage, ...this.data.chatList], @@ -141,15 +156,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({ @@ -163,7 +178,7 @@ Component({ }); }, handleAction(e) { - const { name, active, data } = e.detail; + const { name, active, data, chatId } = e.detail; let message = ''; switch (name) { @@ -193,6 +208,48 @@ Component({ message, theme: 'success', }); + + if (name === 'good' || name === 'bad') { + this.data.chatList.forEach((item) => { + if (item.chatId === chatId) { + item.comment = active ? name : ''; + } + }); + this.setData({ + chatList: this.data.chatList, + }); + } + }, + showPopover(e) { + const { id, longPressPosition } = e.detail; + let comment = ''; + let role = ''; + this.data.chatList.forEach((item) => { + if (item.chatId === id) { + comment = item.comment; + role = item.role; + } + }); + + // 仅当 role 为 user 时才显示 popover + if (role !== 'user') { + return; + } + + this.setData({ + activePopoverId: id, + activePopoverComment: comment, + longPressPosition, + }); + }, + hidePopover() { + this.setData({ + longPressPosition: null, + }); + }, + handlePopoverAction(e) { + e.detail.chatId = this.data.activePopoverId; + this.handleAction(e); }, }, lifetimes: { diff --git a/packages/pro-components/chat/chat-list/_example/base/index.wxml b/packages/pro-components/chat/chat-list/_example/base/index.wxml index 9dc4cfa35..7db468520 100644 --- a/packages/pro-components/chat/chat-list/_example/base/index.wxml +++ b/packages/pro-components/chat/chat-list/_example/base/index.wxml @@ -1,7 +1,8 @@ - + + diff --git a/packages/pro-components/chat/chat-message/README.md b/packages/pro-components/chat/chat-message/README.md index fc5551ec3..a7c49d155 100644 --- a/packages/pro-components/chat/chat-message/README.md +++ b/packages/pro-components/chat/chat-message/README.md @@ -79,7 +79,7 @@ variant | String | base | 气泡框样式,支持基础、线框、文字三种 名称 | 参数 | 描述 -- | -- | -- -longpress | `(detail: { id: string })` | \- +message-longpress | `(detail: { id: string, longPressPosition: { x: number, y: number } })` | 长按事件 ### ChatMessage Slots diff --git a/packages/pro-components/chat/chat-message/chat-message.ts b/packages/pro-components/chat/chat-message/chat-message.ts index 8fbb36542..9f3337199 100644 --- a/packages/pro-components/chat/chat-message/chat-message.ts +++ b/packages/pro-components/chat/chat-message/chat-message.ts @@ -43,9 +43,13 @@ export default class ChatMessage extends SuperComponent { methods = { handleLongPress(e) { - this.triggerEvent('longpress', { + this.triggerEvent('message-longpress', { e, id: this.data.chatId, + longPressPosition: { + x: e.detail.x, + y: e.detail.y, + }, }); }, setShowAvatar() { diff --git a/packages/pro-components/chat/chat-sender/_example/attachments/index.wxml b/packages/pro-components/chat/chat-sender/_example/attachments/index.wxml index 6b5f70cb3..ad7d29793 100644 --- a/packages/pro-components/chat/chat-sender/_example/attachments/index.wxml +++ b/packages/pro-components/chat/chat-sender/_example/attachments/index.wxml @@ -32,11 +32,11 @@ > - + 深度思考 - + diff --git a/packages/pro-components/chat/chat-sender/_example/base/index.wxml b/packages/pro-components/chat/chat-sender/_example/base/index.wxml index 6cc3463ea..f3270e0a4 100644 --- a/packages/pro-components/chat/chat-sender/_example/base/index.wxml +++ b/packages/pro-components/chat/chat-sender/_example/base/index.wxml @@ -33,11 +33,11 @@ > - + 深度思考 - + diff --git a/packages/pro-components/chat/chat-sender/_example/content-citation/index.wxml b/packages/pro-components/chat/chat-sender/_example/content-citation/index.wxml index 380ac3f68..de25dc45e 100644 --- a/packages/pro-components/chat/chat-sender/_example/content-citation/index.wxml +++ b/packages/pro-components/chat/chat-sender/_example/content-citation/index.wxml @@ -41,11 +41,11 @@ - + 深度思考 - + diff --git a/packages/pro-components/chat/chat-sender/_example/file-citation/index.wxml b/packages/pro-components/chat/chat-sender/_example/file-citation/index.wxml index 3874da7d8..2baf2595b 100644 --- a/packages/pro-components/chat/chat-sender/_example/file-citation/index.wxml +++ b/packages/pro-components/chat/chat-sender/_example/file-citation/index.wxml @@ -49,11 +49,11 @@ - + 深度思考 - +