feat:我的动态;我的评价;访客记录;朋友圈操作;上传相册;我的相册;列表和导航按钮调整;朋友圈卡片;用户卡片;查询朋友圈详情;关注公众号帘幕

This commit is contained in:
ctw committed 2025-11-21 10:47:17 +08:00
1 parent 7bc0b920f6
commit 1f4a52807c
27 files changed
+873 -683

No files matched your search

+21
View File
@@ -164,6 +164,27 @@
"navigationBarTitleText": "喜欢",
"navigationStyle": "custom"
}
},
{
"path": "my-moment",
"style": {
"navigationBarTitleText": "我的动态",
"navigationStyle": "custom"
}
},
{
"path": "view-record",
"style": {
"navigationBarTitleText": "访客记录",
"navigationStyle": "custom"
}
},
{
"path": "upload-album",
"style": {
"navigationBarTitleText": "上传照片",
"navigationStyle": "custom"
}
}
]
},
+4 -4
View File
@@ -19,7 +19,7 @@
</view>
<wd-index-bar sticky>
<view v-for="(item, index) in cityIndex" :key="index">
<view v-for="(item, index) in useCityIndex()" :key="index">
<wd-index-anchor :index="item.letter" />
<wd-cell
border
@@ -45,7 +45,7 @@
<script setup lang="ts">
import { getCurrentInstance } from 'vue';
import cityIndex, { type cityItem } from './city-index';
import useCityIndex, { type cityItem } from '@/sheep/hooks/use-city-index';
// @ts-ignore
import sheep from '@/sheep';
@@ -56,13 +56,13 @@
const selectHot = (v: cityItem) => {
sheep.$store('user').setUserCity(v);
eventChannel.emit('changeCity');
uni.navigateBack();
back();
};
const select = (v: cityItem) => {
sheep.$store('user').setUserCity(v);
eventChannel.emit('changeCity');
uni.navigateBack();
back();
};
function back() {
+30 -43
View File
@@ -22,16 +22,11 @@
</template>
</wd-navbar>
<scroll-view
style="height: calc(100vh - 88px)"
scroll-y
refresher-enabled
refresher-background="#222"
:refresher-triggered="refresherTriggered"
:refresher-threshold="100"
@refresherrefresh="onRefresherRefresh"
@refresherabort="onRefresherAbort"
@scrolltolower="onScrollToLower"
<scroll-list
style="height: calc(100dvh - 88px)"
:loadMoreStatus="loadMoreStatus"
@refresh="refreshList"
@loadMore="listLoadMore"
@scroll="onScroll"
>
<view class="w-full h-500rpx relative">
@@ -110,26 +105,16 @@
</view>
</view>
<moment
v-for="item in listData"
:avatar="item.member?.memberAvatar"
:name="item.member?.memberNickname"
:verification="item.verification"
:info="`未知性别 · ${item.member?.memberAge}岁 | ${item.member?.memberOcc}`"
:content="item.description"
:images="[item.coverPic]"
:location="item.issueAddress"
:likes="item.likes"
:comments="item.comments"
/>
<uni-load-more
:status="loadMoreStatus"
:content-text="loadMoreContent"
@clickLoadMore="onClickLoadMore"
/>
<view style="height: 100rpx"></view>
</scroll-view>
<moment-card v-if="listData.length" v-for="item in listData" :data="item" />
<view v-else class="flex px-4 py-4">
<wd-skeleton :row-col="[{ size: '50px', type: 'circle' }]" animation="flashed" />
<wd-skeleton
:custom-style="{ width: '100%', marginLeft: '12px' }"
animation="flashed"
theme="paragraph"
/>
</view>
</scroll-list>
</wd-config-provider>
<view class="fixed bottom-100 left-0 right-0 flex justify-around bg-transparent">
@@ -145,21 +130,14 @@
</template>
<script setup lang="ts">
import { ref, computed, getCurrentInstance, onMounted } from 'vue';
import moment from '@/sheep/components/moment/moment.vue';
import { ref, computed, getCurrentInstance, reactive } from 'vue';
import MomentCard from '@/sheep/components/moment-card/moment-card.vue';
import ScrollList from '@/sheep/components/scroll-list/scroll-list.vue';
import useScroll from '@/sheep/hooks/use-scroll';
import RecentApi from '@/sheep/api/member/recent';
import { onLoad } from '@dcloudio/uni-app';
const {
listData,
refresherTriggered,
loadMoreContent,
loadMoreStatus,
onRefresherRefresh,
onRefresherAbort,
onScrollToLower,
onClickLoadMore,
} = useScroll(RecentApi.quickPage, {
const params = reactive({
scene: 'DYNAMIC_RECOMMEND',
province: '',
city: '',
@@ -169,7 +147,11 @@
const scrollTop = ref(0);
const userDetail = ref<any>({});
onMounted(() => {
onLoad((options: any) => {
const { memberId } = options;
if (!memberId) return uni.showToast({ title: '参数错误', icon: 'none' });
params.memberId = memberId;
const instance: any = getCurrentInstance()?.proxy;
const eventChannel = instance.getOpenerEventChannel();
@@ -178,6 +160,11 @@
});
});
const { listData, loadMoreStatus, refreshList, listLoadMore } = useScroll(
RecentApi.quickPage,
params,
);
const filterStyle = computed(() => {
let blur = 0;
const scrollY = scrollTop.value;
+42 -68
View File
@@ -14,99 +14,73 @@
</template>
</wd-navbar>
<scroll-view
<scroll-list
style="height: calc(100dvh - 44px - 50px)"
scroll-y
scroll-with-animation
refresher-enabled
refresher-background="#222"
:refresher-triggered="refresherTriggered"
:refresher-threshold="100"
@refresherrefresh="onRefresherRefresh"
@refresherabort="onRefresherAbort"
@scrolltolower="onScrollToLower"
:loadMoreStatus="loadMoreStatus"
@refresh="refreshList"
@loadMore="listLoadMore"
>
<view class="flex px-4 py-2" v-for="user in listData" :key="user.id" @click="detail(user)">
<image
class="w-200rpx h-300rpx mr-3 rounded-2 bg-#777"
:src="user.member.memberAvatar"
mode="aspectFill"
/>
<view class="flex-1">
<view class="flex justify-between items-center">
<text class="text-size-base">{{ user.member.memberNickname }}</text>
<text class="px-2 rounded-full text-xs bg-color-theme-dark">{{ '在线' }}</text>
</view>
<view class="mt-2">
<text class="px-2 text-xs c-black rounded-full bg-color-theme-dark">真人认证</text>
</view>
<view class="mt-2 flex flex-wrap gap-3">
<text class="bg-#333 text-color-theme text-xs px-2 rounded-1">
{{ user.gender || '未知性别' }}·{{ user.member.memberAge }}岁
</text>
<text class="bg-#333 text-color-theme text-xs px-2 rounded-1">
{{ user.member.memberHeight }}cm
</text>
<text class="bg-#333 text-color-theme text-xs px-2 rounded-1">
{{ user.member.memberWeight }}kg
</text>
<text class="bg-#333 text-color-theme text-xs px-2 rounded-1">
{{ user.member.memberOcc }}
</text>
<text class="bg-#333 text-color-theme text-xs px-2 rounded-1">
{{ user.issueCity }}km
</text>
</view>
<user-card
v-if="listData.length"
v-for="user in listData"
:key="user.id"
:data="user"
@click="detail(user)"
/>
<view v-else class="py-2 px-4" v-for="index in 4" :key="index">
<view class="flex">
<wd-skeleton :row-col="[{ size: '100px', type: 'rect' }]" animation="gradient" />
<wd-skeleton
:custom-style="{ width: '100%', marginLeft: '12px' }"
:row-col="[{ width: '100%' }, { width: '100%' }]"
animation="gradient"
/>
</view>
<view class="flex -mt-50px">
<wd-skeleton :row-col="[{ size: '100px', type: 'rect' }]" animation="gradient" />
<wd-skeleton
:custom-style="{ width: '100%', marginLeft: '12px' }"
:row-col="[{ width: '100%' }, { width: '50%' }]"
animation="gradient"
/>
</view>
</view>
<uni-load-more
:status="loadMoreStatus"
:content-text="loadMoreContent"
@clickLoadMore="onClickLoadMore"
/>
<view style="height: 100rpx"></view>
</scroll-view>
</scroll-list>
</wd-config-provider>
<s-auth-modal />
</template>
<script setup lang="ts">
import { computed, ref } from 'vue';
import { computed, reactive, ref } from 'vue';
import segmented from '@/sheep/components/segmented/segmented.vue';
import RecentApi from '@/sheep/api/member/recent';
import ScrollList from '@/sheep/components/scroll-list/scroll-list.vue';
import UserCard from '@/sheep/components/user-card/user-card.vue';
import useScroll from '@/sheep/hooks/use-scroll';
// @ts-ignore
import sheep from '@/sheep';
const {
listData,
refresherTriggered,
loadMoreContent,
loadMoreStatus,
onRefresherRefresh,
onRefresherAbort,
onScrollToLower,
onClickLoadMore,
} = useScroll(RecentApi.quickPage, {
const current = ref(0);
const segmentedItems = ['广场', '最近', '新人'];
const userCity = computed(() => sheep.$store('user').userCity);
const params = reactive({
scene: 'DYNAMIC_RECOMMEND',
province: '',
city: '',
memberId: '',
});
const current = ref(0);
const segmentedItems = ['广场', '最近', '新人'];
const userCity = computed(() => {
return sheep.$store('user').userCity;
});
const { listData, loadMoreStatus, refreshList, listLoadMore } = useScroll(
RecentApi.quickPage,
params,
);
const selectAddress = () => {
uni.navigateTo({
url: '/pages/home/city',
events: {
changeCity: () => {
onRefresherRefresh();
refreshList();
},
},
});
@@ -114,7 +88,7 @@
const detail = (user: any) => {
uni.navigateTo({
url: '/pages/home/detail',
url: `/pages/home/detail?memberId=${user.memberId}`,
success: function (res) {
res.eventChannel.emit('recentDetail', user);
},
@@ -123,6 +97,6 @@
const segmentedChange = ({ currentIndex }: { currentIndex: number }) => {
console.log(segmentedItems[currentIndex]);
onRefresherRefresh();
refreshList();
};
</script>
+6 -4
View File
@@ -8,10 +8,12 @@
</view>
</template>
<template #right>
<view class="flex items-center rounded-full h-44rpx bg-color-theme py-1 px-2 text-black">
<uni-icons type="chat" size="20" color="#333" />
<text class="text-sm c-black">互动消息</text>
</view>
<navigator url="/pages/" open-type="navigate" hover-class="navigator-hover">
<view class="flex items-center rounded-full h-44rpx bg-color-theme py-1 px-2 text-black">
<uni-icons type="chat" size="20" color="#333" />
<text class="text-sm c-black">互动消息</text>
</view>
</navigator>
</template>
</wd-navbar>
+29 -48
View File
@@ -7,20 +7,17 @@
</view>
</template>
<template #right>
<uni-icons type="camera" size="28" color="#ffcd32" @click="goPublish"></uni-icons>
<navigator url="/pages/moments/publish" open-type="navigate" hover-class="navigator-hover">
<uni-icons type="camera" size="28" color="#ffcd32" />
</navigator>
</template>
</wd-navbar>
<scroll-view
style="height: calc(100vh - 44px - 50px)"
scroll-y
refresher-enabled
refresher-background="#222"
:refresher-triggered="refresherTriggered"
:refresher-threshold="100"
@refresherrefresh="onRefresherRefresh"
@refresherabort="onRefresherAbort"
@scrolltolower="onScrollToLower"
<scroll-list
style="height: calc(100dvh - 44px - 50px)"
:loadMoreStatus="loadMoreStatus"
@refresh="refreshList"
@loadMore="listLoadMore"
>
<swiper
class="h-300rpx mx-4"
@@ -45,65 +42,49 @@
/>
</swiper-item>
</swiper>
<moment
<moment-card
v-if="listData.length"
v-for="item in listData"
:avatar="item.member?.memberAvatar"
:name="item.member?.memberNickname"
:verification="item.verification"
:info="`未知性别 · ${item.member?.memberAge}岁 | ${item.member?.memberOcc}`"
:content="item.description"
:media="[item.coverPic]"
:location="item.issueAddress"
:likes="item.likes"
:comments="item.comments"
:data="item"
@detail="goDetail(item)"
/>
<uni-load-more
:status="loadMoreStatus"
:content-text="loadMoreContent"
@clickLoadMore="onClickLoadMore"
/>
<view class="h-100rpx"></view>
</scroll-view>
<view v-else class="flex px-4 py-4" v-for="index in 3" :key="index">
<wd-skeleton :row-col="[{ size: '50px', type: 'circle' }]" animation="flashed" />
<wd-skeleton
:custom-style="{ width: '100%', marginLeft: '12px' }"
animation="flashed"
theme="paragraph"
/>
</view>
</scroll-list>
</wd-config-provider>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { reactive, ref } from 'vue';
import segmented from '@/sheep/components/segmented/segmented.vue';
import moment from '@/sheep/components/moment/moment.vue';
import MomentCard from '@/sheep/components/moment-card/moment-card.vue';
import ScrollList from '@/sheep/components/scroll-list/scroll-list.vue';
import useScroll from '@/sheep/hooks/use-scroll';
import RecentApi from '@/sheep/api/member/recent';
const {
listData,
refresherTriggered,
loadMoreContent,
loadMoreStatus,
onRefresherRefresh,
onRefresherAbort,
onScrollToLower,
onClickLoadMore,
} = useScroll(RecentApi.quickPage, {
const params = reactive({
scene: 'DYNAMIC_RECOMMEND',
province: '',
city: '',
memberId: '',
});
const { listData, loadMoreStatus, refreshList, listLoadMore } = useScroll(
RecentApi.quickPage,
params,
);
const current = ref(0);
const segmentedItems = ['动态', '附近'];
const goPublish = () => {
uni.navigateTo({
url: '/pages/moments/publish',
});
};
// 查看用户详情
const goDetail = (user: any) => {
uni.navigateTo({
url: '/pages/home/detail',
url: `/pages/home/detail?memberId=${user.memberId}`,
success: function (res) {
res.eventChannel.emit('recentDetail', user);
},
+8 -6
View File
@@ -5,12 +5,14 @@
<uni-icons type="back" size="30" color="#ffcd32" @click="back"></uni-icons>
</template>
<template #right>
<view
class="bg-color-theme px-3 py-1 rounded-full c-black h-1/2 line-height-normal"
@click="publishMoments"
>
发布
</view>
<navigator hover-class="navigator-hover">
<view
class="bg-color-theme px-3 py-1 rounded-full c-black h-1/2 line-height-normal"
@click="publishMoments"
>
发布
</view>
</navigator>
</template>
</wd-navbar>
@@ -1,54 +0,0 @@
<template>
<scroll-view
class="h-full"
scroll-y
:show-scrollbar="false"
:refresher-enabled="refresherEnabled"
refresher-background="#222"
:refresher-triggered="refresherTriggered"
:refresher-threshold="100"
@refresherrefresh="onRefresherRefresh"
@refresherabort="onRefresherAbort"
@scrolltolower="onScrollToLower"
>
<slot :list="listData" />
<uni-load-more
:status="loadMoreStatus"
:content-text="loadMoreContent"
@clickLoadMore="onClickLoadMore"
/>
<view style="height: 100rpx"></view>
</scroll-view>
</template>
<script setup lang="ts">
import useScroll from '@/sheep/hooks/use-scroll';
const props = withDefaults(
defineProps<{
load?: (...arg: any) => Promise<any>;
refresherEnabled?: boolean;
requestBody?: any;
}>(),
{
load: () => Promise.resolve([]),
refresherEnabled: true,
requestBody: {},
},
);
const {
listData,
refresherTriggered,
loadMoreContent,
loadMoreStatus,
onRefresherRefresh,
onRefresherAbort,
onScrollToLower,
onClickLoadMore,
} = useScroll(props.load, props.requestBody);
defineExpose({
reload: onRefresherRefresh,
});
</script>
@@ -0,0 +1,32 @@
<template>
<scroll-list
:loadMoreStatus="loadMoreStatus"
@refresh="refreshList"
@loadMore="listLoadMore"
:show-scrollbar="false"
:refresherEnabled="false"
>
<slot :list="listData" />
</scroll-list>
</template>
<script setup lang="ts">
import ScrollList from '@/sheep/components/scroll-list/scroll-list.vue';
import useScroll from '@/sheep/hooks/use-scroll';
const props = withDefaults(
defineProps<{
load?: (...arg: any) => Promise<any>;
requestBody?: any;
}>(),
{
load: () => Promise.resolve([]),
requestBody: {},
},
);
const { listData, loadMoreStatus, refreshList, listLoadMore } = useScroll(
props.load,
props.requestBody,
);
</script>
@@ -0,0 +1,43 @@
<template>
<view class="p-4">
<view class="flex items-center justify-between text-color-theme mb-1">
<text>我的相册</text>
<navigator
class="flex-row-center"
url="/pages/profile/upload-album"
open-type="navigate"
hover-class="navigator-hover"
>
<wd-icon name="add-circle1" size="18px" />
<text class="text-28rpx">上传相册</text>
</navigator>
</view>
<view class="flex flex-wrap gap-3">
<view v-for="(item, index) in ablumList" :key="index" @click="previewPhoto(index)">
<image class="size-150rpx rounded-2" :src="item.address" mode="aspectFill" />
</view>
</view>
</view>
</template>
<script setup lang="ts">
export interface AlbumData {
resourceType: 'IMAGE' | 'VIDEO';
address: string;
}
const props = defineProps<{
ablumList: AlbumData[];
}>();
const previewPhoto = (current: number) => {
if (!props.ablumList.length) return;
const urls = props.ablumList.map((item) => item.address);
uni.previewImage({
current,
urls,
indicator: 'number',
});
};
</script>
+6 -39
View File
@@ -18,45 +18,11 @@
:duration="200"
>
<swiper-item v-for="index in segmentedItems.length" :key="index">
<scroll-list :load="load[index]" :refresher-enabled="false">
<swiper-scroll class="h-full" :load="load[index]">
<template #default="{ list }">
<view class="flex px-4 py-2" v-for="user in list" :key="user.id" @click="detail(user)">
<image
class="w-200rpx h-300rpx mr-3 rounded-2 bg-#777"
:src="user.member.memberAvatar"
mode="aspectFill"
/>
<view class="flex-1">
<view class="flex justify-between items-center">
<text class="text-size-base">{{ user.member.memberNickname }}</text>
<text class="px-2 rounded-full text-xs bg-color-theme-dark">{{ '在线' }}</text>
</view>
<view class="mt-2">
<text class="px-2 text-xs c-black rounded-full bg-color-theme-dark">
真人认证
</text>
</view>
<view class="mt-2 flex flex-wrap gap-3">
<text class="bg-#333 text-color-theme text-xs px-2 rounded-1">
{{ user.gender || '未知性别' }}·{{ user.member.memberAge }}岁
</text>
<text class="bg-#333 text-color-theme text-xs px-2 rounded-1">
{{ user.member.memberHeight }}cm
</text>
<text class="bg-#333 text-color-theme text-xs px-2 rounded-1">
{{ user.member.memberWeight }}kg
</text>
<text class="bg-#333 text-color-theme text-xs px-2 rounded-1">
{{ user.member.memberOcc }}
</text>
<text class="bg-#333 text-color-theme text-xs px-2 rounded-1">
{{ user.issueCity }}km
</text>
</view>
</view>
</view>
<user-card v-for="user in list" :key="user.id" :data="user" @click="detail(user)" />
</template>
</scroll-list>
</swiper-scroll>
</swiper-item>
</swiper>
</wd-config-provider>
@@ -66,8 +32,9 @@
import { onLoad } from '@dcloudio/uni-app';
import { ref } from 'vue';
import segmented from '@/sheep/components/segmented/segmented.vue';
import UserCard from '@/sheep/components/user-card/user-card.vue';
import SwiperScroll from './components/swiper-scroll.vue';
import RecentApi from '@/sheep/api/member/recent';
import scrollList from './components/scroll-list.vue';
const current = ref<0 | 1 | number>(0);
const segmentedItems = ['我喜欢', '喜欢我'];
@@ -80,7 +47,7 @@
const detail = (user: any) => {
uni.navigateTo({
url: '/pages/home/detail',
url: `/pages/home/detail?memberId=${user.memberId}`,
success: function (res) {
res.eventChannel.emit('recentDetail', user);
},
+49
View File
@@ -0,0 +1,49 @@
<template>
<wd-config-provider theme="dark">
<wd-navbar title="我的动态" safeAreaInsetTop :bordered="false">
<template #left>
<navigator open-type="navigateBack" hover-class="navigator-hover">
<uni-icons type="back" size="30" color="#ffcd32"></uni-icons>
</navigator>
</template>
<template #right>
<navigator url="/pages/moments/publish" open-type="navigate" hover-class="navigator-hover">
<view class="bg-color-theme px-3 py-1 rounded-full c-black h-1/2 line-height-normal">
发布动态
</view>
</navigator>
</template>
</wd-navbar>
<scroll-list
style="height: calc(100dvh - 44px - 50px)"
:loadMoreStatus="loadMoreStatus"
@refresh="refreshList"
@loadMore="listLoadMore"
>
<moment-card v-if="listData.length" v-for="item in listData" :data="item" />
<view v-else class="flex px-4 py-4" v-for="index in 4" :key="index">
<wd-skeleton :row-col="[{ size: '50px', type: 'circle' }]" animation="flashed" />
<wd-skeleton
:custom-style="{ width: '100%', marginLeft: '12px' }"
animation="flashed"
theme="paragraph"
/>
</view>
</scroll-list>
</wd-config-provider>
</template>
<script setup lang="ts">
import MomentCard from '@/sheep/components/moment-card/moment-card.vue';
import ScrollList from '@/sheep/components/scroll-list/scroll-list.vue';
import useScroll from '@/sheep/hooks/use-scroll';
import RecentApi from '@/sheep/api/member/recent';
import { reactive } from 'vue';
const params = reactive({});
const { listData, loadMoreStatus, refreshList, listLoadMore } = useScroll(
RecentApi.myMomentList,
params,
);
</script>
+120 -35
View File
@@ -3,60 +3,73 @@
<wd-config-provider theme="dark">
<wd-navbar title="我的" safeAreaInsetTop :bordered="false">
<template #right>
<view
class="flex items-center rounded-full h-44rpx bg-color-theme py-1 px-2 text-black"
@click="editUserInfo"
>
<uni-icons type="auth" size="20" color="#333"></uni-icons>
<text class="text-sm">编辑资料</text>
</view>
<navigator hover-class="navigator-hover">
<view
class="flex items-center rounded-full h-44rpx bg-color-theme py-1 px-2 text-black"
@click="editUserInfo"
>
<uni-icons type="auth" size="20" color="#333"></uni-icons>
<text class="text-sm">编辑资料</text>
</view>
</navigator>
</template>
</wd-navbar>
<scroll-view class="h-[calc(100vh-144rpx)]" scroll-y>
<!-- 个人信息 -->
<view class="flex items-center p-6">
<image :src="userInfo.avatar" class="mr-4 size-100px rounded-full bg-#333" />
<image
:src="userInfo.avatar"
class="mr-4 size-100px rounded-full bg-#333 border border-amber border-solid"
mode="aspectFill"
/>
<view class="flex-1">
<view class="mb-1 text-lg">{{ userInfo.nickname }}</view>
<view class="mb-1 text-xs text-#ffffff80">ID: {{ userInfo.id }}</view>
<view class="inline-block rounded-full bg-color-theme px-2 text-xs c-black">
{{ 'vip' }}
</view>
<view class="mb-1 text-base">{{ userInfo.nickname }}</view>
<view class="mb-2 text-xs text-#ffffff80">ID: {{ userInfo.id }}</view>
<text class="bg-#333 text-color-theme-dark text-xs px-2 py-1 rounded-1 truncate">
{{ userCity?.t || '' }}
</text>
</view>
</view>
<!-- 我喜欢和钱包 -->
<view class="flex justify-around my-4 text-base">
<view class="flex flex-col items-center" @click="goLike(0)">
<text class="text-color-theme font-bold">{{ 1 }}</text>
<text class="text-color-theme">我喜欢</text>
<text class="text-color-theme font-600 text-lg">{{ 1 }}</text>
<text class="text-color-theme text-xs">我喜欢</text>
</view>
<view class="flex flex-col items-center" @click="goLike(1)">
<text class="text-color-theme font-bold">{{ 1 }}</text>
<text class="text-color-theme">喜欢我</text>
<text class="text-color-theme font-600 text-lg">{{ 2 }}</text>
<text class="text-color-theme text-xs">喜欢我</text>
</view>
<view class="flex flex-col items-center">
<text class="text-color-theme font-bold">{{ 1 }}</text>
<text class="text-color-theme">钱包</text>
<text class="text-color-theme font-600 text-lg">{{ 3 }}</text>
<text class="text-color-theme text-xs">钱包</text>
</view>
</view>
<!-- 用户相册 -->
<user-ablum :ablumList="ablumList"></user-ablum>
<!-- 菜单 -->
<view class="mt-4 mx-1">
<wd-cell-group>
<wd-cell title="我的收益" value="" is-link to=""></wd-cell>
<wd-cell title="访客记录" value="" is-link></wd-cell>
<wd-cell title="认证中心" value="" is-link></wd-cell>
<wd-cell title="我的动态" value="" is-link></wd-cell>
<wd-cell title="我的评价" value="" is-link></wd-cell>
<wd-cell title="问题反馈" value="" is-link></wd-cell>
<wd-cell title="客服助手" value="" is-link></wd-cell>
<wd-cell title="关注公众号" value="" is-link></wd-cell>
<wd-cell title="设置" value="" is-link></wd-cell>
<wd-cell
v-for="(item, index) in MenuCellList"
:key="index"
:title="item.title"
:value="item.value"
icon-size="24"
:icon="item.icon"
is-link
ellipsis
:to="item.to"
@click="item.click"
/>
</wd-cell-group>
</view>
<view
class="mt-40rpx rounded-full bg-color-theme-dark text-base text-center py-2 mx-8"
class="mt-40rpx rounded-full bg-color-theme-dark text-base text-center py-2 mx-8 active:bg-color-theme"
@click="handleLogout"
>
退 出 登 录
@@ -65,21 +78,70 @@
</scroll-view>
<wd-message-box />
<wd-popup
v-model="myEvaluationShow"
custom-style="border-radius:32rpx;"
closable
:safe-area-inset-bottom="true"
>
<view class="w-90vw h-400rpx flex-col-center gap-4 flex-wrap">
<view class="text-color-theme text-lg">我的评价</view>
<view class="w-90% flex justify-around">
<view class="bg-color-theme-dark flex items-center p-1 rounded-1">
<text class="mr-2 text-xs">身材</text>
<wd-rate v-model="myEvaluation.a" readonly />
</view>
<view class="bg-color-theme-dark flex items-center p-1 rounded-1">
<text class="mr-2 text-xs">颜值</text>
<wd-rate v-model="myEvaluation.a" readonly />
</view>
</view>
<view class="w-90% flex justify-around">
<view class="bg-color-theme-dark flex items-center p-1 rounded-1">
<text class="mr-2 text-xs">有趣</text>
<wd-rate v-model="myEvaluation.a" readonly />
</view>
<view class="bg-color-theme-dark flex items-center p-1 rounded-1">
<text class="mr-2 text-xs">耐心</text>
<wd-rate v-model="myEvaluation.a" readonly />
</view>
</view>
<view class="text-color-theme text-lg">综合评分 1.0</view>
</view>
</wd-popup>
<wd-curtain
v-model="curtainShow"
src="https://img20.360buyimg.com/da/jfs/t1/141592/25/8861/261559/5f68d8c1E33ed78ab/698ad655bfcfbaed.png"
close-position="top-right"
:width="300"
close-on-click-modal
show-menu-by-longpress
/>
</wd-config-provider>
</template>
<script setup lang="ts">
import { computed } from 'vue';
import { computed, reactive, ref } from 'vue';
import UserAblum from './components/user-ablum.vue';
import useAblum from './use-ablum';
// @ts-ignore
import sheep from '@/sheep';
import { useMessage } from '@/uni_modules/wot-design-uni';
import RecentApi from '@/sheep/api/member/recent';
const message = useMessage();
const { ablumList } = useAblum();
const userInfo = computed(() => {
return sheep.$store('user').userInfo;
const userCity = computed(() => sheep.$store('user').userCity);
const myEvaluationShow = ref(false); // 我的评价弹窗
// 我的评价数据
const myEvaluation = reactive({
a: 0,
});
const curtainShow = ref(false); // 关注公众号弹窗
const userInfo = computed(() => sheep.$store('user').userInfo);
// 修改用户信息
const editUserInfo = () => {
uni.navigateTo({
url: '/pages/profile/userinfo',
@@ -93,6 +155,18 @@
});
};
// 查看我的评价
const lookMyEvaluation = async () => {
await RecentApi.myEvaluate();
myEvaluation.a = 1;
myEvaluationShow.value = true;
};
// 关注公众号
const subOfficial = () => {
curtainShow.value = true;
};
// 退出登录
const handleLogout = () => {
message
@@ -104,8 +178,19 @@
sheep.$store('user').logout();
uni.redirectTo({ url: '/pages/login/login' });
})
.catch(() => {
console.log('点击了取消按钮');
});
.catch(() => {});
};
// cell菜单
const MenuCellList = [
{ title: '我的收益', value: '', icon: 'wallet', to: '' },
{ title: '访客记录√', value: '', icon: 'dong', to: '/pages/profile/view-record' },
{ title: '认证中心', value: '', icon: 'user', to: '' },
{ title: '我的动态√', value: '', icon: 'star', to: '/pages/profile/my-moment' },
{ title: '我的评价√', value: '', icon: 'view-module', to: '', click: lookMyEvaluation },
{ title: '问题反馈', value: '', icon: 'backtop-rectangle', to: '' },
{ title: '客服助手', value: '', icon: 'service', to: '' },
{ title: '关注公众号√', value: '获取最新消息', icon: 'qrcode', to: '', click: subOfficial },
{ title: '设置', value: '', icon: 'setting1', to: '' },
];
</script>
+58
View File
@@ -0,0 +1,58 @@
<template>
<wd-config-provider theme="dark">
<wd-navbar title="上传相册" safeAreaInsetTop :bordered="false">
<template #left>
<navigator open-type="navigateBack" hover-class="navigator-hover">
<uni-icons type="back" size="30" color="#ffcd32"></uni-icons>
</navigator>
</template>
</wd-navbar>
<view class="mx-5 my-3 flex justify-between text-color-theme">
<text>相册</text>
<text>{{ ablumUrlList?.length || 0 }}/10</text>
</view>
<view class="px-4">
<wd-upload v-model:file-list="ablumUrlList" :upload-method="customUpload"></wd-upload>
</view>
</wd-config-provider>
<view @click="save">保存</view>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue';
import SUploader from '@/sheep/components/s-uploader/s-uploader.vue';
import useAblum from './use-ablum';
import {
UploadFile,
UploadMethod,
} from '@/uni_modules/wot-design-uni/components/wd-upload/types';
import FileApi from '@/sheep/api/infra/file';
const { ablumList, getUserAlbum } = useAblum();
const ablumUrlList = ref<UploadFile[]>([]);
watch(
() => ablumList.value,
(val) => {
ablumUrlList.value = val.map((item) => ({ url: item.address }));
},
{ immediate: true },
);
const customUpload: UploadMethod = async (file, formData, options) => {
const { data } = await FileApi.uploadFile(file.url);
options.onSuccess(data, file, formData);
console.log(data);
console.log(ablumUrlList.value);
};
// 保存相册
const save = async () => {
// TODO: 调用保存相册的 API
// await RecentApi.saveUserAlbum(ablumList.value);
// 保存成功后重新获取相册列表
await getUserAlbum();
};
</script>
+19
View File
@@ -0,0 +1,19 @@
import { onMounted, ref } from 'vue';
import { AlbumData } from './components/user-ablum.vue';
import RecentApi from '@/sheep/api/member/recent';
export default function useAblum() {
const ablumList = ref<AlbumData[]>([]); // 用户相册
// 获取用户相册
const getUserAlbum = async () => {
const { data = null } = await RecentApi.getUserAlbum({ pageNo: 1, pageSize: 10 });
ablumList.value = data.list ?? [];
};
onMounted(() => {
getUserAlbum();
});
return { ablumList, getUserAlbum };
}
+9 -7
View File
@@ -11,12 +11,14 @@
<uni-icons type="back" size="30" color="#ffcd32" @click="back"></uni-icons>
</template>
<template #right>
<view
class="bg-color-theme px-3 py-1 rounded-full c-black h-1/2 line-height-normal"
@click="saveUserInfo"
>
保存
</view>
<navigator hover-class="navigator-hover">
<view
class="bg-color-theme px-3 py-1 rounded-full c-black h-1/2 line-height-normal"
@click="saveUserInfo"
>
保存
</view>
</navigator>
</template>
</wd-navbar>
@@ -131,7 +133,7 @@
import { reactive } from 'vue';
// @ts-ignore
import UserApi from '@/sheep/api/member/user';
import sUploader from '@/sheep/components/s-uploader/s-uploader.vue';
import SUploader from '@/sheep/components/s-uploader/s-uploader.vue';
// @ts-ignore
import sheep from '@/sheep';
+52
View File
@@ -0,0 +1,52 @@
<template>
<wd-config-provider theme="dark">
<wd-navbar title="访客记录" safeAreaInsetTop :bordered="false">
<template #left>
<navigator open-type="navigateBack" hover-class="navigator-hover">
<uni-icons type="back" size="30" color="#ffcd32"></uni-icons>
</navigator>
</template>
</wd-navbar>
<wd-tabs v-model="activeTab">
<wd-tab title="我看过的">
<view>1</view>
</wd-tab>
<wd-tab title="看过我的">
<view>2</view>
</wd-tab>
</wd-tabs>
<scroll-list
style="height: calc(100dvh - 44px - 42px)"
:loadMoreStatus="loadMoreStatus"
@refresh="refreshList"
@loadMore="listLoadMore"
>
<moment-card v-if="listData.length" v-for="item in 4" :data="item" />
<view v-else class="flex px-4 py-4" v-for="index in 4" :key="index">
<wd-skeleton :row-col="[{ size: '50px', type: 'circle' }]" animation="flashed" />
<wd-skeleton
:custom-style="{ width: '100%', marginLeft: '12px' }"
animation="flashed"
theme="paragraph"
/>
</view>
</scroll-list>
</wd-config-provider>
</template>
<script setup lang="ts">
import MomentCard from '@/sheep/components/moment-card/moment-card.vue';
import ScrollList from '@/sheep/components/scroll-list/scroll-list.vue';
import useScroll from '@/sheep/hooks/use-scroll';
import RecentApi from '@/sheep/api/member/recent';
import { ref, reactive } from 'vue';
const activeTab = ref();
const params = reactive({});
const { listData, loadMoreStatus, refreshList, listLoadMore } = useScroll(
RecentApi.viewRecord,
params,
);
</script>
+58
View File
@@ -51,6 +51,64 @@ const RecentApi = {
},
});
},
// 查看我的动态
myMomentList: (data: any) => {
return request({
url: '/member/recent/xxx/xxx',
method: 'POST',
data,
custom: {
showLoading: true,
loadingMsg: '加载中',
},
});
},
// 查看访客记录
viewRecord: (data: any) => {
return request({
url: '/member/recent/xxx/xxx',
method: 'POST',
data,
custom: {
showLoading: true,
loadingMsg: '加载中',
},
});
},
// 查看我的评价
myEvaluate: () => {
return request({
url: '/member/recent/xxx/xxx',
method: 'POST',
custom: {
showLoading: true,
loadingMsg: '加载中',
},
});
},
// 用户朋友圈操作
recentOperate: (data: any) => {
return request({
url: '/member/recent/operate',
method: 'POST',
data,
custom: {
showLoading: true,
loadingMsg: '操作中',
},
});
},
// 获取用户相册
getUserAlbum: (params: any) => {
return request({
url: '/member/photo/page',
method: 'GET',
params,
custom: {
showLoading: false,
},
});
},
};
export default RecentApi;
-196
View File
@@ -1,196 +0,0 @@
<!-- TODO 霖:是不是怎么复用 s-count-down 组件 -->
<template>
<view class="time" :style="justifyLeft">
<text class="" v-if="tipText">{{ tipText }}</text>
<text
class="styleAll p6"
v-if="isDay === true"
:style="{ background: bgColor.bgColor, color: bgColor.Color }"
>{{ day }}{{ bgColor.isDay ? '天' : '' }}</text
>
<text
class="timeTxt"
v-if="dayText"
:style="{ width: bgColor.timeTxtwidth, color: bgColor.bgColor }"
>{{ dayText }}</text
>
<text
class="styleAll"
:class="isCol ? 'timeCol' : ''"
:style="{ background: bgColor.bgColor, color: bgColor.Color, width: bgColor.width }"
>{{ hour }}</text
>
<text
class="timeTxt"
v-if="hourText"
:class="isCol ? 'whit' : ''"
:style="{ width: bgColor.timeTxtwidth, color: bgColor.bgColor }"
>{{ hourText }}</text
>
<text
class="styleAll"
:class="isCol ? 'timeCol' : ''"
:style="{ background: bgColor.bgColor, color: bgColor.Color, width: bgColor.width }"
>{{ minute }}</text
>
<text
class="timeTxt"
v-if="minuteText"
:class="isCol ? 'whit' : ''"
:style="{ width: bgColor.timeTxtwidth, color: bgColor.bgColor }"
>{{ minuteText }}</text
>
<text
class="styleAll"
:class="isCol ? 'timeCol' : ''"
:style="{ background: bgColor.bgColor, color: bgColor.Color, width: bgColor.width }"
>{{ second }}</text
>
<text class="timeTxt" v-if="secondText">{{ secondText }}</text>
</view>
</template>
<script>
export default {
name: 'countDown',
props: {
justifyLeft: {
type: String,
default: '',
},
//距离开始提示文字
tipText: {
type: String,
default: '倒计时',
},
dayText: {
type: String,
default: '天',
},
hourText: {
type: String,
default: '时',
},
minuteText: {
type: String,
default: '分',
},
secondText: {
type: String,
default: '秒',
},
datatime: {
type: Number,
default: 0,
},
isDay: {
type: Boolean,
default: true,
},
isCol: {
type: Boolean,
default: false,
},
bgColor: {
type: Object,
default: null,
},
},
data: function () {
return {
day: '00',
hour: '00',
minute: '00',
second: '00',
};
},
created: function () {
this.show_time();
},
mounted: function () {},
methods: {
show_time: function () {
let that = this;
function runTime() {
//时间函数
let intDiff = that.datatime - Date.parse(new Date()) / 1000; //获取数据中的时间戳的时间差;
let day = 0,
hour = 0,
minute = 0,
second = 0;
if (intDiff > 0) {
//转换时间
if (that.isDay === true) {
day = Math.floor(intDiff / (60 * 60 * 24));
} else {
day = 0;
}
hour = Math.floor(intDiff / (60 * 60)) - day * 24;
minute = Math.floor(intDiff / 60) - day * 24 * 60 - hour * 60;
second = Math.floor(intDiff) - day * 24 * 60 * 60 - hour * 60 * 60 - minute * 60;
if (hour <= 9) hour = '0' + hour;
if (minute <= 9) minute = '0' + minute;
if (second <= 9) second = '0' + second;
that.day = day;
that.hour = hour;
that.minute = minute;
that.second = second;
} else {
that.day = '00';
that.hour = '00';
that.minute = '00';
that.second = '00';
}
}
runTime();
setInterval(runTime, 1000);
},
},
};
</script>
<style scoped>
.p6 {
padding: 0 8rpx;
}
.styleAll {
/* color: #fff; */
font-size: 24rpx;
height: 36rpx;
line-height: 36rpx;
border-radius: 6rpx;
text-align: center;
/* padding: 0 6rpx; */
}
.timeTxt {
text-align: center;
/* width: 16rpx; */
height: 36rpx;
line-height: 36rpx;
display: inline-block;
}
.whit {
color: #fff !important;
}
.time {
display: flex;
justify-content: center;
}
.red {
color: #fc4141;
margin: 0 4rpx;
}
.timeCol {
/* width: 40rpx;
height: 40rpx;
line-height: 40rpx;
text-align:center;
border-radius: 6px;
background: #fff;
font-size: 24rpx; */
color: #e93323;
}
</style>
@@ -0,0 +1,136 @@
<template>
<view class="border-1 border-b-solid border-#444444 px-4 py-4">
<view class="mb-1 flex items-center" @click="detail">
<image
:src="member.memberAvatar"
class="mr-3 size-100rpx rounded-full bg-#333333"
mode="aspectFill"
/>
<view class="flex-1">
<view class="flex justify-between items-center">
<view class="flex items-center">
<text class="mr-4 text-base">{{ member?.memberNickname }}</text>
<view
class="inline-flex items-center px-1 text-20rpx text-black rounded-1 bg-color-theme-dark"
>
<wd-icon name="discount-filled" size="12px" color="#000"></wd-icon>
<text>真人认证</text>
</view>
</view>
<text class="text-22rpx c-gray">近期</text>
</view>
<view class="mt-1 text-xs c-gray">
{{ `未知性别 · ${member?.memberAge}岁 | ${member?.memberOcc}` }}
</view>
</view>
</view>
<view class="mb-30rpx pl-130rpx">
<text class="leading-[1.5] text-white">{{ data.description }}</text>
<view
class="mt-20rpx flex flex-wrap gap-20rpx"
v-if="data.coverPic && data.coverPic.length > 0"
>
<template v-for="item in [data.coverPic]">
<!-- #ifdef APP-PLUS -->
<su-video v-if="item.endsWith('mp4')" :src="item" />
<!-- #endif -->
<!-- #ifndef APP-PLUS -->
<video v-if="item.endsWith('mp4')" :src="item" />
<!-- #endif -->
<image
v-else
v-if="item.startsWith('http')"
:src="item"
class="size-260rpx rounded-10rpx bg-#333333"
mode="aspectFill"
@click="previewImage(item)"
/>
</template>
</view>
</view>
<view class="mb-2 flex items-center pl-130rpx text-xs text-white/70">
<uni-icons type="location" size="16" color="#B5B4BC"></uni-icons>
<text>{{ data.issueAddress }} · 1km</text>
</view>
<view class="flex gap-60rpx pl-130rpx text-white">
<view class="flex items-center gap-10rpx text-sm">
<uni-icons
v-if="isLike"
type="heart-filled"
size="24"
color="#ffcd32"
@click="handleunLike"
></uni-icons>
<uni-icons v-else type="heart" size="24" color="#B5B4BC" @click="handleLike"></uni-icons>
<text>{{ data.likes || 0 }} 喜欢</text>
</view>
<view class="flex items-center gap-10rpx text-sm" @click="goChat">
<uni-icons type="chat" size="24" color="#B5B4BC"></uni-icons>
<text>{{ data.comments || 0 }} 打招呼</text>
</view>
</view>
</view>
</template>
<script setup lang="ts">
import RecentApi from '@/sheep/api/member/recent';
import { computed, reactive, ref } from 'vue';
const props = defineProps<{
data: any;
}>();
const emit = defineEmits<(e: 'detail') => void>();
const member = computed(() => props.data.member || {});
const isLike = ref(false);
const params = reactive({
memberId: 7, // 被操作的用户id
memberRecentId: 8, // 用户朋友圈编号-不能为空
// 朋友圈操作类型 不能为空
// RECENT_LIKE-朋友圈-点赞
// RECENT_REPORT-朋友圈-举报
// RECENT_SHIELD-朋友圈-屏蔽
// MEMBER_COLLECT-用户-收藏
// MEMBER_SHIELD-用户-屏蔽
// MEMBER_REPORT-用户-举报
// MEMBER_RATING-用户-评价
action: '',
reportType: '1', // 举报类型
scoreSc: 5, // 身材评分
scoreNx: 4, // 耐心评分
scoreSk: 3, // 爽快评分
scoreYq: 2, // 有趣评分
});
// 图片预览
const previewImage = (img: string) => {
uni.previewImage({
urls: [img],
});
};
// 喜欢
const handleLike = async () => {
params.action = 'RECENT_LIKE';
const { code } = await RecentApi.recentOperate(params);
if (code == 200) {
isLike.value = true;
}
};
// 取消喜欢
const handleunLike = async () => {
await RecentApi.recentOperate(params);
isLike.value = false;
};
// 去聊天
const goChat = () => {
uni.showToast({ title: '功能开发中...' });
};
// 详情
const detail = () => {
emit('detail');
};
</script>
-117
View File
@@ -1,117 +0,0 @@
<template>
<view class="border-1 border-b-solid border-#444444 px-4 py-4">
<view class="mb-1 flex items-center" @click="detail">
<image :src="avatar" class="mr-3 size-100rpx rounded-full bg-#333333" mode="aspectFill" />
<view class="flex-1">
<view class="flex items-center">
<text class="mr-4 text-base">{{ name }}</text>
<text class="rounded-6rpx bg-color-theme px-1 text-xs text-black">实人认证</text>
</view>
<view class="mt-1 text-xs c-gray">{{ info }}</view>
</view>
</view>
<view class="mb-30rpx pl-130rpx">
<text class="leading-[1.5] text-white">{{ content }}</text>
<view class="mt-20rpx flex flex-wrap gap-20rpx" v-if="media && media.length > 0">
<template v-for="item in media">
<!-- #ifdef APP-PLUS -->
<su-video v-if="item.endsWith('mp4')" :src="item" />
<!-- #endif -->
<!-- #ifndef APP-PLUS -->
<video v-if="item.endsWith('mp4')" :src="item" />
<!-- #endif -->
<image
v-else
v-if="item.startsWith('http')"
:src="item"
class="size-260rpx rounded-10rpx bg-#333333"
mode="aspectFill"
@click="previewImage(item)"
/>
</template>
</view>
</view>
<view class="mb-2 flex items-center pl-130rpx text-xs text-white/70">
<uni-icons type="location" size="16" color="#B5B4BC"></uni-icons>
<text>{{ location }} · 1km</text>
</view>
<view class="flex gap-60rpx pl-130rpx text-white">
<view class="flex items-center gap-10rpx text-sm">
<uni-icons
v-if="isLike"
type="heart-filled"
size="24"
color="#ffcd32"
@click="handleunLike"
></uni-icons>
<uni-icons v-else type="heart" size="24" color="#B5B4BC" @click="handleLike"></uni-icons>
<text>{{ likes || 0 }} 喜欢</text>
</view>
<view class="flex items-center gap-10rpx text-sm" @click="goChat">
<uni-icons type="chat" size="24" color="#B5B4BC"></uni-icons>
<text>{{ comments || 0 }} 打招呼</text>
</view>
</view>
</view>
</template>
<script setup lang="ts">
import { ref } from 'vue';
withDefaults(
defineProps<
Partial<{
avatar: string;
name: string;
verification: boolean;
info: string;
content: string;
media: string[];
location: string;
likes: number | string;
comments: number | string;
}>
>(),
{
avatar: '',
name: '',
verification: false,
info: '',
content: '',
media: () => [],
location: '',
likes: 0,
comments: 0,
},
);
const emit = defineEmits<(e: 'detail') => void>();
const isLike = ref(false);
// 图片预览
const previewImage = (img: string) => {
uni.previewImage({
urls: [img],
});
};
// 喜欢
const handleLike = () => {
isLike.value = true;
};
// 取消喜欢
const handleunLike = () => {
isLike.value = false;
};
// 去聊天
const goChat = () => {
uni.showToast({ title: '功能开发中...' });
};
// 详情
const detail = () => {
emit('detail');
};
</script>
@@ -0,0 +1,75 @@
<template>
<scroll-view
scroll-y
refresher-enabled
enable-back-to-top
refresher-background="#222"
:refresher-triggered="refresherTriggered"
:refresher-threshold="100"
@refresherabort="onRefresherAbort"
@refresherrefresh="onRefresherRefresh"
@scrolltolower="onScrollToLower"
@scroll="(e: any) => emit('scroll', e)"
v-bind="attrs"
>
<slot />
<uni-load-more
:status="loadMoreStatus"
:content-text="loadMoreContent"
@clickLoadMore="onScrollToLower"
/>
<view style="height: 100rpx"></view>
</scroll-view>
</template>
<script setup lang="ts">
import { onMounted, reactive, ref, useAttrs } from 'vue';
const attrs = useAttrs();
const props = withDefaults(
defineProps<{
loadMoreStatus?: 'more' | 'loading' | 'noMore';
}>(),
{
loadMoreStatus: 'noMore',
},
);
const emit = defineEmits<{
(e: 'refresh', done: () => void): void;
(e: 'loadMore'): void;
(e: 'scroll', event: any): void;
}>();
const refresherTriggered = ref(false);
const loadMoreContent = reactive({
contentdown: '正在加载...',
contentrefresh: '正在加载...',
contentnomore: '没有更多数据了',
});
onMounted(() => {
onScrollToLower();
});
// 下拉刷新中止
const onRefresherAbort = () => {
refresherTriggered.value = false;
};
// 触发下拉刷新
const onRefresherRefresh = () => {
refresherTriggered.value = true;
emit('refresh', () => {
refresherTriggered.value = false;
});
};
// 触发上拉加载
const onScrollToLower = () => {
if (props.loadMoreStatus === 'loading' || props.loadMoreStatus === 'noMore') {
return;
}
emit('loadMore');
};
</script>
+2 -2
View File
@@ -1,6 +1,6 @@
<template>
<view
class="flex items-center relative mx-auto border-1 border-solid border-#666 rounded-full overflow-hidden"
class="flex items-center relative mx-auto border-1 border-solid border-#666 bg-#333 rounded-full overflow-hidden p-1"
:style="segmentedWidth"
>
<view
@@ -13,7 +13,7 @@
<text>{{ item }}</text>
</view>
<div
class="absolute left-0 top-0 h-full bg-color-theme-dark rounded-full transform duration-100"
class="absolute h-2/3 bg-color-theme-dark rounded-full transform duration-100"
:style="activeStyle"
></div>
</view>
@@ -0,0 +1,46 @@
<template>
<view class="flex px-4 py-2">
<image
class="w-200rpx h-300rpx mr-3 rounded-2 bg-#777"
:src="member.memberAvatar"
mode="aspectFill"
/>
<view class="flex-1">
<view class="flex justify-between items-center">
<text class="text-size-base">{{ member.memberNickname }}</text>
<text class="py-1 px-2 rounded-full text-xs bg-color-theme-dark">{{ '在线' }}</text>
</view>
<view class="mt-2 inline-flex px-2 py-1 text-xs c-black rounded-1 bg-color-theme-dark">
<wd-icon name="discount-filled" size="16px" color="#000"></wd-icon>
<text>真人认证</text>
</view>
<view class="mt-2 flex flex-wrap gap-3">
<text class="bg-#333 text-color-theme-dark text-xs px-2 py-1 rounded-1">
{{ '未知性别' }}·{{ member.memberAge }}岁
</text>
<text class="bg-#333 text-color-theme-dark text-xs px-2 py-1 rounded-1">
{{ member.memberHeight }}cm
</text>
<text class="bg-#333 text-color-theme-dark text-xs px-2 py-1 rounded-1">
{{ member.memberWeight }}kg
</text>
<text class="bg-#333 text-color-theme-dark text-xs px-2 py-1 rounded-1">
{{ member.memberOcc }}
</text>
<text class="bg-#333 text-color-theme-dark text-xs px-2 py-1 rounded-1">
{{ data.issueCity }}km
</text>
</view>
</view>
</view>
</template>
<script setup lang="ts">
import { computed } from 'vue';
const props = defineProps<{
data?: any;
}>();
const member = computed(() => props.data.member || {});
</script>
@@ -9,7 +9,7 @@ export type cityItem = {
lat?: string;
};
const cityIndexList: any = [
const useCityIndex = () => [
{
letter: 'A',
data: [
@@ -2160,4 +2160,4 @@ const cityIndexList: any = [
},
];
export default cityIndexList;
export default useCityIndex;
+20 -58
View File
@@ -1,94 +1,56 @@
import { onMounted, reactive, ref } from 'vue';
import { reactive, ref } from 'vue';
export default function useScroll(fetchList: (...arg: any) => Promise<any>, fetchBody: any = {}) {
const refresherTriggered = ref(false);
const loadMoreContent = reactive({
contentdown: ' ',
contentrefresh: '正在加载...',
contentnomore: '没有更多数据了',
});
const loadMoreStatus = ref<'more' | 'loading' | 'noMore'>('more');
export default function useScroll(fetch: (...arg: any) => Promise<any>, params: any = {}) {
const listData = ref<any[]>([]);
const pageInfo = reactive({
const loadMoreStatus = ref<'more' | 'loading' | 'noMore'>('more');
const pageParams = reactive({
pageNo: 1,
pageSize: 10,
total: 0,
hasMore: true,
});
onMounted(() => {
loadData(false);
});
const total = ref(0);
const loadData = async (isRefresh: boolean = false) => {
try {
if (pageInfo.pageNo === 1) {
if (pageParams.pageNo === 1) {
uni.showLoading({ title: '加载中...' });
}
if (isRefresh) {
pageInfo.pageNo = 1;
const { data = [] } = await fetchList({ ...pageInfo, ...fetchBody });
pageParams.pageNo = 1;
const { data = [] } = await fetch({ ...pageParams, ...params });
listData.value = data.list ?? [];
pageInfo.total = data.total;
total.value = data.total;
} else {
const { data = [] } = await fetchList({ ...pageInfo, ...fetchBody });
const { data = [] } = await fetch({ ...pageParams, ...params });
listData.value.push(...(data.list ?? []));
pageInfo.total = data.total;
total.value = data.total;
}
pageInfo.pageNo = pageInfo.pageNo + 1;
pageParams.pageNo = pageParams.pageNo + 1;
if (listData.value?.length >= pageInfo.total) {
if (listData.value?.length >= total.value) {
loadMoreStatus.value = 'noMore';
} else {
loadMoreStatus.value = 'more';
}
return true;
} catch (error) {
console.error('加载数据失败:', error);
return false;
} finally {
uni.hideLoading();
}
};
// 触发下拉刷新
const onRefresherRefresh = async () => {
refresherTriggered.value = true;
const success = await loadData(true);
refresherTriggered.value = false;
const refreshList = async (done: () => void = () => {}) => {
await loadData(true);
done();
};
// 下拉刷新中止
const onRefresherAbort = () => {
console.log('下拉刷新中止');
refresherTriggered.value = false;
};
// 触发上拉加载
const onScrollToLower = async () => {
if (loadMoreStatus.value === 'loading' || loadMoreStatus.value === 'noMore') {
return;
}
loadMoreStatus.value = 'loading';
await loadData(false);
};
// 点击加载更多
const onClickLoadMore = () => {
if (loadMoreStatus.value === 'more') {
onScrollToLower();
}
const listLoadMore = () => {
loadData(false);
};
return {
listData,
refresherTriggered,
loadMoreContent,
loadMoreStatus,
onRefresherRefresh,
onRefresherAbort,
onScrollToLower,
onClickLoadMore,
refreshList,
listLoadMore,
};
}
+6
View File
@@ -54,6 +54,12 @@ export default {
color: '#ffcd32',
},
],
[
'text-color-theme-dark',
{
color: 'rgba(255, 205, 49, 0.8)',
},
],
[
'bg-color',
{