开发吉祥物界面

This commit is contained in:
田岩
2025-07-18 18:26:52 +08:00
parent 24d3023c70
commit 76a5bcca0f
13 changed files with 403 additions and 77 deletions
+72 -37
View File
@@ -1,5 +1,9 @@
import request from '@/api/request'
import common from "@/common/common";
import {
queryCurrentValidMascotInfo
} from "@/api/mascot.js"
import {
setToken,
setUserInfo,
@@ -21,7 +25,36 @@ export const useAccountLoginApp = (data) => request({
if (rtnCode === '0000') {
setToken(body)
// 获取科技鹿
queryCurrentValidMascotInfo().then((res) => {
const userInfo = getUserInfo()
setUserInfo({
...userInfo,
'mascotInfo': res
})
console.log('科技', res);
if (res.imgAddr) {
setTimeout(() => {
const img = new Image(); // 创建Image对象
// 图片加载成功(缓存完成)
img.onload = () => {
console.log(`图片缓存成功: ${url}`);
resolve(img); // 返回加载完成的Image对象
};
// 图片加载失败
img.onerror = () => {
console.error(`图片缓存失败: ${url}`);
reject(new Error(`Failed to load image: ${url}`));
};
// 开始加载图片(设置src触发请求,浏览器会自动缓存)
img.src = url;
})
}
})
const user_data = await queryCurrentUser()
return user_data
}
@@ -76,46 +109,48 @@ export const queryCurrentUser = (data) => request({
// 预加载头像
// #ifdef APP-PLUS
const updateUserAvatar = (imagePath) => {
const userInfo = getUserInfo()
setUserInfo({
...userInfo,
'imagePath': imagePath
})
const userInfo = getUserInfo()
setUserInfo({
...userInfo,
'imagePath': imagePath
})
}
try {
const pathName = res.body.imageAddr
const url = base_url + pathName
// 生成唯一文件名,避免冲突
const filename = pathName.split('/').pop()
const localFilePath = '_downloads/' + filename
// 先检查是否存在
uni.getFileInfo({
filePath: localFilePath,
success: () => {
console.log('头像已存在,无需下载');
updateUserAvatar(localFilePath)
},
fail: () => {
console.log('开始下载头像:', url);
const dtask = plus.downloader.createDownload(
url, {
method: 'GET',
filename: '_downloads/' + filename
},
(download, status) => {
if (status === 200) {
console.log('头像下载成功:', download.filename);
updateUserAvatar(download.filename)
}
}
)
dtask.start();
}
})
const pathName = res.body.imageAddr
const url = base_url + pathName
// 生成唯一文件名,避免冲突
const filename = pathName.split('/').pop()
const localFilePath = '_downloads/' + filename
// 先检查是否存在
uni.getFileInfo({
filePath: localFilePath,
success: () => {
console.log('头像已存在,无需下载');
updateUserAvatar(localFilePath)
},
fail: () => {
console.log('开始下载头像:', url);
const dtask = plus.downloader.createDownload(
url, {
method: 'GET',
filename: '_downloads/' + filename
},
(download, status) => {
if (status === 200) {
console.log('头像下载成功:', download.filename);
updateUserAvatar(download.filename)
}
}
)
dtask.start();
}
})
} catch (error) {
console.error('头像预加载过程发生错误:', error);
console.error('头像预加载过程发生错误:', error);
}
// #endif
return res.body
+61
View File
@@ -0,0 +1,61 @@
import request from '@/api/request'
const base_url = '/traapp'
/**
* 查询吉祥物列表
* 出参:
mascotId 吉祥物ID String
mascotName 吉祥物名称 String
mascotNameEn 吉祥物英文名称 String
mascotDesc 吉祥物简介 String
mascotNo 吉祥物编号 String
imgAddr 吉祥物图片 String
imgThumbAddr 吉祥物缩略图 String
showOrder 显示顺序 int
*/
export const queryValidTraMascotInfo = (data) => {
return request({
url: base_url + '/traMascotInfo/queryValidTraMascotInfo',
method: 'post',
toastErrors: true,
data
});
};
/**
* 设置吉祥物
* 入参:
mascotId 必输项:true 类型:String
*/
export const setTraMascotInfo = (data) => {
return request({
url: base_url + '/traMascotInfo/setTraMascotInfo',
method: 'post',
toastErrors: true,
data
});
};
// 查询当前已经选择的吉祥物
/**
* 查询当前已经选择的吉祥物
* 出参:
mascotId 吉祥物ID String
mascotName 吉祥物名称 String
mascotNameEn 吉祥物英文名称 String
mascotDesc 吉祥物简介 String
mascotNo 吉祥物编号 String
imgAddr 吉祥物图片 String
imgThumbAddr 吉祥物缩略图 String
showOrder 显示顺序 int
*/
export const queryCurrentValidMascotInfo = (data) => {
return request({
url: base_url + '/traMascotInfo/queryCurrentValidMascotInfo',
method: 'post',
toastErrors: true,
data
});
};
+2
View File
@@ -6,7 +6,9 @@ import common from '@/common/common.js'
const ENV = import.meta.env
export const get_base_url = url => {
if (ENV.MODE === 'development') { // 开发环境
return ENV.VITE_APP_BASE_API_Url
// H5必须用非https,手机端必须用https
// #ifdef H5
const baseUrl = ENV.VITE_APP_BASE_API_Url
-4
View File
@@ -8,9 +8,5 @@ export const GENDER = [{
{
value: "f",
label: "女性",
},
{
value: "o",
label: "其他",
}
] // 性别
@@ -12,7 +12,7 @@
</view>
<view class="info-middle font_pf">
<view class="fz-30 fw-400 mb-8">更新日期</view>
<view class="fz-30 fw-400">{{ common.formatDate2(modelValue.mtTime, 'yyyy-MM-dd HH:mm') }}</view>
<view class="fz-30 fw-400">{{ (modelValue.mtTime || '').substr(0,16) }}</view>
</view>
<view class="info-bottom">
<view class="bottom-left">
@@ -104,6 +104,7 @@
font-size: 22rpx;
margin-right: 14rpx;
background-color: #f1f3f8;
margin-top: 6rpx;
}
}
.bottom-right {
+1 -1
View File
@@ -130,11 +130,11 @@
onMounted(() => {
uni.$on('refresh_comment_data', () => {
commentRef.value?.getData();
tabAct.value = 2
})
})
onLoad((params) => {
crsNum.value = params.crsNum;
});
onShow(()=>{
getData();
+1 -1
View File
@@ -487,7 +487,7 @@
flex-direction: column;
position: relative;
z-index: 0;
overflow-x: hidden;
// 背景图
.bg_img {
position: absolute;
+224 -29
View File
@@ -1,18 +1,55 @@
<template>
<view class="main_div max_page">
<nav-bar :is_seat="false"></nav-bar>
<image src="@/static/images/mascot/bg_1.png" class="bg_img" mode="aspectFit"></image>
<!-- <nav-bar :is_seat="false"></nav-bar> -->
<view class="bg_img">
<image src="@/static/images/mascot/bg_1.png" class="img" mode="aspectFit"></image>
</view>
<view class="fl1"></view>
<view class="title_div">
<image src="@/static/images/mascot/title.png" class="img" mode="widthFix"></image>
</view>
<view class="fl1"></view>
<view class="mascot_div">
<image src="@/static/images/mascot/ma_2.png" class="img" mode="widthFix"></image>
<view class="tip_div">
<view class="tip_msg">选择形象开启学习之旅</view>
</view>
<view class="fl1"></view>
<view class="mascot_div">
<view class="doct_icon left" @click="doct_click(1)">
<view class="doct_icon_div">
<image src="/src/static/images/mascot/btn_left.png" class="img" mode="widthFix"></image>
</view>
</view>
<swiper class="swiper" circular :current="swiperIndex" @animationfinish='animationfinish'>
<swiper-item class="" v-for="(item, index) in mascotList" :key="index">
<view class="swiper-item-div">
<!-- <image src="@/static/images/mascot/ma_1.png" class="img" mode="widthFix"></image> -->
<image-preview :src="item.imgAddr" class="img" mode="widthFix"></image-preview>
</view>
</swiper-item>
<!-- <swiper-item class="">
<view class="swiper-item-div">
<image src="@/static/images/mascot/ma_2.png" class="img" mode="widthFix"></image>
</view>
</swiper-item>
<swiper-item class="">
<view class="swiper-item-div">
<image src="@/static/images/mascot/ma_3.png" class="img" mode="widthFix"></image>
</view>
</swiper-item>
<swiper-item class="">
<view class="swiper-item-div">
<image src="@/static/images/mascot/ma_4.png" class="img" mode="widthFix"></image>
</view>
</swiper-item> -->
</swiper>
<view class="doct_icon right" @click="doct_click(-1)">
<view class="doct_icon_div">
<image src="/src/static/images/mascot/btn_right.png" class="img" mode="widthFix"></image>
</view>
</view>
</view>
<view class="button_div">
<image src="@/static/images/mascot/btn_2.png" class="img" mode="aspectFit"></image>
<image src="@/static/images/mascot/btn_2.png" class="img" mode="aspectFit" @click="select_it()"></image>
</view>
<view class="fl1"></view>
</view>
@@ -20,47 +57,205 @@
<script setup>
import {
ref
onMounted,
onUnmounted,
ref,
reactive
} from 'vue';
import {
queryValidTraMascotInfo,
setTraMascotInfo
} from "@/api/mascot.js"
import common from '@/common/common.js'
import {
setUserInfo,
getUserInfo
} from "@/common/common";
import {
onLoad
} from '@dcloudio/uni-app';
const mascotList = reactive([])
onLoad(() => {
common.loading()
queryValidTraMascotInfo().then(({
body
}) => {
Object.assign(mascotList, {
...body
})
console.log(mascotList);
common.hideLoading()
})
})
const swiperCount = 4; // 总共有4个轮播项
let swiperIndex = ref(0); // 当前显示第1个(索引0
const isAnimating = ref(false); // 标记动画是否进行中
const animationfinish = () => {
console.log("动画结束,允许下次点击");
isAnimating.value = false; // 动画结束后重置状态
};
const doct_click = (num) => {
if (isAnimating.value) return; // 1. 如果动画正在进行,直接忽略点击
isAnimating.value = true;
let newIndex = (swiperIndex.value + num + swiperCount) % swiperCount;
swiperIndex.value = newIndex; // 更新当前索引
};
// 选择他
const select_it = () => {
const item = mascotList[swiperIndex.value]
common.loading()
setTraMascotInfo({
mascotId: item.mascotId
}).then(res => {
const userInfo = getUserInfo()
setUserInfo({
...userInfo,
'mascotInfo': item
})
common.hideLoading()
common.msg('设置成功')
setTimeout(() => {
common.navigateBack()
}, 400)
}).catch(() => {
common.hideLoading()
})
}
onMounted(() => {
})
onUnmounted(() => {
})
</script>
<style scoped lang="scss">
.title_div{
width: 70vw;
.img{
.title_div {
width: 60vw;
.img {
width: 100%;
}
text-shadow:10rpx 0 30rpx #3c3c3c;
}
.mascot_div{
width: 90vw;
.img{
width: 100%;
.tip_div {
.tip_msg {
font-family: PingFangSC;
font-weight: 400;
font-size: 30rpx;
color: #FFFFFF;
line-height: 40rpx;
text-align: center;
font-style: normal;
}
text-shadow:0 0 30rpx #dedede;
}
.button_div{
width: 80vw;
.img{
width: 100%;
}
}
.bg_img {
position: absolute;
top: 0;
left: 0;
.mascot_div {
width: 100%;
height: 100%;
z-index: -1;
display: flex;
align-items: center;
position: relative;
.swiper {
white-space: nowrap;
height: 120vw;
flex: 1;
}
.swiper-item-div {
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
height: 120vw;
//
.img {
width: 80vw;
height: 100%;
}
}
.doct_icon {
padding: 0%;
display: flex;
.doct_icon_div {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
padding: 40rpx 0;
}
&.left {
top: 40%;
left: 2%;
z-index: 10;
}
&.right {
top: 40%;
right: 2%;
}
position:absolute;
width:100rpx;
display: flex;
align-items: center;
flex-direction: column;
.img {
width: 40%;
}
}
}
.button_div {
// width: 50vw;
margin-top: 20rpx;
width: 80%;
height: 120rpx;
.img {
width: 100%;
height: 100%;
}
}
.bg_img {
position: absolute;
top: -2%;
left: -1%;
width: 102%;
height: 104%;
z-index: -1;
.img {
width: 100%;
height: 100%;
}
}
.main_div {
display: flex;
flex-direction: column;
position: relative;
max-width: 100vh;
align-items: center;
overflow: hidden;
}
</style>
+39 -3
View File
@@ -8,7 +8,6 @@
<view class="title font_pf">设置</view>
</view>
<view class="detail-body">
<uv-cell-group :border="false">
<uv-cell @click="click_update_avatar" name="avatar" isLink title="头像">
<template #title>
@@ -32,7 +31,7 @@
</picker>
</template>
</uv-cell>
<uv-cell title="形象" @click="common.navigateTo('/pages/mascot/mascot_select_list')" :isLink="true" :border="false"></uv-cell>
<uv-cell title="形象" @click="gotoMascot()" :isLink="true" :border="false"></uv-cell>
</uv-cell-group>
</view>
<avatar-cropper v-if="avatarCropperStatus" mode="ratio" :imageUrl="avatarCropperUrl" :width="500" :height="500"
@@ -63,7 +62,10 @@
updateDfSysUserExtandInfoGender,
updateDfSysUserExtandInfoImageAddr
} from "@/api/user.js"
import {queryValidTraMascotInfo} from "@/api/mascot.js"
import {
get_base_url
} from '@/api/request.js'
const index = ref(0);
const avatarCropperUrl = ref('');
const aaa = ref('');
@@ -74,6 +76,40 @@
});
const avatarCropperStatus = ref(true)
const sexOptions = GENDER
const base_url = get_base_url()
// 去选择百禄
const gotoMascot = () => {
common.navigateTo('/pages/mascot/mascot_select_list')
// common.loading()
// queryValidTraMascotInfo().then(({body}) => {
// console.log(body);
// common.setPageCache('mascotList', body)
// body.map(({imgAddr}) => {
// const url = imgAddr
// if (imgAddr){
// const img = new Image();
// img.onload = () => {
// console.log(`图片缓存成功: ${url}`);
// // resolve(img);
// };
// img.onerror = () => {
// console.error(`图片缓存失败: ${url}`);
// // reject(new Error(`Failed to load image: ${url}`));
// };
// img.src = base_url + url;
// }
// })
// common.hideLoading()
// common.navigateTo('/pages/mascot/mascot_select_list')
// })
}
const showGenderText = computed(() => {
const item = sexOptions.find((item) => item.value == userInfo.value.gender)
if (item) {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 31 KiB