开发产品详情页面,调试接口 90%

This commit is contained in:
hejin 2025-08-20 00:09:05 +08:00
parent 9b4edad29e
commit bf4e28d8d7
13 changed files with 388 additions and 10 deletions

View File

@ -71,3 +71,11 @@ export const prodOrNewsCatgApi = (catgId) => {
export const prodPageApi = (params) => {
return request.get('/web/prodPageList', {params})
}
/**
* @function 获取产品新闻详情
* @param {string} id
**/
export const prodOrNewsInfoApi = (id) => {
return request.get(`/web/prodNewsInfo?id=${id}`)
}

View File

@ -1,15 +1,381 @@
<template>
<view class="pages">
产品详情
<Tabs
:list="tabsList"
v-model:active="tabsActive"
/>
<view class="container">
<swiper
class="swiper"
circular
:autoplay="true"
:current="swiperCurrent"
@change="swiperChange"
>
<swiper-item v-for="(item,index) in productsImages" :key="index">
<view class="swiper-item">
<image :src="item" mode="aspectFill"></image>
</view>
</swiper-item>
</swiper>
<view class="siwper-number">
{{ swiperCurrent + 1 }}/{{productsImages.length}}
</view>
<view class="info">
<view class="title">
{{info.title}}
</view>
<view class="rich-text" v-html="info.description"></view>
</view>
</view>
<view class="module">
{{$t('products.productDetails')}}
</view>
<view
class="container"
style="padding: 18rpx 26rpx;"
v-html="info.content"
>
</view>
<view class="module">
{{$t('products.inquiry')}}
</view>
<view class="container">
<image class="inquiry-bg" src="@/assets/images/bg/Inquiry-bg.png"></image>
<uni-forms
ref="dataFormRef"
class="form-box"
:model="dataForm"
:rules="dataFormRules"
label-position="top"
>
<uni-forms-item name="name" v-if="formConfig.name">
<template #label>
<view class="label-box">
<text v-if="formConfig.nameMust" class="required">*</text>
<image
class="label-icon"
src="@/assets/images/icon/user.png"
>
</image>
<label>{{$t('contactUs.name')}}</label>
</view>
</template>
<uni-easyinput type="text" v-model="dataForm.name" :placeholder="$t('contactUs.name')" />
</uni-forms-item>
<uni-forms-item name="title" v-if="formConfig.title">
<template #label>
<view class="label-box">
<text v-if="formConfig.titleMust" class="required">*</text>
<image
class="label-icon"
src="@/assets/images/icon/title.png"
>
</image>
<label>{{$t('contactUs.title')}}</label>
</view>
</template>
<uni-easyinput type="text" v-model="dataForm.title" :placeholder="$t('contactUs.title')" />
</uni-forms-item>
<uni-forms-item name="company" v-if="formConfig.company">
<template #label>
<view class="label-box">
<text v-if="formConfig.companyMust" class="required">*</text>
<image
class="label-icon"
src="@/assets/images/icon/company.png"
>
</image>
<label>{{$t('contactUs.company')}}</label>
</view>
</template>
<uni-easyinput type="text" v-model="dataForm.company" :placeholder="$t('contactUs.company')" />
</uni-forms-item>
<uni-forms-item name="email" v-if="formConfig.email">
<template #label>
<view class="label-box">
<text v-if="formConfig.emailMust" class="required">*</text>
<image
class="label-icon"
src="@/assets/images/icon/mail.png"
>
</image>
<label>{{$t('contactUs.mail')}}</label>
</view>
</template>
<uni-easyinput type="text" v-model="dataForm.email" :placeholder="$t('contactUs.mail')" />
</uni-forms-item>
<uni-forms-item name="tel" v-if="formConfig.tel">
<template #label>
<view class="label-box">
<text v-if="formConfig.telMust" class="required">*</text>
<image
class="label-icon"
src="@/assets/images/icon/phone.png"
>
</image>
<label>{{$t('contactUs.contactWay')}}</label>
</view>
</template>
<uni-easyinput type="text" v-model="dataForm.tel" :placeholder="$t('contactUs.contactWay')" />
</uni-forms-item>
<uni-forms-item name="content">
<template #label>
<view class="label-box">
<image
class="label-icon"
src="@/assets/images/icon/msg.png"
>
</image>
<label>{{$t('contactUs.desc')}}</label>
</view>
</template>
<uni-easyinput type="textarea" v-model="dataForm.content" :placeholder="$t('contactUs.desc')" />
</uni-forms-item>
<button class="submit-btn" @click="submit">{{$t('common.sending')}}</button>
</uni-forms>
</view>
<view class="module">
{{$t('news.relatedProducts')}}
</view>
<view class="container">
<view class="product-list">
<view
class="product-item"
v-for="item in relatedProducts"
:key="item.id"
>
<image class="cover" :src="item.mainPic" mode="aspectFill"></image>
<view class="text-ellipsis title">
{{item.title}}
</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { onLoad } from '@dcloudio/uni-app';
import { ref } from 'vue';
import { ref, computed } from 'vue';
import { useI18n } from 'vue-i18n';
import {
prodOrNewsInfoApi,
formOptionsApi,
submitFormApi,
} from '@/api/index.js';
const { t } = useI18n()
const tabsActive = ref(0)
const tabsList = [
t('menu.Products'),
t('products.productDetails'),
t('products.inquiry'),
t('news.relatedProducts')
]
const id = ref('')
const info = ref({})
const productsImages = ref([])
const getInfo = () => {
prodOrNewsInfoApi(id.value).then(({data:res}) => {
info.value = res.data.busiProdNew
let picsArr = res.data.busiProdNew.pics ? res.data.busiProdNew.pics.split(',') : [];
productsImages.value = [
res.data.busiProdNew.mainPic,
...picsArr
]
uni.setNavigationBarTitle({
title: res.data.busiProdNew.title
})
})
}
const swiperCurrent = ref(0)
const swiperChange = (e) => {
swiperCurrent.value = e.detail.current
}
const dataFormRef = ref()
const dataForm = ref({
name: '',
title: '',
company: '',
email: '',
tel: '',
content: '',
equipment: 'App'
})
const dataFormRules = computed(() => {
let config = formConfig.value
let rules = {
name: {
rules: [
{ required: config.nameMust, errorMessage: t('contactUs.name') }
]
},
title: {
rules: [
{ required: config.titleMust, errorMessage: t('contactUs.title') }
]
},
company: {
rules: [
{ required: config.companyMust, errorMessage: t('contactUs.company') }
]
},
email: {
rules: [
{ required: config.emailMust, errorMessage: t('contactUs.mail') }
]
},
tel: {
rules: [
{ required: config.telMust, errorMessage: t('contactUs.desc') }
]
}
}
return rules
})
const formConfig = ref({})
const getFormOptions = () => {
formOptionsApi().then(({data:res}) => {
formConfig.value = res.data
})
}
const submit = () => {
dataFormRef.value.validate().then(() => {
submitFormApi(dataForm.value).then(() => {
uni.$showTost(t('common.submitSuccess'))
dataForm.value.name = ''
dataForm.value.title = ''
dataForm.value.company = ''
dataForm.value.email = ''
dataForm.value.tel = ''
dataForm.value.content = ''
dataFormRef.value.clearValidate()
})
})
}
const relatedProducts = ref([
{id:123,title: 'SINOTRUK HOWO Tractor Truck Head',mainPic:'https://dianliang123.oss-cn-qingdao.aliyuncs.com/user/2025/07/09/55979a0deee24031a38e934c6b06ca20.jpg'},
{id:121233,title: 'SINOTRUK HOWO Tractor Truck Head',mainPic:'https://dianliang123.oss-cn-qingdao.aliyuncs.com/user/2025/07/09/55979a0deee24031a38e934c6b06ca20.jpg'},
{id:122221113,title: 'SINOTRUK HOWO Tractor Truck Head',mainPic:'https://dianliang123.oss-cn-qingdao.aliyuncs.com/user/2025/07/09/55979a0deee24031a38e934c6b06ca20.jpg'},
{id:121113123,title: 'SINOTRUK HOWO Tractor Truck Head',mainPic:'https://dianliang123.oss-cn-qingdao.aliyuncs.com/user/2025/07/09/55979a0deee24031a38e934c6b06ca20.jpg'}
])
onLoad((options) => {
id.value = options.id
getInfo()
getFormOptions()
})
</script>
<style lang="scss" scoped>
.pages {
overflow: hidden;
padding: 0 18rpx;
::v-deep .tabs {
justify-content: space-around;
.tabs-item {
margin-right: 0;
}
}
.container {
width: 100%;
height: min-content;
background-color: #ffffff;
position: relative;
border-radius: 20rpx;
overflow-x: auto;
word-break: break-all;
.swiper {
width: 100%;
height: 714rpx;
.swiper-item {
width: 100%;
height: 714rpx;
image {
width: 100%;
height: 100%;
}
}
}
.siwper-number {
width: max-content;
height: min-content;
padding: 6rpx 30rpx;
position: absolute;
top: 650rpx;
right: 28rpx;
border-radius: 28rpx;
color: #fff;
background: rgba(0,0,0,0.31);
z-index: 999;
}
.info {
width: 100%;
padding: 34rpx 20rpx;
.title {
margin-bottom: 40rpx;
color: #292d2e;
font-weight: bold;
}
}
.inquiry-bg {
width: 100%;
height: 411rpx;
}
::v-deep .form-box {
padding: 0rpx 24rpx;
position: relative;
top: -150rpx;
}
.product-list {
padding: 38rpx 12rpx;
display: flex;
flex-wrap: wrap;
background-color: #fff;
.product-item {
width: 49%;
height: 468rpx;
margin-bottom: 14rpx;
border: 2rpx solid #ebf3f7;
border-radius: 8rpx;
&:nth-child(2n) {
margin-left: 2%;
}
.cover {
width: 100%;
height: 358rpx;
}
.title {
padding: 16rpx 16rpx 0;
color: #0d0e0e;
border-top: 2rpx dashed #ebf3f7;
}
}
}
}
.module {
margin: 38rpx 0;
color: #292d2e;
font-weight: bold;
}
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 817 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 596 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 464 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 543 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 733 B

View File

@ -47,7 +47,8 @@
"viewmore": "view more",
"ProductLabel": "Product",
"keywords": "keywords",
"Quickcontact": "Quick contact"
"Quickcontact": "Quick contact",
"sending": "sending"
},
"menu": {
"Home": "Home",

View File

@ -47,7 +47,8 @@
"viewmore": "查看更多",
"ProductLabel": "产品",
"keywords": "关键字",
"Quickcontact": "快速联系"
"Quickcontact": "快速联系",
"sending": "发送"
},
"menu": {
"Home": "首页",

View File

@ -49,7 +49,8 @@
"path": "product-details",
"style": {
"navigationBarTitleText": "Product details",
"enablePullDownRefresh": true
"enablePullDownRefresh": true,
"navigationStyle": "default"
}
},
{

View File

@ -74,6 +74,7 @@
class="prod-item"
v-for="item in prodList"
:key="item.id"
@click="goProdDetails(item)"
>
<image :src="item.mainPic" mode="aspectFit"></image>
<view class="text-ellipsis">
@ -179,10 +180,10 @@
const onlineModalShow = ref(false)
const onlineModalRef = ref()
const clickMsg = () => {
onlineModalShow.value = false
nextTick(() => {
const goProdDetails = (row) => {
uni.navigateTo({
url: `/application/product-details?id=${row.id}`
})
}