243 lines
5.7 KiB
Vue
243 lines
5.7 KiB
Vue
<template>
|
|
<view class="mold-page">
|
|
<!-- 自定义导航栏 -->
|
|
<view class="custom-navbar" :style="{ paddingTop: statusBarHeight + 'px' }">
|
|
<view class="custom-navbar__content" :style="{ height: navBarHeight + 'px' }">
|
|
<text class="custom-navbar__title">版房专区</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 搜索框 -->
|
|
<view class="search-bar">
|
|
<input
|
|
class="search-bar__input"
|
|
type="text"
|
|
placeholder="搜索名称、款号、条码号、款式"
|
|
:value="keyword"
|
|
@input="onSearchInput"
|
|
@confirm="doSearch"
|
|
/>
|
|
</view>
|
|
|
|
<!-- 版房列表 -->
|
|
<view class="mold-list">
|
|
<view v-for="mold in filteredMolds" :key="mold.id" class="mold-card">
|
|
<text class="mold-card__name">{{ mold.name }}</text>
|
|
<scroll-view v-if="(mold.images || []).length > 0" class="mold-card__images" scroll-x>
|
|
<image
|
|
v-for="(img, idx) in (mold.images || [])"
|
|
:key="idx"
|
|
class="mold-card__img"
|
|
:src="fullUrl(img)"
|
|
mode="aspectFill"
|
|
@click="previewImage(mold.images || [], idx)"
|
|
/>
|
|
</scroll-view>
|
|
<view v-else class="mold-card__no-img">
|
|
<text>暂无图片</text>
|
|
</view>
|
|
<view class="mold-card__footer">
|
|
<text v-if="mold.styleNo" class="mold-card__tag">款号: {{ mold.styleNo }}</text>
|
|
<text v-if="mold.style" class="mold-card__tag">款式: {{ mold.style }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 空状态 -->
|
|
<view v-if="!loading && filteredMolds.length === 0" class="empty-tip">
|
|
<text>{{ keyword ? '未找到匹配结果' : '暂无版房信息' }}</text>
|
|
<view v-if="keyword" class="empty-tip__contact" @click="contactService">
|
|
联系客服咨询定制
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 加载中 -->
|
|
<view v-if="loading" class="loading-tip">
|
|
<text>加载中...</text>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, computed, onMounted } from 'vue'
|
|
// @ts-ignore - uni-app 页面生命周期
|
|
import { onShow } from '@dcloudio/uni-app'
|
|
import type { MoldInfo } from '../../types/mold'
|
|
import { get } from '../../utils/request'
|
|
import { BASE_URL } from '../../utils/request'
|
|
import { searchMolds } from '../../utils/moldSearch'
|
|
|
|
const molds = ref<MoldInfo[]>([])
|
|
const keyword = ref('')
|
|
const loading = ref(false)
|
|
|
|
const statusBarHeight = ref(20)
|
|
const navBarHeight = ref(44)
|
|
try {
|
|
const sysInfo = uni.getSystemInfoSync()
|
|
statusBarHeight.value = sysInfo.statusBarHeight || 20
|
|
// #ifdef MP-WEIXIN
|
|
const menuBtn = uni.getMenuButtonBoundingClientRect()
|
|
navBarHeight.value = (menuBtn.top - (sysInfo.statusBarHeight || 20)) * 2 + menuBtn.height
|
|
// #endif
|
|
} catch { /* fallback */ }
|
|
|
|
const filteredMolds = computed(() => searchMolds(molds.value, keyword.value))
|
|
|
|
function fullUrl(path: string): string {
|
|
if (!path) return ''
|
|
if (path.startsWith('http')) return path
|
|
return BASE_URL + path
|
|
}
|
|
|
|
function parseImages(images: any): string[] {
|
|
if (Array.isArray(images)) return images
|
|
if (typeof images === 'string') {
|
|
try { return JSON.parse(images) } catch { return [] }
|
|
}
|
|
return []
|
|
}
|
|
|
|
function onSearchInput(e: { detail: { value: string } }) {
|
|
keyword.value = e.detail.value
|
|
}
|
|
|
|
function doSearch() {
|
|
// 本地搜索,无需额外操作
|
|
}
|
|
|
|
function previewImage(images: string[], current: number) {
|
|
const urls = images.map(img => fullUrl(img))
|
|
uni.previewImage({ urls, current: urls[current] })
|
|
}
|
|
|
|
function contactService() {
|
|
uni.showModal({
|
|
title: '联系客服',
|
|
content: '如需定制服务,请添加客服微信咨询',
|
|
showCancel: false,
|
|
})
|
|
}
|
|
|
|
async function loadMolds() {
|
|
loading.value = true
|
|
try {
|
|
const res = await get<{ list: any[]; total: number }>('/api/molds', { pageSize: 100 } as any)
|
|
const list = res?.list || []
|
|
molds.value = list.map((m: any) => ({
|
|
...m,
|
|
images: parseImages(m.images),
|
|
}))
|
|
} catch {
|
|
// 错误已在 request 中统一处理
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
onMounted(() => {
|
|
loadMolds()
|
|
})
|
|
|
|
onShow(() => {
|
|
loadMolds()
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
.mold-page {
|
|
min-height: 100vh;
|
|
background: #f5f5f5;
|
|
}
|
|
.custom-navbar {
|
|
background: linear-gradient(to right, #FFCFDE, #FFA6C4);
|
|
}
|
|
.custom-navbar__content {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
.custom-navbar__title {
|
|
font-size: 34rpx;
|
|
font-weight: bold;
|
|
color: #333;
|
|
}
|
|
.search-bar {
|
|
background: #fff;
|
|
padding: 16rpx 24rpx;
|
|
}
|
|
.search-bar__input {
|
|
background: #f5f5f5;
|
|
border-radius: 32rpx;
|
|
padding: 16rpx 24rpx;
|
|
font-size: 26rpx;
|
|
color: #333;
|
|
}
|
|
.mold-list {
|
|
padding: 16rpx;
|
|
}
|
|
.mold-card {
|
|
background: #fff;
|
|
border-radius: 16rpx;
|
|
padding: 24rpx;
|
|
margin-bottom: 16rpx;
|
|
}
|
|
.mold-card__name {
|
|
font-size: 30rpx;
|
|
font-weight: bold;
|
|
color: #333;
|
|
display: block;
|
|
margin-bottom: 16rpx;
|
|
}
|
|
.mold-card__images {
|
|
white-space: nowrap;
|
|
margin-bottom: 12rpx;
|
|
}
|
|
.mold-card__img {
|
|
width: 200rpx;
|
|
height: 200rpx;
|
|
border-radius: 8rpx;
|
|
margin-right: 12rpx;
|
|
display: inline-block;
|
|
}
|
|
.mold-card__no-img {
|
|
height: 200rpx;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background: #f5f5f5;
|
|
border-radius: 8rpx;
|
|
color: #999;
|
|
font-size: 26rpx;
|
|
margin-bottom: 12rpx;
|
|
}
|
|
.mold-card__footer {
|
|
display: flex;
|
|
gap: 16rpx;
|
|
}
|
|
.mold-card__tag {
|
|
font-size: 22rpx;
|
|
color: #999;
|
|
background: #f5f5f5;
|
|
padding: 4rpx 12rpx;
|
|
border-radius: 4rpx;
|
|
}
|
|
.empty-tip {
|
|
text-align: center;
|
|
padding: 80rpx 0;
|
|
color: #999;
|
|
font-size: 28rpx;
|
|
}
|
|
.empty-tip__contact {
|
|
margin-top: 20rpx;
|
|
color: #e4393c;
|
|
font-size: 26rpx;
|
|
}
|
|
.loading-tip {
|
|
text-align: center;
|
|
padding: 60rpx 0;
|
|
color: #999;
|
|
font-size: 28rpx;
|
|
}
|
|
</style>
|