hookehuyr

新增简单详情页

1 /* 1 /*
2 * @Date: 2024-08-26 10:42:15 2 * @Date: 2024-08-26 10:42:15
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2024-12-27 16:38:24 4 + * @LastEditTime: 2025-01-03 09:22:05
5 * @FilePath: /hager/src/route.js 5 * @FilePath: /hager/src/route.js
6 * @Description: 文件描述 6 * @Description: 文件描述
7 */ 7 */
...@@ -51,6 +51,15 @@ export default [{ ...@@ -51,6 +51,15 @@ export default [{
51 }, 51 },
52 children: [] 52 children: []
53 }, { 53 }, {
54 + path: '/product/detail_lite/:id',
55 + name: '详情页lite',
56 + component: () => import('@/views/product/detail_lite'),
57 + meta: {
58 + title: '海格电气',
59 + tag: 'product'
60 + },
61 + children: []
62 +}, {
54 path: '/solution/index', 63 path: '/solution/index',
55 name: '解决方案', 64 name: '解决方案',
56 component: () => import('@/views/solution/index'), 65 component: () => import('@/views/solution/index'),
...@@ -78,24 +87,6 @@ export default [{ ...@@ -78,24 +87,6 @@ export default [{
78 }, 87 },
79 children: [] 88 children: []
80 }, { 89 }, {
81 - path: '/solution/detail_test/:id/:timestamp',
82 - name: '解决方案详情1-test',
83 - component: () => import('@/views/solution/detail_test'),
84 - meta: {
85 - title: '解决方案 | Hager China',
86 - tag: 'solution'
87 - },
88 - children: []
89 -}, {
90 - path: '/solution/detail_test/:id/:current_index/:timestamp',
91 - name: '解决方案详情2-test',
92 - component: () => import('@/views/solution/detail_test'),
93 - meta: {
94 - title: '解决方案 | Hager China',
95 - tag: 'solution'
96 - },
97 - children: []
98 -}, {
99 path: '/solution/case/:id/:current_index?', 90 path: '/solution/case/:id/:current_index?',
100 name: '成功案例', 91 name: '成功案例',
101 component: () => import('@/views/solution/case'), 92 component: () => import('@/views/solution/case'),
...@@ -124,10 +115,10 @@ export default [{ ...@@ -124,10 +115,10 @@ export default [{
124 children: [] 115 children: []
125 }, { 116 }, {
126 path: '/about/china', 117 path: '/about/china',
127 - name: '海格电气在中国', 118 + name: '海格中国',
128 component: () => import('@/views/about/china'), 119 component: () => import('@/views/about/china'),
129 meta: { 120 meta: {
130 - title: '海格电气在中国 | Hager China', 121 + title: '海格中国 | Hager China',
131 tag: 'about' 122 tag: 'about'
132 }, 123 },
133 children: [] 124 children: []
......
1 +<!--
2 + * @Date: 2024-09-29 14:26:41
3 + * @LastEditors: hookehuyr hookehuyr@gmail.com
4 + * @LastEditTime: 2025-01-03 10:54:19
5 + * @FilePath: /hager/src/views/product/detail_lite.vue
6 + * @Description: 文件描述
7 +-->
8 +<template>
9 + <div class="product-detail no-select">
10 + <hager-box>
11 + <div style="margin-top: 1.5rem;">
12 + <el-breadcrumb separator="/">
13 + <el-breadcrumb-item v-if="!is_xs" :to="{ path: allPath }">所有产品</el-breadcrumb-item>
14 + <el-breadcrumb-item :to="{ path: productPath }">{{ info.parent_name }}</el-breadcrumb-item>
15 + <!-- <el-breadcrumb-item>{{ info.parent_name }}</el-breadcrumb-item> -->
16 + <el-breadcrumb-item :to="{ path: categoryPath }">{{ info.category_name }}</el-breadcrumb-item>
17 + <el-breadcrumb-item>{{ info.product_name }}</el-breadcrumb-item>
18 + </el-breadcrumb>
19 + </div>
20 + </hager-box>
21 + <hager-box v-if="is_enable" class="box-n">
22 + <el-row v-if="!is_xs" :gutter="10" style="margin-bottom: 3rem;">
23 + <el-col :span="7">
24 + <hager-carousel :images="info_images"></hager-carousel>
25 + </el-col>
26 + <el-col :span="17">
27 + <div class="product-detail-info">
28 + <div class="product-title" style="">{{ info.product_name }}</div>
29 + <div class="product-sub" style="margin: 1rem 0 2rem;" v-html="info.post_excerpt"></div>
30 + </div>
31 + </el-col>
32 + </el-row>
33 + <div v-else>
34 + <div class="product-detail-info">
35 + <div class="product-title" style="">{{ info.product_name }}</div>
36 + <div class="product-sub" style="margin: 1rem 0 2rem;" v-html="info.post_excerpt"></div>
37 + </div>
38 + <div v-for="(item, index) in info_images" :key="index" class="product-item-img">
39 + <el-image style="height: auto; width: 50vw;" :src="item" fit="cover"></el-image>
40 + </div>
41 + </div>
42 + </hager-box>
43 + <hager-box v-if="is_enable" class="box-2n">
44 + <hager-h1 title="产品优势" sub="Product Advantages"></hager-h1>
45 + <div :class="['product-advantage', is_xs ? 'xs' : '']">
46 + <div :class="['item', is_xs ? 'xs' : '']" v-for="(item, index) in product_advantages" :key="index">
47 + <el-row :gutter="0" v-for="(x, idx) in item" :key="idx">
48 + <el-col :span="24" v-if="x">
49 + <!-- <div class="item-content">
50 + <span class="item-icon">·</span>{{ x }}
51 + </div> -->
52 + <div class="item-content" v-html="x"></div>
53 + </el-col>
54 + </el-row>
55 + </div>
56 + </div>
57 + </hager-box>
58 + <hager-box v-if="is_enable && !is_file" class="box-n">
59 + <hager-h1 title="产品资料" sub="Product Information"></hager-h1>
60 + <div class="product-info">
61 + <div class="info-control">
62 + <el-row :gutter="0">
63 + <el-col :span="is_xs ? 24 : 19">
64 + <div :class="['control-left', is_xs ? 'xs' : '']">
65 + <div
66 + v-if="item.list.length"
67 + v-for="(item, index) in download_list" :key="item.id"
68 + :class="[
69 + 'button', is_xs ? 'xs' : '',
70 + item.show ? 'active' : ''
71 + ]"
72 + @click="onClick(item)">
73 + {{ item.name }}
74 + </div>
75 + </div>
76 + </el-col>
77 + <el-col v-if="!is_xs" :span="5">
78 + <div>
79 + <div @click="goToDownload" :class="['button', is_download_checked ? 'active' : '']">发送到邮箱</div>
80 + </div>
81 + </el-col>
82 + </el-row>
83 + </div>
84 + <div v-if="item.show" v-for="(item, index) in download_list" :key="item.id">
85 + <div class="mini-download-wrapper" v-if="is_xs">
86 + <div>
87 + <span @click="checkAll(item)">全选</span>&nbsp;
88 + <span v-if="item.checked_sum">已选 {{ item.checked_sum }}</span>
89 + </div>
90 + <div @click="goToDownload" :class="['button', is_download_checked ? 'active' : '']">发送到邮箱</div>
91 + </div>
92 + <div class="info-list">
93 + <el-row :gutter="0" v-for="(file, idx) in item.list" :key="idx" style="margin-bottom: 1rem;">
94 + <el-col :span="18">
95 + <div class="info-list-title">
96 + <el-row :gutter="0">
97 + <el-col :span="is_xs ? 3 : 1">
98 + <!-- <i v-if="file.checked" @click="checkItem(file)" class="el-icon-folder-checked download-checked"></i> -->
99 + <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">
100 + <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">
101 + <!-- <i v-else @click="checkItem(file)" class="el-icon-folder download-unchecked"></i>&nbsp; -->
102 + </el-col>
103 + <el-col :span="is_xs ? 21 : 23">
104 + <div class="info-list-title-content">
105 + <div style="word-break: break-all;">
106 + <i v-if="!is_xs" class="el-icon-document" style="font-size: 1.35rem;"></i>
107 + {{ file.name }}
108 + </div>
109 + <div>
110 + &nbsp;{{ file.size }}
111 + </div>
112 + </div>
113 + </el-col>
114 + </el-row>
115 + </div>
116 + </el-col>
117 + <el-col :span="6">
118 + <div class="info-list-control">
119 + <div @click="preview(file)">预览</div>
120 + <div @click="sendEmail(file)" class="icon-wrapper">
121 + <img style="height: 1rem; width: auto;" src="https://cdn.ipadbiz.cn/hager/icon/%E9%82%AE%E4%BB%B6@2x.png">
122 + </div>
123 + </div>
124 + </el-col>
125 + </el-row>
126 + </div>
127 + </div>
128 + </div>
129 + </hager-box>
130 + <hager-box v-if="!is_enable" class="no-product">
131 + <div class="product-img-wrapper">
132 + <img :class="['product-img', is_xs ? 'xs' : '']" style="" src="https://cdn.ipadbiz.cn/hager/img/product/%E7%BB%84%20130@2x.png">
133 + </div>
134 + <div class="product-text-wrapper">
135 + <div :class="['product-text-zh', is_xs ? 'xs' : '']">更多内容,敬请期待!</div>
136 + <div :class="['product-text-en', is_xs ? 'xs' : '']">Please look forward to more content!</div>
137 + </div>
138 + </hager-box>
139 + </div>
140 +</template>
141 +
142 +<script>
143 +import mixin from 'common/mixin';
144 +import hagerBox from '@/components/common/hagerBox';
145 +import hagerCarousel from '@/components/hagerCarousel';
146 +import hagerH1 from '@/components/common/hagerH1.vue';
147 +import { MessageBox, Message, Loading } from 'element-ui';
148 +import { getProductInfoAPI, getUserInfoAPI, downEmailAPI, downZipAPI } from "@/api/hager.js";
149 +
150 +export default {
151 + // TAG:配置页面meta和标题信息
152 + metaInfo () {
153 + return {
154 + meta: [
155 + { name: 'keyword', content: this.keyword },
156 + { name: 'description', content: this.description }
157 + ]
158 + }
159 + },
160 + components: { hagerBox, hagerCarousel, hagerH1 },
161 + mixins: [mixin.init],
162 + data () {
163 + return {
164 + download_list: [],
165 + info: {},
166 + info_images: [],
167 + product_advantages: [],
168 + checked_items: [],
169 + is_login: false,
170 + is_enable: true, // 产品是否有效
171 + is_file: false, // 是否有产品资料
172 + keyword: '',
173 + description: '',
174 + }
175 + },
176 + computed: {
177 + is_download_checked () {
178 + let sum = 0;
179 + this.download_list.forEach(item => {
180 + item.list.forEach(file => {
181 + if (file.checked) {
182 + sum++;
183 + }
184 + });
185 + });
186 + return sum;
187 + },
188 + allPath () {
189 + return `/product/index/all/${Date.now()}`;
190 + },
191 + productPath () {
192 + return `/product/index/${this.info.parent_id}/${Date.now()}`;
193 + },
194 + categoryPath () {
195 + return `/product/index/${this.info.category_id}/${Date.now()}`;
196 + },
197 + },
198 + async mounted () {
199 + this.getInfo();
200 + this.getUserInfo();
201 + // 监听 popstate 事件
202 + window.addEventListener('popstate', this.handlePopState);
203 + },
204 + beforeDestroy() {
205 + // 移除事件监听器
206 + window.removeEventListener('popstate', this.handlePopState);
207 + },
208 + watch: {
209 + // 监听路由参数变化时,更新输入框的值
210 + async '$route.params.id' (val, old) {
211 + if (old !== val) {
212 + this.getInfo();
213 + }
214 + }
215 + },
216 + methods: {
217 + goToMenu (evt) {
218 + // 阻止默认行为
219 + evt.preventDefault();
220 + },
221 + handlePopState(event) {
222 + // 自定义跳转逻辑
223 + // console.log('popstate triggered', event);
224 +
225 + // 例如:跳转到指定路径
226 + // this.$router.push('/custom-page');
227 + },
228 + async getInfo () {
229 + this.download_list = [{
230 + id: 1,
231 + type: 'yangben',
232 + name: '产品样本',
233 + show: false,
234 + list: [],
235 + checked_sum: 0,
236 + }, {
237 + id: 2,
238 + type: 'canshu',
239 + name: '技术参数',
240 + show: false,
241 + list: [],
242 + checked_sum: 0,
243 + }, {
244 + id: 3,
245 + type: 'shuomingshu',
246 + name: '产品手册',
247 + show: false,
248 + list: [],
249 + checked_sum: 0,
250 + }, {
251 + id: 4,
252 + type: 'jiaocheng',
253 + name: '安装教程',
254 + show: false,
255 + list: [],
256 + checked_sum: 0,
257 + }];
258 + this.info_images = [];
259 + const { code, data } = await getProductInfoAPI( { id: this.$route.params.id });
260 + if (code) {
261 + this.info = data;
262 + this.keyword = data.post_keyword;
263 + this.description = data.post_description;
264 + // 产品是否可用
265 + this.is_enable = data.product_status === 'publish' ? true : false;
266 + if (this.info.file?.img) {
267 + this.info_images = this.info.file.img.map(item => item.value);
268 + }
269 + // if (!this.info_images.length) { // 没有图片
270 + // this.info_images.push('https://cdn.ipadbiz.cn/hager/img/no-product-img.png');
271 + // }
272 + // 产品优势
273 + this.product_advantages = this.splitIntoEqualChunks(this.info.product_advantages);
274 + // 产品资料数据结构
275 + for (const key in this.info.file) {
276 + const element = this.info.file[key];
277 + this.download_list.forEach(item => {
278 + if (key === item.type) {
279 + item.list = element.map(item => ({ ...item, checked: false }));
280 + item.show = false;
281 + }
282 + });
283 + };
284 + // 默认选中第一个有数据的分类
285 + for (let index = 0; index < this.download_list.length; index++) {
286 + if (this.download_list[index].list.length) {
287 + this.download_list[index].show = true;
288 + break;
289 + }
290 + }
291 + // 判断是否有产品资料
292 + this.is_file = this.download_list.filter(item => item.list.length).length === 0;
293 + // 设置页面标题
294 + document.title = this.info.product_name + ' | Hager China';
295 + }
296 + },
297 + onClick (v) {
298 + this.download_list.forEach(item => {
299 + if (v.id === item.id) {
300 + item.show = true;
301 + } else {
302 + item.show = false;
303 + }
304 + });
305 + },
306 + async getUserInfo () {
307 + const { code, data } = await getUserInfoAPI();
308 + if (code) {
309 + if (data) {
310 + this.is_login = true; // 已登录
311 + } else {
312 + this.is_login = false; // 未登录
313 + }
314 + }
315 + },
316 + async goToDownload () {
317 + if (!this.is_login) {
318 + Message({
319 + type: 'error',
320 + message: '请先登录'
321 + });
322 + return;
323 + }
324 + if (this.is_download_checked) {
325 + let ids = [];
326 + this.download_list.forEach(item => {
327 + item.list.forEach(file => {
328 + if (file.checked) {
329 + ids.push(file.id)
330 + }
331 + })
332 + });
333 + let loadingInstance = Loading.service({ fullscreen: true, background: 'rgba(0, 0, 0, 0.3)' });
334 + const { code, data } = await downEmailAPI();
335 + if (code) {
336 + await downZipAPI({ name: data.name, ids });
337 + // 发送邮箱接口
338 + Message({
339 + type: 'success',
340 + message: '邮件发送成功'
341 + });
342 + this.$nextTick(() => { // 以服务的方式调用的 Loading 需要异步关闭
343 + loadingInstance.close();
344 + });
345 + } else {
346 + this.$nextTick(() => { // 以服务的方式调用的 Loading 需要异步关闭
347 + loadingInstance.close();
348 + });
349 + }
350 + }
351 + },
352 + checkAll (item) { // 全选当前显示的下载列表
353 + item.list.forEach(file => file.checked = true);
354 + item.checked_sum = item.list.filter(item => item.checked).length;
355 + },
356 + async sendEmail (item) {
357 + if (!this.is_login) {
358 + Message({
359 + type: 'error',
360 + message: '请先登录'
361 + });
362 + return;
363 + }
364 + let loadingInstance = Loading.service({ fullscreen: true, background: 'rgba(0, 0, 0, 0.3)' });
365 + const { code, data } = await downEmailAPI();
366 + if (code) {
367 + await downZipAPI({ name: data.name, ids: [item.id] });
368 + // 发送邮箱接口
369 + Message({
370 + type: 'success',
371 + message: '邮件发送成功'
372 + });
373 + this.$nextTick(() => { // 以服务的方式调用的 Loading 需要异步关闭
374 + loadingInstance.close();
375 + });
376 + } else {
377 + this.$nextTick(() => { // 以服务的方式调用的 Loading 需要异步关闭
378 + loadingInstance.close();
379 + });
380 + }
381 + },
382 + preview (item) {
383 + window.open(item.value, '_blank');
384 + },
385 + splitArrayIntoChunks(list) {
386 + const productAdvantages = list;
387 + const chunkSize = 5;
388 + const result = [];
389 +
390 + for (let i = 0; i < productAdvantages.length; i += chunkSize) {
391 + // 使用 slice 方法按每组 5 个元素分割
392 + const chunk = productAdvantages.slice(i, i + chunkSize);
393 + result.push(chunk);
394 + }
395 +
396 + return result;
397 + },
398 + splitIntoEqualChunks(list) {
399 + if (this.is_xs && list.length === 1) { // 移动端只有一个元素,直接返回一个包含该元素的数组
400 + return [list]
401 + }
402 + const middle = Math.ceil(list.length / 2); // 计算数组的一半,向上取整
403 + const result = [];
404 +
405 + // 第一个子数组是从 0 到 middle 的部分
406 + result[0] = list.slice(0, middle);
407 +
408 + // 第二个子数组是从 middle 到末尾的部分
409 + result[1] = list.slice(middle);
410 +
411 + return result;
412 + },
413 + checkItem (item) { // 选中资料项目
414 + item.checked = !item.checked;
415 + this.download_list.forEach(item => {
416 + item.checked_sum = item.list.filter(item => item.checked).length;
417 + });
418 + },
419 + }
420 +}
421 +</script>
422 +
423 +<style lang="less" scoped>
424 +.product-detail {
425 + .box-n {
426 + background-color: #fff;
427 + padding: 2rem 0;
428 + }
429 + .box-2n {
430 + background-color: #f1f1f1;
431 + padding: 2rem 0;
432 + }
433 + .product-detail-info {
434 + .product-title {
435 + font-size: 1.5rem;
436 + color: @secondary-color;
437 + }
438 + .product-sub {
439 + // margin: 1rem 0 2rem;
440 + // color: @text-color;
441 + }
442 + .product-info-list {
443 + padding: 0 1rem;
444 + li {
445 + line-height: 2;
446 + font-size: 0.9rem;
447 + }
448 + }
449 + }
450 + .product-advantage {
451 + margin-top: 1rem;
452 + display: flex;
453 + flex-wrap: wrap;
454 + // gap: 3rem;
455 + .item {
456 + width: calc(50% - 3rem);
457 + box-sizing: border-box;
458 + margin-right: 3rem;
459 + margin-bottom: 1rem;
460 + padding-top: 1rem;
461 + background-color: #f0f0f0;
462 + border-top: 4px solid @primary-color;
463 + line-height: 1.25;
464 + &.xs {
465 + padding-bottom: 1rem;
466 + width: 100%;
467 + }
468 + .item-content {
469 + // display: flex;
470 + // align-items: center;
471 + display: inline;
472 + line-height: 2;
473 + .item-icon {
474 + color: @primary-color;
475 + font-size: 2rem;
476 + }
477 + }
478 + }
479 + &.xs {
480 + display: block;
481 + }
482 + }
483 + .product-info {
484 + .info-control {
485 + // display: flex;
486 + border-bottom: 4px solid @primary-color;
487 + padding-bottom: 1rem;
488 + margin-top: 2rem;
489 + .control-left {
490 + display: flex;
491 + // flex: 1 0 0;
492 + &.xs {
493 + display: flex;
494 + flex-wrap: nowrap; /* 禁止换行 */
495 + overflow-x: auto; /* 启用横向滚动 */
496 + -webkit-overflow-scrolling: touch; /* 使滚动更平滑,适用于移动端 */
497 + }
498 + }
499 + .button {
500 + background-color: #f3f3f3;
501 + padding: 1rem 2.2rem;
502 + border-radius: 5px;
503 + margin-right: 1rem;
504 + text-align: center;
505 + &:hover {
506 + cursor: pointer;
507 + }
508 + &.active {
509 + background-color: @primary-color;
510 + color: #fff;
511 + }
512 + &.xs {
513 + flex: 0 0 auto; /* 子元素保持固定大小 */
514 + width: 5rem; /* 可以根据需要设置宽度 */
515 + margin-right: 10px; /* 子元素之间的间距 */
516 + }
517 + }
518 + }
519 + .info-list {
520 + // display: flex;
521 + // justify-content: space-between;
522 + // align-items: center;
523 + padding-top: 2rem;
524 + color: #6b6b6b;
525 + .info-list-title {
526 + // display: flex;
527 + // align-items: center;
528 + }
529 + .info-list-title-content {
530 + display: flex;
531 + justify-content: space-between;
532 + // align-items: center;
533 + }
534 + .info-list-control {
535 + display: flex;
536 + justify-content: flex-end;
537 + align-items: center;
538 + color: @primary-color;
539 + div {
540 + margin-right: 1rem;
541 + &:hover {
542 + cursor: pointer;
543 + color: @primary-color;
544 + text-decoration: underline;
545 + }
546 + }
547 + .icon-wrapper {
548 + display: flex;
549 + justify-content: center; /* 水平居中 */
550 + align-items: center; /* 垂直居中 */
551 + img {
552 + max-width: 100%; /* 确保图片不会超出容器 */
553 + height: auto; /* 保持图片的宽高比 */
554 + }
555 + }
556 + }
557 +
558 + .download-checked {
559 + font-size: 1.5rem;
560 + color: @primary-color;
561 + &:hover {
562 + cursor: pointer;
563 + }
564 + }
565 + .download-unchecked {
566 + font-size: 1.5rem;
567 + &:hover {
568 + cursor: pointer;
569 + }
570 + }
571 + }
572 +
573 + .mini-download-wrapper {
574 + display: flex;
575 + align-items: center;
576 + justify-content: space-between;
577 + margin-top: 1rem;
578 + .button {
579 + background-color: #f3f3f3;
580 + padding: 0.85rem 1rem;
581 + border-radius: 5px;
582 + text-align: center;
583 + &.active {
584 + background-color: @primary-color;
585 + color: #fff;
586 + }
587 + }
588 + }
589 + }
590 +
591 + .product-item-img {
592 + height: auto;
593 + padding: 1.5rem;
594 + text-align: center;
595 + color: #333;
596 + border-radius: 8px;
597 + background-color: #FFF;
598 + margin-bottom: 1rem;
599 + border: 1px solid #ebebeb;
600 + }
601 +
602 + .no-product {
603 + .product-img-wrapper {
604 + display: flex;
605 + align-items: center;
606 + justify-content: center;
607 + margin: 2rem 0;
608 + .product-img {
609 + height: 25vw;
610 + width: auto;
611 + &.xs {
612 + height: 12rem;
613 + }
614 + }
615 + }
616 + .product-text-wrapper {
617 + display: flex;
618 + align-items: center;
619 + justify-content: center;
620 + flex-direction: column;
621 + margin: 2rem 0;
622 + .product-text-zh {
623 + font-size: 1.3rem;
624 + font-weight: bold;
625 + margin-bottom: 0.5rem;
626 + color: @secondary-color;
627 + &.xs {
628 + font-size: 1.05rem;
629 + }
630 + }
631 + .product-text-en {
632 + font-size: 1.15rem;
633 + font-weight: bold;
634 + color: @primary-color;
635 + &.xs {
636 + font-size: 0.95rem;
637 + }
638 + }
639 + }
640 + }
641 +
642 +}
643 +</style>