| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 |
- import { useEffect, useRef, useState } from "react";
- import { Image, View, ScrollView, Video } from "@tarojs/components";
- import { formatSeconds, saveMediaFile } from "@/utils/index";
- import PageCustom from "@/components/page-custom/index";
- import NavBarNormal from "@/components/NavBarNormal/index";
- import { checkPermission, showAuthModal } from "@/utils/auth";
- import { uploadAndNavToGenNewAvatar } from "@/utils/avatar";
- import IconPlusBig from "@/components/icon/icon-plus-big";
- import IconPlayWhite24 from '@/components/icon/IconPlayWhite20'
- import { deleteAvatar, fetchMyAvatars } from "@/service/storage";
- import style from "./index.module.less";
- import { TAvatarItem } from "@/service/storage";
- import { useAgentStore, useAgentStoreActions } from "@/store/agentStore";
- import Taro, { useDidShow, useUnload } from "@tarojs/taro";
- import { isSuccess } from "@/utils";
- import WemetaRadio from "@/components/WemetaRadio/index";
- import { useModalStore } from "@/store/modalStore";
- import { useLoadMoreInfinite, createKey } from "@/utils/loadMoreInfinite";
- import BottomBar from "@/components/BottomBar";
- import WemetaButton from "@/components/buttons/WemetaButton";
- export default function Index() {
- const agent = useAgentStore((state) => state.agent);
- const { setCurrentEditAvatar } = useAgentStoreActions()
- const [scrollTop, setScrollTop] = useState(0);
- const scrollPositionRef = useRef(0);
- const { showModal } = useModalStore((state) => state.actions);
- const fetcher = async ([_url, { pageIndex, pageSize }]) => {
- const res = await fetchMyAvatars({ pageIndex: pageIndex, pageSize });
- return res.data;
- };
- const { list, loadMore, mutate } = useLoadMoreInfinite<TAvatarItem[]>(
- createKey("fetchMyAvatars"),
- fetcher
- );
- const [current, setCurrent] = useState<TAvatarItem | null>(null);
- // 选择形象
- const handleSelect = async (e: any, item: TAvatarItem) => {
- e.stopPropagation()
- console.log(item);
- if (current?.avatarId === item.avatarId) {
- setCurrent(null)
- } else {
- setCurrent(item);
- }
- };
- const handleSetBackground = () => {
- current && setCurrentEditAvatar(current)
- Taro.navigateTo({ url: '/pages/agent-avatar-confirm/index' });
- }
- const onScrollToLower = () => {
- loadMore();
- console.log("lower");
- };
- const handleCreate = () => {
- uploadAndNavToGenNewAvatar();
- };
- const handleDelete = async (e: any) => {
- e.stopPropagation()
- if (!current || !current.canDel) {
- return
- }
- showModal({
- content: <>确认删除该形象?</>,
- async onConfirm() {
- const response = await deleteAvatar(current.avatarId);
- if (isSuccess(response.status)) {
- setCurrent(null)
- mutate();
- }
- },
- });
- };
- const handlePreview = (index: number) => {
- Taro.previewMedia({
- current: index,
- //@ts-ignore
- sources: list.map((item) => {
- return {
- url: item.avatarUrl,
- type: item.isVideo ? 'video' : 'image',
- }
- }),
- })
- }
- const saveMedia = async (tmpPath: string) => {
- const res = await saveMediaFile(tmpPath, current?.isVideo);
- if (res) {
- Taro.showToast({
- title: '保存成功'
- })
- return
- }
- Taro.showToast({
- title: '保存失败'
- })
- }
- const handleDownload = async () => {
- if (!current?.avatarUrl) {
- return
- }
- // 保存至相册
- Taro.showLoading();
- const authed = await checkPermission("scope.writePhotosAlbum");
- if (!authed) {
- Taro.hideLoading();
- showAuthModal("需要您相册权限");
- return;
- }
- Taro.downloadFile({
- url: current.avatarUrl,
- success: (res) => {
- if (res.statusCode === 200) {
- saveMedia(res.tempFilePath)
- }
- },
- fail: () => {
- Taro.hideLoading();
- },
- })
- };
- useDidShow(() => {
- mutate()
- })
- useUnload(()=> {
- Taro.hideLoading()
- })
- const renderMedia = (avatar: TAvatarItem, index: number) => {
- if (avatar.isVideo) {
- return <>
- <View className={style.videoContainer} onClick={() => handlePreview(index)}>
- <Video
- controls={false}
- showCenterPlayBtn={false}
- loop={true}
- muted={true}
- objectFit="cover"
- src={avatar.avatarUrl}
- className="w-full h-full"
- />
- <View className={style.blurBg}></View>
- <View className={style.durationStatus}>
- <IconPlayWhite24 />
- <View className="text-10">{formatSeconds(Math.round(avatar.videoSeconds))}</View>
- </View>
- </View>
- </>
- }
- return <Image src={`${avatar.avatarUrl}?x-oss-process=image/quality,Q_60/format,jpg`} mode="widthFix" className="w-full" onClick={() => handlePreview(index)} />;
- };
- const renderList = () => {
- if (!list.length) {
- return (
- <>
- {/* <EmptyData type={"search"}></EmptyData> */}
- </>
- );
- }
- return list.map((avatar, index) => {
- const currentUsed = agent?.avatarUrl === avatar.avatarUrl;
- const isCurrentSelected = current?.avatarId === avatar.avatarId;
- return (
- <View
- className={`${currentUsed ? style.gridItemActived : style.gridItem}`}
- >
- <View
- className={style.selected}
- onClick={(e) => handleSelect(e, avatar)}
- >
- <WemetaRadio theme="light" checkbox checked={isCurrentSelected} />
- </View>
- {currentUsed && <View className={style.gridItemCurrentUsedMark}></View>}
- {/* <View className={style.gridItemCurrentUsedMark}></View> */}
- {!avatar.isOriginal && <View className={style.aiTips}>图片由AI生成</View>}
- {renderMedia(avatar, index)}
- </View>
- );
- });
- };
- return (
- <PageCustom>
- <NavBarNormal>历史形象</NavBarNormal>
- <View className={style.container}>
- <ScrollView
- scrollY
- onScrollToLower={onScrollToLower}
- scrollTop={scrollTop}
- onScroll={(e) => {
- scrollPositionRef.current = e.detail.scrollTop;
- }}
- style={{
- flex: 1,
- height: "100%", // 高度自适应
- }}
- >
- <View className="w-full p-16 pb-120">
- <View className={style.grid}>
- <View className={style.gridItemCreateBtn} onClick={handleCreate}>
- <View className={style.icon}>
- <IconPlusBig></IconPlusBig>
- </View>
- <View className="pt-8 text-12 leading-20 text-gray-4">
- 创建新形象
- </View>
- </View>
- {renderList()}
- </View>
- </View>
- </ScrollView>
- <BottomBar className="pt-12 px-16">
- <WemetaButton type='danger' className="w-88 text-red" disabled={!current?.canDel} onClick={handleDelete}>删除</WemetaButton>
- <WemetaButton type='normal' className="w-102" disabled={!current} onClick={handleDownload}>下载</WemetaButton>
- <WemetaButton type="primary" className="flex-1" disabled={!current} onClick={handleSetBackground}>设置为聊天背景</WemetaButton>
- </BottomBar>
- </View>
- </PageCustom>
- );
- }
|