index.tsx 5.8 KB

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