This commit is contained in:
chashaobao
2025-10-15 20:44:20 +08:00
parent 7ba04b27ff
commit 3d2b121b92
23 changed files with 724 additions and 65 deletions

View File

@ -0,0 +1,79 @@
@import '@/styles/common.less';
.group-certification-list {
min-height: calc(100vh - 98rpx);
&__banner {
font-weight: 400;
font-size: 24px;
height: 72px;
padding: 32px 32px 25px;
line-height: 36px;
color: #999999;
}
&__title {
height: 72px;
width: 100%;
padding: 0 24px;
box-sizing: border-box;
line-height: 72px;
font-size: 24px;
color: rgba(0, 0, 0, 0.5);
position: fixed;
top: 227rpx;
left: 0;
z-index: 1;
background: #fff;
&-border {
border-bottom: 1px solid #e6e7e8;
.flex-row();
}
&-time {
padding: 0 8px;
flex: 0 0 120px;
width: 120px;
flex-shrink: 0;
}
&-name {
text-align: right;
flex: 1;
}
}
&__pull-refresh {
margin-top: 72px;
}
&__item {
height: 100px;
width: 100%;
padding: 24px 32px 0 32px;
box-sizing: border-box;
font-size: 28px;
background: #fff;
&-border {
border-bottom: 1px solid #e6e7e8;
}
&-content {
.flex-row();
width: 100%;
padding-bottom: 24px;
}
&-time {
padding: 0 8px;
flex: 0 0 120px;
width: 120px;
flex-shrink: 0;
}
&-name {
text-align: right;
flex: 1;
}
}
}

View File

@ -0,0 +1,153 @@
import { List, PullRefresh } from '@taroify/core';
import classNames from 'classnames';
import { useCallback, useEffect, useRef, useState } from 'react';
import ListPlaceholder from '@/components/list-placeholder';
import { AuthedGroupInfo } from '@/types/partner';
import { logWithPrefix } from '@/utils/common';
import { formatTimestamp, getAuthedGroupList as requestData } from '@/utils/partner';
import './index.less';
const PREFIX = 'group-certification-list';
const log = logWithPrefix(PREFIX);
const FIRST_PAGE = 0;
function GroupCertificationList(props: {
refreshDisabled?: boolean;
visible?: boolean;
listHeight?: number;
className?: string;
onListEmpty?: () => void;
}) {
const { className, listHeight, refreshDisabled, visible = true, onListEmpty } = props;
const [hasMore, setHasMore] = useState(false);
const [refreshing, setRefreshing] = useState(false);
const [loadingMore, setLoadingMore] = useState(false);
const [loadMoreError, setLoadMoreError] = useState(false);
const [dataList, setDataList] = useState<AuthedGroupInfo[]>([]);
const currentPage = useRef<number>(FIRST_PAGE);
const onListEmptyRef = useRef(onListEmpty);
const handleRefresh = useCallback(async () => {
log('start pull refresh');
try {
setRefreshing(true);
setLoadMoreError(false);
const content = await requestData();
setDataList(content);
currentPage.current = 1;
// setHasMore(currentPage.current < totalPages);
!content.length && onListEmptyRef.current?.();
log('pull refresh success');
} catch (e) {
setDataList([]);
setHasMore(false);
setLoadMoreError(true);
currentPage.current = FIRST_PAGE;
log('pull refresh failed');
} finally {
setRefreshing(false);
}
}, []);
const handleLoadMore = useCallback(async () => {
log('start load more', hasMore);
if (!hasMore) {
return;
}
setLoadMoreError(false);
setLoadingMore(true);
try {
const content = await requestData();
setDataList([...dataList, ...content]);
currentPage.current = currentPage.current + 1;
// setHasMore(currentPage.current < totalPages);
log('load more success');
} catch (e) {
setLoadMoreError(true);
log('load more failed');
} finally {
setLoadingMore(false);
}
}, [dataList, hasMore]);
useEffect(() => {
onListEmptyRef.current = onListEmpty;
}, [onListEmpty]);
// 初始化数据&配置变更后刷新数据
useEffect(() => {
// 列表不可见时,先不做处理
if (!visible) {
log('visible changed, but is not visible, only clear list');
return;
}
const refresh = async () => {
log('visible changed, start refresh list data');
try {
setDataList([]);
setLoadingMore(true);
setLoadMoreError(false);
const content = await requestData();
setDataList(content);
currentPage.current = 1;
// setHasMore(currentPage.current < totalPages);
!content.length && onListEmptyRef.current?.();
} catch (e) {
setDataList([]);
setHasMore(false);
setLoadMoreError(true);
} finally {
log('visible changed, refresh list data end');
setLoadingMore(false);
}
};
refresh();
}, [visible]);
return (
<div className={PREFIX}>
<div className={`${PREFIX}__banner`}>
</div>
<div className={`${PREFIX}__title`}>
<div className={`${PREFIX}__title-border`}>
<div className={`${PREFIX}__title-time`}></div>
<div className={`${PREFIX}__title-name`}></div>
</div>
</div>
<PullRefresh
className={classNames(`${PREFIX}__pull-refresh`, className)}
loading={refreshing}
onRefresh={handleRefresh}
disabled={refreshDisabled}
>
<List
hasMore={hasMore}
onLoad={handleLoadMore}
loading={loadingMore || refreshing}
disabled={loadMoreError || !visible}
fixedHeight={typeof listHeight !== 'undefined'}
style={listHeight ? { height: `${listHeight}px` } : undefined}
>
{dataList.map(item => (
<div className={`${PREFIX}__item`} key={item.openGid}>
<div className={`${PREFIX}__item-border`}>
<div className={`${PREFIX}__item-content`}>
<div className={`${PREFIX}__item-time`}>{formatTimestamp(item.authDate, true)}</div>
<div className={`${PREFIX}__item-name`}>{item.groupName}</div>
</div>
</div>
</div>
))}
<ListPlaceholder hasMore={false} loadingMore={loadingMore} loadMoreError={loadMoreError} />
</List>
</PullRefresh>
</div>
);
}
export default GroupCertificationList;

View File

@ -7,12 +7,11 @@ import { useCallback, useState } from 'react';
import { RoleType } from '@/constants/app';
import { CacheKey } from '@/constants/cache-key';
import { CITY_CODE_TO_NAME_MAP } from '@/constants/city';
import { GROUPS } from '@/constants/group';
import useServiceUrls from '@/hooks/use-service-urls';
import { getRoleTypeWithDefault } from '@/utils/app';
import { openCustomerServiceChat } from '@/utils/common';
import { getCurrentCityCode } from '@/utils/location';
import { checkCityCode, validCityCode } from '@/utils/user';
import './index.less';
const PREFIX = 'join-group-hint';
@ -25,7 +24,8 @@ const DEFAULT_GROUP = {
export function JoinGroupHint() {
const cityCode = getCurrentCityCode();
const roleType = getRoleTypeWithDefault();
const group = GROUPS.find(g => String(g.cityCode) === cityCode);
const serviceUrls = useServiceUrls();
const group = serviceUrls.find(g => String(g.cityCode) === cityCode);
const [clicked, setClicked] = useState(!!Taro.getStorageSync(CacheKey.JOIN_GROUP_CARD_CLICKED));
const handleClick = useCallback(() => {
if (group && !checkCityCode(cityCode)) {

View File

@ -3,10 +3,14 @@ import Taro from '@tarojs/taro';
import { Swiper } from '@taroify/core';
import { GoodJob } from '@taroify/icons';
import { useCallback } from 'react';
import { useCallback, useEffect, useRef, useState } from 'react';
import { PageUrl } from '@/constants/app';
import { EarnType, UserProfitListItem } from '@/types/partner';
import { openCustomerServiceChat } from '@/utils/common';
import { getCouponQrCode, generateMembershipCoupon } from '@/utils/coupon';
import { generateMembershipCoupon, getCouponQrCode } from '@/utils/coupon';
import { formatMoney, formatTimestamp, getLastProfitList } from '@/utils/partner';
import { navigateTo } from '@/utils/route';
import './index.less';
const PREFIX = 'partner-intro';
@ -112,11 +116,44 @@ export default function PartnerIntro() {
}
};
const handleConfirm = useCallback(() => {}, []);
const handleConfirm = useCallback(() => {
navigateTo(PageUrl.GroupOwnerCertificate);
}, []);
const handleOpenService = useCallback(() => {
openCustomerServiceChat('https://work.weixin.qq.com/kfid/kfc4fcf6b109b3771d7');
}, []);
const timerRef = useRef<NodeJS.Timeout | null>(null);
const [bannerList, setBannerList] = useState<UserProfitListItem[]>([]);
const getBannerList = useCallback(async () => {
if (timerRef.current) {
clearTimeout(timerRef.current);
timerRef.current = null;
}
const list = await getLastProfitList();
setBannerList(s => [...s, ...list]);
timerRef.current = setTimeout(
() => {
getBannerList();
},
3000 * (list.length || 10)
);
}, []);
useEffect(() => {
getBannerList();
return () => {
if (timerRef.current) {
clearTimeout(timerRef.current);
timerRef.current = null;
}
};
}, [getBannerList]);
return (
<div className={PREFIX}>
<div className={`${PREFIX}__banner`}>
@ -130,18 +167,23 @@ export default function PartnerIntro() {
mode="aspectFill"
/>
<Swiper className={`${PREFIX}__swiper`} autoplay={3000} touchable={false}>
<Swiper.Item className={`${PREFIX}__swiper-item`}>
<div className={`${PREFIX}__swiper-item-time`}>2024.02.02 12:23:23</div>
<div className={`${PREFIX}__swiper-item-details`}>
<div className={`${PREFIX}__swiper-item-id`}>zbldakjdjsksada</div>
<div className={`${PREFIX}__swiper-item-info`}>
<div className="money">+2.15</div>
{bannerList.map((item, index) => (
<Swiper.Item className={`${PREFIX}__swiper-item`} key={index}>
<div className={`${PREFIX}__swiper-item-time`}>{formatTimestamp(item.updatedAt)}</div>
<div className={`${PREFIX}__swiper-item-details`}>
<div className={`${PREFIX}__swiper-item-id`}>{item.userId}</div>
<div className={`${PREFIX}__swiper-item-info`}>
{[EarnType.CHAT_ACTIVITY_SHARE_L1, EarnType.CHAT_ACTIVITY_SHARE_L2].includes(item.earnType)
? '主播被开聊'
: '会员支付'}
<div className="money">+{formatMoney(item.total)}</div>
</div>
<div className={`${PREFIX}__swiper-item-info`}>
<div className="money">{formatMoney(item.amount)}</div>
</div>
</div>
<div className={`${PREFIX}__swiper-item-info`}>
<div className="money">1200.15</div>
</div>
</div>
</Swiper.Item>
</Swiper.Item>
))}
</Swiper>
</div>