feat:城市选择;首页广场

This commit is contained in:
ctw committed 2025-11-14 18:02:08 +08:00
1 parent 7df0107dbf
commit d72817b8ea
17 files changed
+2342 -141

No files matched your search

+2 -2
View File
@@ -5,8 +5,8 @@ SHOPRO_VERSION=v2.4.1
SHOPRO_API_PATH=/app-api
# 后端接口 - 测试环境(通过 process.env.NODE_ENV == development)
SHOPRO_DEV_BASE_URL=http://192.168.101.13:48083
# SHOPRO_DEV_BASE_URL = http://yunai.natapp1.cc
# SHOPRO_DEV_BASE_URL=http://192.168.101.13:48083
SHOPRO_DEV_BASE_URL = http://chatapi.zianxin.com
# 后端接口 - 正式环境(通过 process.env.NODE_ENV != development)
SHOPRO_BASE_URL=http://api-dashboard.yudao.iocoder.cn
+1 -1
View File
@@ -8,7 +8,7 @@
// fail: () => {},
// });
// 加载Shopro底层依赖
// ShoproInit();
ShoproInit();
});
onShow(() => {
+1
View File
@@ -13,4 +13,5 @@ html {
user-select: none;
background-color: $color-background;
color: $color-text;
font-size: 14px;
}
+14 -4
View File
@@ -41,12 +41,10 @@
"root": "pages/home",
"pages": [
{
"path": "address-change",
"path": "city",
"style": {
"navigationBarTitleText": "城市",
"navigationStyle": "default",
"navigationBarBackgroundColor": "#222222",
"navigationBarTextStyle": "white"
"navigationStyle": "custom"
}
},
{
@@ -58,6 +56,18 @@
}
]
},
{
"root": "pages/moments",
"pages": [
{
"path": "publish",
"style": {
"navigationBarTitleText": "发布动态",
"navigationStyle": "custom"
}
}
]
},
{
"root": "pages/profile",
"pages": [
-28
View File
@@ -1,28 +0,0 @@
<template>
<view class="address-index">
<uni-indexed-list :options="list" :showSelect="false" @click="select"></uni-indexed-list>
</view>
</template>
<script setup>
const list = [
{
letter: "A",
data: ["1", "2", "3", "4", "5", "6"],
},
{
letter: "B",
data: ["1", "2", "3", "4", "5", "6"],
},
{
letter: "C",
data: ["1", "2", "3", "4", "5", "6"],
},
];
const select = () => {
uni.switchTab({ url: "/pages/home/home" });
};
</script>
<style scoped lang="scss"></style>
File diff suppressed because it is too large. Load diff
+66
View File
@@ -0,0 +1,66 @@
<template>
<van-config-provider theme="dark">
<van-nav-bar title="城市" fixed z-index="10">
<template #left>
<uni-icons type="back" size="30" color="#ffcd32" @click="back"></uni-icons>
</template>
</van-nav-bar>
<view class="mt-100rpx">
<van-search v-model="cityName" shape="round" background="#222222" placeholder="搜索" />
</view>
<view class="px-3 text-sm">热门城市</view>
<view class="flex flex-wrap gap-3 my-3 mx-4">
<text
v-for="(item, index) in hotCity"
:key="index"
class="bg-color-light text-color-theme px-2 rounded-1"
@click.stop="selectHot(item)"
>
{{ item.t }}
</text>
</view>
<van-index-bar highlight-color="#ffcd32" :sticky-offset-top="46">
<template v-for="(item, index) in cityIndex" :key="index">
<van-index-anchor :index="item.letter" />
<van-cell v-for="(v, i) in item.data" :key="i" :title="v.t" @click.stop="select(v)" />
</template>
</van-index-bar>
</van-config-provider>
</template>
<script lang="ts">
const hotCity = [
{ t: '北京', v: 1 },
{ t: '上海', v: 2 },
{ t: '嘉兴', v: 3 },
{ t: '杭州', v: 4 },
];
</script>
<script setup lang="ts">
import { ref } from 'vue';
import cityIndexList, { type cityItem } from './city-index';
// @ts-ignore
import sheep from '@/sheep';
const cityIndex = cityIndexList;
const cityName = ref('');
// 选择热门城市
const selectHot = (v: cityItem) => {
sheep.$store('user').setUserCity(v);
uni.navigateBack();
};
const select = (v: cityItem) => {
sheep.$store('user').setUserCity(v);
uni.navigateBack();
};
function back() {
uni.navigateBack();
}
</script>
+17 -27
View File
@@ -16,7 +16,7 @@
<template v-slot:left>
<view class="location" @click="selectAddress">
<uni-icons type="location" size="24" color="#ffcd32"></uni-icons>
<text>{{}}</text>
<text>{{ userCity.t || '未选择' }}</text>
</view>
</template>
<template v-slot:right></template>
@@ -34,14 +34,14 @@
@scrolltolower="onScrollToLower"
>
<view class="user-card" v-for="user in listData" :key="user.id" @click="detail">
<image class="user-image" :src="user.avatar" />
<image class="user-image" :src="user.member.memberAvatar" />
<view class="user-info">
<view class="user">
<text class="user-name">{{ user.name }}</text>
<text class="user-status">{{ user.status || '离线' }}</text>
<text class="text-lg">{{ user.member.memberNickname }}</text>
<text class="px-2 rounded-full bg-color-theme-dark">{{ '在线' }}</text>
</view>
<view class="verification">
<text class="verify-badge">真人认证</text>
<text class="px-2 rounded-full bg-color-theme-dark">真人认证</text>
</view>
<view class="user-details">
<text class="tag">{{ user.gender }}·{{ user.age }}岁</text>
@@ -62,10 +62,12 @@
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { computed, ref } from 'vue';
import segmented from '@/sheep/components/segmented/segmented.vue';
import makeFriendApi from '@/sheep/api/make-friend';
import RecentApi from '@/sheep/api/member/recent';
import useScroll from '@/sheep/hooks/use-scroll';
// @ts-ignore
import sheep from '@/sheep';
const {
listData,
@@ -76,14 +78,20 @@
onRefresherAbort,
onScrollToLower,
onClickLoadMore,
} = useScroll(makeFriendApi.getMakeFriendList);
} = useScroll(RecentApi.quickPage, {
scene: 'DYNAMIC_RECOMMEND',
province: '',
city: '',
memberId: '',
});
const userCity = computed(() => sheep.$store('user').userCity);
const current = ref(0);
const segmentedItems = ['广场', '最近', '新人'];
const selectAddress = () => {
uni.navigateTo({
url: '/pages/home/address-change',
url: '/pages/home/city',
});
};
@@ -131,27 +139,9 @@
align-items: center;
justify-content: space-between;
margin-top: 16rpx;
.user-name {
font-size: $font-size-large;
font-weight: bold;
}
.user-status {
background-color: $color-theme-d;
font-size: $font-size-small;
padding: 10rpx 20rpx;
border-radius: 36rpx;
color: white;
}
}
.verification {
margin-top: 16rpx;
.verify-badge {
background-color: $color-theme;
font-size: $font-size-small;
color: black;
padding: 6rpx 12rpx;
border-radius: 6rpx;
}
}
.user-details {
margin-top: 26rpx;
+3
View File
@@ -0,0 +1,3 @@
<template> 111 </template>
<script setup lang="ts"></script>
+1 -1
View File
@@ -90,7 +90,7 @@
align-items: center;
background-color: $color-theme;
border-radius: 40rpx;
padding: 4rpx 20rpx;
padding: 0 10rpx;
.text {
font-size: $font-size-medium;
color: #333;
+21 -13
View File
@@ -5,7 +5,7 @@
<uni-icons type="back" size="30" color="#ffcd32" @click="back"></uni-icons>
</template>
<template #right>
<view class="bg-color-theme px-2 py-1 rounded-full c-black" @click="saveUserInfo">
<view class="bg-color-theme px-3 py-1 rounded-full c-black" @click="saveUserInfo">
保存
</view>
</template>
@@ -19,7 +19,7 @@
fileMediatype="image"
limit="1"
mode="grid"
:imageStyles="{ width: '168rpx', height: '168rpx', borderRadius: '168rpx' }"
:imageStyles="{ width: '168rpx', height: '168rpx' }"
/>
</view>
@@ -39,7 +39,7 @@
<van-cell-group inset>
<van-cell title="昵称" value="输入">
<template #value>
<input type="text" :maxlength="12" :value="userinfo.nickname" />
<input type="text" v-model="userinfo.nickname" :maxlength="12" />
</template>
</van-cell>
<van-cell
@@ -83,10 +83,10 @@
<view class="mx-5 my-3 flex justify-between">
<text>个人相册</text>
<text>{{ userinfo.photos.length }}/9</text>
<text>{{ userinfo.photo.length || 0 }}/9</text>
</view>
<view class="px-4">
<s-uploader v-model:url="userinfo.photos" fileMediatype="image" limit="9" mode="grid" />
<s-uploader v-model:url="userinfo.photo" fileMediatype="image" limit="9" mode="grid" />
</view>
<view class="h-100"></view>
</scroll-view>
@@ -135,9 +135,9 @@
const columnsHeight = Array.from({ length: 100 }, (_, i) => ({
text: i + 100 + 'cm',
value: i + 100,
}));
})).reverse();
// 体重选择器选项
const columnsWeight = Array.from({ length: 100 }, (_, i) => ({
const columnsWeight = Array.from({ length: 80 }, (_, i) => ({
text: i + 20 + 'kg',
value: i + 20,
}));
@@ -156,7 +156,7 @@
<script setup lang="ts">
import { onLoad } from '@dcloudio/uni-app';
import { reactive, ref } from 'vue';
import { reactive, ref, watch } from 'vue';
// @ts-ignore
import UserApi from '@/sheep/api/member/user';
import sUploader from '@/sheep/components/s-uploader/s-uploader.vue';
@@ -165,23 +165,24 @@
// 获取用户信息
const { data } = await UserApi.getUserInfo();
Object.assign(userinfo, data, {
birthday: data.birthday ?? '',
birthday: data.birthday ? data.birthday : '',
height: data.height ?? '',
weight: data.weight ?? '',
photo: data.photo?.map((item: { address: string }) => item.address),
});
console.log(userinfo);
});
// 用户信息
const userinfo = reactive<any>({
avatar: [],
avatar: '',
nickname: '',
birthday: '',
height: '',
weight: '',
occ: '',
description: '',
photos: [],
photo: [],
});
const showPicker = ref(false); // 选择器显隐
const pickerFiled = ref<'' | 'birthday' | 'height' | 'weight' | 'occ'>('');
@@ -202,7 +203,14 @@
showPicker.value = false;
};
function saveUserInfo() {}
// 保存用户信息
const saveUserInfo = async () => {
const params = {
...userinfo,
photo: userinfo.photo.map((url: string) => ({ resourceType: 'IMAGE', address: url })),
};
await UserApi.updateUser(params);
};
function back() {
uni.navigateBack();
-43
View File
@@ -1,43 +0,0 @@
// import request from "@/sheep/request";
const mockUsers = Array.from({ length: 26 }).map((_, index) => ({
id: index,
name: "山峰" + (index + 1),
avatar: "/static/avatar2.jpg",
gender: "男",
age: 30,
height: "185",
weight: "75",
occupation: "健身教练",
distance: "5.2",
photoCount: 3,
isVip: false,
status: "在线",
}));
const makeFriendApi = {
// 获得用户收件地址列表
// getAddressList: () => {
// return request({
// url: "/member/address/list",
// method: "GET",
// });
// },
getMakeFriendList: async (page: number = 1, pageSize: number = 10) => {
await new Promise((resolve) => setTimeout(resolve, 1000));
const startIndex = (page - 1) * pageSize;
const endIndex = startIndex + pageSize;
const newUsers = mockUsers.slice(startIndex, endIndex);
return {
page,
pageSize,
total: 26,
data: newUsers,
};
},
};
export default makeFriendApi;
+18
View File
@@ -0,0 +1,18 @@
// @ts-ignore
import request from '@/sheep/request';
const RecentApi = {
// 查询附近/广场
quickPage: (data: any) => {
return request({
url: '/member/recent/quick-page',
method: 'POST',
data,
custom: {
showLoading: true,
},
});
},
};
export default RecentApi;
+2 -1
View File
@@ -21,7 +21,8 @@ const UserApi = {
custom: {
auth: true,
showSuccess: true,
successMsg: '更新成功',
showLoading: true,
successMsg: '保存成功',
},
});
},
+21 -21
View File
@@ -1,13 +1,13 @@
import { onMounted, reactive, ref } from "vue";
import { onMounted, reactive, ref } from 'vue';
export default function useScroll(fetchList: (...arg: any) => Promise<any>) {
export default function useScroll(fetchList: (...arg: any) => Promise<any>, fetchBody: any) {
const refresherTriggered = ref(false);
const loadMoreContent = reactive({
contentdown: " ",
contentrefresh: "正在加载...",
contentnomore: "没有更多数据了",
contentdown: ' ',
contentrefresh: '正在加载...',
contentnomore: '没有更多数据了',
});
const loadMoreStatus = ref<"more" | "loading" | "noMore">("more");
const loadMoreStatus = ref<'more' | 'loading' | 'noMore'>('more');
const listData = ref<any[]>([]);
const pageInfo = reactive({
current: 1,
@@ -22,29 +22,29 @@ export default function useScroll(fetchList: (...arg: any) => Promise<any>) {
const loadData = async (isRefresh: boolean = false) => {
try {
if (pageInfo.current === 1) {
uni.showLoading({ title: "加载中..." });
uni.showLoading({ title: '加载中...' });
}
if (isRefresh) {
pageInfo.current = 1;
const { total, data } = await fetchList(pageInfo.current);
listData.value = data;
pageInfo.total = total;
const { data } = await fetchList({ ...pageInfo, ...fetchBody });
listData.value = data.list;
pageInfo.total = data.total;
} else {
const { total, data } = await fetchList(pageInfo.current);
listData.value.push(...data);
pageInfo.total = total;
const { data } = await fetchList({ ...pageInfo, ...fetchBody });
listData.value.push(...data.list);
pageInfo.total = data.total;
}
pageInfo.current = pageInfo.current + 1;
if (listData.value.length >= pageInfo.total) {
loadMoreStatus.value = "noMore";
loadMoreStatus.value = 'noMore';
} else {
loadMoreStatus.value = "more";
loadMoreStatus.value = 'more';
}
return true;
} catch (error) {
console.error("加载数据失败:", error);
console.error('加载数据失败:', error);
return false;
} finally {
uni.hideLoading();
@@ -57,28 +57,28 @@ export default function useScroll(fetchList: (...arg: any) => Promise<any>) {
const success = await loadData(true);
refresherTriggered.value = false;
if (success) {
uni.showToast({ title: "刷新成功", icon: "success" });
uni.showToast({ title: '刷新成功', icon: 'success' });
}
};
// 下拉刷新中止
const onRefresherAbort = () => {
console.log("下拉刷新中止");
console.log('下拉刷新中止');
refresherTriggered.value = false;
};
// 触发上拉加载
const onScrollToLower = async () => {
if (loadMoreStatus.value === "loading" || loadMoreStatus.value === "noMore") {
if (loadMoreStatus.value === 'loading' || loadMoreStatus.value === 'noMore') {
return;
}
loadMoreStatus.value = "loading";
loadMoreStatus.value = 'loading';
await loadData(false);
};
// 点击加载更多
const onClickLoadMore = () => {
if (loadMoreStatus.value === "more") {
if (loadMoreStatus.value === 'more') {
onScrollToLower();
}
};
+6
View File
@@ -44,6 +44,7 @@ const user = defineStore({
isLogin: !!uni.getStorageSync('token'), // 登录状态
numData: cloneDeep(defaultNumData), // 用户其他数据
lastUpdateTime: 0, // 上次更新时间
userCity: { t: '', v: 0 },
}),
actions: {
@@ -151,6 +152,11 @@ const user = defineStore({
this.resetUserData();
return !this.isLogin;
},
// 设置用户城市
setUserCity(city) {
this.userCity = city;
},
},
persist: {
enabled: true,
+6
View File
@@ -29,6 +29,12 @@ export default async (command: 'build' | 'serve', mode: string) => {
hmr: {
overlay: true,
},
proxy: {
'/app-api': {
target: env.SHOPRO_DEV_BASE_URL,
changeOrigin: true,
},
},
},
resolve: {
alias: {