feat:相册上传;开通VIP

This commit is contained in:
ctw committed 2025-11-21 15:59:36 +08:00
1 parent 1f4a52807c
commit 18f3b76cf2
6 files changed
+316 -23

No files matched your search

+7
View File
@@ -185,6 +185,13 @@
"navigationBarTitleText": "上传照片",
"navigationStyle": "custom"
}
},
{
"path": "apply-vip",
"style": {
"navigationBarTitleText": "开通VIP",
"navigationStyle": "custom"
}
}
]
},
+12 -6
View File
@@ -29,7 +29,7 @@
@loadMore="listLoadMore"
@scroll="onScroll"
>
<view class="w-full h-500rpx relative">
<view class="w-full h-600rpx relative">
<image
class="w-full h-full absolute inset-0"
:src="userDetail.coverPic"
@@ -44,18 +44,24 @@
mode="aspectFill"
/>
<view class="text-base mb-20rpx">{{ userDetail.member?.memberNickname }}</view>
<view class="bg-color-theme text-xs c-black px-2 rounded-1 mb-20rpx">真人认证</view>
<view
class="mb-20rpx 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="flex flex-wrap justify-center mb-20rpx">
<text class="px-2 rounded-1 mr-2 bg-#222 text-color-theme">
<text class="px-2 py-1 rounded-1 mr-2 bg-#222 text-color-theme-dark">
{{ '未知性别 · ' + userDetail.member?.memberAge || '' + '岁' }}
</text>
<text class="px-2 rounded-1 mr-2 bg-#222 text-color-theme">
<text class="px-2 py-1 rounded-1 mr-2 bg-#222 text-color-theme-dark">
{{ userDetail.member?.memberHeight || '' + 'cm' }}
</text>
<text class="px-2 rounded-1 mr-2 bg-#222 text-color-theme">
<text class="px-2 py-1 rounded-1 mr-2 bg-#222 text-color-theme-dark">
{{ userDetail.member?.memberWeight || '' + 'kg' }}
</text>
<text class="px-2 rounded-1 mr-2 bg-#222 text-color-theme">
<text class="px-2 py-1 rounded-1 mr-2 bg-#222 text-color-theme-dark">
{{ userDetail.member?.memberOcc || '' + 'kg' }}
</text>
</view>
+150
View File
@@ -0,0 +1,150 @@
<template>
<wd-config-provider theme="dark">
<wd-navbar title="开通VIP" 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>
<scroll-view style="height: calc(100dvh - 88px)" scroll-y>
<view
class="mx-4 mt-4 p-4 rounded-2 bg-#000 b-4 b-solid b-t-#ffcd32/80 b-l-#ffcd32/60 b-r-#ffcd32/60 b-b-#ffcd32/40"
>
<view class="text-color-theme-dark font-900 font-italic text-xl mb-1">VIP</view>
<view class="flex-col-center mb-4">
<view class="text-gray mb-2 text-xl font-900 font-italic tracking-1.5">
高端 / 专业 / 快速
</view>
<view class="text-gray text-xs tracking-3">精英人士约会社交</view>
</view>
</view>
<view class="mt-5 px-4 text-base font-600">VIP会员</view>
<view class="mt-3 px-4">
<scroll-view scroll-x class="w-full" :show-scrollbar="false">
<view class="flex">
<view
v-for="(item, index) in openTypeList"
:key="item.id"
class="mr-3 ml-1 my-1"
@click="curOpenTypeId = item.id"
>
<view
class="w-220rpx rounded-3 flex-col-center transition-all duration-200"
:class="[
curOpenTypeId === item.id
? 'bg-#111 text-white b-3 b-solid b-#ffcd32/60'
: 'b-3 b-solid b-#333',
]"
>
<view class="mt-2 text-sm text-#ffffff">{{ item.title }}</view>
<view class="mt-1 text-lg font-900 text-color-theme-dark"
>¥{{ fen2yuan(item.preferentialPrice) }}</view
>
<view class="mt-1 text-sm line-through text-gray">
¥{{ fen2yuan(item.originalPrice) }}
</view>
<view class="my-2 text-xs text-gray">{{ item.duration || '' }}天</view>
</view>
</view>
</view>
</scroll-view>
</view>
<view class="mt-4 px-4 text-xs text-gray leading-relaxed text-center">
开通即视为同意
<text class="text-color-theme-dark">《VIP会员服务协议》</text>
和
<text class="text-color-theme-dark">《自动续费协议》</text>
</view>
<view
v-if="openTypeList?.length"
class="mt-4 w-2/3 mx-auto py-2 text-center rounded-full bg-color-theme-dark text-black text-sm active:bg-color-theme"
@click="handleOpenVip"
>
立即开通VIP
</view>
<view class="mt-6 px-4">
<view class="grid grid-cols-2 gap-3">
<view
v-for="(item, index) in benefits"
:key="index"
class="p-3 rounded-2 bg-#111 flex items-center"
>
<view class="flex-1">
<view class="text-sm mb-1">{{ item.title }}</view>
<view class="text-xs text-#ffffff80">{{ item.desc }}</view>
</view>
</view>
</view>
</view>
</scroll-view>
<wd-message-box />
</wd-config-provider>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue';
// @ts-ignore
import { fen2yuan } from '@/sheep/hooks/useGoods';
import { onLoad } from '@dcloudio/uni-app';
import RecentApi from '@/sheep/api/member/recent';
import { useMessage } from '@/uni_modules/wot-design-uni';
const messageBox = useMessage();
interface OpenTypeItem {
id: number;
title: string;
icon: string;
preferentialPrice: number;
originalPrice: number;
duration: number;
status: string;
isHot: boolean;
sort: number;
createTime: number;
}
const benefits = [
{ title: '无限次打招呼', desc: '每天畅聊不设上限,优先曝光给心仪的人' },
{ title: '优先展示', desc: '在附近和推荐列表中获得更高权重' },
{ title: '查看谁喜欢我', desc: '查看所有喜欢你的用户' },
{ title: '专属身份标识', desc: '昵称后展示 VIP 标识,提升可信度' },
];
const openTypeList = ref<OpenTypeItem[]>(); // 会员类型列表
const curOpenTypeId = ref<number>(); // 当前选择的会员类型id
const currentOpenType = computed<OpenTypeItem | undefined>(() =>
openTypeList.value?.find((item) => item.id === curOpenTypeId.value),
); // 当前选择的会员类型
onLoad(async () => {
const { data = null } = await RecentApi.getMemberOpenTypeList();
openTypeList.value = data ?? [];
if (openTypeList.value && openTypeList.value[0]) {
curOpenTypeId.value = openTypeList.value[0].id;
}
});
// 开通会员
const handleOpenVip = () => {
if (!curOpenTypeId.value || !currentOpenType.value?.id)
return uni.showToast({ title: '请选择会员类型', icon: 'none' });
messageBox
.confirm({
msg: '确认开通?',
title: '提示',
})
.then(async () => {
const { code } = await RecentApi.memberOpenTypePay({ openTypeId: curOpenTypeId.value });
if (code !== 0) return uni.showToast({ title: '开通失败', icon: 'fail' });
uni.showToast({ title: '开通成功', icon: 'success' });
})
.catch(() => {});
};
</script>
+19
View File
@@ -48,6 +48,25 @@
</view>
</view>
<!-- 开通vip -->
<view
class="text-color-theme-dark mx-4 p-3 rounded-2 bg-#000 b-4 b-solid b-t-#ffcd32/80 b-l-#ffcd32/60 b-r-#ffcd32/60 b-b-#ffcd32/40 flex justify-between"
>
<view class="font-900 font-italic text-lg">VIP</view>
<view class="flex items-center">
<text class="text-xs">尊享vip免费特权</text>
<navigator
url="/pages/profile/apply-vip"
open-type="navigate"
hover-class="navigator-hover"
>
<text class="ml-2 px-2 py-1 rounded-full text-sm bg-color-theme text-black">
立即开通
</text>
</navigator>
</view>
</view>
<!-- 用户相册 -->
<user-ablum :ablumList="ablumList"></user-ablum>
+81 -17
View File
@@ -9,50 +9,114 @@
</wd-navbar>
<view class="mx-5 my-3 flex justify-between text-color-theme">
<text>相册</text>
<text>{{ ablumUrlList?.length || 0 }}/10</text>
<text>图片</text>
<text>{{ imageFileList?.length || 0 }}/10</text>
</view>
<view class="px-4">
<wd-upload v-model:file-list="ablumUrlList" :upload-method="customUpload"></wd-upload>
<wd-upload
class=""
v-model:file-list="imageFileList"
image-mode="aspectFill"
:upload-method="customUpload"
accept="image"
multiple
:limit="10"
:max-size="500000"
:before-remove="beforeRemove"
/>
</view>
<view class="mx-5 my-3 flex justify-between text-color-theme">
<text>视频</text>
<text>{{ videoFileList?.length || 0 }}/10</text>
</view>
<view class="px-4">
<wd-upload
class=""
v-model:file-list="videoFileList"
image-mode="aspectFill"
:upload-method="customUpload"
accept="video"
multiple
:limit="10"
:max-size="2000000"
:before-remove="beforeRemove"
/>
</view>
<wd-message-box />
<wd-toast />
</wd-config-provider>
<view @click="save">保存</view>
<view
class="mt-40rpx w-1/3 mx-auto rounded-full bg-color-theme-dark text-base text-center py-2 active:bg-color-theme"
@click="save"
>
保 存
</view>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue';
import SUploader from '@/sheep/components/s-uploader/s-uploader.vue';
import { computed, ref, watch } from 'vue';
import useAblum from './use-ablum';
import {
import type {
UploadFile,
UploadMethod,
} from '@/uni_modules/wot-design-uni/components/wd-upload/types';
// @ts-ignore
import FileApi from '@/sheep/api/infra/file';
import RecentApi from '@/sheep/api/member/recent';
import { useMessage, useToast } from '@/uni_modules/wot-design-uni';
const messageBox = useMessage();
const toast = useToast();
const { ablumList, getUserAlbum } = useAblum();
const ablumUrlList = ref<UploadFile[]>([]);
const imageFileList = ref<UploadFile[]>([]);
const videoFileList = ref<UploadFile[]>([]);
watch(
() => ablumList.value,
(val) => {
ablumUrlList.value = val.map((item) => ({ url: item.address }));
imageFileList.value = val.map((item) => ({ url: item.address }));
// videoFileList.value = val.map((item) => ({ url: item.address }));
},
{ immediate: true },
);
const customUpload: UploadMethod = async (file, formData, options) => {
const { data } = await FileApi.uploadFile(file.url);
const { code, data, msg } = await FileApi.uploadFile(file.url);
if (code !== 0) {
return options.onError(msg, file, formData);
}
options.onSuccess(data, file, formData);
console.log(data);
console.log(ablumUrlList.value);
};
// 保存相册
// 移除确认
const beforeRemove = ({ file, fileList, resolve }: any) => {
messageBox
.confirm({
msg: '是否移除',
title: '提示',
})
.then(() => {
toast.success('移除成功');
resolve(true);
})
.catch(() => {
// toast.show('取消删除操作');
});
};
const images = computed(() => {
return imageFileList.value.map((item) => ({ address: item.url, resourceType: 'IMAGE' }));
});
const videos = computed(() => {
return imageFileList.value.map((item) => ({ address: item.url, resourceType: 'VIDEO' }));
});
// 保存
const save = async () => {
// TODO: 调用保存相册的 API
// await RecentApi.saveUserAlbum(ablumList.value);
// 保存成功后重新获取相册列表
await getUserAlbum();
await RecentApi.saveUserAlbum([...images.value, ...videos.value]);
getUserAlbum();
};
</script>
+47
View File
@@ -109,6 +109,53 @@ const RecentApi = {
},
});
},
// 保存用户相册
saveUserAlbum: (data: any) => {
return request({
url: '/member/photo/upload',
method: 'POST',
data,
custom: {
showLoading: true,
loadingMsg: '保存中',
},
});
},
// 移除用户相册
deleteUserAlbum: (id: any) => {
return request({
url: '/member/photo/delete',
method: 'GET',
params: { id },
custom: {
showLoading: true,
loadingMsg: '操作中',
},
});
},
// 获取开通的会员类型列表
getMemberOpenTypeList: () => {
return request({
url: '/member/open-type/list',
method: 'GET',
custom: {
showLoading: true,
loadingMsg: '加载中',
},
});
},
// 开通会员
memberOpenTypePay: (data: any) => {
return request({
url: '/member/open-type/pay',
method: 'POST',
data,
custom: {
showLoading: true,
loadingMsg: '加载中',
},
});
},
};
export default RecentApi;