将大体积的图片改成从阿里云读取

This commit is contained in:
mirage 2026-03-25 10:19:36 +08:00
parent a3e1bc98f4
commit 6056e5282e
20 changed files with 337 additions and 38 deletions

View File

@ -90,7 +90,6 @@ public class QiniuStorage {
try {
String accessKey = this.config.getOrDefault("access_key", "");
String secretKey = this.config.getOrDefault("secret_key", "");
String bucket = this.config.getOrDefault("bucket", "");
String domain = this.config.getOrDefault("domain", "");
Auth auth = Auth.create(accessKey, secretKey);

View File

@ -14,8 +14,11 @@ import com.mdd.common.entity.Class;
import com.mdd.common.entity.admin.Admin;
import com.mdd.common.mapper.*;
import com.mdd.common.mapper.admin.AdminMapper;
import com.mdd.common.util.ConfigUtils;
import com.mdd.common.util.TimeUtils;
import com.mdd.common.vo.student.StudentInfoListedVo;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.collections4.map.SingletonMap;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
@ -348,4 +351,14 @@ public class EnrollmentService {
.lt("pre_registration_time", endTime)
);
}
public Map<String, Object> getAliyunUrl() {
Map<String, String> aliyunConfig = ConfigUtils.getMap("storage", "aliyun");
if (MapUtils.isNotEmpty(aliyunConfig)) {
String url = MapUtils.getString(aliyunConfig, "domain", "");
return new SingletonMap<>("aliyunUrl", url);
}
return Collections.emptyMap();
}
}

View File

@ -65,4 +65,10 @@ public class EnrollmentController {
public AjaxResult<Map<String, Object>> buildEnrollmentTrend(@RequestParam("teacherId") Integer teacherId, @RequestParam("rangeType") String rangeType) {
return AjaxResult.success(enrollmentService.buildEnrollmentTrend(teacherId, rangeType));
}
@GetMapping("/getAliyunUrl")
@ApiOperation(value = "获取阿里云的url")
public AjaxResult<Map<String, Object>> getAliyunUrl() {
return AjaxResult.success(enrollmentService.getAliyunUrl());
}
}

View File

@ -4,6 +4,8 @@ import { useAppStore } from './stores/app'
import { useUserStore } from './stores/user'
import { useThemeStore } from './stores/theme'
import { useRoute, useRouter } from 'uniapp-router-next'
import { initAppConfig } from './utils/configUtils'
import { initTabBarIcons } from './utils/tabbarUtils'
const appStore = useAppStore()
const { getUser } = useUserStore()
const { getTheme } = useThemeStore()
@ -44,10 +46,15 @@ const getConfig = async () => {
onLaunch(async () => {
getTheme()
getConfig()
// URL
await initAppConfig()
//#ifdef H5
setH5WebIcon()
//#endif
await getUser()
// tabbar
initTabBarIcons()
})
</script>
<style lang="scss">

View File

@ -98,3 +98,11 @@ export function getEnrollmentDetail(id: number) {
{ urlPrefix: '' }
)
}
// 获取阿里云URL
export function getAliyunUrl() {
return request.get(
{ url: 'frontapi/enrollment/getAliyunUrl' },
{ urlPrefix: '' }
)
}

View File

@ -14,7 +14,7 @@
<view>{{ item.create_time }}</view>
<view class="flex items-center">
<image
src="/static/images/icon/icon_visit.png"
:src="visitIconSrc"
class="w-[30rpx] h-[30rpx]"
></image>
<view class="ml-[10rpx]">{{ item.click }}</view>
@ -27,6 +27,7 @@
<script lang="ts" setup>
import { ref } from 'vue'
import { getAliyunImageUrl } from '@/utils/imageUtils'
const props = withDefaults(
defineProps<{
@ -38,6 +39,8 @@ const props = withDefaults(
newsId: 0
}
)
const visitIconSrc = getAliyunImageUrl('static/images/icon/icon_visit.png')
</script>
<style lang="scss" scoped>

View File

@ -1,5 +1,5 @@
<template>
<view class="user-info mb-[0rpx]">
<view class="user-info mb-[0rpx]" :style="userInfoStyle">
<!-- #ifndef H5 -->
<u-sticky h5-nav-height="0" bg-color="transparent">
<u-navbar
@ -33,7 +33,7 @@
</view>
</view>
<navigator v-else class="flex items-center" hover-class="none" url="/pages/login/login">
<u-avatar src="/static/images/user/default_avatar.png" :size="120"></u-avatar>
<u-avatar :src="defaultAvatarSrc" :size="120"></u-avatar>
<view class="text-white text-3xl ml-[20rpx]">未登录</view>
</navigator>
</view>
@ -42,6 +42,7 @@
<script lang="ts" setup>
import { useCopy } from '@/hooks/useCopy'
import { computed } from 'vue'
import { getAliyunImageUrl } from '@/utils/imageUtils'
const props = defineProps({
pageMeta: {
@ -74,6 +75,15 @@ const metaData: any = computed(() => {
return props.pageMeta[0].content
})
const defaultAvatarSrc = getAliyunImageUrl('static/images/user/default_avatar.png')
const userInfoBgImage = getAliyunImageUrl('static/images/user/my_topbg.png')
const userInfoStyle = computed(() => ({
backgroundImage: `url(${userInfoBgImage}), linear-gradient(90deg, #3b82f6, #2563eb)`,
backgroundRepeat: 'no-repeat',
backgroundPosition: 'bottom',
backgroundSize: '100%'
}))
const navigateTo = (url: string) => {
uni.navigateTo({
url
@ -82,11 +92,4 @@ const navigateTo = (url: string) => {
</script>
<style lang="scss" scoped>
.user-info {
background: url(../../../static/images/user/my_topbg.png),
linear-gradient(90deg, $u-type-primary, $u-minor-color);
background-repeat: no-repeat;
background-position: bottom;
background-size: 100%;
}
</style>

View File

@ -8,7 +8,7 @@
<!-- 顶部区域Logo + 欢迎文字 + 首页图片 -->
<view class="header-section">
<image
src="/static/yubaoming/school_logo.png"
:src="schoolLogoSrc"
mode="aspectFit"
class="school-logo"
/>
@ -17,7 +17,7 @@
<view class="subtitle">祝您招生顺利业绩长虹</view>
</view>
<image
src="/static/yubaoming/home.png"
:src="homeImageSrc"
mode="widthFix"
class="home-image"
/>
@ -112,6 +112,8 @@ import { computed, reactive, ref } from 'vue'
import { useAppStore } from '@/stores/app'
import { useUserStore } from '@/stores/user'
import { storeToRefs } from 'pinia'
import { getAliyunImageUrl } from '@/utils/imageUtils'
import { ensureStorageConfig } from '@/utils/configUtils'
// #ifdef MP
import MpPrivacyPopup from './component/mp-privacy-popup.vue'
@ -207,6 +209,16 @@ const goToLogin = () => {
})
}
//
const schoolLogoSrc = ref(getAliyunImageUrl('static/yubaoming/school_logo.png'))
const homeImageSrc = ref(getAliyunImageUrl('static/yubaoming/home.png'))
const initImageSources = async () => {
await ensureStorageConfig()
schoolLogoSrc.value = getAliyunImageUrl('static/yubaoming/school_logo.png')
homeImageSrc.value = getAliyunImageUrl('static/yubaoming/home.png')
}
const shareQrcode = () => {
uni.switchTab({
url: '/pages/user/user'
@ -217,6 +229,7 @@ const shareQrcode = () => {
}
onLoad(() => {
initImageSources()
getData()
})

View File

@ -9,7 +9,7 @@
<view class="nav-title">我的招生</view>
</view>
<image
src="/static/yubaoming/recruitment_3.png"
:src="recruitmentBgImageSrc"
mode="aspectFill"
class="page-bg"
/>
@ -19,7 +19,7 @@
</view>
<view class="student-image-wrapper">
<image
src="/static/yubaoming/student.png"
:src="studentImageSrc"
mode="aspectFit"
class="student-image"
/>
@ -68,11 +68,23 @@
import { ref, shallowRef } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { getPreRegistrationList } from '@/api/app'
import { getAliyunImageUrl } from '@/utils/imageUtils'
import { ensureStorageConfig } from '@/utils/configUtils'
const list = ref<any[]>([])
const paging = shallowRef()
const queryList = async (pageNo, pageSize) => {
//
const recruitmentBgImageSrc = ref(getAliyunImageUrl('static/yubaoming/recruitment_3.png'))
const studentImageSrc = ref(getAliyunImageUrl('static/yubaoming/student.png'))
const initImageSources = async () => {
await ensureStorageConfig()
recruitmentBgImageSrc.value = getAliyunImageUrl('static/yubaoming/recruitment_3.png')
studentImageSrc.value = getAliyunImageUrl('static/yubaoming/student.png')
}
const queryList = async (pageNo: number, pageSize: number) => {
console.log('=== queryList 开始执行 ===', pageNo, pageSize)
try {
const params = {
@ -101,6 +113,7 @@ const goBack = () => {
}
onLoad(() => {
initImageSources()
queryList(1, 10)
})
</script>

View File

@ -13,7 +13,7 @@
<view class="text-muted mr-[40rpx] flex-1">{{ newsData.create_time }}</view>
<view class="flex items-center text-muted flex-none">
<image
src="/static/images/icon/icon_visit.png"
:src="visitIconSrc"
class="w-[30rpx] h-[30rpx]"
></image>
<view class="ml-[10rpx]">{{ newsData.click }}</view>
@ -48,9 +48,11 @@
import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { getArticleDetail, addCollect, cancelCollect } from '@/api/news'
import { getAliyunImageUrl } from '@/utils/imageUtils'
const newsData = ref<any>({})
let newsId = ''
const visitIconSrc = getAliyunImageUrl('static/images/icon/icon_visit.png')
const getData = async (id) => {
newsData.value = await getArticleDetail({ id })

View File

@ -86,17 +86,18 @@ import { PageStatusEnum } from '@/enums/appEnums'
import { onLoad } from '@dcloudio/uni-app'
import { computed, reactive, ref } from 'vue'
import { useRouter } from 'uniapp-router-next'
import { getAliyunImageUrl } from '@/utils/imageUtils'
const router = useRouter()
const mapStatus = {
succeed: {
text: '支付成功',
image: '/static/images/payment/icon_succeed.png'
image: getAliyunImageUrl('static/images/payment/icon_succeed.png')
},
waiting: {
text: '等待支付',
image: '/static/images/payment/icon_waiting.png'
image: getAliyunImageUrl('static/images/payment/icon_waiting.png')
}
}
const status = ref(PageStatusEnum['LOADING'])

View File

@ -232,9 +232,9 @@ const submitBtnStyle = {
boxShadow: '0 8rpx 24rpx rgba(59, 130, 246, 0.3)'
}
const getTeacherData = async (params: { teacherId?: string; invitationCode?: string }) => {
const getTeacherData = async (teacherId: string) => {
try {
const res = await getTeacherInfo(params)
const res = await getTeacherInfo({ teacherId: Number(teacherId) })
if (res.code === 1 && res.data) {
formData.teacher = res.data.teacherName
formData.recruitmentTeacherId = res.data.teacherId
@ -344,7 +344,7 @@ const validateForm = () => {
const submit = async () => {
console.log('========== 开始提交 ==========')
console.log('当前表单数据:', JSON.parse(JSON.stringify(formData)))
if (!validateForm()) {
console.log('表单验证失败')
return
@ -430,16 +430,8 @@ onMounted(() => {
})
onLoad((options: any) => {
if (options.scene) {
getTeacherData({ invitationCode: decodeURIComponent(options.scene) })
return
}
if (options.invitationCode) {
getTeacherData({ invitationCode: options.invitationCode })
return
}
if (options.teacherId) {
getTeacherData({ teacherId: options.teacherId })
getTeacherData(options.teacherId)
}
})
</script>

View File

@ -3,7 +3,7 @@
<!-- 顶部横幅背景 -->
<view class="header-banner">
<image
src="/static/yubaoming/top_banner.png"
:src="bannerImageSrc"
mode="widthFix"
class="banner-image"
/>
@ -98,7 +98,7 @@
<view class="action-grid">
<view class="action-item" @click="goToRecruitment">
<image
src="/static/yubaoming/my_recruitment_menu.png"
:src="getAliyunImageUrl('static/yubaoming/my_recruitment_menu.png')"
mode="aspectFit"
class="action-img"
/>
@ -106,7 +106,7 @@
</view>
<view class="action-item" @click="openQrcodeModal">
<image
src="/static/yubaoming/recruitment_qrcode.png"
:src="getAliyunImageUrl('static/yubaoming/recruitment_qrcode.png')"
mode="aspectFit"
class="action-img"
/>
@ -114,7 +114,7 @@
</view>
<view class="action-item" @click="goTo('/pages/user_data/user_data')">
<image
src="/static/yubaoming/user_profile.png"
:src="getAliyunImageUrl('static/yubaoming/user_profile.png')"
mode="aspectFit"
class="action-img"
/>
@ -122,7 +122,7 @@
</view>
<view class="action-item" @click="goTo('/pages/change_password/change_password')">
<image
src="/static/yubaoming/change_password.png"
:src="getAliyunImageUrl('static/yubaoming/change_password.png')"
mode="aspectFit"
class="action-img"
/>
@ -137,7 +137,7 @@
<view class="action-list-item" @click="switchAccount">
<view class="item-left">
<image
src="/static/yubaoming/switch_account.png"
:src="getAliyunImageUrl('static/yubaoming/switch_account.png')"
mode="aspectFit"
class="item-img"
/>
@ -148,7 +148,7 @@
<view class="action-list-item" @click="logout">
<view class="item-left">
<image
src="/static/yubaoming/logout.png"
:src="getAliyunImageUrl('static/yubaoming/logout.png')"
mode="aspectFit"
class="item-img"
/>
@ -209,6 +209,8 @@ import { computed, reactive, ref } from 'vue'
import { getEnrollmentStatistical, getTeacherQrcodeImage, getTeacherInfo } from '@/api/app'
import { TOKEN_KEY } from '@/enums/constantEnums'
import cache from '@/utils/cache'
import { getAliyunImageUrl, loadImageWithFallback } from '@/utils/imageUtils'
import { ensureStorageConfig } from '@/utils/configUtils'
const qrcodeUrl = ref('')
const showQrcodeModal = ref(false)
@ -230,6 +232,14 @@ const btnStyle = {
const userStore = useUserStore()
const { userInfo, isLogin } = storeToRefs(userStore)
//
const bannerImageSrc = ref(getAliyunImageUrl('static/yubaoming/top_banner.png'))
const initImageSources = async () => {
await ensureStorageConfig()
bannerImageSrc.value = getAliyunImageUrl('static/yubaoming/top_banner.png')
}
//
const progressPercent = computed(() => {
const target = 50
@ -437,6 +447,7 @@ const logout = () => {
}
onShow(async () => {
await initImageSources()
console.log('=== onShow 开始执行 ===')
console.log('初始登录状态:', isLogin.value)
console.log('缓存中的token:', cache.get(TOKEN_KEY))

Binary file not shown.

Before

Width:  |  Height:  |  Size: 318 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 931 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 553 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 315 KiB

View File

@ -0,0 +1,97 @@
/**
*
* URL等
*/
import { getAliyunImageUrl } from './imageUtils'
import { getAliyunUrl } from '@/api/app'
function getDefaultStorageConfig() {
return {
aliyunBaseUrl: ''
}
}
async function fetchAndCacheStorageConfig() {
const configResponse = await getAliyunUrl()
// 兼容两种返回:
// 1) 拦截器已解包:{ aliyunUrl: '...' }
// 2) 未解包原始结构:{ code: 1, data: { aliyunUrl: '...' } }
const serverConfig =
configResponse && typeof configResponse === 'object' && 'aliyunUrl' in configResponse
? configResponse
: configResponse?.code === 1
? configResponse.data || {}
: {}
const storageConfig = {
aliyunBaseUrl: (serverConfig as any).aliyunUrl || ''
}
uni.setStorageSync('storageConfig', storageConfig)
return storageConfig
}
/**
*
*
*/
export async function initAppConfig() {
try {
const config = await fetchAndCacheStorageConfig()
console.log('应用配置初始化成功', config)
} catch (error) {
console.error('应用配置初始化失败:', error)
uni.setStorageSync('storageConfig', getDefaultStorageConfig())
}
}
/**
*
*/
export async function ensureStorageConfig() {
const config = uni.getStorageSync('storageConfig') || {}
if (config.aliyunBaseUrl) {
return config
}
try {
return await fetchAndCacheStorageConfig()
} catch (error) {
console.error('确保存储配置失败:', error)
const defaultConfig = getDefaultStorageConfig()
uni.setStorageSync('storageConfig', defaultConfig)
return defaultConfig
}
}
/**
* tabbar图标路径
* @param iconType ('home' | 'user')
* @param isActive
* @returns
*/
export function getTabBarIconPath(iconType: 'home' | 'user', isActive: boolean = false): string {
// 从配置中获取阿里云基础URL
const config = uni.getStorageSync('storageConfig') || {}
const baseUrl = config.aliyunBaseUrl || ''
// 定义本地路径映射
const localPaths = {
home: {
normal: 'static/images/tabbar/home.png',
active: 'static/yubaoming/home_icon_active.png'
},
user: {
normal: 'static/images/tabbar/user.png',
active: 'static/yubaoming/my_icon_active.png'
}
}
// 如果配置了阿里云基础URL则使用阿里云路径
if (baseUrl) {
const imagePath = isActive ? localPaths[iconType].active : localPaths[iconType].normal
return getAliyunImageUrl(imagePath)
}
// 否则返回本地路径
return isActive ? localPaths[iconType].active : localPaths[iconType].normal
}

View File

@ -0,0 +1,72 @@
/**
*
*
*/
import request from '@/utils/request'
/**
* URL
* @param imageKey key
* @returns URL
*/
export function getAliyunImageUrl(imageKey: string): string {
// 从配置中获取阿里云基础URL如果配置不存在则返回原路径
const config = uni.getStorageSync('storageConfig') || {}
const baseUrl = config.aliyunBaseUrl || config.baseUrl || ''
if (baseUrl && imageKey) {
// 确保URL格式正确
const normalizedBaseUrl = baseUrl.endsWith('/') ? baseUrl : baseUrl + '/'
return normalizedBaseUrl + imageKey
}
// 如果没有配置,则返回原始图片路径(本地路径)
return imageKey
}
/**
* API获取图片URL
* @param teacherId ID
* @returns URL
*/
export async function getTeacherQrCodeUrl(teacherId: number): Promise<string> {
try {
const response = await request.get(
{ url: `frontapi/teacher/qrcode?id=${teacherId}` },
{ urlPrefix: '', isTransformResponse: false }
)
if (response && response.code === 1 && response.data) {
return response.data
}
console.error('获取教师二维码URL失败:', response)
return ''
} catch (error) {
console.error('获取教师二维码URL异常:', error)
return ''
}
}
/**
*
* 退
* @param imageUrl URL
* @param localImagePath
* @returns Promise<string> 使
*/
export async function loadImageWithFallback(
imageUrl: string,
localImagePath: string
): Promise<string> {
if (!imageUrl) return localImagePath
return new Promise((resolve) => {
// 尝试加载网络图片
const image = new Image()
image.onload = () => resolve(imageUrl)
image.onerror = () => resolve(localImagePath)
image.src = imageUrl
})
}

View File

@ -0,0 +1,59 @@
/**
* TabBar工具类
* tabbar图标
*/
import { getTabBarIconPath } from './configUtils'
import { ensureStorageConfig } from './configUtils'
/**
* tabbar图标
* @param index tabbar索引
* @param iconType
* @param isActive
*/
export function setTabBarIcon(index: number, iconType: 'home' | 'user', isActive: boolean = false) {
try {
// 获取阿里云图标路径
const iconPath = getTabBarIconPath(iconType, isActive)
// 设置tabbar图标
if (isActive) {
uni.setTabBarItem({
index,
selectedIconPath: iconPath
})
} else {
uni.setTabBarItem({
index,
iconPath
})
}
} catch (error) {
console.error(`设置tabbar图标失败:`, error)
}
}
/**
* tabbar图标
*/
export function updateAllTabBarIcons() {
// 更新首页tabbar图标 (索引0)
setTabBarIcon(0, 'home', false)
setTabBarIcon(0, 'home', true)
// 更新个人中心tabbar图标 (索引1)
setTabBarIcon(1, 'user', false)
setTabBarIcon(1, 'user', true)
}
/**
* tabbar图标
*/
export function initTabBarIcons() {
// 延迟执行,确保配置已加载
setTimeout(async () => {
await ensureStorageConfig()
updateAllTabBarIcons()
}, 1000)
}