feat:首页和案例库功能
This commit is contained in:
188
src/pages/home-index/project-submission-detail/index.vue
Normal file
188
src/pages/home-index/project-submission-detail/index.vue
Normal file
@@ -0,0 +1,188 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue'
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app'
|
||||
import { getProjectSubmissionDetail } from '@/api/project-submission'
|
||||
import type { ProjectSubmissionItem, ProjectServiceType } from '@/types/project-submission'
|
||||
import { ensureLoggedIn } from '@/utils/auth-guard'
|
||||
import { navigateBackWithFallback } from '@/utils/navigate-back'
|
||||
import { resolveProjectSubmissionMedia } from '@/utils/resolve-project-submission-media'
|
||||
import heroBg from '@/static/icons/background.png'
|
||||
|
||||
const detail = ref<ProjectSubmissionItem | null>(null)
|
||||
const loading = ref(true)
|
||||
const heroLogo = ref('')
|
||||
const serviceIcons = ref<Record<string, string>>({})
|
||||
|
||||
const sortedServiceTypes = computed<ProjectServiceType[]>(() => {
|
||||
if (!detail.value?.serviceTypes?.length)
|
||||
return []
|
||||
return [...detail.value.serviceTypes].sort(
|
||||
(a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0),
|
||||
)
|
||||
})
|
||||
|
||||
async function loadDetail(id: string) {
|
||||
loading.value = true
|
||||
uni.showLoading({ title: '加载中...', mask: true })
|
||||
|
||||
try {
|
||||
const data = await getProjectSubmissionDetail(id)
|
||||
detail.value = data
|
||||
|
||||
const media = await resolveProjectSubmissionMedia(data)
|
||||
heroLogo.value = media.logoUrl || ''
|
||||
serviceIcons.value = media.serviceIcons
|
||||
}
|
||||
catch {
|
||||
detail.value = null
|
||||
uni.showToast({ title: '加载失败', icon: 'none' })
|
||||
}
|
||||
finally {
|
||||
loading.value = false
|
||||
uni.hideLoading()
|
||||
}
|
||||
}
|
||||
|
||||
onLoad((options) => {
|
||||
const id = options?.id as string
|
||||
if (!id) {
|
||||
loading.value = false
|
||||
uni.showToast({ title: '参数错误', icon: 'none' })
|
||||
return
|
||||
}
|
||||
loadDetail(id)
|
||||
})
|
||||
|
||||
onShow(() => {
|
||||
ensureLoggedIn()
|
||||
})
|
||||
|
||||
function handleBack() {
|
||||
navigateBackWithFallback('/pages/home-index/index')
|
||||
}
|
||||
|
||||
function handleSubmit() {
|
||||
if (!detail.value)
|
||||
return
|
||||
|
||||
const businessType = detail.value.businessType || detail.value.title
|
||||
uni.navigateTo({
|
||||
url: `/pages/home-index/requirement-submit/index?submissionId=${detail.value.id}&businessType=${encodeURIComponent(businessType)}`,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view
|
||||
v-if="detail"
|
||||
class="business-detail"
|
||||
>
|
||||
<view class="business-detail__navbar">
|
||||
<view
|
||||
class="business-detail__back"
|
||||
@tap="handleBack"
|
||||
>
|
||||
<image
|
||||
class="business-detail__back-icon"
|
||||
src="/static/icons/icon-back.svg"
|
||||
mode="aspectFit"
|
||||
/>
|
||||
</view>
|
||||
<text class="business-detail__navbar-title">
|
||||
业务详情
|
||||
</text>
|
||||
<view class="business-detail__navbar-placeholder" />
|
||||
</view>
|
||||
|
||||
<scroll-view
|
||||
class="business-detail__scroll"
|
||||
scroll-y
|
||||
:show-scrollbar="false"
|
||||
>
|
||||
<view class="business-detail__hero">
|
||||
<image
|
||||
class="business-detail__hero-bg"
|
||||
:src="heroBg"
|
||||
mode="scaleToFill"
|
||||
/>
|
||||
<view class="business-detail__hero-inner">
|
||||
<image
|
||||
v-if="heroLogo"
|
||||
class="business-detail__hero-icon"
|
||||
:src="heroLogo"
|
||||
mode="aspectFit"
|
||||
/>
|
||||
<text class="business-detail__hero-title">
|
||||
{{ detail.title }}
|
||||
</text>
|
||||
<text
|
||||
v-if="detail.subtitle"
|
||||
class="business-detail__hero-subtitle"
|
||||
>
|
||||
{{ detail.subtitle }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view
|
||||
v-if="sortedServiceTypes.length"
|
||||
class="business-detail__section"
|
||||
>
|
||||
<text class="business-detail__section-title">
|
||||
服务类型
|
||||
</text>
|
||||
<view class="business-detail__type-row">
|
||||
<view
|
||||
v-for="type in sortedServiceTypes"
|
||||
:key="type.id"
|
||||
class="business-detail__type-item"
|
||||
>
|
||||
<image
|
||||
v-if="serviceIcons[String(type.id)]"
|
||||
class="business-detail__type-icon"
|
||||
:src="serviceIcons[String(type.id)]"
|
||||
mode="aspectFit"
|
||||
/>
|
||||
<text class="business-detail__type-label">
|
||||
{{ type.serviceName }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<view class="business-detail__footer">
|
||||
<view
|
||||
class="business-detail__submit-btn"
|
||||
@tap="handleSubmit"
|
||||
>
|
||||
立即提报
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view
|
||||
v-else-if="!loading"
|
||||
class="business-detail business-detail--empty"
|
||||
>
|
||||
<text class="business-detail__empty-text">
|
||||
暂无详情
|
||||
</text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '../business-detail/index.scss';
|
||||
|
||||
.business-detail--empty {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.business-detail__empty-text {
|
||||
font-size: 28rpx;
|
||||
color: #999999;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user