index.tsx 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. /**
  2. * 生成微信分享给聊天框内的图片卡片
  3. */
  4. import { Canvas } from "@tarojs/components";
  5. import style from './index.module.less'
  6. import { getCanvasTempPath } from "@/utils/index";
  7. import {
  8. Application,
  9. ImgLoader,
  10. Container,
  11. Image as DuduImage,
  12. RichText,
  13. } from "../../libs/duducanvas/index";
  14. import Taro, { useShareAppMessage, useShareTimeline } from "@tarojs/taro";
  15. import { getSharePromise } from "./shareUtils";
  16. import Stage from "@/libs/duducanvas/Stage";
  17. import { TAgent, TAgentDetail } from "@/types/agent";
  18. import { DEFAULT_AVATAR } from "@/config";
  19. const getCanvasSize = () => {
  20. // 根据屏幕宽度计算 canvas 宽度
  21. const windowInfo = Taro.getWindowInfo();
  22. const screenWidth = windowInfo.windowWidth;
  23. console.log(windowInfo, 'WindowInfo');
  24. const designWidth = 375;
  25. const designHeight = 300;
  26. // 宽高放大一倍
  27. const canvasWidth = screenWidth * 2;
  28. const canvasHeight = (screenWidth / designWidth) * designHeight * 2;
  29. const ratio = canvasWidth / 210;
  30. return {
  31. canvasWidth,
  32. canvasHeight,
  33. ratio,
  34. };
  35. };
  36. const drawCircleEffect = (avatar: Container, ratio: number)=> {
  37. const circle0 = new Container();
  38. circle0.width = 178 * ratio;
  39. circle0.height = 178 * ratio;
  40. circle0.borderRadius = "100%";
  41. circle0.shadow = "0 0 20px rgba(0,0,0,.02)";
  42. circle0.backgroundColor = "#f6f6f6";
  43. const circle1 = new Container();
  44. circle1.x = 0;
  45. circle1.y = 0;
  46. circle1.width = 138 * ratio;
  47. circle1.height = 138 * ratio;
  48. circle1.borderRadius = "100%";
  49. circle1.shadow = "0 0 20px rgba(0,0,0,.02)";
  50. circle1.backgroundColor = "#f8f8f8";
  51. const circle2 = new Container();
  52. circle2.x = 0;
  53. circle2.y = 0;
  54. circle2.width = 102 * ratio;
  55. circle2.height = 102 * ratio;
  56. circle2.borderRadius = "100%";
  57. circle2.shadow = "0 0 20px rgba(0,0,0,.02)";
  58. circle2.backgroundColor = "#fafafa";
  59. circle2.addChild(avatar);
  60. circle1.addChild(circle2);
  61. circle0.addChild(circle1);
  62. return circle0
  63. }
  64. interface Props {
  65. agent: TAgentDetail;
  66. }
  67. export default (props: Props) => {
  68. const { canvasWidth, canvasHeight, ratio } = getCanvasSize();
  69. let stage: Stage|null;
  70. // character = useCurrentCharacter
  71. const agent = props.agent
  72. const initCanvas = async () => {
  73. // console.log('share:', character)
  74. if(!agent){
  75. return
  76. }
  77. const app = new Application(
  78. "#myShareCanvas",
  79. { width: canvasWidth, height: canvasHeight },
  80. null
  81. );
  82. stage = await app.init();
  83. if(!stage){
  84. return;
  85. }
  86. let avatarImg = agent.avatarLogo ?? DEFAULT_AVATAR
  87. const card = new Container();
  88. // 如果有头像,加载头像图片先
  89. const imgArr = [
  90. {
  91. id: "avatar",
  92. src: avatarImg,
  93. }
  94. ]
  95. const loader = new ImgLoader(stage.canvas, imgArr);
  96. await loader.load();
  97. card.x = 0;
  98. card.y = -140;
  99. card.gap = 5;
  100. card.width = 210 * ratio;
  101. card.height = 200 * ratio;
  102. // 矩形用于头像,及头像背景效果
  103. const rect = new Container();
  104. rect.y = -140 * ratio;
  105. rect.direction = "column";
  106. rect.justifyContent = "space-around";
  107. rect.width = card.width * ratio;
  108. rect.height = 200 * ratio;
  109. rect.borderRadius = 0;
  110. card.addChild(rect);
  111. // 头像
  112. const avatarTexture = loader.get("avatar");
  113. if (avatarTexture) {
  114. const dWidth = 80;
  115. const avatar = new DuduImage({
  116. image: avatarTexture.image,
  117. dWidth: (dWidth) * ratio,
  118. dHeight: (avatarTexture.height * dWidth/avatarTexture.width) * ratio,
  119. });
  120. const avatarWrapper = new Container()
  121. avatarWrapper.width = dWidth * ratio
  122. avatarWrapper.height = dWidth * ratio
  123. avatarWrapper.overflowHidden = true
  124. avatarWrapper.borderRadius = '100%'
  125. avatarWrapper.addChild(avatar)
  126. const circleBg = drawCircleEffect(avatarWrapper, ratio)
  127. card.backgroundColor = "white";
  128. rect.backgroundColor = "#f5f5f5";
  129. rect.addChild(circleBg)
  130. }
  131. // 名称与公司名容器
  132. const infoList = new Container();
  133. infoList.y = 110 * ratio;
  134. infoList.direction = "column";
  135. infoList.gap = 4 * ratio;
  136. infoList.width = card.width * ratio;
  137. infoList.height = 42 * ratio;
  138. // 用户名
  139. const name = new RichText({
  140. text: agent?.name ?? '',
  141. fontSize: 15 * ratio,
  142. color: "black",
  143. fontWeight: 500,
  144. });
  145. name.wrapWidth = 180 * ratio;
  146. name.lineClamp = 1;
  147. name.shadow = '0 0 4 white'
  148. name.height = 22 * ratio;
  149. // 单位名
  150. const companyName = new RichText();
  151. companyName.lineClamp = 1;
  152. companyName.text = agent?.entName ?? '';
  153. companyName.wrapWidth = 160 * ratio;
  154. companyName.fontSize = 12 * ratio;
  155. companyName.color = "rgba(0, 0, 0, .45)";
  156. companyName.letterSpace = 4;
  157. companyName.lineGap = 8;
  158. companyName.shadow = '0 0 4 white'
  159. infoList.addChild(name, companyName);
  160. stage.addChild(card, infoList);
  161. stage.update();
  162. };
  163. // 延迟获取 canvas
  164. // Taro.nextTick(() => {
  165. // initCanvas();
  166. // });
  167. const shareTitle = '快和我的智能体聊聊吧' // '想了解我?快和我的AI聊聊吧',
  168. useShareAppMessage(async () => {
  169. const agentId = agent?.agentId;
  170. console.log(agent)
  171. if(!agentId){
  172. return {
  173. title: shareTitle,
  174. path: `/pages/profile/index?agentId=${agentId}`,
  175. }
  176. }
  177. Taro.showLoading()
  178. await initCanvas();
  179. let tmpImage = ''
  180. if(stage){
  181. tmpImage = await getCanvasTempPath(stage.canvas, "myShareCanvas");
  182. }
  183. const reponse = await getSharePromise(agentId, shareTitle, tmpImage)
  184. Taro.hideLoading()
  185. return reponse;
  186. });
  187. useShareTimeline(() => {
  188. const agentId = agent?.agentId;
  189. const o = {
  190. title: shareTitle,
  191. query: `agentId=${agentId}`,
  192. };
  193. return o;
  194. });
  195. return (
  196. <Canvas
  197. type="2d"
  198. id="myShareCanvas"
  199. width={String(canvasWidth)}
  200. height={String(canvasHeight)}
  201. style={`width: ${canvasWidth / 2}px; height: ${canvasHeight / 2}px;`}
  202. className={style.canvas}
  203. />
  204. );
  205. };