Bläddra i källkod

家政消息迁移

suyuanyuan 1 dag sedan
förälder
incheckning
9aecfb52e9
100 ändrade filer med 2942 tillägg och 0 borttagningar
  1. 5 0
      TUIKit-Homemaking/.npmignore
  2. 3 0
      TUIKit-Homemaking/.npmrc
  3. 112 0
      TUIKit-Homemaking/CHANGELOG.md
  4. 54 0
      TUIKit-Homemaking/README.md
  5. 14 0
      TUIKit-Homemaking/adapter-vue.ts
  6. 12 0
      TUIKit-Homemaking/assets/icon/add.svg
  7. 12 0
      TUIKit-Homemaking/assets/icon/at.svg
  8. 6 0
      TUIKit-Homemaking/assets/icon/audio.svg
  9. 16 0
      TUIKit-Homemaking/assets/icon/back.svg
  10. 6 0
      TUIKit-Homemaking/assets/icon/call-video.svg
  11. 6 0
      TUIKit-Homemaking/assets/icon/call-voice.svg
  12. BIN
      TUIKit-Homemaking/assets/icon/call.png
  13. BIN
      TUIKit-Homemaking/assets/icon/camera-uni.png
  14. 23 0
      TUIKit-Homemaking/assets/icon/cancel.svg
  15. 3 0
      TUIKit-Homemaking/assets/icon/check-sm.svg
  16. 3 0
      TUIKit-Homemaking/assets/icon/close-dark.svg
  17. BIN
      TUIKit-Homemaking/assets/icon/close-image.png
  18. 7 0
      TUIKit-Homemaking/assets/icon/convertText_en.svg
  19. 8 0
      TUIKit-Homemaking/assets/icon/convertText_zh.svg
  20. 5 0
      TUIKit-Homemaking/assets/icon/d-left-arrow.svg
  21. 5 0
      TUIKit-Homemaking/assets/icon/d-right-arrow.svg
  22. 25 0
      TUIKit-Homemaking/assets/icon/del-icon.svg
  23. 1 0
      TUIKit-Homemaking/assets/icon/double-arrow.svg
  24. 3 0
      TUIKit-Homemaking/assets/icon/down-icon.svg
  25. BIN
      TUIKit-Homemaking/assets/icon/downaload-image.png
  26. 6 0
      TUIKit-Homemaking/assets/icon/download.svg
  27. 7 0
      TUIKit-Homemaking/assets/icon/edit.svg
  28. 10 0
      TUIKit-Homemaking/assets/icon/evaluate.svg
  29. BIN
      TUIKit-Homemaking/assets/icon/face-uni.png
  30. BIN
      TUIKit-Homemaking/assets/icon/face.png
  31. BIN
      TUIKit-Homemaking/assets/icon/files.png
  32. 7 0
      TUIKit-Homemaking/assets/icon/icon-arrow-left.svg
  33. 36 0
      TUIKit-Homemaking/assets/icon/icon-c2c.svg
  34. 6 0
      TUIKit-Homemaking/assets/icon/icon-close.svg
  35. BIN
      TUIKit-Homemaking/assets/icon/image-uni.png
  36. BIN
      TUIKit-Homemaking/assets/icon/image.png
  37. 3 0
      TUIKit-Homemaking/assets/icon/input-close.svg
  38. 6 0
      TUIKit-Homemaking/assets/icon/left-arrow.svg
  39. BIN
      TUIKit-Homemaking/assets/icon/loading.gif
  40. BIN
      TUIKit-Homemaking/assets/icon/loading.png
  41. 6 0
      TUIKit-Homemaking/assets/icon/minus.svg
  42. BIN
      TUIKit-Homemaking/assets/icon/more-uni.png
  43. BIN
      TUIKit-Homemaking/assets/icon/more.png
  44. 1 0
      TUIKit-Homemaking/assets/icon/msg-audio.svg
  45. 30 0
      TUIKit-Homemaking/assets/icon/msg-copy.svg
  46. 33 0
      TUIKit-Homemaking/assets/icon/msg-del.svg
  47. 31 0
      TUIKit-Homemaking/assets/icon/msg-forward.svg
  48. 8 0
      TUIKit-Homemaking/assets/icon/msg-quote.svg
  49. 29 0
      TUIKit-Homemaking/assets/icon/msg-revoke.svg
  50. 8 0
      TUIKit-Homemaking/assets/icon/mute.svg
  51. 7 0
      TUIKit-Homemaking/assets/icon/plus.svg
  52. 14 0
      TUIKit-Homemaking/assets/icon/right-arrow.svg
  53. 3 0
      TUIKit-Homemaking/assets/icon/right-icon.svg
  54. 7 0
      TUIKit-Homemaking/assets/icon/rotate-left.svg
  55. 7 0
      TUIKit-Homemaking/assets/icon/rotate-right.svg
  56. 52 0
      TUIKit-Homemaking/assets/icon/search-default.svg
  57. 7 0
      TUIKit-Homemaking/assets/icon/search-more.svg
  58. 5 0
      TUIKit-Homemaking/assets/icon/search.svg
  59. 27 0
      TUIKit-Homemaking/assets/icon/selected.svg
  60. 8 0
      TUIKit-Homemaking/assets/icon/setting.svg
  61. BIN
      TUIKit-Homemaking/assets/icon/star-light.png
  62. BIN
      TUIKit-Homemaking/assets/icon/star.png
  63. 6 0
      TUIKit-Homemaking/assets/icon/start-group.svg
  64. 12 0
      TUIKit-Homemaking/assets/icon/translate.svg
  65. BIN
      TUIKit-Homemaking/assets/icon/video-play.png
  66. BIN
      TUIKit-Homemaking/assets/icon/video-uni.png
  67. BIN
      TUIKit-Homemaking/assets/icon/video.png
  68. 9 0
      TUIKit-Homemaking/assets/icon/words.svg
  69. 9 0
      TUIKit-Homemaking/assets/icon/zoom-in.svg
  70. 9 0
      TUIKit-Homemaking/assets/icon/zoom-out.svg
  71. 59 0
      TUIKit-Homemaking/assets/styles/common.scss
  72. 99 0
      TUIKit-Homemaking/assets/styles/sample.scss
  73. 62 0
      TUIKit-Homemaking/components/TUIChat/chat-header/index.vue
  74. 24 0
      TUIKit-Homemaking/components/TUIChat/config.ts
  75. 132 0
      TUIKit-Homemaking/components/TUIChat/forward/index.vue
  76. 6 0
      TUIKit-Homemaking/components/TUIChat/index.ts
  77. 299 0
      TUIKit-Homemaking/components/TUIChat/index.vue
  78. 168 0
      TUIKit-Homemaking/components/TUIChat/message-input-toolbar/emoji-picker/emoji-picker-dialog.vue
  79. 2 0
      TUIKit-Homemaking/components/TUIChat/message-input-toolbar/emoji-picker/index.ts
  80. 78 0
      TUIKit-Homemaking/components/TUIChat/message-input-toolbar/emoji-picker/index.vue
  81. 25 0
      TUIKit-Homemaking/components/TUIChat/message-input-toolbar/emoji-picker/style/h5.scss
  82. 4 0
      TUIKit-Homemaking/components/TUIChat/message-input-toolbar/emoji-picker/style/index.scss
  83. 55 0
      TUIKit-Homemaking/components/TUIChat/message-input-toolbar/emoji-picker/style/web.scss
  84. 2 0
      TUIKit-Homemaking/components/TUIChat/message-input-toolbar/evaluate/index.ts
  85. 213 0
      TUIKit-Homemaking/components/TUIChat/message-input-toolbar/evaluate/index.vue
  86. 57 0
      TUIKit-Homemaking/components/TUIChat/message-input-toolbar/evaluate/style/color.scss
  87. 63 0
      TUIKit-Homemaking/components/TUIChat/message-input-toolbar/evaluate/style/h5.scss
  88. 4 0
      TUIKit-Homemaking/components/TUIChat/message-input-toolbar/evaluate/style/index.scss
  89. 93 0
      TUIKit-Homemaking/components/TUIChat/message-input-toolbar/evaluate/style/web.scss
  90. 2 0
      TUIKit-Homemaking/components/TUIChat/message-input-toolbar/file-upload/index.ts
  91. 74 0
      TUIKit-Homemaking/components/TUIChat/message-input-toolbar/file-upload/index.vue
  92. 2 0
      TUIKit-Homemaking/components/TUIChat/message-input-toolbar/image-upload/index.ts
  93. 146 0
      TUIKit-Homemaking/components/TUIChat/message-input-toolbar/image-upload/index.vue
  94. 2 0
      TUIKit-Homemaking/components/TUIChat/message-input-toolbar/index.ts
  95. 255 0
      TUIKit-Homemaking/components/TUIChat/message-input-toolbar/index.vue
  96. 2 0
      TUIKit-Homemaking/components/TUIChat/message-input-toolbar/otgoing-call/index.ts
  97. 117 0
      TUIKit-Homemaking/components/TUIChat/message-input-toolbar/otgoing-call/index.vue
  98. 54 0
      TUIKit-Homemaking/components/TUIChat/message-input-toolbar/server/index.vue
  99. 105 0
      TUIKit-Homemaking/components/TUIChat/message-input-toolbar/style/uni.scss
  100. 0 0
      TUIKit-Homemaking/components/TUIChat/message-input-toolbar/toolbar-item-container/index.vue

+ 5 - 0
TUIKit-Homemaking/.npmignore

@@ -0,0 +1,5 @@
+node_modules
+package-lock.json
+pnpm-lock.yaml
+dist
+**/dist/

+ 3 - 0
TUIKit-Homemaking/.npmrc

@@ -0,0 +1,3 @@
+auto-install-peers=true
+strict-peer-dependencies=false
+# shamefully-hoist=true

+ 112 - 0
TUIKit-Homemaking/CHANGELOG.md

@@ -0,0 +1,112 @@
+## [2.1.3] (2024-05-17)
+
+### Features
+- TUIKit 适配 uniapp cli
+- 点击空白区域时收起小表情面板和工具栏
+- callkit 提供音视频通话中途加人能力 不包括app平台
+
+### Fix
+- 修复视频一定概率无法播放的问题
+- 修复消息引用的视觉左侧未对齐的问题
+
+## [2.1.1] (2024-04-26)
+
+### Features
+- 支持语音转文字
+- 文本消息转翻译兼容小表情上屏,兼容提及所有人
+
+### Fix
+- 优化已读回执详情列表超长昵称的显示效果
+- 解决转发消息已读回执失效的问题
+- 解决加没有群申请时额外请求用户信息的问题
+
+## [2.1.0] (2024-04-12)
+
+### Features
+- 新增消息翻译功能
+
+### Fix
+- uniapp 修复选人组件搜索失效问题
+
+## [2.0.9] (2024-03-29)
+
+### Features
+- ScrollButton 支持未读新消息提示
+- 群未决申请展示优化
+
+### Update
+- 下线本地审核相关入口
+
+### Fix
+- 修复 nick 过长样式溢出问题
+
+## [2.0.8] (2024-03-15)
+
+### Fix
+- 修复已知问题,提升稳定性
+
+## [2.0.7] (2024-03-15)
+
+### Features
+- 会话列表菜单出现位置跟随手指
+
+### Fix
+- 修复一定概率下图片无法预览的问题
+
+## [2.0.6] (2024-03-01)
+
+### Features
+
+- 升级 universal api 引入方式
+- 支持 TUISearch 消息云端搜索
+
+## [2.0.5] (2024-02-04)
+
+### Features
+
+- 聊天界面更新黄脸小表情
+- 添加音频播放动画
+
+### Fix
+
+- 语音场景优化 修复了语音播放相关的体验问题
+
+## [2.0.4] (2024-01-19)
+
+### Features
+
+- 支持文本消息复制
+
+### Fix
+
+- 修复 uniapp 打包 APP、小程序 语音首次发送失败问题
+
+## [2.0.3] (2024-01-12)
+
+### Features
+
+- TUIContact 关系链支持用户在线状态。
+- TUIContact 中获取客服列表的时机调整为 Engine 设置商业化能力位之后。
+
+### Fix
+
+- 修复已知问题,提升稳定性
+
+## [2.0.2] (2024-01-05)
+
+### Fix
+
+- 修复已知问题,提升稳定性
+
+## [2.0.0] (2023-12-21)
+
+### Features
+
+- 全面支持 uniapp Vue2 & uniapp Vue3,包括以下主体功能:
+  - TUIChat: 负责消息界面展示,包括多类型消息收发,消息引用/删除/撤回/转发、查询消息已读回执详情等功能。
+  - TUIConversation: 负责会话列表的展示和编辑,包括会话置顶、会话消息免打扰、会话删除等功能.
+  - TUIGroup: 负责群聊的创建以及群资料、群成员、群组权限、群公告、群禁言的管理。
+  - TUIContact: 负责联系人与群组展示,添加好友,移入黑名单,好友备注,信息展示等功能。
+- 同时,我们还提供了功能丰富的插件系统:
+  - TUICustomerService: 在线客服插件,支持灵活的路由排队、客服接待、智能机器人功能,配合功能丰富的管理端与数据分析能力,支持客服多终端办公,免费试用请点击 https://cloud.tencent.com/document/product/269/92648#ae4e3f5c-94db-4df3-8a49-65d23ce417b8 开通。
+  - TUICallKit: 音视频通话 UI 组件,支持两人或多人进行音视频通话,覆盖游戏社交、在线客服、视频客服、在线问诊、保险咨询等场景,免费试用请点击 https://cloud.tencent.com/document/product/269/79861#step1 开通。

+ 54 - 0
TUIKit-Homemaking/README.md

@@ -0,0 +1,54 @@
+## 关于 chat-uikit-uniapp
+
+chat-uikit-uniapp (vue2 / vue3)是基于腾讯云 Chat SDK 的一款 uniapp UI 组件库,它提供了一些通用的 UI 组件,包含会话、聊天、群组、关系链等功能。基于这些精心设计的 UI 组件,您可以快速构建优雅的、可靠的、可扩展的 Chat 应用。
+chat-uikit-uniapp 界面效果如下图所示:
+![](https://qcloudimg.tencent-cloud.cn/raw/2f16b1be0591a325250f9066af898036.png)
+
+## chat-uikit-uniapp 支持平台
+
+- Android
+- iOS
+- 微信小程序
+- H5
+
+## 含 UI 集成 TUILogin 使用说明
+
+``` javascript
+// 引入 TUILogin 模块
+import { TUILogin } from '@tencentcloud/tui-core';
+```
+初始化登录参数 options 配置说明:
+| 参数 | 类型 | 含义 |
+| --- | --- | --- |
+| SDKAppID | number | 云通信应用的 SDKAppID,必填 |
+| userID | string | 用户 ID,必填 |
+| userSig |string | 用户登录密钥,必填 |
+| TIMPush | any | 推送插件实例,uniapp 打包 app 时集成推送插件可用 |
+| pushConfig | object | 推送插件配置信息,uniapp 打包 app 时集成推送插件可用 |
+| useUploadPlugin | boolean | 是否使用上传插件, 默认 false |
+| proxyServer | string | WebSocket 服务器代理地址 |
+| fileUploadProxy | string | 图片、视频、文件上传代理地址 |
+| fileDownloadProxy | string | 图片、视频、文件下载代理地址 |
+| framework | string \| undefined | 使用的 UI 框架,可选值: vue2、vue3、undefined,必填 |
+
+``` javascript
+// 初始化登录
+TUILogin.login(options);
+```
+
+``` javascript
+// 登出
+TUILogin.logout();
+```
+
+``` javascript
+// 设置 Chat SDK 日志输出级别
+TUILogin.setLogLevel(0); // 0:普通日志级别 1:release 级别日志 2:告警级别 3:错误级别 4:无日志级别
+```
+
+``` javascript
+// 获取 Chat SDK 实例
+const { chat } = TUILogin.getContext();
+```
+
+## 【源码集成】[请参考 TUIKit 集成文档](https://cloud.tencent.com/document/product/269/64507)

+ 14 - 0
TUIKit-Homemaking/adapter-vue.ts

@@ -0,0 +1,14 @@
+let vueVersion: number;
+let framework = 'vue2';
+// #ifndef VUE3
+export * from '@vue/composition-api';
+vueVersion = 2;
+// #endif
+
+// #ifdef VUE3
+export * from 'vue';
+vueVersion = 3;
+framework = 'vue3';
+// #endif
+console.warn(`[adapter-vue]: vue version is ${vueVersion}`);
+export { vueVersion, framework };

+ 12 - 0
TUIKit-Homemaking/assets/icon/add.svg

@@ -0,0 +1,12 @@
+<svg width="14" height="15" viewBox="0 0 14 15" fill="none" xmlns="http://www.w3.org/2000/svg">
+    <g opacity="0.80492">
+        <rect x="0.25" y="7.25" width="13.5" height="0.5" rx="0.25" stroke="#232832"
+            style="stroke:#232832;stroke:color(display-p3 0.1360 0.1574 0.1949);stroke-opacity:1;"
+            stroke-width="0.5" />
+        <rect x="6.75" y="14.25" width="13.5" height="0.5" rx="0.25"
+            transform="rotate(-90 6.75 14.25)" stroke="#232832"
+            style="stroke:#232832;stroke:color(display-p3 0.1360 0.1574 0.1949);stroke-opacity:1;"
+            stroke-width="0.5" />
+    </g>
+</svg>
+    

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 12 - 0
TUIKit-Homemaking/assets/icon/at.svg


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 6 - 0
TUIKit-Homemaking/assets/icon/audio.svg


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 16 - 0
TUIKit-Homemaking/assets/icon/back.svg


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 6 - 0
TUIKit-Homemaking/assets/icon/call-video.svg


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 6 - 0
TUIKit-Homemaking/assets/icon/call-voice.svg


BIN
TUIKit-Homemaking/assets/icon/call.png


BIN
TUIKit-Homemaking/assets/icon/camera-uni.png


+ 23 - 0
TUIKit-Homemaking/assets/icon/cancel.svg

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16px" height="16px" viewBox="0 0 16 16" version="1.1">
+  <title>清除</title>
+  <g id="页面-2备份" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+    <g id="创建群聊" transform="translate(-1243.000000, -413.000000)">
+      <g id="Group-1364" transform="translate(650.000000, 343.000000)">
+        <g id="Group-1363" transform="translate(290.000000, 46.000000)">
+          <g id="Group-1358" transform="translate(0.000000, 24.000000)">
+            <g id="清除" transform="translate(303.000000, 0.000000)">
+              <path d="M0,0 L16,0 L16,16 L0,16 L0,0 Z" id="矩形"></path>
+              <path d="M1,8 C1,11.8659999 4.13400006,15 8,15 C11.8659999,15 15,11.8659999 15,8 C15,4.13400006 11.8659999,1 8,1 L8,1 C4.13400006,1 1,4.13400006 1,8 Z" fill="#999999"></path>
+              <g id="编组" transform="translate(8.000000, 8.000000) rotate(-315.000000) translate(-8.000000, -8.000000) translate(4.000000, 4.000000)" fill="#FFFFFF">
+                <rect id="矩形备份" transform="translate(4.000000, 4.000000) rotate(-90.000000) translate(-4.000000, -4.000000) " x="1.8189894e-12" y="3.5" width="8" height="1" rx="0.5"></rect>
+                <rect id="矩形备份" transform="translate(4.000000, 4.000000) rotate(-360.000000) translate(-4.000000, -4.000000) " x="0" y="3.5" width="8" height="1" rx="0.5"></rect>
+              </g>
+              <rect id="矩形" x="0" y="0" width="16" height="16"></rect>
+            </g>
+          </g>
+        </g>
+      </g>
+    </g>
+  </g>
+</svg>

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 3 - 0
TUIKit-Homemaking/assets/icon/check-sm.svg


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 3 - 0
TUIKit-Homemaking/assets/icon/close-dark.svg


BIN
TUIKit-Homemaking/assets/icon/close-image.png


+ 7 - 0
TUIKit-Homemaking/assets/icon/convertText_en.svg

@@ -0,0 +1,7 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<mask id="path-1-inside-1_2075_534" fill="white">
+<rect y="6.10352e-05" width="16" height="16" rx="0.5"/>
+</mask>
+<rect y="6.10352e-05" width="16" height="16" rx="0.5" fill="white" stroke="#444444" stroke-width="4" mask="url(#path-1-inside-1_2075_534)"/>
+<path d="M7.276 3.43201H8.872L12.148 12H10.648L9.868 9.85201H6.28L5.5 12H4L7.276 3.43201ZM6.7 8.70001H9.448L8.104 4.94401H8.056L6.7 8.70001Z" fill="#444444"/>
+</svg>

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 8 - 0
TUIKit-Homemaking/assets/icon/convertText_zh.svg


+ 5 - 0
TUIKit-Homemaking/assets/icon/d-left-arrow.svg

@@ -0,0 +1,5 @@
+<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
+    <path fill="#444444"
+        style="fill:#444444;fill:color(display-p3 0.2667 0.2667 0.2667);fill-opacity:1;"
+        d="M529.408 149.376a29.12 29.12 0 0 1 41.728 0 30.592 30.592 0 0 1 0 42.688L259.264 511.936l311.872 319.936a30.592 30.592 0 0 1-.512 43.264 29.12 29.12 0 0 1-41.216-.512L197.76 534.272a32 32 0 0 1 0-44.672l331.648-340.224zm256 0a29.12 29.12 0 0 1 41.728 0 30.592 30.592 0 0 1 0 42.688L515.264 511.936l311.872 319.936a30.592 30.592 0 0 1-.512 43.264 29.12 29.12 0 0 1-41.216-.512L453.76 534.272a32 32 0 0 1 0-44.672l331.648-340.224z"></path>
+</svg>

+ 5 - 0
TUIKit-Homemaking/assets/icon/d-right-arrow.svg

@@ -0,0 +1,5 @@
+<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
+    <path fill="#444444"
+        style="fill:#444444;fill:color(display-p3 0.2667 0.2667 0.2667);fill-opacity:1;"
+        d="M452.864 149.312a29.12 29.12 0 0 1 41.728.064L826.24 489.664a32 32 0 0 1 0 44.672L494.592 874.624a29.12 29.12 0 0 1-41.728 0 30.592 30.592 0 0 1 0-42.752L764.736 512 452.864 192a30.592 30.592 0 0 1 0-42.688zm-256 0a29.12 29.12 0 0 1 41.728.064L570.24 489.664a32 32 0 0 1 0 44.672L238.592 874.624a29.12 29.12 0 0 1-41.728 0 30.592 30.592 0 0 1 0-42.752L508.736 512 196.864 192a30.592 30.592 0 0 1 0-42.688z"></path>
+</svg>

+ 25 - 0
TUIKit-Homemaking/assets/icon/del-icon.svg

@@ -0,0 +1,25 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+    <g id="&#231;&#188;&#150;&#231;&#187;&#132; 9&#229;&#164;&#135;&#228;&#187;&#189;">
+        <path id="&#231;&#155;&#180;&#231;&#186;&#191;" d="M2.15682 4.76268H14.0347"
+            stroke="#FF584C"
+            style="stroke:#FF584C;stroke:color(display-p3 1.0000 0.3451 0.2980);stroke-opacity:1;"
+            stroke-linecap="round" />
+        <path id="&#231;&#155;&#180;&#231;&#186;&#191;&#229;&#164;&#135;&#228;&#187;&#189;"
+            d="M5.23978 2.15307H11.1684" stroke="#FF584C"
+            style="stroke:#FF584C;stroke:color(display-p3 1.0000 0.3451 0.2980);stroke-opacity:1;"
+            stroke-linecap="round" />
+        <path id="&#231;&#155;&#180;&#231;&#186;&#191;&#229;&#164;&#135;&#228;&#187;&#189; 2"
+            d="M6.90014 7.32796V10.9714" stroke="#FF584C"
+            style="stroke:#FF584C;stroke:color(display-p3 1.0000 0.3451 0.2980);stroke-opacity:1;"
+            stroke-linecap="round" />
+        <path id="&#231;&#155;&#180;&#231;&#186;&#191;&#229;&#164;&#135;&#228;&#187;&#189; 3"
+            d="M9.58605 7.32796V10.9714" stroke="#FF584C"
+            style="stroke:#FF584C;stroke:color(display-p3 1.0000 0.3451 0.2980);stroke-opacity:1;"
+            stroke-linecap="round" />
+        <path id="&#231;&#159;&#169;&#229;&#189;&#162;"
+            d="M4.14331 4.8316H12.1596V12.9091C12.1596 13.5367 11.6508 14.0454 11.0232 14.0454H5.27968C4.65208 14.0454 4.14331 13.5367 4.14331 12.9091V4.8316Z"
+            stroke="#FF584C"
+            style="stroke:#FF584C;stroke:color(display-p3 1.0000 0.3451 0.2980);stroke-opacity:1;" />
+    </g>
+</svg>
+    

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 0
TUIKit-Homemaking/assets/icon/double-arrow.svg


+ 3 - 0
TUIKit-Homemaking/assets/icon/down-icon.svg

@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M12 5L7.21955 10L3 5" stroke="#979797"/>
+</svg>

BIN
TUIKit-Homemaking/assets/icon/downaload-image.png


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 6 - 0
TUIKit-Homemaking/assets/icon/download.svg


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 7 - 0
TUIKit-Homemaking/assets/icon/edit.svg


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 10 - 0
TUIKit-Homemaking/assets/icon/evaluate.svg


BIN
TUIKit-Homemaking/assets/icon/face-uni.png


BIN
TUIKit-Homemaking/assets/icon/face.png


BIN
TUIKit-Homemaking/assets/icon/files.png


+ 7 - 0
TUIKit-Homemaking/assets/icon/icon-arrow-left.svg

@@ -0,0 +1,7 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg class="icon" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1"
+  xmlns="http://www.w3.org/2000/svg">
+  <path fill="#444444"
+    d="M384 512L731.733333 202.666667c17.066667-14.933333 19.2-42.666667 4.266667-59.733334-14.933333-17.066667-42.666667-19.2-59.733333-4.266666l-384 341.333333c-10.666667 8.533333-14.933333 19.2-14.933334 32s4.266667 23.466667 14.933334 32l384 341.333333c8.533333 6.4 19.2 10.666667 27.733333 10.666667 12.8 0 23.466667-4.266667 32-14.933333 14.933333-17.066667 14.933333-44.8-4.266667-59.733334L384 512z" />
+</svg>

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 36 - 0
TUIKit-Homemaking/assets/icon/icon-c2c.svg


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 6 - 0
TUIKit-Homemaking/assets/icon/icon-close.svg


BIN
TUIKit-Homemaking/assets/icon/image-uni.png


BIN
TUIKit-Homemaking/assets/icon/image.png


+ 3 - 0
TUIKit-Homemaking/assets/icon/input-close.svg

@@ -0,0 +1,3 @@
+<svg width="15" height="14" viewBox="0 0 15 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M7.5 14C11.366 14 14.5 10.866 14.5 7C14.5 3.13401 11.366 0 7.5 0C3.63401 0 0.5 3.13401 0.5 7C0.5 10.866 3.63401 14 7.5 14ZM9.98528 3.47487L11.0459 4.53553L8.57107 7.01041L11.0459 9.48528L9.98528 10.5459L7.51041 8.07107L5.03553 10.5459L3.97487 9.48528L6.44975 7.01041L3.97487 4.53553L5.03553 3.47487L7.51041 5.94975L9.98528 3.47487Z" fill="#B2B2B2" style="fill:#B2B2B2;fill:color(display-p3 0.6980 0.6980 0.6980);fill-opacity:1;"/>
+</svg>

+ 6 - 0
TUIKit-Homemaking/assets/icon/left-arrow.svg

@@ -0,0 +1,6 @@
+<svg width="8" height="14" viewBox="0 0 8 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+    <path
+        d="M2.1614 7.00004L7.64211 12.2881L6.5614 13.3308L1.0807 8.04275L0 7.00004L1.0807 5.95733L6.5614 0.669312L7.64211 1.71202L2.1614 7.00004Z"
+        fill="#444444"
+        style="fill:#444444;fill:color(display-p3 0.2667 0.2667 0.2667);fill-opacity:1;" />
+</svg>

BIN
TUIKit-Homemaking/assets/icon/loading.gif


BIN
TUIKit-Homemaking/assets/icon/loading.png


+ 6 - 0
TUIKit-Homemaking/assets/icon/minus.svg

@@ -0,0 +1,6 @@
+<svg width="36" height="4" viewBox="0 0 36 4" fill="none" xmlns="http://www.w3.org/2000/svg">
+    <path fill-rule="evenodd" clip-rule="evenodd"
+        d="M19.499 0.5L36 0.5V3.5H19.499H16.499H0V0.5L16.499 0.5H19.499Z" fill="#BBBBBB"
+        style="fill:#BBBBBB;fill:color(display-p3 0.7333 0.7333 0.7333);fill-opacity:1;" />
+</svg>
+    

BIN
TUIKit-Homemaking/assets/icon/more-uni.png


BIN
TUIKit-Homemaking/assets/icon/more.png


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 0
TUIKit-Homemaking/assets/icon/msg-audio.svg


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 30 - 0
TUIKit-Homemaking/assets/icon/msg-copy.svg


+ 33 - 0
TUIKit-Homemaking/assets/icon/msg-del.svg

@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="40px" height="40px" viewBox="0 0 40 40" version="1.1">
+  <title>矩形</title>
+  <defs>
+    <path d="M467,0 C474.731986,-2.71135202e-14 481,6.2680135 481,14 L481,247 C481,254.731986 474.731986,261 467,261 L353.036,261 L340.862492,273.204941 C339.302377,274.769018 336.769719,274.77223 335.205642,273.212116 C335.203247,273.209727 335.200856,273.207335 335.198467,273.204941 L323.024,261 L14,261 C6.2680135,261 2.72325209e-15,254.731986 0,247 L0,14 C8.29461588e-16,6.2680135 6.2680135,3.19669972e-15 14,0 L467,0 Z" id="path-1"></path>
+    <filter x="-10.1%" y="-14.0%" width="120.2%" height="135.4%" filterUnits="objectBoundingBox" id="filter-2">
+      <feOffset dx="0" dy="10" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+      <feGaussianBlur stdDeviation="14.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
+      <feColorMatrix values="0 0 0 0 0   0 0 0 0 0   0 0 0 0 0  0 0 0 0.06 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
+    </filter>
+  </defs>
+  <g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+    <g id="消息状态" transform="translate(-779.000000, -326.000000)">
+      <g id="编组-11" transform="translate(499.000000, 163.000000)">
+        <g id="形状结合">
+          <use fill="black" fill-opacity="1" filter="url(#filter-2)" xlink:href="#path-1"></use>
+          <use fill="#FFFFFF" fill-rule="evenodd" xlink:href="#path-1"></use>
+        </g>
+        <g id="编组-13备份" transform="translate(246.000000, 131.583780)">
+          <g id="编组-17" transform="translate(34.000000, 31.416220)">
+            <g id="编组-18" transform="translate(4.000000, 2.847939)">
+              <path d="M27,8.04349833 L27,34.26099 L5,34.26099 L5,8.04349833 L27,8.04349833 Z" id="路径-5" stroke="#444444" stroke-width="4"></path>
+              <rect id="矩形" fill="#444444" x="9.14285714" y="0" width="14" height="4.02899889"></rect>
+              <rect id="矩形" fill="#444444" x="0" y="6.04349833" width="32" height="4.02899889"></rect>
+              <path d="M14,15.1087458 L14,27.1957425 L10,27.1957425 L10,15.1087458 L14,15.1087458 Z M22,15.1087458 L22,27.1957425 L18,27.1957425 L18,15.1087458 L22,15.1087458 Z" id="形状结合" fill="#444444"></path>
+            </g>
+          </g>
+        </g>
+        <g id="编组-19" transform="translate(8.000000, 1.000000)"></g>
+      </g>
+    </g>
+  </g>
+</svg>

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 31 - 0
TUIKit-Homemaking/assets/icon/msg-forward.svg


+ 8 - 0
TUIKit-Homemaking/assets/icon/msg-quote.svg

@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 41" class="design-iconfont">
+  <g fill="none" fill-rule="evenodd">
+    <path d="M34,2 L34,28.6209709 L20.7153357,28.6209709 L17.9993455,31.4022694 L15.2847485,28.6219998 L2,28.6219998 L2,2 L34,2 Z" transform="translate(2 3.273066)" fill-rule="nonzero" stroke="#444" stroke-width="4"/>
+    <path fill="#444" d="M11 16.12483H15V20.15603749H11z" transform="translate(0 .24966)"/>
+    <path fill="#444" d="M18 16.12483H22V20.15603749H18z" transform="translate(0 .24966)"/>
+    <path fill="#444" d="M25 16.12483H29V20.15603749H25z" transform="translate(0 .24966)"/>
+  </g>
+</svg>

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 29 - 0
TUIKit-Homemaking/assets/icon/msg-revoke.svg


+ 8 - 0
TUIKit-Homemaking/assets/icon/mute.svg

@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" class="design-iconfont">
+  <g fill="none" fill-rule="evenodd">
+    <path d="M4.13744611,6.61713753 L20.551,23 L0,23 L0,21 L3,21 L3,11 C3,9.40883362 3.41291862,7.91410954 4.13744611,6.61713753 Z M21.481,21 L24,21 L24,23 L23.485,23 L21.481,21 Z M12,2 C16.9705627,2 21,6.02943725 21,11 L21,20.52 L5.36684476,4.91705738 C7.01203082,3.12402075 9.37475086,2 12,2 Z" fill="#CCC" transform="translate(4 3)"/>
+    <path fill="#CCC" fill-rule="nonzero" d="M13 0L13 4 11 4 11 0z" transform="translate(4 3)"/>
+    <path stroke="#CCC" d="M8.5 24.5H15.5V25.5H8.5z" transform="translate(4 3)"/>
+    <path stroke="#CCC" stroke-width="2" transform="matrix(-1 0 0 1 31.089472 3)" d="M25.4499982 0.1546001L1.63947409 23.8855564"/>
+  </g>
+</svg>

+ 7 - 0
TUIKit-Homemaking/assets/icon/plus.svg

@@ -0,0 +1,7 @@
+<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
+    <path fill-rule="evenodd" clip-rule="evenodd"
+        d="M21.5 0L21.499 18.5H40V21.5H21.499L21.5 40H18.5L18.499 21.5H0V18.5H18.499L18.5 0H21.5Z"
+        fill="#BBBBBB"
+        style="fill:#BBBBBB;fill:color(display-p3 0.7333 0.7333 0.7333);fill-opacity:1;" />
+</svg>
+    

+ 14 - 0
TUIKit-Homemaking/assets/icon/right-arrow.svg

@@ -0,0 +1,14 @@
+<svg width="9" height="14" viewBox="0 0 9 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+    <g clip-path="url(#clip0_2200_23553)">
+        <path
+            d="M6.48068 6.83073L0.999983 12.1188L2.08069 13.1615L7.56139 7.87344L8.64209 6.83073L7.56139 5.78802L2.08069 0.5L0.999983 1.54271L6.48068 6.83073Z"
+            fill="#444444"
+            style="fill:#444444;fill:color(display-p3 0.2667 0.2667 0.2667);fill-opacity:1;" />
+    </g>
+    <defs>
+        <clipPath id="clip0_2200_23553">
+            <rect width="8" height="13" fill="white" style="fill:white;fill:white;fill-opacity:1;"
+                transform="matrix(-1 0 0 1 8.64209 0.5)" />
+        </clipPath>
+    </defs>
+</svg>

+ 3 - 0
TUIKit-Homemaking/assets/icon/right-icon.svg

@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M5 3L10 7.78045L5 12" stroke="#979797"/>
+</svg>

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 7 - 0
TUIKit-Homemaking/assets/icon/rotate-left.svg


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 7 - 0
TUIKit-Homemaking/assets/icon/rotate-right.svg


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 52 - 0
TUIKit-Homemaking/assets/icon/search-default.svg


+ 7 - 0
TUIKit-Homemaking/assets/icon/search-more.svg

@@ -0,0 +1,7 @@
+<svg width="25" height="25" viewBox="0 0 25 25" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M0.5 4.5C0.5 2.29086 2.29086 0.5 4.5 0.5L20.5 0.5C22.7091 0.5 24.5 2.29086 24.5 4.5V20.5C24.5 22.7091 22.7091 24.5 20.5 24.5H4.5C2.29086 24.5 0.5 22.7091 0.5 20.5V4.5Z" fill="#F4F5F9" style="fill:#F4F5F9;fill:color(display-p3 0.9569 0.9608 0.9765);fill-opacity:1;"/>
+<g opacity="0.80492">
+<rect x="5.75" y="12.25" width="13.5" height="0.5" rx="0.25" stroke="#232832" style="stroke:#232832;stroke:color(display-p3 0.1360 0.1574 0.1949);stroke-opacity:1;" stroke-width="0.5"/>
+<rect x="12.25" y="19.25" width="13.5" height="0.5" rx="0.25" transform="rotate(-90 12.25 19.25)" stroke="#232832" style="stroke:#232832;stroke:color(display-p3 0.1360 0.1574 0.1949);stroke-opacity:1;" stroke-width="0.5"/>
+</g>
+</svg>

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 5 - 0
TUIKit-Homemaking/assets/icon/search.svg


+ 27 - 0
TUIKit-Homemaking/assets/icon/selected.svg

@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16px" height="16px" viewBox="0 0 16 16" version="1.1">
+  <title>编组 14</title>
+  <defs>
+    <filter x="-10.6%" y="-5.4%" width="121.2%" height="110.9%" filterUnits="objectBoundingBox" id="filter-1">
+      <feOffset dx="0" dy="7" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+      <feGaussianBlur stdDeviation="10" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
+      <feColorMatrix values="0 0 0 0 0   0 0 0 0 0   0 0 0 0 0  0 0 0 0.1 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+      <feMerge>
+        <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+        <feMergeNode in="SourceGraphic"></feMergeNode>
+      </feMerge>
+    </filter>
+  </defs>
+  <g id="new" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+    <g id="自定义消息" transform="translate(-458.000000, -318.000000)">
+      <g id="编组-32" filter="url(#filter-1)" transform="translate(44.000000, 60.000000)">
+        <g id="编组-24" transform="translate(30.000000, 250.000000)">
+          <g id="编组-14" transform="translate(384.000000, 8.000000)">
+            <circle id="椭圆形" fill="#006EFF" fill-rule="nonzero" cx="8" cy="8" r="8"></circle>
+            <polyline id="路径-4" stroke="#FFFFFF" stroke-width="2" transform="translate(8.042641, 6.242641) rotate(-315.000000) translate(-8.042641, -6.242641) " points="6.04264069 10.2426407 10.0426407 10.2426407 10.0426407 2.24264069"></polyline>
+          </g>
+        </g>
+      </g>
+    </g>
+  </g>
+</svg>

+ 8 - 0
TUIKit-Homemaking/assets/icon/setting.svg

@@ -0,0 +1,8 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+    <g id="&#231;&#188;&#150;&#231;&#187;&#132; 14" opacity="0.802743">
+        <path id="&#229;&#189;&#162;&#231;&#138;&#182;&#231;&#187;&#147;&#229;&#144;&#136;"
+            fill-rule="evenodd" clip-rule="evenodd"
+            d="M6 10.5C6 11.3284 5.32843 12 4.5 12C3.67157 12 3 11.3284 3 10.5C3 9.67157 3.67157 9 4.5 9C5.32843 9 6 9.67157 6 10.5ZM12 10.5C12 11.3284 11.3284 12 10.5 12C9.67157 12 9 11.3284 9 10.5C9 9.67157 9.67157 9 10.5 9C11.3284 9 12 9.67157 12 10.5ZM16.5 12C17.3284 12 18 11.3284 18 10.5C18 9.67157 17.3284 9 16.5 9C15.6716 9 15 9.67157 15 10.5C15 11.3284 15.6716 12 16.5 12Z"
+            fill="#232832" />
+    </g>
+</svg>

BIN
TUIKit-Homemaking/assets/icon/star-light.png


BIN
TUIKit-Homemaking/assets/icon/star.png


+ 6 - 0
TUIKit-Homemaking/assets/icon/start-group.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14" fill="none">
+  <circle r="2.61111" transform="matrix(1 0 0 -1 8.55545 3.88889)" stroke="#4C5059"></circle>
+  <circle r="2.61111" transform="matrix(1 0 0 -1 4.66678 3.88889)" fill="#F4F5F9" stroke="#4C5059"></circle>
+  <path d="M5.16675 11.7778C5.16675 9.84484 6.73375 8.27783 8.66675 8.27783H10.0001C11.9331 8.27783 13.5001 9.84484 13.5001 11.7778V12.7223H5.16675V11.7778Z" stroke="#4C5059"></path>
+  <path d="M0.5 11.7778C0.5 9.84484 2.067 8.27783 4 8.27783H5.33333C7.26633 8.27783 8.83333 9.84484 8.83333 11.7778V12.7223H0.5V11.7778Z" fill="#F4F5F9" stroke="#4C5059"></path>
+</svg>

+ 12 - 0
TUIKit-Homemaking/assets/icon/translate.svg

@@ -0,0 +1,12 @@
+<svg width="19" height="18" viewBox="0 0 19 18" fill="none" xmlns="http://www.w3.org/2000/svg">
+<mask id="path-1-inside-1_313_82772" fill="white">
+<rect x="7" y="7.62939e-06" width="12" height="12" rx="0.5"/>
+</mask>
+<rect x="7" y="7.62939e-06" width="12" height="12" rx="0.5" fill="#444444" stroke="#CCCCCC" stroke-width="4" mask="url(#path-1-inside-1_313_82772)"/>
+<path d="M12.7426 3.61601H12.6745L12.6496 3.67939L10.9636 7.96339L10.9098 8.10001H11.0566H11.5846H11.6536L11.6781 8.03553L12.1096 6.90001H13.9397L14.3712 8.03553L14.3957 8.10001H14.4646H14.9986H15.1455L15.0917 7.96339L13.4057 3.67939L13.3808 3.61601H13.3126H12.7426ZM13.7079 6.28601H12.3421L13.03 4.49341L13.7079 6.28601Z" fill="#CCCCCC" stroke="#CCCCCC" stroke-width="0.2"/>
+<mask id="path-3-inside-2_313_82772" fill="white">
+<rect y="6.00001" width="12" height="12" rx="0.5"/>
+</mask>
+<rect y="6.00001" width="12" height="12" rx="0.5" fill="#444444" stroke="#CCCCCC" stroke-width="4" mask="url(#path-3-inside-2_313_82772)"/>
+<path d="M5.77801 8.97401H5.67801V9.07401V10.054H3.63H3.53V10.154V12.974V13.074H3.63H4.062H4.162V12.974V12.696H5.67801V14.642V14.742H5.77801H6.222H6.322V14.642V12.696H7.84401V12.974V13.074H7.94401H8.37601H8.47601V12.974V10.154V10.054H8.37601H6.322V9.07401V8.97401H6.222H5.77801ZM4.162 12.076V10.674H5.67801V12.076H4.162ZM6.322 12.076V10.674H7.84401V12.076H6.322Z" fill="#CCCCCC" stroke="#CCCCCC" stroke-width="0.2"/>
+</svg>

BIN
TUIKit-Homemaking/assets/icon/video-play.png


BIN
TUIKit-Homemaking/assets/icon/video-uni.png


BIN
TUIKit-Homemaking/assets/icon/video.png


+ 9 - 0
TUIKit-Homemaking/assets/icon/words.svg

@@ -0,0 +1,9 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+    <g opacity="0.795169">
+        <path
+            d="M9.60349 12.4231H9.35784L9.20772 12.6175L8.01519 14.1621L6.92003 12.6321L6.77045 12.4231H6.51345H3.25C2.2835 12.4231 1.5 11.6396 1.5 10.6731V3.25C1.5 2.2835 2.2835 1.5 3.25 1.5H12.75C13.7165 1.5 14.5 2.2835 14.5 3.25V8.80223V10.6731C14.5 11.6396 13.7165 12.4231 12.75 12.4231H9.60349Z"
+            stroke="#232832" />
+        <path d="M9.29061 3.74268L5.97266 6.33109L9.88719 7.13334L6.61672 9.74268" stroke="#232832"
+            stroke-linecap="round" stroke-linejoin="round" />
+    </g>
+</svg>

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 9 - 0
TUIKit-Homemaking/assets/icon/zoom-in.svg


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 9 - 0
TUIKit-Homemaking/assets/icon/zoom-out.svg


+ 59 - 0
TUIKit-Homemaking/assets/styles/common.scss

@@ -0,0 +1,59 @@
+body, div, ul, ol, dt, dd, li, dl, h1, h2, h3, h4, p {
+  margin:0;
+  padding:0;
+  font-style:normal;
+
+  /* font:12px/22px"\5B8B\4F53",Arial,Helvetica,sans-serif; */
+}
+
+ol, ul, li {
+  list-style:none;
+}
+
+img {
+  border:0;
+  vertical-align:middle;
+  pointer-events:none;
+}
+
+body {
+  color:#000;
+  background:#FFF;
+}
+
+.clear {
+  clear:both;
+  height:1px;
+  width:100%;
+  overflow:hidden;
+  margin-top:-1px;
+}
+
+a {
+  color:#000;
+  text-decoration:none;
+  cursor: pointer;
+}
+
+a:hover {
+  text-decoration:none;
+}
+
+input, textarea {
+  user-select: auto;
+}
+
+input:focus, input:active, textarea:focus, textarea:active {
+  outline: none;
+}
+
+.chat-aside {
+  position: absolute;
+  top: 50px;
+  right: 0;
+  box-sizing: border-box;
+  width: 360px !important;
+  border-radius: 8px 0 0 8px;
+  z-index: 9999;
+  max-height: calc(100% - 50px);
+}

+ 99 - 0
TUIKit-Homemaking/assets/styles/sample.scss

@@ -0,0 +1,99 @@
+/* stylelint-disable */
+.TUIKit {
+  display: flex;
+  width: 100vw;
+  height: 100vh;
+  overflow: hidden;
+  text-align: left;
+  .TUIKit-navbar {
+    background: #e8e8e9;
+    overflow: hidden;
+    .TUIKit-navbar-item {
+      padding: 10px;
+      color: #405eff;
+      font-weight: 500;
+      cursor: pointer;
+    }
+    .TUIKit-navbar-item-active {
+      background: #dddddd;
+    }
+  }
+  .TUIKit-main-container {
+    flex: 1;
+    display: flex;
+    overflow: hidden;
+    .TUIKit-main {
+      flex: 1;
+      display: flex;
+      .TUIKit-main-aside {
+        min-width: 285px;
+        flex: 0 0 24%;
+        border-right: 1px solid #f4f5f9;
+      }
+      .TUIKit-main-main {
+        flex: 1;
+        display: flex;
+        .chat {
+          flex: 1;
+        }
+        .chat-aside {
+          position: absolute;
+          top: 50px;
+          right: 0;
+          box-sizing: border-box;
+          max-width: 360px;
+          max-height: calc(100% - 50px);
+          border-radius: 8px 0 0 8px;
+          z-index: 9999;
+        }
+      }
+    }
+    .callkit-container {
+      position: fixed;
+      left: calc(50% - 25rem);
+      top: calc(50% - 18rem);
+      width: 50rem;
+      height: 36rem;
+    }
+    .callkit-container.miniMized {
+      left: auto;
+      right: 10px;
+      top: 70px;
+      background: transparent;
+    }
+  }
+}
+.TUIKit-h5 {
+  display: flex;
+  flex-direction: column-reverse;
+  .TUIKit-navbar {
+    display: flex;
+    flex-direction: row;
+    .TUIKit-navbar-item {
+      flex: 1;
+      text-align: center;
+      cursor: none;
+    }
+  }
+  .TUIKit-main-container {
+    flex: 1;
+    .TUIKit-main {
+      .TUIKit-main-aside {
+        flex: 1;
+      }
+      .TUIKit-main-main {
+        .chat-popup {
+          position: absolute;
+          max-width: 100%;
+          max-height: 100%;
+        }
+      }
+    }
+    .callkit-container {
+      left: 0;
+      top: 0;
+      width: 100%;
+      height: 100%;
+    }
+  }
+}

+ 62 - 0
TUIKit-Homemaking/components/TUIChat/chat-header/index.vue

@@ -0,0 +1,62 @@
+<template>
+  <view style="display: none" />
+</template>
+
+<script setup lang="ts">
+import {
+  TUIStore,
+  StoreName,
+  IConversationModel,
+  TUITranslateService,
+} from "@tencentcloud/chat-uikit-engine";
+import { TUIGlobal } from "@tencentcloud/universal-api";
+import { onLoad } from "@dcloudio/uni-app";
+import { onMounted, onUnmounted, ref } from "../../../adapter-vue";
+
+const currentConversation = ref<IConversationModel>();
+const typingStatus = ref(false);
+
+const setChatHeaderContent = (content: string) => {
+  TUIGlobal?.setNavigationBarTitle({
+    title: content || "云通信 IM",
+  });
+};
+
+onMounted(() => {
+  TUIStore.watch(StoreName.CONV, {
+    currentConversation: onCurrentConversationUpdated,
+  });
+  TUIStore.watch(StoreName.CHAT, {
+    typingStatus: onTypingStatusUpdated,
+  });
+});
+
+onUnmounted(() => {
+  TUIStore.unwatch(StoreName.CONV, {
+    currentConversation: onCurrentConversationUpdated,
+  });
+  TUIStore.unwatch(StoreName.CHAT, {
+    typingStatus: onTypingStatusUpdated,
+  });
+});
+
+onLoad(() => {
+  setChatHeaderContent(currentConversation.value?.getShowName());
+});
+
+function onCurrentConversationUpdated(conversation: IConversationModel) {
+  currentConversation.value = conversation;
+  if (!typingStatus.value) {
+    setChatHeaderContent(currentConversation?.value?.getShowName());
+  }
+}
+
+function onTypingStatusUpdated(status: boolean) {
+  typingStatus.value = status;
+  if (typingStatus.value) {
+    setChatHeaderContent(TUITranslateService.t("TUIChat.对方正在输入"));
+  } else {
+    setChatHeaderContent(currentConversation.value?.getShowName());
+  }
+}
+</script>

+ 24 - 0
TUIKit-Homemaking/components/TUIChat/config.ts

@@ -0,0 +1,24 @@
+class TUIChatConfig {
+  static instance: TUIChatConfig;
+  private chatType: string;
+  constructor() {
+    this.chatType = '';
+  }
+
+  static getInstance(): TUIChatConfig {
+    if (!TUIChatConfig.instance) {
+      TUIChatConfig.instance = new TUIChatConfig();
+    }
+    return TUIChatConfig.instance;
+  }
+
+  setChatType(chatType: string) {
+    this.chatType = chatType;
+  }
+
+  getChatType() {
+    return this.chatType;
+  }
+}
+
+export default TUIChatConfig.getInstance();

+ 132 - 0
TUIKit-Homemaking/components/TUIChat/forward/index.vue

@@ -0,0 +1,132 @@
+<template>
+  <Overlay
+    :visible="isShowForwardPanel"
+    :useMask="false"
+  >
+    <Transfer
+      :title="TUITranslateService.t('TUIChat.转发')"
+      :isSearch="false"
+      :isCustomItem="false"
+      :list="customConversationList"
+      :isHiddenBackIcon="isUniFrameWork"
+      @cancel="closeForwardPanel"
+      @submit="onSubmit"
+    />
+  </Overlay>
+</template>
+
+<script lang="ts" setup>
+import { onMounted, onUnmounted, ref } from '../../../adapter-vue';
+import {
+  TUIStore,
+  StoreName,
+  TUIChatService,
+  TUITranslateService,
+  IConversationModel,
+} from '@tencentcloud/chat-uikit-engine';
+import Overlay from '../../common/Overlay/index.vue';
+import Transfer from '../../common/Transfer/index.vue';
+import { Toast, TOAST_TYPE } from '../../../components/common/Toast';
+import { isUniFrameWork } from '../../../utils/env';
+import { isEnabledMessageReadReceiptGlobal } from '../utils/utils';
+import { createOfflinePushInfo } from '../utils/sendMessage';
+
+const isShowForwardPanel = ref(false);
+const customConversationList = ref();
+
+onMounted(() => {
+  TUIStore.watch(StoreName.CONV, {
+    conversationList: onConversationListUpdated,
+  });
+  TUIStore.watch(StoreName.CUSTOM, {
+    singleForwardMessageID: onSingleForwardMessageIDUpdated,
+  });
+});
+
+onUnmounted(() => {
+  // 组件卸载时需要清掉数据 否则小程序会自动打开
+  TUIStore.update(StoreName.CUSTOM, 'singleForwardMessageID', undefined);
+  TUIStore.unwatch(StoreName.CONV, {
+    conversationList: onConversationListUpdated,
+  });
+  TUIStore.unwatch(StoreName.CUSTOM, {
+    singleForwardMessageID: onSingleForwardMessageIDUpdated,
+  });
+});
+
+function onSingleForwardMessageIDUpdated(messageID: string) {
+  if (typeof messageID !== 'undefined') {
+    openForwardPanel();
+  }
+}
+
+function closeForwardPanel(): void {
+  // ! 必须通过close函数关闭转发面板 singleForwardMessage必须清掉
+  TUIStore.update(StoreName.CUSTOM, 'singleForwardMessageID', undefined);
+  isShowForwardPanel.value = false;
+}
+
+function openForwardPanel(): void {
+  isShowForwardPanel.value = true;
+}
+
+function finishSelected(selectedConvIDWrapperList: Array<{ userID: string }>): void {
+  /**
+   * 这里传递的是 coversationID
+   * 但为了实现 Transfer 的复用 这里用 userID 代替 ConversationID
+   */
+  const selectedConversationList = selectedConvIDWrapperList.map((convIDWrapper) => {
+    const { userID: conversationID } = convIDWrapper;
+    return TUIStore.getConversationModel(conversationID);
+  });
+  const singleForwardMessageID: string = TUIStore.getData(StoreName.CUSTOM, 'singleForwardMessageID');
+  const message = TUIStore.getMessageModel(singleForwardMessageID);
+  const sendMessageOptions: any = {};
+  for (let i = 0; i < selectedConversationList.length; i++) {
+    const conversation = selectedConversationList[i];
+    const { conversationID } = conversation;
+    sendMessageOptions[conversationID] = {
+      offlinePushInfo: createOfflinePushInfo(conversation),
+    };
+  }
+  TUIChatService.sendForwardMessage(
+    selectedConversationList,
+    [message],
+    {
+      params: {
+        needReadReceipt: isEnabledMessageReadReceiptGlobal(),
+      },
+      ...sendMessageOptions,
+    },
+  ).catch((error: { message: string; code: number }) => {
+    if (error.code === 80001) {
+      Toast({
+        message: TUITranslateService.t('内容包含敏感词汇'),
+        type: TOAST_TYPE.ERROR,
+      });
+    } else {
+      Toast({
+        message: error.message as string,
+        type: TOAST_TYPE.ERROR,
+      });
+    }
+  });
+  closeForwardPanel();
+}
+
+function onSubmit(convIDWrapperList: Array<{ userID: string }>) {
+  if (convIDWrapperList?.length === 0) return;
+  finishSelected(convIDWrapperList);
+}
+
+function onConversationListUpdated(list: IConversationModel[]) {
+  customConversationList.value = list.map((conversation) => {
+    return {
+      // 为了实现Transfer的复用,这里用userID代替ConversationID
+      userID: conversation.conversationID,
+      nick: conversation.getShowName(),
+      avatar: conversation.getAvatar(),
+    };
+  });
+}
+</script>

+ 6 - 0
TUIKit-Homemaking/components/TUIChat/index.ts

@@ -0,0 +1,6 @@
+import TUIChat from './index.vue';
+import Server from './server';
+
+new Server();
+
+export default TUIChat;

+ 299 - 0
TUIKit-Homemaking/components/TUIChat/index.vue

@@ -0,0 +1,299 @@
+<template>
+  <div class="chat">
+    <div :class="['tui-chat', !isPC && 'tui-chat-h5']">
+      <div
+        v-if="!currentConversationID"
+        :class="['tui-chat-default', !isPC && 'tui-chat-h5-default']"
+      >
+        <slot />
+      </div>
+      <div
+        v-if="currentConversationID"
+        :class="['tui-chat', !isPC && 'tui-chat-h5']"
+      >
+        <ChatHeader
+          :class="[
+            'tui-chat-header',
+            !isPC && 'tui-chat-H5-header',
+            isUniFrameWork && 'tui-chat-uniapp-header',
+          ]"
+          @closeChat="closeChat"
+        />
+        <Forward />
+        <MessageList
+          :address="address"
+          ref="messageListRef"
+          :class="[
+            'tui-chat-message-list',
+            !isPC && 'tui-chat-h5-message-list',
+          ]"
+          :isGroup="isGroup"
+          :groupID="groupID"
+          @handleEditor="handleEditor"
+          @closeInputToolBar="() => changeToolbarDisplayType('none')"
+          :infoData="infoData"
+        />
+        <!-- 兼容 uni 打包支付宝小程序 v-show 无效问题 -->
+        <MessageInputToolbar
+          v-if="isInputToolbarShow"
+          :class="[
+            'tui-chat-message-input-toolbar',
+            !isPC && 'tui-chat-h5-message-input-toolbar',
+            isUniFrameWork && 'tui-chat-uni-message-input-toolbar',
+          ]"
+          :displayType="inputToolbarDisplayType"
+          :infoData="infoData"
+          @insertEmoji="insertEmoji"
+          @changeToolbarDisplayType="changeToolbarDisplayType"
+          @scrollToLatestMessage="scrollToLatestMessage"
+        />
+        <MessageInput
+          ref="messageInputRef"
+          :class="[
+            'tui-chat-message-input',
+            !isPC && 'tui-chat-h5-message-input',
+            isUniFrameWork && 'tui-chat-uni-message-input',
+            isWeChat && 'tui-chat-wx-message-input',
+          ]"
+          :isMuted="false"
+          :muteText="TUITranslateService.t('TUIChat.您已被管理员禁言')"
+          :placeholder="TUITranslateService.t('TUIChat.请输入消息')"
+          :inputToolbarDisplayType="inputToolbarDisplayType"
+          @changeToolbarDisplayType="changeToolbarDisplayType"
+          :infoData="infoData"
+        />
+      </div>
+      <!-- 群组管理 -->
+      <div
+        v-if="isUniFrameWork && isGroup && groupManageExt"
+        class="group-profile"
+        @click="handleGroup"
+      >
+        {{ groupManageExt.text }}
+        <!-- 更多 -->
+      </div>
+    </div>
+  </div>
+</template>
+<script lang="ts" setup>
+import TUIChatEngine, {
+  TUITranslateService,
+  TUIConversationService,
+  TUIStore,
+  StoreName,
+  IMessageModel,
+  IConversationModel,
+} from "@tencentcloud/chat-uikit-engine";
+import TUICore, { TUIConstants, ExtensionInfo } from "@tencentcloud/tui-core";
+import { ref, onMounted, onUnmounted, computed } from "../../adapter-vue";
+import ChatHeader from "./chat-header/index.vue";
+import MessageList from "./message-list/index.vue";
+import MessageInput from "./message-input/index.vue";
+import Forward from "./forward/index.vue";
+import MessageInputToolbar from "./message-input-toolbar/index.vue";
+import { isPC, isWeChat, isUniFrameWork } from "../../utils/env";
+import { ToolbarDisplayType } from "../../interface";
+import TUIChatConfig from "./config";
+import config from "@/request/config";
+import { onLoad, onShow } from "@dcloudio/uni-app";
+const address = ref();
+onShow(() => {
+  uni.$on("commitMapClick", function (res) {
+    address.value = res;
+  });
+});
+
+const emits = defineEmits(["closeChat"]);
+
+const messageInputRef = ref();
+const messageListRef = ref<InstanceType<typeof MessageList>>();
+const currentConversationID = ref();
+// 是否显示群组管理
+const isGroup = ref(false);
+const groupID = ref("");
+const groupManageExt = ref<ExtensionInfo | undefined>(undefined);
+const inputToolbarDisplayType = ref<ToolbarDisplayType>("none");
+// 沟通职位信息
+const infoData = ref({});
+
+// 获取地址栏参数
+function getParamValue(paramName) {
+  const regExp = new RegExp("[?&]" + paramName + "=([^&#]*)");
+  const results = regExp.exec(window.location.href);
+  if (results) {
+    return decodeURIComponent(results[1]);
+  } else {
+    return null;
+  }
+}
+
+onMounted(() => {
+  TUIStore.watch(StoreName.CONV, {
+    currentConversation: onCurrentConversationUpdate,
+  });
+  initData();
+});
+
+const initData = () => {
+  let data = {
+    shopUserId: getParamValue("shopUserId"),
+    userId: getParamValue("userId") || getParamValue("recruitUserId"),
+    refId: getParamValue("refId"),
+  };
+
+  let url = config.baseUrl + "/homemaking/communicate/status";
+  const header = {
+    "Content-Type": "application/x-www-form-urlencoded",
+    Authorization: uni.getStorageSync("token")
+      ? uni.getStorageSync("token")
+      : uni.getStorageSync("unitoken"),
+  };
+
+  uni.request({
+    url: url,
+    method: "GET",
+    header: header,
+    data: data,
+    success: function (res) {
+      infoData.value = res.data.data;
+
+      // 判断之前是否聊过当前产品,如果未聊过,则发送一条自定义消息,已聊过,不发送
+      if (
+        getParamValue("refId") &&
+        getParamValue("refId") != res.data.data.refId
+      ) {
+        let params = {
+          isSend: 1,
+          msgType: "TIMCustomElem",
+          refId: getParamValue("refId"),
+          sendRefType: 1,
+          sendType: 0,
+          shopUserId: getParamValue("shopUserId"),
+          userId: getParamValue("userId"),
+          msgContent: {},
+        };
+        let headerData = {
+          "Content-Type": "application/json",
+          Authorization: uni.getStorageSync("token")
+            ? uni.getStorageSync("token")
+            : uni.getStorageSync("unitoken"),
+        };
+        // }
+        uni.request({
+          url: config.baseUrl + "/homemaking/communicate",
+          method: "POST",
+          header: headerData,
+          data: params,
+          success: function (res) {
+            console.log("已发送商品自定义消息");
+          },
+        });
+      }
+    },
+  });
+};
+
+onUnmounted(() => {
+  TUIStore.unwatch(StoreName.CONV, {
+    currentConversation: onCurrentConversationUpdate,
+  });
+  reset();
+});
+
+function onCurrentConversationUpdate(conversation: IConversationModel) {
+  if (currentConversationID.value === conversation?.conversationID) {
+    return;
+  }
+  // TUIChat 每次切换会话,需要初始化 chatType;
+  TUIChatConfig.setChatType(conversation?.type);
+  // 由 TUICustomerServicePlugin 插件判断如果当前会话是客服会话,则设置 chatType 并激活会话。
+  TUICore.callService({
+    serviceName: TUIConstants.TUICustomerServicePlugin.SERVICE.NAME,
+    method:
+      TUIConstants.TUICustomerServicePlugin.SERVICE.METHOD.ACTIVE_CONVERSATION,
+    params: { conversationID: conversation?.conversationID },
+  });
+  currentConversationID.value = conversation?.conversationID;
+  isGroup.value = conversation?.type === TUIChatEngine.TYPES.CONV_GROUP;
+  // while chat converstaion changed, notify callkit current conversation type, c2c or group
+  TUICore.notifyEvent(
+    TUIConstants.TUIChat.EVENT.CHAT_STATE_CHANGED,
+    TUIConstants.TUIChat.EVENT_SUB_KEY.CHAT_OPENED,
+    {
+      groupID: conversation?.groupProfile?.groupID,
+    }
+  );
+  if (
+    isUniFrameWork &&
+    isGroup.value &&
+    groupID.value !== conversation?.groupProfile?.groupID
+  ) {
+    const extList = TUICore.getExtensionList(
+      TUIConstants.TUIChat.EXTENSION.CHAT_HEADER.EXT_ID,
+      {
+        filterManageGroup: !isGroup.value,
+      }
+    );
+    groupManageExt.value = extList[0];
+  }
+  if (isUniFrameWork && !isGroup.value) {
+    groupManageExt.value = undefined;
+  }
+  groupID.value = conversation?.groupProfile?.groupID;
+}
+
+const isInputToolbarShow = computed<boolean>(() => {
+  return isUniFrameWork ? inputToolbarDisplayType.value !== "none" : true;
+});
+
+// 清空当前 conversationID
+const reset = () => {
+  TUIConversationService.switchConversation();
+};
+
+const closeChat = (conversationID: string) => {
+  emits("closeChat", conversationID);
+  reset();
+};
+
+const insertEmoji = (emojiObj: object) => {
+  messageInputRef.value?.insertEmoji(emojiObj);
+};
+
+const handleEditor = (message: IMessageModel, type: string) => {
+  if (!message || !type) return;
+  switch (type) {
+    case "reference":
+      // todo
+      break;
+    case "reply":
+      // todo
+      break;
+    case "reedit":
+      if (message?.payload?.text) {
+        messageInputRef?.value?.reEdit(message?.payload?.text);
+      }
+      break;
+    default:
+      break;
+  }
+};
+
+const handleGroup = () => {
+  groupManageExt.value.listener.onClicked({ groupID: groupID.value });
+};
+
+function changeToolbarDisplayType(type: ToolbarDisplayType) {
+  inputToolbarDisplayType.value =
+    inputToolbarDisplayType.value === type ? "none" : type;
+  if (inputToolbarDisplayType.value !== "none" && isUniFrameWork) {
+    uni.$emit("scroll-to-bottom");
+  }
+}
+
+function scrollToLatestMessage() {
+  messageListRef.value?.scrollToLatestMessage();
+}
+</script>
+
+<style scoped lang="scss" src="./style/index.scss"></style>

+ 168 - 0
TUIKit-Homemaking/components/TUIChat/message-input-toolbar/emoji-picker/emoji-picker-dialog.vue

@@ -0,0 +1,168 @@
+<template>
+  <div
+    ref="emojiPickerDialog"
+    :class="{
+      'emoji-picker': true,
+      'emoji-picker-h5': !isPC
+    }"
+  >
+    <ul
+      ref="emojiPickerListRef"
+      :class="['emoji-picker-list', !isPC && 'emoji-picker-h5-list']"
+    >
+      <li
+        v-for="(childrenItem, childrenIndex) in currentEmojiList"
+        :key="childrenIndex"
+        class="emoji-picker-list-item"
+        @click="select(childrenItem, childrenIndex)"
+      >
+        <img
+          v-if="currentTabItem.type === EMOJI_TYPE.BASIC"
+          class="emoji"
+          :src="currentTabItem.url + basicEmojiMap[childrenItem]"
+        >
+        <img
+          v-else-if="currentTabItem.type === EMOJI_TYPE.BIG"
+          class="emoji-big"
+          :src="currentTabItem.url + childrenItem + '@2x.png'"
+        >
+        <img
+          v-else
+          class="emoji-custom"
+          :src="currentTabItem.url + childrenItem"
+        >
+      </li>
+    </ul>
+    <ul class="emoji-picker-tab">
+      <li
+        v-for="(item, index) in list"
+        :key="index"
+        class="emoji-picker-tab-item"
+        @click="toggleEmojiTab(index)"
+      >
+        <Icon
+          v-if="item.type === EMOJI_TYPE.BASIC"
+          class="icon"
+          :file="faceIcon"
+        />
+        <img
+          v-else-if="item.type === EMOJI_TYPE.BIG"
+          class="icon-big"
+          :src="item.url + item.list[0] + '@2x.png'"
+        >
+        <img
+          v-else
+          class="icon-custom"
+          :src="item.url + item.list[0]"
+        >
+      </li>
+      <li
+        v-if="isUniFrameWork"
+        class="send-btn"
+        @click="sendMessage"
+      >
+        发送
+      </li>
+    </ul>
+  </div>
+</template>
+<script lang="ts" setup>
+import { ref, onMounted, onUnmounted } from '../../../../adapter-vue';
+import {
+  TUIChatService,
+  TUIStore,
+  StoreName,
+  IConversationModel,
+  SendMessageParams,
+} from '@tencentcloud/chat-uikit-engine';
+import Icon from '../../../common/Icon.vue';
+import faceIcon from '../../../../assets/icon/face.png';
+import { EMOJI_TYPE } from '.././../../../constant';
+import { isPC, isUniFrameWork } from '../../../../utils/env';
+import { IEmojiList, IEmojiListItem } from '../../../../interface';
+import { isEnabledMessageReadReceiptGlobal } from '../../utils/utils';
+import { emojiList, basicEmojiMap, basicEmojiList } from '../../utils/emojiList';
+
+const emits = defineEmits(['insertEmoji', 'onClose', 'sendMessage']);
+const list = ref<IEmojiList>(emojiList);
+const currentTabIndex = ref<number>(0);
+const currentTabItem = ref<IEmojiListItem>(list?.value[0]);
+const currentEmojiList = ref<string[]>(list?.value[0]?.list);
+const currentConversation = ref();
+const emojiPickerDialog = ref();
+const emojiPickerListRef = ref();
+
+onMounted(() => {
+  TUIStore.watch(StoreName.CONV, {
+    currentConversation: onCurrentConversationUpdate,
+  });
+});
+
+onUnmounted(() => {
+  TUIStore.unwatch(StoreName.CONV, {
+    currentConversation: onCurrentConversationUpdate,
+  });
+});
+
+const toggleEmojiTab = (index: number) => {
+  currentTabIndex.value = index;
+  currentTabItem.value = list?.value[index];
+  currentEmojiList.value = list?.value[index]?.list;
+  // 滚动条回滚到顶部
+  // 原生 web & h5
+  if (!isUniFrameWork) {
+    emojiPickerListRef?.value && (emojiPickerListRef.value.scrollTop = 0);
+  }
+};
+
+const select = (item: any, index: number) => {
+  const options: any = {
+    emoji: { key: item, name: basicEmojiList[item] },
+    type: currentTabItem?.value?.type,
+  };
+  switch (currentTabItem?.value?.type) {
+    case EMOJI_TYPE.BASIC:
+      options.url = currentTabItem?.value?.url + basicEmojiMap[item];
+      if (isUniFrameWork) {
+        uni.$emit('insert-emoji', options);
+      } else {
+        emits('insertEmoji', options);
+      }
+      break;
+    case EMOJI_TYPE.BIG:
+      sendFaceMessage(index, currentTabItem.value);
+      break;
+    case EMOJI_TYPE.CUSTOM:
+      sendFaceMessage(index, currentTabItem.value);
+      break;
+    default:
+      break;
+  }
+  isPC && emits('onClose');
+};
+
+const sendFaceMessage = (index: number, listItem: IEmojiListItem) => {
+  const options = {
+    to:
+      currentConversation?.value?.groupProfile?.groupID
+      || currentConversation?.value?.userProfile?.userID,
+    conversationType: currentConversation?.value?.type,
+    payload: {
+      index: listItem.index,
+      data: listItem.list[index],
+    },
+    needReadReceipt: isEnabledMessageReadReceiptGlobal(),
+  } as SendMessageParams;
+  TUIChatService.sendFaceMessage(options);
+};
+
+function sendMessage() {
+  uni.$emit('send-message-in-emoji-picker');
+}
+
+function onCurrentConversationUpdate(conversation: IConversationModel) {
+  currentConversation.value = conversation;
+}
+</script>
+
+<style lang="scss" scoped src="./style/index.scss"></style>

+ 2 - 0
TUIKit-Homemaking/components/TUIChat/message-input-toolbar/emoji-picker/index.ts

@@ -0,0 +1,2 @@
+import EmojiPicker from './index.vue';
+export default EmojiPicker;

+ 78 - 0
TUIKit-Homemaking/components/TUIChat/message-input-toolbar/emoji-picker/index.vue

@@ -0,0 +1,78 @@
+<template>
+  <ToolbarItemContainer
+    ref="container"
+    :iconFile="faceIcon"
+    title="表情"
+    @onDialogShow="onDialogShow"
+    @onDialogClose="onDialogClose"
+  >
+    <EmojiPickerDialog
+      @insertEmoji="insertEmoji"
+      @sendMessage="sendMessage"
+      @onClose="onClose"
+    />
+  </ToolbarItemContainer>
+</template>
+<script lang="ts" setup>
+import {
+  TUIStore,
+  StoreName,
+  IConversationModel,
+} from '@tencentcloud/chat-uikit-engine';
+import { ref } from '../../../../adapter-vue';
+import faceIcon from '../../../../assets/icon/face.png';
+import EmojiPickerDialog from './emoji-picker-dialog.vue';
+import ToolbarItemContainer from '../toolbar-item-container/index.vue';
+import { isH5 } from '../../../../utils/env';
+import { ToolbarDisplayType } from '../../../../interface';
+
+interface IEmits {
+  (e: 'sendMessage'): void;
+  (e: 'toggleComponent'): void;
+  (e: 'insertEmoji', emoji: any): void;
+  (e: 'dialogShowInH5', dialogRef: HTMLElement): void;
+  (e: 'dialogCloseInH5', dialogRef: HTMLElement): void;
+  (e: 'changeToolbarDisplayType', type: ToolbarDisplayType): void;
+}
+
+const emits = defineEmits<IEmits>();
+const currentConversation = ref();
+const container = ref<InstanceType<typeof ToolbarItemContainer>>();
+
+TUIStore.watch(StoreName.CONV, {
+  currentConversation: (conversation: IConversationModel) => {
+    currentConversation.value = conversation;
+  },
+});
+
+const onDialogShow = (dialogRef: any) => {
+  if (!isH5) {
+    return;
+  }
+  emits('changeToolbarDisplayType', 'emojiPicker');
+  emits('dialogShowInH5', dialogRef.value);
+};
+
+const onDialogClose = (dialogRef: any) => {
+  if (!isH5) {
+    return;
+  }
+  emits('changeToolbarDisplayType', 'none');
+  emits('dialogCloseInH5', dialogRef.value);
+};
+
+const insertEmoji = (emojiObj) => {
+  emits('insertEmoji', emojiObj);
+};
+const sendMessage = () => {
+  emits('sendMessage');
+};
+const onClose = () => {
+  container.value?.toggleDialogDisplay(false);
+};
+
+defineExpose({
+  closeEmojiPicker: onClose,
+});
+</script>
+<style lang="scss" scoped src="./style/index.scss"></style>

+ 25 - 0
TUIKit-Homemaking/components/TUIChat/message-input-toolbar/emoji-picker/style/h5.scss

@@ -0,0 +1,25 @@
+.emoji-picker-h5 {
+  width: 100%;
+
+  &-list {
+    justify-content: space-between;
+  }
+
+  &-list::after {
+    content: "";
+    display: block;
+    flex: 1 1 auto;
+  }
+
+  .send-btn {
+    width: 50px;
+    height: 30px;
+    background-color: #55C06A;
+    position: absolute;
+    right: 10px;
+    font-size: 16px;
+    color: #fff;
+    text-align: center;
+    line-height: 30px;
+  }
+}

+ 4 - 0
TUIKit-Homemaking/components/TUIChat/message-input-toolbar/emoji-picker/style/index.scss

@@ -0,0 +1,4 @@
+@import "../../../../../assets/styles/common";
+@import "./web";
+@import "./h5";
+

+ 55 - 0
TUIKit-Homemaking/components/TUIChat/message-input-toolbar/emoji-picker/style/web.scss

@@ -0,0 +1,55 @@
+.emoji-picker {
+  width: 450px;
+  height: 300px;
+  display: flex;
+  flex-direction: column;
+
+  &-list {
+    flex: 1;
+    display: flex;
+    flex-wrap: wrap;
+    overflow-y: auto;
+    margin: 2px;
+
+    &::-webkit-scrollbar {
+      display: none;
+    }
+
+    &-item {
+      cursor: pointer;
+      padding: 5px;
+
+      .emoji {
+        width: 30px;
+        height: 30px;
+      }
+
+      .emoji-big {
+        width: 70px;
+        height: 70px;
+      }
+    }
+  }
+
+  &-tab {
+    display: flex;
+    align-items: center;
+
+    &-item {
+      padding: 0 10px;
+      cursor: pointer;
+
+      .icon {
+        margin: 10px;
+        width: 20px;
+        height: 20px;
+
+        &-big {
+          margin: 2px 0;
+          width: 30px;
+          height: 30px;
+        }
+      }
+    }
+  }
+}

+ 2 - 0
TUIKit-Homemaking/components/TUIChat/message-input-toolbar/evaluate/index.ts

@@ -0,0 +1,2 @@
+import Evaluate from './index.vue';
+export default Evaluate;

+ 213 - 0
TUIKit-Homemaking/components/TUIChat/message-input-toolbar/evaluate/index.vue

@@ -0,0 +1,213 @@
+<template>
+  <ToolbarItemContainer
+    ref="container"
+    :iconFile="evaluateIcon"
+    title="面试邀请"
+    :needBottomPopup="true"
+    :iconWidth="isUniFrameWork ? '26px' : '20px'"
+    :iconHeight="isUniFrameWork ? '26px' : '20px'"
+    @onDialogShow="onDialogShow"
+    @onDialogClose="onDialogClose"
+  >
+    <div :class="['evaluate', !isPC && 'evaluate-h5']">
+      <div :class="['evaluate-header', !isPC && 'evaluate-h5-header']">
+        <div :class="['evaluate-header-content', !isPC && 'evaluate-h5-header-content']">
+          {{ TUITranslateService.t("发送面试邀请") }}
+        </div>
+        <div
+          v-if="!isPC"
+          :class="['evaluate-header-close', !isPC && 'evaluate-h5-header-close']"
+          @click.stop="closeDialog"
+        >
+          {{ TUITranslateService.t("关闭") }}
+        </div>
+      </div>
+      <div :class="['evaluate-content', !isPC && 'evaluate-h5-content']">
+        <picker
+          class="picker"
+          style="
+            height: 40px;
+            width: 94%;
+            background: #f8f8f8;
+            text-align: left;
+            line-height: 39px;
+            padding: 0px 11px;
+          "
+          mode="date"
+          :value="date"
+          @change="bindDateChange"
+        >
+          <view class="uni-input">{{ date ? date : "请选择面试时间" }}</view>
+        </picker>
+
+        <textarea
+          v-model="comment"
+          placeholder="请输入面试地址"
+          :class="['evaluate-content-text', !isPC && 'evaluate-h5-content-text']"
+        />
+        <input
+          style="
+            height: 40px;
+            width: 94%;
+            background: #f8f8f8;
+            text-align: left;
+            line-height: 39px;
+            padding: 0px 11px;
+            margin-bottom: 20px;
+          "
+          @input="replaceInput"
+          :value="inpvalue"
+          focus
+          placeholder="联系电话"
+        />
+
+        <div :class="['evaluate-content-button', !isPC && 'evaluate-h5-content-button']">
+          <button
+            :class="['btn', isEvaluateValid ? 'btn-valid' : 'btn-invalid']"
+            @click="submitEvaluate"
+          >
+            {{ TUITranslateService.t("发送邀请") }}
+          </button>
+        </div>
+      </div>
+    </div>
+  </ToolbarItemContainer>
+</template>
+<script setup lang="ts">
+import {
+  TUITranslateService,
+  TUIStore,
+  StoreName,
+  IConversationModel,
+  TUIChatService,
+  SendMessageParams,
+} from "@tencentcloud/chat-uikit-engine";
+import { ref, computed } from "../../../../adapter-vue";
+import ToolbarItemContainer from "../toolbar-item-container/index.vue";
+import evaluateIcon from "../../../../assets/icon/evaluate.svg";
+import Link from "../../../../utils/documentLink";
+import Icon from "../../../common/Icon.vue";
+import starIcon from "../../../../assets/icon/star.png";
+import starLightIcon from "../../../../assets/icon/star-light.png";
+import { CHAT_MSG_CUSTOM_TYPE } from "../../../../constant";
+import { isPC, isH5, isUniFrameWork } from "../../../../utils/env";
+import { isEnabledMessageReadReceiptGlobal } from "../../utils/utils";
+import { createOfflinePushInfo } from "../../utils/sendMessage";
+
+const date = ref("");
+const inpvalue = ref("");
+const props = defineProps({
+  starTotal: {
+    type: Number,
+    default: 5,
+  },
+});
+const emits = defineEmits(["onDialogPopupShowOrHide"]);
+
+const container = ref();
+
+const starList = ref<number>(props.starTotal);
+const currentStarIndex = ref<number>(-1);
+const comment = ref("");
+const currentConversation = ref<IConversationModel>();
+
+TUIStore.watch(StoreName.CONV, {
+  currentConversation: (conversation: IConversationModel) => {
+    currentConversation.value = conversation;
+  },
+});
+
+const isEvaluateValid = computed(
+  () => comment.value.length || currentStarIndex.value >= 0
+);
+const bindDateChange = (e) => {
+  date.value = e.detail.value;
+};
+const replaceInput = (e) => {
+  inpvalue.value = e.detail.value;
+};
+
+const onDialogShow = () => {
+  emits("onDialogPopupShowOrHide", true);
+};
+
+const onDialogClose = () => {
+  resetEvaluate();
+  emits("onDialogPopupShowOrHide", false);
+};
+
+const openLink = () => {
+  if (isPC || isH5) {
+    window.open(Link?.customMessage?.url);
+  }
+};
+
+const closeDialog = () => {
+  container?.value?.toggleDialogDisplay(false);
+};
+
+const resetEvaluate = () => {
+  currentStarIndex.value = -1;
+  comment.value = "";
+};
+
+const selectStar = (starIndex?: any) => {
+  if (currentStarIndex.value === starIndex) {
+    currentStarIndex.value = currentStarIndex.value - 1;
+  } else {
+    currentStarIndex.value = starIndex;
+  }
+};
+
+const submitEvaluate = () => {
+  // 评价消息,星星数和文本必须有一个才可以提交
+  if (currentStarIndex.value < 0 && !comment.value.length) {
+    return;
+  }
+
+  let promise = TUIChatService.sendCustomMessage({
+    payload: {
+      data: JSON.stringify({
+        // 订单类消息标识字段
+        businessID: "order",
+        // 订单标题
+        companyname: "云赋能网络信息有限公司",
+        interviewtime: date.value, //面试时间
+        Interviewlocation: comment.value, //面试地点
+        iphone: inpvalue.value, //联系方式
+        name: "王希望", //联系人
+        imageUrl:
+          "https://qcloudimg.tencent-cloud.cn/trisys/assets/product/images/SOOZNXCHkHcm50wX2ndp4.png",
+      }),
+      description: "",
+      extension: "",
+    },
+  });
+
+  // const options = {
+  //   to:
+  //     currentConversation?.value?.groupProfile?.groupID
+  //     || currentConversation?.value?.userProfile?.userID,
+  //   conversationType: currentConversation?.value?.type,
+  //   payload: {
+  //     data: JSON.stringify({
+  //       businessID: CHAT_MSG_CUSTOM_TYPE.EVALUATE,
+  //       version: 1,
+  //       score: currentStarIndex.value + 1,
+  //       comment: comment.value,
+  //     }),
+  //     description: '对本次的服务评价',
+  //     extension: '对本次的服务评价',
+  //   },
+  //   needReadReceipt: isEnabledMessageReadReceiptGlobal(),
+  // };
+  // const sendMessageOptions: any = {
+  //   offlinePushInfo: createOfflinePushInfo(currentConversation),
+  // };
+  // TUIChatService.sendCustomMessage(options as SendMessageParams, sendMessageOptions);
+  // 提交后关闭 dialog
+  // close dialog after submit evaluate
+  container?.value?.toggleDialogDisplay(false);
+};
+</script>
+<style scoped lang="scss" src="./style/index.scss"></style>

+ 57 - 0
TUIKit-Homemaking/components/TUIChat/message-input-toolbar/evaluate/style/color.scss

@@ -0,0 +1,57 @@
+.evaluate {
+  background: #fff;
+  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+
+  &-header {
+    &-content {
+      font-weight: 500;
+      color: #1c1c1c;
+    }
+  }
+
+  &-adv {
+    font-weight: 500;
+    color: #999;
+
+    a {
+      color: #006eff;
+    }
+  }
+
+  &-content {
+    &-text {
+      background: #f8f8f8;
+      border: 1px solid #ececec;
+    }
+
+    &-list {
+      &-item {
+        font-weight: 400;
+        color: #50545c;
+      }
+    }
+  }
+
+  &-H5 {
+    &-main {
+      background: rgba(0, 0, 0, 0.5);
+
+      .evaluate-main-content {
+        background: #fff;
+
+        p {
+          a {
+            color: #3370ff;
+          }
+        }
+
+        .close {
+          font-family: PingFangSC-Regular;
+          font-weight: 400;
+          color: #3370ff;
+          letter-spacing: 0;
+        }
+      }
+    }
+  }
+}

+ 63 - 0
TUIKit-Homemaking/components/TUIChat/message-input-toolbar/evaluate/style/h5.scss

@@ -0,0 +1,63 @@
+.evaluate-h5 {
+  position: static;
+  width: 100%;
+  height: fit-content;
+  border-radius: 0;
+  background: #fff;
+  // padding: 23px !important;
+  box-sizing: border-box;
+
+  &-header {
+    display: flex;
+    justify-content: space-between;
+
+    &-content {
+      font-size: 18px;
+    }
+
+    &-close {
+      font-size: 18px;
+      line-height: 27px;
+      font-weight: 400;
+      color: #3370ff;
+    }
+  }
+
+  &-content {
+    order: 1;
+
+    &-list {
+      &-item {
+        width: 40px;
+        height: 24px;
+        text-align: center;
+        cursor: auto;
+        font-size: 12px;
+      }
+    }
+
+    &-text {
+      font-size: 16px;
+      width: 100%;
+    }
+
+    &-button {
+      width: 100%;
+      display: flex;
+
+      .btn {
+        flex: 1;
+        padding: 14px 0;
+        font-size: 18px;
+        cursor: auto;
+      }
+    }
+  }
+
+  &-adv {
+    font-size: 14px;
+    font-weight: normal;
+    text-align: left;
+    color: #000;
+  }
+}

+ 4 - 0
TUIKit-Homemaking/components/TUIChat/message-input-toolbar/evaluate/style/index.scss

@@ -0,0 +1,4 @@
+@import "./color";
+@import "./web";
+@import "./h5";
+@import "../../../../../assets/styles/common";

+ 93 - 0
TUIKit-Homemaking/components/TUIChat/message-input-toolbar/evaluate/style/web.scss

@@ -0,0 +1,93 @@
+.evaluate {
+  position: absolute;
+  z-index: 5;
+  width: 315px;
+  top: -255px;
+  // padding: 12px;
+  display: flex;
+  flex-direction: column;
+  border-radius: 8px;
+  background: url("https://web.sdk.qcloud.com/im/assets/images/login-background.png") no-repeat;
+  background-color: #fff;
+  background-size: cover;
+  background-position-x: 128px;
+  background-position-y: 77px;
+  user-select: none;
+
+  &-header {
+    &-content {
+      font-style: normal;
+      font-size: 12px;
+      line-height: 17px;
+      text-align: center;
+    }
+  }
+
+  &-content {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    padding: 12px 0;
+
+    &-list {
+      flex: 1;
+      display: flex;
+
+      &-item {
+        width: 24px;
+        height: 24px;
+        text-align: center;
+        cursor: pointer;
+        padding: 4px 0;
+        font-size: 12px;
+        padding-right: 15px;
+
+        &:last-child {
+          padding-right: 0 !important;
+        }
+      }
+    }
+
+    &-text {
+      box-sizing: border-box;
+      width: 288px;
+      height: 90px;
+      margin: 12px 0;
+      padding: 12px;
+      border-radius: 2px;
+      resize: none;
+    }
+
+    &-button {
+      .btn {
+        border: none;
+        border-radius: 5px;
+        font-size: 12px;
+        text-align: center;
+        line-height: 24px;
+        padding: 2px 46px;
+        font-weight: 400;
+        color: #fff;
+      }
+
+      .btn-valid {
+        background-color: #3370ff;
+        cursor: pointer;
+      }
+
+      .btn-invalid{
+        background-color: rgb(160, 207, 255);
+        cursor: not-allowed;
+      }
+    }
+  }
+
+  &-adv {
+    font-size: 12px;
+    text-align: center;
+
+    a {
+      display: inline-block;
+    }
+  }
+}

+ 2 - 0
TUIKit-Homemaking/components/TUIChat/message-input-toolbar/file-upload/index.ts

@@ -0,0 +1,2 @@
+import ImageUpload from './index.vue';
+export default ImageUpload;

+ 74 - 0
TUIKit-Homemaking/components/TUIChat/message-input-toolbar/file-upload/index.vue

@@ -0,0 +1,74 @@
+<template>
+  <ToolbarItemContainer
+    :iconFile="fileIcon"
+    title="文件"
+    :iconWidth="isUniFrameWork ? '32px' : '21px'"
+    :iconHeight="isUniFrameWork ? '25px' : '18px'"
+    :needDialog="false"
+    @onIconClick="onIconClick"
+  >
+    <div :class="['file-upload', !isPC && 'file-upload-h5']">
+      <input
+        ref="inputRef"
+        title="文件"
+        type="file"
+        data-type="file"
+        accept="*"
+        @change="sendFileMessage"
+      >
+    </div>
+  </ToolbarItemContainer>
+</template>
+<script lang="ts" setup>
+import {
+  TUIChatService,
+  TUIStore,
+  StoreName,
+  IConversationModel,
+  SendMessageParams,
+} from '@tencentcloud/chat-uikit-engine';
+import { ref } from '../../../../adapter-vue';
+import ToolbarItemContainer from '../toolbar-item-container/index.vue';
+import fileIcon from '../../../../assets/icon/files.png';
+import { isPC, isUniFrameWork } from '../../../../utils/env';
+import { isEnabledMessageReadReceiptGlobal } from '../../utils/utils';
+
+const inputRef = ref();
+const currentConversation = ref<IConversationModel>();
+
+TUIStore.watch(StoreName.CONV, {
+  currentConversation: (conversation: IConversationModel) => {
+    currentConversation.value = conversation;
+  },
+});
+
+const onIconClick = () => {
+  if (isUniFrameWork) {
+    // uniapp app 不支持选择文件发送
+    return;
+  } else {
+    inputRef?.value?.click && inputRef?.value?.click();
+  }
+};
+
+const sendFileMessage = (e: any) => {
+  if (e?.target?.files?.length <= 0) {
+    return;
+  }
+  const options = {
+    to:
+      currentConversation?.value?.groupProfile?.groupID
+      || currentConversation?.value?.userProfile?.userID,
+    conversationType: currentConversation?.value?.type,
+    payload: {
+      file: e?.target,
+    },
+    needReadReceipt: isEnabledMessageReadReceiptGlobal(),
+  } as SendMessageParams;
+  TUIChatService.sendFileMessage(options);
+  e.target.value = '';
+};
+</script>
+<style lang="scss" scoped>
+@import "../../../../assets/styles/common";
+</style>

+ 2 - 0
TUIKit-Homemaking/components/TUIChat/message-input-toolbar/image-upload/index.ts

@@ -0,0 +1,2 @@
+import ImageUpload from './index.vue';
+export default ImageUpload;

+ 146 - 0
TUIKit-Homemaking/components/TUIChat/message-input-toolbar/image-upload/index.vue

@@ -0,0 +1,146 @@
+<template>
+  <ToolbarItemContainer
+    :iconFile="imageToolbarForShow.icon"
+    :title="imageToolbarForShow.title"
+    iconWidth="30px"
+    iconHeight="30px"
+    :needDialog="false"
+    @onIconClick="onIconClick"
+  >
+    <div
+      v-if="!isUniFrameWork"
+      :class="['image-upload', !isPC && 'image-upload-h5']"
+    >
+      <input
+        ref="inputRef"
+        title="图片"
+        type="file"
+        data-type="image"
+        accept="image/gif,image/jpeg,image/jpg,image/png,image/bmp,image/webp"
+        @change="sendImageInWeb"
+      />
+    </div>
+  </ToolbarItemContainer>
+</template>
+<script lang="ts" setup>
+import {
+  TUIChatService,
+  TUIStore,
+  StoreName,
+  IConversationModel,
+  SendMessageParams,
+} from "@tencentcloud/chat-uikit-engine";
+import { TUIGlobal } from "@tencentcloud/universal-api";
+import { ref, computed } from "../../../../adapter-vue";
+import { isPC, isWeChat, isUniFrameWork } from "../../../../utils/env";
+import ToolbarItemContainer from "../toolbar-item-container/index.vue";
+import imageIcon from "@/static/images/user/tool-icon1.png";
+import imageUniIcon from "@/static/images/user/tool-icon1.png";
+import cameraUniIcon from "@/static/images/user/tool-icon2.png";
+import { isEnabledMessageReadReceiptGlobal } from "../../utils/utils";
+
+const props = defineProps({
+  // 图片源, 仅uniapp版本有效, web版本仅支持从相册中选择图片
+  // album: 从相册中选择
+  // camera: 使用相机拍摄
+  imageSourceType: {
+    type: String,
+    default: "album",
+  },
+});
+
+const inputRef = ref();
+const currentConversation = ref<IConversationModel>();
+const IMAGE_TOOLBAR_SHOW_MAP = {
+  web_album: {
+    icon: imageIcon,
+    title: "图片",
+  },
+  uni_album: {
+    icon: imageUniIcon,
+    title: "图片",
+  },
+  uni_camera: {
+    icon: cameraUniIcon,
+    title: "拍照",
+  },
+};
+
+TUIStore.watch(StoreName.CONV, {
+  currentConversation: (conversation: IConversationModel) => {
+    currentConversation.value = conversation;
+  },
+});
+
+const imageToolbarForShow = computed((): { icon: string; title: string } => {
+  if (isUniFrameWork) {
+    return props.imageSourceType === "camera"
+      ? IMAGE_TOOLBAR_SHOW_MAP["uni_camera"]
+      : IMAGE_TOOLBAR_SHOW_MAP["uni_album"];
+  } else {
+    return IMAGE_TOOLBAR_SHOW_MAP["web_album"];
+  }
+});
+
+const onIconClick = () => {
+  // uniapp 环境 发送图片
+  if (isUniFrameWork) {
+    // 增加 TUIGlobal.chooseMedia 条件限制,防御 uni 打包其他平台小程序时由于打包问题导致 isWeChat 为 true 出现运行时报错
+    if (isWeChat && TUIGlobal?.chooseMedia) {
+      // 微信小程序从基础库 2.21.0 开始, wx.chooseImage 停止维护,请使用 uni.chooseMedia 代替
+      TUIGlobal?.chooseMedia({
+        count: 1,
+        mediaType: ["image"], // 图片
+        sizeType: ["original", "compressed"], // 可以指定是原图还是压缩图,默认二者都有
+        sourceType: [props.imageSourceType], // 从相册选择或使用相机拍摄
+        success: function (res: any) {
+          sendImageMessage(res);
+        },
+      });
+    } else {
+      // uniapp h5/app 发送图片
+      TUIGlobal?.chooseImage({
+        count: 1,
+        sourceType: [props.imageSourceType], // 从相册选择或使用相机拍摄
+        success: function (res) {
+          sendImageMessage(res);
+        },
+      });
+    }
+  } else {
+    if (inputRef.value?.click) {
+      inputRef.value.click();
+    }
+  }
+};
+
+const sendImageInWeb = (e: any) => {
+  if (e?.target?.files?.length <= 0) {
+    return;
+  }
+  sendImageMessage(e?.target);
+  e.target.value = "";
+};
+
+const sendImageMessage = (files: any) => {
+  if (!files) {
+    return;
+  }
+  const options = {
+    to:
+      currentConversation?.value?.groupProfile?.groupID ||
+      currentConversation?.value?.userProfile?.userID,
+    conversationType: currentConversation?.value?.type,
+    payload: {
+      file: files,
+    },
+    needReadReceipt: isEnabledMessageReadReceiptGlobal(),
+  } as SendMessageParams;
+  // todo: 需要处理uniapp文件没有宽高的变形问题,需要linda看看
+  TUIChatService.sendImageMessage(options);
+};
+</script>
+
+<style lang="scss" scoped>
+@import "../../../../assets/styles/common";
+</style>

+ 2 - 0
TUIKit-Homemaking/components/TUIChat/message-input-toolbar/index.ts

@@ -0,0 +1,2 @@
+import MessageInputToolbar from './index.vue';
+export default MessageInputToolbar;

+ 255 - 0
TUIKit-Homemaking/components/TUIChat/message-input-toolbar/index.vue

@@ -0,0 +1,255 @@
+<template>
+  <div
+    :class="[
+      'message-input-toolbar',
+      'message-input-toolbar-h5',
+      'message-input-toolbar-uni',
+    ]"
+  >
+    <div v-if="props.displayType === 'emojiPicker'">
+      <EmojiPickerDialog />
+    </div>
+    <div v-else>
+      <swiper
+        :class="['message-input-toolbar-swiper']"
+        :indicator-dots="isSwiperIndicatorDotsEnable"
+        :autoplay="false"
+        :circular="false"
+      >
+        <swiper-item
+          :class="[
+            'message-input-toolbar-list',
+            'message-input-toolbar-h5-list',
+            'message-input-toolbar-uni-list',
+          ]"
+        >
+          <ImageUpload imageSourceType="camera" />
+          <ImageUpload imageSourceType="album" />
+          <!-- <OtgoingCAll></OtgoingCAll> -->
+          <!-- <VideoUpload videoSourceType="album" />
+          <VideoUpload videoSourceType="camera" /> -->
+          <!-- <template v-if="currentExtensionList[0]">
+            <div
+              v-for="(extension, index) in currentExtensionList.slice(0, 4)"
+              :key="index"
+            >
+              <ToolbarItemContainer
+                v-if="extension"
+                :iconFile="genExtensionIcon(extension)"
+                :title="genExtensionText(extension)"
+                iconWidth="25px"
+                iconHeight="25px"
+                :needDialog="false"
+                @onIconClick="onExtensionClick(extension)"
+              />
+            </div>
+          </template> -->
+          <!-- <Evaluate
+            v-if="currentExtensionList.length < 4"
+            @onDialogPopupShowOrHide="handleSwiperDotShow"
+          /> -->
+          <!-- <Words @onDialogPopupShowOrHide="handleSwiperDotShow" />
+           -->
+          <server :infoData="props.infoData" />
+        </swiper-item>
+        <swiper-item
+          v-if="currentExtensionList[2] && currentExtensionList.length >= 3"
+          :class="[
+            'message-input-toolbar-list',
+            'message-input-toolbar-h5-list',
+            'message-input-toolbar-uni-list',
+          ]"
+        >
+          <div v-for="(extension, index) in currentExtensionList.slice(4)" :key="index">
+            <ToolbarItemContainer
+              v-if="extension"
+              :iconFile="genExtensionIcon(extension)"
+              :title="genExtensionText(extension)"
+              iconWidth="25px"
+              iconHeight="25px"
+              :needDialog="false"
+              @onIconClick="onExtensionClick(extension)"
+            />
+          </div>
+          <Evaluate
+            v-if="currentExtensionList.length >= 4"
+            @onDialogPopupShowOrHide="handleSwiperDotShow"
+          />
+          <Words
+            v-if="currentExtensionList.length >= 3"
+            @onDialogPopupShowOrHide="handleSwiperDotShow"
+          />
+        </swiper-item>
+      </swiper>
+    </div>
+    <UserSelector
+      ref="userSelectorRef"
+      :type="selectorShowType"
+      :currentConversation="currentConversation"
+      :isGroup="isGroup"
+      @submit="onUserSelectorSubmit"
+      @cancel="onUserSelectorCancel"
+    />
+  </div>
+</template>
+<script setup lang="ts">
+import { ref, onUnmounted, onMounted } from "../../../adapter-vue";
+import TUIChatEngine, {
+  IConversationModel,
+  TUIStore,
+  StoreName,
+} from "@tencentcloud/chat-uikit-engine";
+import TUICore, { ExtensionInfo, TUIConstants } from "@tencentcloud/tui-core";
+import ImageUpload from "./image-upload/index.vue";
+import VideoUpload from "./video-upload/index.vue";
+import OtgoingCAll from "./otgoing-call/index.vue";
+import server from "./server/index.vue";
+import Evaluate from "./evaluate/index.vue";
+import Words from "./words/index.vue";
+import ToolbarItemContainer from "./toolbar-item-container/index.vue";
+import EmojiPickerDialog from "./emoji-picker/emoji-picker-dialog.vue";
+import UserSelector from "./user-selector/index.vue";
+import TUIChatConfig from "../config";
+import { enableSampleTaskStatus } from "../../../utils/enableSampleTaskStatus";
+import { ToolbarDisplayType } from "../../../interface";
+
+interface IProps {
+  displayType: ToolbarDisplayType;
+  infoData: Object;
+}
+
+const props = withDefaults(defineProps<IProps>(), {});
+
+const currentConversation = ref<IConversationModel>();
+const isGroup = ref<boolean>(false);
+const selectorShowType = ref<string>("");
+const userSelectorRef = ref();
+const currentUserSelectorExtension = ref<ExtensionInfo | null>();
+const currentExtensionList = ref<ExtensionInfo[]>([]);
+const isSwiperIndicatorDotsEnable = ref<boolean>(false);
+
+// extensions
+const extensionList: ExtensionInfo[] = [
+  ...TUICore.getExtensionList(TUIConstants.TUIChat.EXTENSION.INPUT_MORE.EXT_ID),
+];
+
+const getExtensionList = (conversationID: string) => {
+  if (!conversationID) {
+    // uniapp build ios app has null in last index need to filter
+    return (currentExtensionList.value = extensionList.filter((extension) => extension));
+  }
+  const chatType = TUIChatConfig.getChatType();
+  const options: any = {
+    chatType,
+  };
+  // 向下兼容,callkit 没有chatType 判断时,使用 filterVoice、filterVideo 过滤
+  if (chatType === "customerService") {
+    options.filterVoice = true;
+    options.filterVideo = true;
+    enableSampleTaskStatus("customerService");
+  }
+  // uniapp build ios app has null in last index need to filter
+  currentExtensionList.value = [
+    ...TUICore.getExtensionList(
+      TUIConstants.TUIChat.EXTENSION.INPUT_MORE.EXT_ID,
+      options
+    ),
+  ].filter((extension) => extension);
+};
+
+const onCurrentConversationUpdate = (conversation: IConversationModel) => {
+  if (
+    conversation?.conversationID &&
+    currentConversation.value?.conversationID !== conversation?.conversationID
+  ) {
+    getExtensionList(conversation?.conversationID);
+    if (currentExtensionList.value.length > 2) {
+      isSwiperIndicatorDotsEnable.value = true;
+    }
+  }
+  currentConversation.value = conversation;
+  if (currentConversation?.value?.type === TUIChatEngine.TYPES.CONV_GROUP) {
+    isGroup.value = true;
+  } else {
+    isGroup.value = false;
+  }
+};
+
+onMounted(() => {
+  TUIStore.watch(StoreName.CONV, {
+    currentConversation: onCurrentConversationUpdate,
+  });
+});
+
+onUnmounted(() => {
+  TUIStore.unwatch(StoreName.CONV, {
+    currentConversation: onCurrentConversationUpdate,
+  });
+});
+
+// handle extensions onclick
+const onExtensionClick = (extension: ExtensionInfo) => {
+  // uniapp vue2 build wx lose listener proto
+  const extensionModel = currentExtensionList.value.find(
+    (targetExtension) => targetExtension?.data?.name === extension?.data?.name
+  );
+  switch (extensionModel?.data?.name) {
+    case "voiceCall":
+      onCallExtensionClicked(extensionModel, 1);
+      break;
+    case "videoCall":
+      onCallExtensionClicked(extensionModel, 2);
+      break;
+    case "search":
+      extensionModel?.listener?.onClicked?.();
+      break;
+    default:
+      break;
+  }
+};
+
+const onCallExtensionClicked = (extension: ExtensionInfo, callType: number) => {
+  selectorShowType.value = extension?.data?.name;
+  if (currentConversation?.value?.type === TUIChatEngine.TYPES.CONV_C2C) {
+    extension?.listener?.onClicked?.({
+      userIDList: [currentConversation?.value?.conversationID?.slice(3)],
+      type: callType,
+    });
+  } else if (isGroup.value) {
+    currentUserSelectorExtension.value = extension;
+    userSelectorRef?.value?.toggleShow && userSelectorRef.value.toggleShow(true);
+  }
+};
+
+const genExtensionIcon = (extension: any) => {
+  return extension?.icon;
+};
+const genExtensionText = (extension: any) => {
+  return extension?.text;
+};
+
+const onUserSelectorSubmit = (selectedInfo: any) => {
+  currentUserSelectorExtension.value?.listener?.onClicked?.(selectedInfo);
+  currentUserSelectorExtension.value = null;
+};
+
+const onUserSelectorCancel = () => {
+  currentUserSelectorExtension.value = null;
+};
+
+const handleSwiperDotShow = (showStatus: boolean) => {
+  isSwiperIndicatorDotsEnable.value =
+    currentExtensionList.value.length > 2 ? !showStatus : false;
+};
+</script>
+<script lang="ts">
+export default {
+  options: {
+    styleIsolation: "shared",
+  },
+};
+</script>
+<style lang="scss">
+@import "../../../assets/styles/common";
+@import "./style/uni";
+</style>

+ 2 - 0
TUIKit-Homemaking/components/TUIChat/message-input-toolbar/otgoing-call/index.ts

@@ -0,0 +1,2 @@
+import OtgoingCAll from './index.vue';
+export default OtgoingCAll;

+ 117 - 0
TUIKit-Homemaking/components/TUIChat/message-input-toolbar/otgoing-call/index.vue

@@ -0,0 +1,117 @@
+<template>
+  <ToolbarItemContainer
+    ref="container"
+    :iconFile="evaluateIcon"
+    title="打电话"
+    :needBottomPopup="true"
+    :iconWidth="isUniFrameWork ? '26px' : '20px'"
+    :iconHeight="isUniFrameWork ? '26px' : '20px'"
+    @onDialogShow="onDialogShow"
+    @onDialogClose="onDialogClose"
+  >
+    <div :class="['evaluate', !isPC && 'evaluate-h5']">
+      <div :class="['evaluate-content-button', !isPC && 'evaluate-h5-content-button']">
+        <button
+          :class="['btn', isEvaluateValid ? 'btn-valid' : 'btn-invalid']"
+          @click="submitEvaluate"
+        >
+          {{ TUITranslateService.t("发送手机号") }}
+        </button>
+      </div>
+    </div>
+  </ToolbarItemContainer>
+</template>
+<script setup lang="ts">
+import {
+  TUITranslateService,
+  TUIStore,
+  StoreName,
+  IConversationModel,
+  TUIChatService,
+  SendMessageParams,
+} from "@tencentcloud/chat-uikit-engine";
+import { ref, computed } from "../../../../adapter-vue";
+import ToolbarItemContainer from "../toolbar-item-container/index.vue";
+import evaluateIcon from "../../../../assets/icon/evaluate.svg";
+import Link from "../../../../utils/documentLink";
+import Icon from "../../../common/Icon.vue";
+import starIcon from "../../../../assets/icon/star.png";
+import starLightIcon from "../../../../assets/icon/star-light.png";
+import { CHAT_MSG_CUSTOM_TYPE } from "../../../../constant";
+import { isPC, isH5, isUniFrameWork } from "../../../../utils/env";
+import { isEnabledMessageReadReceiptGlobal } from "../../utils/utils";
+import { createOfflinePushInfo } from "../../utils/sendMessage";
+const props = defineProps({
+  starTotal: {
+    type: Number,
+    default: 5,
+  },
+});
+const emits = defineEmits(["onDialogPopupShowOrHide"]);
+
+const container = ref();
+
+const starList = ref<number>(props.starTotal);
+const currentStarIndex = ref<number>(-1);
+const comment = ref("");
+const currentConversation = ref<IConversationModel>();
+
+TUIStore.watch(StoreName.CONV, {
+  currentConversation: (conversation: IConversationModel) => {
+    currentConversation.value = conversation;
+  },
+});
+
+const isEvaluateValid = computed(
+  () => comment.value.length || currentStarIndex.value >= 0
+);
+
+const onDialogShow = () => {
+  emits("onDialogPopupShowOrHide", true);
+};
+
+const onDialogClose = () => {
+  resetEvaluate();
+  emits("onDialogPopupShowOrHide", false);
+};
+
+const openLink = () => {
+  if (isPC || isH5) {
+    window.open(Link?.customMessage?.url);
+  }
+};
+
+const closeDialog = () => {
+  container?.value?.toggleDialogDisplay(false);
+};
+
+const resetEvaluate = () => {
+  currentStarIndex.value = -1;
+  comment.value = "";
+};
+
+const selectStar = (starIndex?: any) => {
+  if (currentStarIndex.value === starIndex) {
+    currentStarIndex.value = currentStarIndex.value - 1;
+  } else {
+    currentStarIndex.value = starIndex;
+  }
+};
+
+const submitEvaluate = () => {
+  let promise = TUIChatService.sendCustomMessage({
+    payload: {
+      data: JSON.stringify({
+        businessID: "phone",
+        title: "用户名称的手机号",
+        iphone: "18790411793",
+     
+      }),
+      description: "",
+      extension: "",
+    },
+  });
+  container?.value?.toggleDialogDisplay(false);
+};
+</script>
+<style scoped lang="scss" src="../../style/index.scss"></style>

+ 54 - 0
TUIKit-Homemaking/components/TUIChat/message-input-toolbar/server/index.vue

@@ -0,0 +1,54 @@
+<template>
+  <ToolbarItemContainer
+    :iconFile="Icon"
+    title="我的发布"
+    :needDialog="false"
+    iconWidth="30px"
+    iconHeight="30px"
+    @onIconClick="onIconClick"
+  >
+    <div class="video-upload">
+      <input
+        ref="inputRef"
+        title="我的发布"
+        type="file"
+        data-type="video"
+        accept="video/*"
+      />
+    </div>
+  </ToolbarItemContainer>
+</template>
+<script lang="ts" setup>
+import ToolbarItemContainer from "../toolbar-item-container/index.vue";
+import Icon from "@/static/images/user/tool-icon4.png";
+
+interface IProps {
+  infoData: Object;
+}
+const props = withDefaults(defineProps<IProps>(), {});
+
+const onIconClick = () => {
+  uni.navigateTo({
+    url:
+      "/pages/merChantSide/publish/my-publish?shopUserId=" +
+      props.infoData.shopUserId +
+      "&userId=" +
+      props.infoData.userId,
+  });
+};
+
+// 获取地址栏参数
+function getParamValue(paramName) {
+  const regExp = new RegExp("[?&]" + paramName + "=([^&#]*)");
+  const results = regExp.exec(window.location.href);
+  if (results) {
+    return decodeURIComponent(results[1]);
+  } else {
+    return null;
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import "../../../../assets/styles/common";
+</style>

+ 105 - 0
TUIKit-Homemaking/components/TUIChat/message-input-toolbar/style/uni.scss

@@ -0,0 +1,105 @@
+/* stylelint-disable */
+.message-input-toolbar {
+  border-top: 1px solid #f4f5f9;
+  width: 100%;
+  max-width: 100%;
+  display: flex;
+  flex-direction: row;
+  justify-content: space-between;
+  z-index: 100;
+
+  &-list {
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+
+    .extension-list {
+      list-style: none;
+      display: flex;
+
+      &-item {
+        width: 20px;
+        height: 20px;
+        padding: 12px 10px 1px;
+        cursor: pointer;
+      }
+    }
+  }
+}
+
+.message-input-toolbar-h5 {
+  padding: 5px 10px;
+  box-sizing: border-box;
+  flex-direction: column;
+}
+
+.message-input-toolbar-uni {
+  background-color: #ebf0f6;
+  flex-direction: column;
+  z-index: 100;
+
+  &-list {
+    flex: 1;
+    display: grid;
+    grid-template-columns: repeat(4, 25%);
+    grid-template-rows: repeat(2, 100px);
+  }
+}
+
+// uniapp swiper style
+wx-swiper .wx-swiper-wrapper,
+wx-swiper .wx-swiper-slides,
+wx-swiper .wx-swiper-slide-frame,
+.message-input-toolbar-list {
+  overflow: visible !important;
+}
+
+.message-input-toolbar {
+
+  .bottom-popup,
+  .bottom-popup-h5,
+  .bottom-popup-uni {
+    position: sticky !important;
+  }
+}
+
+.message-input-toolbar-swiper {
+  width: 100%;
+  height: 220px;
+
+  ::v-deep .uni-swiper-wrapper,
+  wx-swiper .wx-swiper-wrapper {
+    overflow: visible !important;
+
+    .uni-swiper-slides,
+    .wx-swiper-slides,
+    wx-swiper .wx-swiper-slides {
+      overflow: visible !important;
+
+      .uni-swiper-slide-frame,
+      .wx-swiper-slide-frame,
+      wx-swiper .wx-swiper-slide-frame {
+        overflow: visible !important;
+
+        .message-input-toolbar-list {
+          overflow: visible !important;
+        }
+
+        .toolbar-item-container-uni {
+          position: static !important;
+        }
+
+        .toolbar-item-container-dialog {
+          position: absolute !important;
+          background: transparent;
+          left: -10px;
+          bottom: -5px;
+
+          .bottom-popup-uni {
+            position: sticky !important;
+          }
+        }
+      }
+    }
+  }
+}

+ 0 - 0
TUIKit-Homemaking/components/TUIChat/message-input-toolbar/toolbar-item-container/index.vue


Vissa filer visades inte eftersom för många filer har ändrats