index.tsx 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. import { useEffect, useRef, useState } from "react";
  2. import { Image, View, ScrollView, Video } from "@tarojs/components";
  3. import { formatSeconds } from "@/utils/index";
  4. import PageCustom from "@/components/page-custom/index";
  5. import NavBarNormal from "@/components/NavBarNormal/index";
  6. import { uploadAndNavToGenNewAvatar } from "@/utils/avatar";
  7. import IconPlusBig from "@/components/icon/icon-plus-big";
  8. import { editAgentAvatar } from "@/service/agent";
  9. import { deleteAvatar, fetchMyAvatars } from "@/service/storage";
  10. import style from "./index.module.less";
  11. import { TAvatarItem } from "@/service/storage";
  12. import { useAgentStore } from "@/store/agentStore";
  13. import Taro from "@tarojs/taro";
  14. import { isSuccess } from "@/utils";
  15. import IconDeleteGray16 from "@/components/icon/IconDeleteGray16";
  16. import EmptyData from "@/components/empty-data";
  17. import { useModalStore } from "@/store/modalStore";
  18. import { useLoadMoreInfinite, createKey } from "@/utils/loadMoreInfinite";
  19. export default function Index() {
  20. const { agent, fetchAgent } = useAgentStore();
  21. const [scrollTop, setScrollTop] = useState(0);
  22. const scrollPositionRef = useRef(0);
  23. const { showModal } = useModalStore();
  24. const fetcher = async ([_url, { pageIndex, pageSize }]) => {
  25. const res = await fetchMyAvatars({ pageIndex, pageSize });
  26. return res.data;
  27. };
  28. const { list, loadMore, mutate } = useLoadMoreInfinite<TAvatarItem[]>(
  29. createKey("fetchMyAvatars"),
  30. fetcher
  31. );
  32. const [current, setCurrent] = useState<TAvatarItem | null>(null);
  33. const handleClick = async (item: TAvatarItem) => {
  34. console.log(item);
  35. if (!agent?.agentId) {
  36. return;
  37. }
  38. Taro.showLoading();
  39. const result = await editAgentAvatar(agent.agentId, item.avatarId, false);
  40. await fetchAgent(agent.agentId);
  41. Taro.hideLoading();
  42. setCurrent(item);
  43. if (isSuccess(result.status)) {
  44. Taro.navigateBack();
  45. }
  46. };
  47. const onScrollToLower = () => {
  48. loadMore();
  49. console.log("lower");
  50. };
  51. const handleCreate = () => {
  52. uploadAndNavToGenNewAvatar();
  53. };
  54. const handleDelete = async (e: any, avatar: TAvatarItem) => {
  55. e.stopPropagation();
  56. showModal({
  57. content: <>确认删除该形象?</>,
  58. async onConfirm() {
  59. const response = await deleteAvatar(avatar.avatarId);
  60. if (isSuccess(response.status)) {
  61. mutate();
  62. }
  63. },
  64. });
  65. };
  66. const renderMedia = (avatar: TAvatarItem) => {
  67. if (avatar.isVideo) {
  68. return (
  69. <View className={style.videoContainer}>
  70. <Video
  71. controls={false}
  72. showCenterPlayBtn={false}
  73. loop={true}
  74. muted={true}
  75. objectFit="cover"
  76. src={avatar.avatarUrl}
  77. className="w-full h-full"
  78. />
  79. <View className={style.durationStatus}>
  80. <View className={style.playBtn}></View>
  81. <View>{formatSeconds(Math.round(avatar.videoSeconds))}</View>
  82. </View>
  83. )}
  84. </View>
  85. );
  86. }
  87. return <Image src={avatar.avatarUrl} mode="widthFix" className="w-full" />;
  88. };
  89. const renderList = () => {
  90. if (!list.length) {
  91. return (
  92. <>
  93. <EmptyData type={"search"}></EmptyData>
  94. </>
  95. );
  96. }
  97. return list.map((avatar) => {
  98. const isCurrent = agent?.avatarUrl === avatar.avatarUrl;
  99. return (
  100. <View
  101. className={`${isCurrent ? style.gridItemActived : style.gridItem}`}
  102. onClick={() => handleClick(avatar)}
  103. >
  104. {!isCurrent && (
  105. <View
  106. className={style.deleteButton}
  107. onClick={(e) => handleDelete(e, avatar)}
  108. >
  109. <IconDeleteGray16 />
  110. </View>
  111. )}
  112. {renderMedia(avatar)}
  113. </View>
  114. );
  115. });
  116. };
  117. return (
  118. <PageCustom>
  119. <NavBarNormal>历史形象</NavBarNormal>
  120. <View className={style.container}>
  121. <ScrollView
  122. scrollY
  123. onScrollToLower={onScrollToLower}
  124. scrollTop={scrollTop}
  125. onScroll={(e) => {
  126. scrollPositionRef.current = e.detail.scrollTop;
  127. }}
  128. style={{
  129. flex: 1,
  130. height: "100%", // 高度自适应
  131. }}
  132. >
  133. <View className="w-full p-16 pb-120">
  134. <View className={style.grid}>
  135. <View className={style.gridItem} onClick={handleCreate}>
  136. <View className={style.icon}>
  137. <IconPlusBig></IconPlusBig>
  138. </View>
  139. <View className="pt-8 text-12 leading-20 text-gray-45">
  140. 创建新形象
  141. </View>
  142. </View>
  143. {renderList()}
  144. </View>
  145. </View>
  146. </ScrollView>
  147. </View>
  148. </PageCustom>
  149. );
  150. }