hookehuyr

新增简单详情页

/*
* @Date: 2024-08-26 10:42:15
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2024-12-27 16:38:24
* @LastEditTime: 2025-01-03 09:22:05
* @FilePath: /hager/src/route.js
* @Description: 文件描述
*/
......@@ -51,6 +51,15 @@ export default [{
},
children: []
}, {
path: '/product/detail_lite/:id',
name: '详情页lite',
component: () => import('@/views/product/detail_lite'),
meta: {
title: '海格电气',
tag: 'product'
},
children: []
}, {
path: '/solution/index',
name: '解决方案',
component: () => import('@/views/solution/index'),
......@@ -78,24 +87,6 @@ export default [{
},
children: []
}, {
path: '/solution/detail_test/:id/:timestamp',
name: '解决方案详情1-test',
component: () => import('@/views/solution/detail_test'),
meta: {
title: '解决方案 | Hager China',
tag: 'solution'
},
children: []
}, {
path: '/solution/detail_test/:id/:current_index/:timestamp',
name: '解决方案详情2-test',
component: () => import('@/views/solution/detail_test'),
meta: {
title: '解决方案 | Hager China',
tag: 'solution'
},
children: []
}, {
path: '/solution/case/:id/:current_index?',
name: '成功案例',
component: () => import('@/views/solution/case'),
......@@ -124,10 +115,10 @@ export default [{
children: []
}, {
path: '/about/china',
name: '海格电气在中国',
name: '海格中国',
component: () => import('@/views/about/china'),
meta: {
title: '海格电气在中国 | Hager China',
title: '海格中国 | Hager China',
tag: 'about'
},
children: []
......
<!--
* @Date: 2024-09-29 14:26:41
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-01-03 10:54:19
* @FilePath: /hager/src/views/product/detail_lite.vue
* @Description: 文件描述
-->
<template>
<div class="product-detail no-select">
<hager-box>
<div style="margin-top: 1.5rem;">
<el-breadcrumb separator="/">
<el-breadcrumb-item v-if="!is_xs" :to="{ path: allPath }">所有产品</el-breadcrumb-item>
<el-breadcrumb-item :to="{ path: productPath }">{{ info.parent_name }}</el-breadcrumb-item>
<!-- <el-breadcrumb-item>{{ info.parent_name }}</el-breadcrumb-item> -->
<el-breadcrumb-item :to="{ path: categoryPath }">{{ info.category_name }}</el-breadcrumb-item>
<el-breadcrumb-item>{{ info.product_name }}</el-breadcrumb-item>
</el-breadcrumb>
</div>
</hager-box>
<hager-box v-if="is_enable" class="box-n">
<el-row v-if="!is_xs" :gutter="10" style="margin-bottom: 3rem;">
<el-col :span="7">
<hager-carousel :images="info_images"></hager-carousel>
</el-col>
<el-col :span="17">
<div class="product-detail-info">
<div class="product-title" style="">{{ info.product_name }}</div>
<div class="product-sub" style="margin: 1rem 0 2rem;" v-html="info.post_excerpt"></div>
</div>
</el-col>
</el-row>
<div v-else>
<div class="product-detail-info">
<div class="product-title" style="">{{ info.product_name }}</div>
<div class="product-sub" style="margin: 1rem 0 2rem;" v-html="info.post_excerpt"></div>
</div>
<div v-for="(item, index) in info_images" :key="index" class="product-item-img">
<el-image style="height: auto; width: 50vw;" :src="item" fit="cover"></el-image>
</div>
</div>
</hager-box>
<hager-box v-if="is_enable" class="box-2n">
<hager-h1 title="产品优势" sub="Product Advantages"></hager-h1>
<div :class="['product-advantage', is_xs ? 'xs' : '']">
<div :class="['item', is_xs ? 'xs' : '']" v-for="(item, index) in product_advantages" :key="index">
<el-row :gutter="0" v-for="(x, idx) in item" :key="idx">
<el-col :span="24" v-if="x">
<!-- <div class="item-content">
<span class="item-icon">·</span>{{ x }}
</div> -->
<div class="item-content" v-html="x"></div>
</el-col>
</el-row>
</div>
</div>
</hager-box>
<hager-box v-if="is_enable && !is_file" class="box-n">
<hager-h1 title="产品资料" sub="Product Information"></hager-h1>
<div class="product-info">
<div class="info-control">
<el-row :gutter="0">
<el-col :span="is_xs ? 24 : 19">
<div :class="['control-left', is_xs ? 'xs' : '']">
<div
v-if="item.list.length"
v-for="(item, index) in download_list" :key="item.id"
:class="[
'button', is_xs ? 'xs' : '',
item.show ? 'active' : ''
]"
@click="onClick(item)">
{{ item.name }}
</div>
</div>
</el-col>
<el-col v-if="!is_xs" :span="5">
<div>
<div @click="goToDownload" :class="['button', is_download_checked ? 'active' : '']">发送到邮箱</div>
</div>
</el-col>
</el-row>
</div>
<div v-if="item.show" v-for="(item, index) in download_list" :key="item.id">
<div class="mini-download-wrapper" v-if="is_xs">
<div>
<span @click="checkAll(item)">全选</span>&nbsp;
<span v-if="item.checked_sum">已选 {{ item.checked_sum }}</span>
</div>
<div @click="goToDownload" :class="['button', is_download_checked ? 'active' : '']">发送到邮箱</div>
</div>
<div class="info-list">
<el-row :gutter="0" v-for="(file, idx) in item.list" :key="idx" style="margin-bottom: 1rem;">
<el-col :span="18">
<div class="info-list-title">
<el-row :gutter="0">
<el-col :span="is_xs ? 3 : 1">
<!-- <i v-if="file.checked" @click="checkItem(file)" class="el-icon-folder-checked download-checked"></i> -->
<img v-if="file.checked" @click="checkItem(file)" style="width: 1.25rem; height: 1.25rem;" class="download-checked" src="https://cdn.ipadbiz.cn/hager/icon/%E9%80%89%E6%8B%A902@2x.png">
<img v-else @click="checkItem(file)" style="width: 1.25rem; height: 1.25rem;" class="download-unchecked" src="https://cdn.ipadbiz.cn/hager/icon/%E9%80%89%E6%8B%A901@2x.png">
<!-- <i v-else @click="checkItem(file)" class="el-icon-folder download-unchecked"></i>&nbsp; -->
</el-col>
<el-col :span="is_xs ? 21 : 23">
<div class="info-list-title-content">
<div style="word-break: break-all;">
<i v-if="!is_xs" class="el-icon-document" style="font-size: 1.35rem;"></i>
{{ file.name }}
</div>
<div>
&nbsp;{{ file.size }}
</div>
</div>
</el-col>
</el-row>
</div>
</el-col>
<el-col :span="6">
<div class="info-list-control">
<div @click="preview(file)">预览</div>
<div @click="sendEmail(file)" class="icon-wrapper">
<img style="height: 1rem; width: auto;" src="https://cdn.ipadbiz.cn/hager/icon/%E9%82%AE%E4%BB%B6@2x.png">
</div>
</div>
</el-col>
</el-row>
</div>
</div>
</div>
</hager-box>
<hager-box v-if="!is_enable" class="no-product">
<div class="product-img-wrapper">
<img :class="['product-img', is_xs ? 'xs' : '']" style="" src="https://cdn.ipadbiz.cn/hager/img/product/%E7%BB%84%20130@2x.png">
</div>
<div class="product-text-wrapper">
<div :class="['product-text-zh', is_xs ? 'xs' : '']">更多内容,敬请期待!</div>
<div :class="['product-text-en', is_xs ? 'xs' : '']">Please look forward to more content!</div>
</div>
</hager-box>
</div>
</template>
<script>
import mixin from 'common/mixin';
import hagerBox from '@/components/common/hagerBox';
import hagerCarousel from '@/components/hagerCarousel';
import hagerH1 from '@/components/common/hagerH1.vue';
import { MessageBox, Message, Loading } from 'element-ui';
import { getProductInfoAPI, getUserInfoAPI, downEmailAPI, downZipAPI } from "@/api/hager.js";
export default {
// TAG:配置页面meta和标题信息
metaInfo () {
return {
meta: [
{ name: 'keyword', content: this.keyword },
{ name: 'description', content: this.description }
]
}
},
components: { hagerBox, hagerCarousel, hagerH1 },
mixins: [mixin.init],
data () {
return {
download_list: [],
info: {},
info_images: [],
product_advantages: [],
checked_items: [],
is_login: false,
is_enable: true, // 产品是否有效
is_file: false, // 是否有产品资料
keyword: '',
description: '',
}
},
computed: {
is_download_checked () {
let sum = 0;
this.download_list.forEach(item => {
item.list.forEach(file => {
if (file.checked) {
sum++;
}
});
});
return sum;
},
allPath () {
return `/product/index/all/${Date.now()}`;
},
productPath () {
return `/product/index/${this.info.parent_id}/${Date.now()}`;
},
categoryPath () {
return `/product/index/${this.info.category_id}/${Date.now()}`;
},
},
async mounted () {
this.getInfo();
this.getUserInfo();
// 监听 popstate 事件
window.addEventListener('popstate', this.handlePopState);
},
beforeDestroy() {
// 移除事件监听器
window.removeEventListener('popstate', this.handlePopState);
},
watch: {
// 监听路由参数变化时,更新输入框的值
async '$route.params.id' (val, old) {
if (old !== val) {
this.getInfo();
}
}
},
methods: {
goToMenu (evt) {
// 阻止默认行为
evt.preventDefault();
},
handlePopState(event) {
// 自定义跳转逻辑
// console.log('popstate triggered', event);
// 例如:跳转到指定路径
// this.$router.push('/custom-page');
},
async getInfo () {
this.download_list = [{
id: 1,
type: 'yangben',
name: '产品样本',
show: false,
list: [],
checked_sum: 0,
}, {
id: 2,
type: 'canshu',
name: '技术参数',
show: false,
list: [],
checked_sum: 0,
}, {
id: 3,
type: 'shuomingshu',
name: '产品手册',
show: false,
list: [],
checked_sum: 0,
}, {
id: 4,
type: 'jiaocheng',
name: '安装教程',
show: false,
list: [],
checked_sum: 0,
}];
this.info_images = [];
const { code, data } = await getProductInfoAPI( { id: this.$route.params.id });
if (code) {
this.info = data;
this.keyword = data.post_keyword;
this.description = data.post_description;
// 产品是否可用
this.is_enable = data.product_status === 'publish' ? true : false;
if (this.info.file?.img) {
this.info_images = this.info.file.img.map(item => item.value);
}
// if (!this.info_images.length) { // 没有图片
// this.info_images.push('https://cdn.ipadbiz.cn/hager/img/no-product-img.png');
// }
// 产品优势
this.product_advantages = this.splitIntoEqualChunks(this.info.product_advantages);
// 产品资料数据结构
for (const key in this.info.file) {
const element = this.info.file[key];
this.download_list.forEach(item => {
if (key === item.type) {
item.list = element.map(item => ({ ...item, checked: false }));
item.show = false;
}
});
};
// 默认选中第一个有数据的分类
for (let index = 0; index < this.download_list.length; index++) {
if (this.download_list[index].list.length) {
this.download_list[index].show = true;
break;
}
}
// 判断是否有产品资料
this.is_file = this.download_list.filter(item => item.list.length).length === 0;
// 设置页面标题
document.title = this.info.product_name + ' | Hager China';
}
},
onClick (v) {
this.download_list.forEach(item => {
if (v.id === item.id) {
item.show = true;
} else {
item.show = false;
}
});
},
async getUserInfo () {
const { code, data } = await getUserInfoAPI();
if (code) {
if (data) {
this.is_login = true; // 已登录
} else {
this.is_login = false; // 未登录
}
}
},
async goToDownload () {
if (!this.is_login) {
Message({
type: 'error',
message: '请先登录'
});
return;
}
if (this.is_download_checked) {
let ids = [];
this.download_list.forEach(item => {
item.list.forEach(file => {
if (file.checked) {
ids.push(file.id)
}
})
});
let loadingInstance = Loading.service({ fullscreen: true, background: 'rgba(0, 0, 0, 0.3)' });
const { code, data } = await downEmailAPI();
if (code) {
await downZipAPI({ name: data.name, ids });
// 发送邮箱接口
Message({
type: 'success',
message: '邮件发送成功'
});
this.$nextTick(() => { // 以服务的方式调用的 Loading 需要异步关闭
loadingInstance.close();
});
} else {
this.$nextTick(() => { // 以服务的方式调用的 Loading 需要异步关闭
loadingInstance.close();
});
}
}
},
checkAll (item) { // 全选当前显示的下载列表
item.list.forEach(file => file.checked = true);
item.checked_sum = item.list.filter(item => item.checked).length;
},
async sendEmail (item) {
if (!this.is_login) {
Message({
type: 'error',
message: '请先登录'
});
return;
}
let loadingInstance = Loading.service({ fullscreen: true, background: 'rgba(0, 0, 0, 0.3)' });
const { code, data } = await downEmailAPI();
if (code) {
await downZipAPI({ name: data.name, ids: [item.id] });
// 发送邮箱接口
Message({
type: 'success',
message: '邮件发送成功'
});
this.$nextTick(() => { // 以服务的方式调用的 Loading 需要异步关闭
loadingInstance.close();
});
} else {
this.$nextTick(() => { // 以服务的方式调用的 Loading 需要异步关闭
loadingInstance.close();
});
}
},
preview (item) {
window.open(item.value, '_blank');
},
splitArrayIntoChunks(list) {
const productAdvantages = list;
const chunkSize = 5;
const result = [];
for (let i = 0; i < productAdvantages.length; i += chunkSize) {
// 使用 slice 方法按每组 5 个元素分割
const chunk = productAdvantages.slice(i, i + chunkSize);
result.push(chunk);
}
return result;
},
splitIntoEqualChunks(list) {
if (this.is_xs && list.length === 1) { // 移动端只有一个元素,直接返回一个包含该元素的数组
return [list]
}
const middle = Math.ceil(list.length / 2); // 计算数组的一半,向上取整
const result = [];
// 第一个子数组是从 0 到 middle 的部分
result[0] = list.slice(0, middle);
// 第二个子数组是从 middle 到末尾的部分
result[1] = list.slice(middle);
return result;
},
checkItem (item) { // 选中资料项目
item.checked = !item.checked;
this.download_list.forEach(item => {
item.checked_sum = item.list.filter(item => item.checked).length;
});
},
}
}
</script>
<style lang="less" scoped>
.product-detail {
.box-n {
background-color: #fff;
padding: 2rem 0;
}
.box-2n {
background-color: #f1f1f1;
padding: 2rem 0;
}
.product-detail-info {
.product-title {
font-size: 1.5rem;
color: @secondary-color;
}
.product-sub {
// margin: 1rem 0 2rem;
// color: @text-color;
}
.product-info-list {
padding: 0 1rem;
li {
line-height: 2;
font-size: 0.9rem;
}
}
}
.product-advantage {
margin-top: 1rem;
display: flex;
flex-wrap: wrap;
// gap: 3rem;
.item {
width: calc(50% - 3rem);
box-sizing: border-box;
margin-right: 3rem;
margin-bottom: 1rem;
padding-top: 1rem;
background-color: #f0f0f0;
border-top: 4px solid @primary-color;
line-height: 1.25;
&.xs {
padding-bottom: 1rem;
width: 100%;
}
.item-content {
// display: flex;
// align-items: center;
display: inline;
line-height: 2;
.item-icon {
color: @primary-color;
font-size: 2rem;
}
}
}
&.xs {
display: block;
}
}
.product-info {
.info-control {
// display: flex;
border-bottom: 4px solid @primary-color;
padding-bottom: 1rem;
margin-top: 2rem;
.control-left {
display: flex;
// flex: 1 0 0;
&.xs {
display: flex;
flex-wrap: nowrap; /* 禁止换行 */
overflow-x: auto; /* 启用横向滚动 */
-webkit-overflow-scrolling: touch; /* 使滚动更平滑,适用于移动端 */
}
}
.button {
background-color: #f3f3f3;
padding: 1rem 2.2rem;
border-radius: 5px;
margin-right: 1rem;
text-align: center;
&:hover {
cursor: pointer;
}
&.active {
background-color: @primary-color;
color: #fff;
}
&.xs {
flex: 0 0 auto; /* 子元素保持固定大小 */
width: 5rem; /* 可以根据需要设置宽度 */
margin-right: 10px; /* 子元素之间的间距 */
}
}
}
.info-list {
// display: flex;
// justify-content: space-between;
// align-items: center;
padding-top: 2rem;
color: #6b6b6b;
.info-list-title {
// display: flex;
// align-items: center;
}
.info-list-title-content {
display: flex;
justify-content: space-between;
// align-items: center;
}
.info-list-control {
display: flex;
justify-content: flex-end;
align-items: center;
color: @primary-color;
div {
margin-right: 1rem;
&:hover {
cursor: pointer;
color: @primary-color;
text-decoration: underline;
}
}
.icon-wrapper {
display: flex;
justify-content: center; /* 水平居中 */
align-items: center; /* 垂直居中 */
img {
max-width: 100%; /* 确保图片不会超出容器 */
height: auto; /* 保持图片的宽高比 */
}
}
}
.download-checked {
font-size: 1.5rem;
color: @primary-color;
&:hover {
cursor: pointer;
}
}
.download-unchecked {
font-size: 1.5rem;
&:hover {
cursor: pointer;
}
}
}
.mini-download-wrapper {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 1rem;
.button {
background-color: #f3f3f3;
padding: 0.85rem 1rem;
border-radius: 5px;
text-align: center;
&.active {
background-color: @primary-color;
color: #fff;
}
}
}
}
.product-item-img {
height: auto;
padding: 1.5rem;
text-align: center;
color: #333;
border-radius: 8px;
background-color: #FFF;
margin-bottom: 1rem;
border: 1px solid #ebebeb;
}
.no-product {
.product-img-wrapper {
display: flex;
align-items: center;
justify-content: center;
margin: 2rem 0;
.product-img {
height: 25vw;
width: auto;
&.xs {
height: 12rem;
}
}
}
.product-text-wrapper {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
margin: 2rem 0;
.product-text-zh {
font-size: 1.3rem;
font-weight: bold;
margin-bottom: 0.5rem;
color: @secondary-color;
&.xs {
font-size: 1.05rem;
}
}
.product-text-en {
font-size: 1.15rem;
font-weight: bold;
color: @primary-color;
&.xs {
font-size: 0.95rem;
}
}
}
}
}
</style>