|
|
@@ -1,27 +1,480 @@
|
|
|
<config>
|
|
|
{
|
|
|
-'navigationBarTitleText': '产品对比'
|
|
|
+'navigationBarTitleText': '产品对比',
|
|
|
+'disableScroll': true
|
|
|
}
|
|
|
</config>
|
|
|
<template>
|
|
|
- <div></div>
|
|
|
+ <scroll-view style="height:100vh" :scroll-y="!showPopup" enable-flex @scroll="scroll">
|
|
|
+ <div class="content" v-if="!loading">
|
|
|
+ <div class="top tr" :class="{ fixedTop: fixedTop }">
|
|
|
+ <div class="left td" :class="{ fixedLeft: fixedLeft }">产品</div>
|
|
|
+ <div class="td pro" v-for="(item, index) in showContrastList" :key="index" @click="showMore(item.id)">
|
|
|
+ <div class="name">
|
|
|
+ {{ getName(item) }}
|
|
|
+ </div>
|
|
|
+ <van-icon v-if="contrastList.length > 2" name="arrow-down" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="tr">
|
|
|
+ <div class="left td" :class="{ fixedLeft: fixedLeft }">
|
|
|
+ 图片
|
|
|
+ </div>
|
|
|
+ <div class="td pro" v-for="(item, index) in showContrastList" :key="index">
|
|
|
+ <van-image :src="getList(item.img)" :width="60" :height="60" fit="cover" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="tr">
|
|
|
+ <div class="left td" :class="{ fixedLeft: fixedLeft }">
|
|
|
+ {{ $t('chan-pin-pin-pai') }}
|
|
|
+ </div>
|
|
|
+ <div class="td pro" v-for="(item, index) in showContrastList" :key="index">
|
|
|
+ {{ item.brand }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="tr">
|
|
|
+ <div class="left td" :class="{ fixedLeft: fixedLeft }">
|
|
|
+ 产品类别
|
|
|
+ </div>
|
|
|
+ <div class="td pro" v-for="(item, index) in showContrastList" :key="index">
|
|
|
+ {{ getName(item.productCategory) }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="tr">
|
|
|
+ <div class="left td" :class="{ fixedLeft: fixedLeft }">
|
|
|
+ {{ $t('ying-yong-ling-yu') }}
|
|
|
+ </div>
|
|
|
+ <div class="td pro" v-for="(item, index) in showContrastList" :key="index">
|
|
|
+ {{ getApplicationField(item) }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="tr">
|
|
|
+ <div class="left td" :class="{ fixedLeft: fixedLeft }">
|
|
|
+ {{ $t('chan-pin-biao-qian') }}
|
|
|
+ </div>
|
|
|
+ <div class="td pro" v-for="(item, index) in showContrastList" :key="index">
|
|
|
+ <div class="tags">
|
|
|
+ <div class="tag" v-for="(tag, tagIndex) in gstTags(item)" :key="tagIndex">
|
|
|
+ {{ tag }}
|
|
|
+ </div>
|
|
|
+ <span v-if="gstTags(item).length === 0">-</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="tr">
|
|
|
+ <div class="left td" :class="{ fixedLeft: fixedLeft }">
|
|
|
+ {{ $t('ping-jun-jiao-huo-zhou-qi') }}
|
|
|
+ </div>
|
|
|
+ <div class="td pro" v-for="(item, index) in showContrastList" :key="index">
|
|
|
+ {{ item.averageLeadTime || '-' }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="tr">
|
|
|
+ <div class="left td" :class="{ fixedLeft: fixedLeft }">
|
|
|
+ 线下体验
|
|
|
+ </div>
|
|
|
+ <div class="td pro" v-for="(item, index) in showContrastList" :key="index">
|
|
|
+ {{ item.offlineExperience ? '可以' : '-' }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <block v-for="(p, pIndex) in tableParameters" :key="pIndex">
|
|
|
+ <div class="tr firstLevel" v-if="p.isPre">
|
|
|
+ <div class="td left" :class="{ fixedLeft: fixedLeft }">{{ p.chName }}</div>
|
|
|
+ <template v-if="!p.children">
|
|
|
+ <div class="td pro" v-for="item in showContrastList" :key="item.id">
|
|
|
+ {{ getKey(item.id, p.chName) }}
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+ <div class="tr secondLevel" v-else>
|
|
|
+ <div class="td left" :class="{ fixedLeft: fixedLeft }">{{ p.chName }}</div>
|
|
|
+ <template v-if="!p.children">
|
|
|
+ <div class="td pro" v-for="item in showContrastList" :key="item.id">
|
|
|
+ {{ getKey(item.id, p.chName) }}
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+ </block>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <van-popup :show="showPopup" round position="bottom" custom-style="height: 656rpx" @close="showPopup = false">
|
|
|
+ <div class="title">选择商品</div>
|
|
|
+ <scroll-view scroll-y style="height:576rpx">
|
|
|
+ <div class="product-list">
|
|
|
+ <product-row
|
|
|
+ :checked="[...chooseIds].includes(item.id)"
|
|
|
+ v-for="item in popList"
|
|
|
+ :key="item.id"
|
|
|
+ :info="item"
|
|
|
+ :hasDel="false"
|
|
|
+ @choose="choose"
|
|
|
+ checkPosition="right"
|
|
|
+ ></product-row>
|
|
|
+ </div>
|
|
|
+ </scroll-view>
|
|
|
+ </van-popup>
|
|
|
+ </scroll-view>
|
|
|
</template>
|
|
|
<script>
|
|
|
import { mapState } from 'vuex';
|
|
|
+import ProductRow from '../components/product/RowMini.vue';
|
|
|
export default {
|
|
|
data() {
|
|
|
- return {};
|
|
|
+ return {
|
|
|
+ parameters: [],
|
|
|
+ fixedTop: false,
|
|
|
+ fixedLeft: false,
|
|
|
+ chooseIds: [],
|
|
|
+ showPopup: false,
|
|
|
+ nowChooseId: 0,
|
|
|
+ loading: false
|
|
|
+ };
|
|
|
},
|
|
|
computed: {
|
|
|
...mapState(['contrastInfo']),
|
|
|
contrastList() {
|
|
|
return this.contrastInfo.product || [];
|
|
|
+ },
|
|
|
+ popList() {
|
|
|
+ return [...this.contrastList].filter(item => {
|
|
|
+ return !this.chooseIds.includes(item.id) || item.id === this.nowChooseId;
|
|
|
+ });
|
|
|
+ },
|
|
|
+ showContrastList() {
|
|
|
+ return [...this.chooseIds].map(item => {
|
|
|
+ return [...this.contrastList].find(_child => {
|
|
|
+ return _child.id === item;
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+ tableParameters() {
|
|
|
+ const parameters = { ...this.parameters };
|
|
|
+ const _map = new Map();
|
|
|
+ for (let productId in parameters) {
|
|
|
+ let _parameters = parameters[productId];
|
|
|
+
|
|
|
+ if (![...this.chooseIds].includes(Number(productId))) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ _parameters.forEach(_parameter => {
|
|
|
+ if (!_map.has(_parameter.chName)) {
|
|
|
+ _map.set(_parameter.chName, {
|
|
|
+ chName: _parameter.chName,
|
|
|
+ enName: _parameter.enName,
|
|
|
+ sort: _parameter.value ? 1 : 0
|
|
|
+ });
|
|
|
+ } else if (_parameter.value) {
|
|
|
+ let before = { ..._map.get(_parameter.chName) };
|
|
|
+ _map.set(_parameter.chName, {
|
|
|
+ ...before,
|
|
|
+ sort: before.sort + 1
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ if (_parameter.children) {
|
|
|
+ _parameter.children.forEach(_child => {
|
|
|
+ if (!_map.has(_child.chName)) {
|
|
|
+ _map.set(_child.chName, {
|
|
|
+ chName: _child.chName,
|
|
|
+ enName: _child.enName,
|
|
|
+ pre: _parameter.chName,
|
|
|
+ sort: _child.value ? 1 : 0
|
|
|
+ });
|
|
|
+ } else if (_child.value) {
|
|
|
+ let before = { ..._map.get(_child.chName) };
|
|
|
+ _map.set(_child.chName, {
|
|
|
+ ...before,
|
|
|
+ sort: before.sort + 1
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ let backList = [..._map.values()].sort((a, b) => {
|
|
|
+ return b.sort - a.sort;
|
|
|
+ });
|
|
|
+
|
|
|
+ let list = backList.filter(item => {
|
|
|
+ return !item.pre;
|
|
|
+ });
|
|
|
+
|
|
|
+ list = list.map(item => {
|
|
|
+ let _num = backList
|
|
|
+ .filter(_c => {
|
|
|
+ return _c.pre === item.chName;
|
|
|
+ })
|
|
|
+ .reduce((total, curr) => {
|
|
|
+ return total + curr.sort;
|
|
|
+ }, 0);
|
|
|
+ return [
|
|
|
+ {
|
|
|
+ ...item,
|
|
|
+ children: backList.filter(_c => {
|
|
|
+ return _c.pre === item.chName;
|
|
|
+ }).length,
|
|
|
+ isPre: true,
|
|
|
+ sort: _num || item.sort
|
|
|
+ },
|
|
|
+ backList.filter(_c => {
|
|
|
+ return _c.pre === item.chName;
|
|
|
+ })
|
|
|
+ ];
|
|
|
+ });
|
|
|
+
|
|
|
+ list = list.sort((a, b) => {
|
|
|
+ return b[0].sort - a[0].sort;
|
|
|
+ });
|
|
|
+
|
|
|
+ list = list.flat(Infinity);
|
|
|
+
|
|
|
+ return list;
|
|
|
+ },
|
|
|
+ productParameterMap() {
|
|
|
+ const _map = new Map();
|
|
|
+ const parameters = { ...this.parameters };
|
|
|
+ for (let productId in parameters) {
|
|
|
+ let _parameters = parameters[productId];
|
|
|
+ let _parametersMap = new Map();
|
|
|
+ _parameters.forEach(_parameter => {
|
|
|
+ if (_parameter.value) {
|
|
|
+ _parametersMap.set(_parameter.chName, _parameter.value);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (_parameter.children) {
|
|
|
+ _parameter.children.forEach(_child => {
|
|
|
+ if (_child.value) {
|
|
|
+ _parametersMap.set(_child.chName, _child.value);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ _map.set(productId, _parametersMap);
|
|
|
+ }
|
|
|
+
|
|
|
+ return _map;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ onLoad(options) {
|
|
|
+ this.loading = true;
|
|
|
+ this.$loading('加载中...');
|
|
|
+ if (options.chooseIds) {
|
|
|
+ this.chooseIds = options.chooseIds.split(',').map(item => {
|
|
|
+ return Number(item);
|
|
|
+ });
|
|
|
}
|
|
|
},
|
|
|
methods: {
|
|
|
loginMethods() {
|
|
|
- this.$store.dispatch('getContrastInfo');
|
|
|
+ this.$store.dispatch('getContrastInfo').then(res => {
|
|
|
+ if (res.product.length > 0) {
|
|
|
+ this.getParameters();
|
|
|
+ if (this.chooseIds.length === 0) {
|
|
|
+ this.chooseIds = res.product
|
|
|
+ .filter((item, index) => {
|
|
|
+ return index < 2;
|
|
|
+ })
|
|
|
+ .map(item => {
|
|
|
+ return item.id;
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ this.loading = false;
|
|
|
+ this.$loading.close();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ getParameters() {
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.$http
|
|
|
+ .post('/productParameter/productsParameter', {
|
|
|
+ ids: this.contrastList
|
|
|
+ .map(item => {
|
|
|
+ return item.id;
|
|
|
+ })
|
|
|
+ .join(',')
|
|
|
+ })
|
|
|
+ .then(res => {
|
|
|
+ for (let key in res) {
|
|
|
+ res[key] = this.filter(res[key]);
|
|
|
+ }
|
|
|
+ console.log(res);
|
|
|
+ this.parameters = res;
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+ filter(list) {
|
|
|
+ return list.map(item => {
|
|
|
+ if (item.children.length > 0) {
|
|
|
+ return {
|
|
|
+ ...item,
|
|
|
+ chName: item.chName.replace(/ /g, ''),
|
|
|
+ children: this.filter(item.children)
|
|
|
+ };
|
|
|
+ } else {
|
|
|
+ return {
|
|
|
+ ...item,
|
|
|
+ chName: item.chName.replace(/' '/g, '')
|
|
|
+ };
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ getKey(productId, name) {
|
|
|
+ return this.productParameterMap.get(productId.toString()).has(name)
|
|
|
+ ? this.productParameterMap.get(productId.toString()).get(name)
|
|
|
+ : '-';
|
|
|
+ },
|
|
|
+ getApplicationField(productInfo) {
|
|
|
+ let list = productInfo.applicationField ? [...productInfo.applicationField] : [];
|
|
|
+ list = list.map(item => {
|
|
|
+ return this.getName(item);
|
|
|
+ });
|
|
|
+ if (productInfo.customApplicationField) {
|
|
|
+ const _list = productInfo.customApplicationField.split(',');
|
|
|
+
|
|
|
+ list = [...list, ..._list];
|
|
|
+ }
|
|
|
+ return list.join('、');
|
|
|
+ },
|
|
|
+ gstTags(productInfo) {
|
|
|
+ return productInfo.tag || [];
|
|
|
+ },
|
|
|
+ scroll(e) {
|
|
|
+ if (e.detail.scrollTop > 0) {
|
|
|
+ this.fixedTop = true;
|
|
|
+ } else {
|
|
|
+ this.fixedTop = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // if (e.detail.scrollLeft > 0) {
|
|
|
+ // this.fixedLeft = true;
|
|
|
+ // } else {
|
|
|
+ // this.fixedLeft = false;
|
|
|
+ // }
|
|
|
+ },
|
|
|
+ choose(id) {
|
|
|
+ const chooseIds = [...this.chooseIds];
|
|
|
+ chooseIds.splice(chooseIds.indexOf(this.nowChooseId), 1, id);
|
|
|
+ this.chooseIds = chooseIds;
|
|
|
+ this.showPopup = false;
|
|
|
+ },
|
|
|
+ showMore(id) {
|
|
|
+ if (this.contrastList.length <= 2) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.nowChooseId = id;
|
|
|
+ this.showPopup = true;
|
|
|
}
|
|
|
+ },
|
|
|
+ components: {
|
|
|
+ ProductRow
|
|
|
}
|
|
|
};
|
|
|
</script>
|
|
|
+<style lang="less">
|
|
|
+.tr {
|
|
|
+ display: flex;
|
|
|
+ width: 100%;
|
|
|
+ z-index: 1;
|
|
|
+ .td {
|
|
|
+ padding: 9px;
|
|
|
+ background: #ffffff;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ text-align: center;
|
|
|
+ z-index: 1;
|
|
|
+ box-sizing: border-box;
|
|
|
+
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #292c33;
|
|
|
+ line-height: 22px;
|
|
|
+
|
|
|
+ &:not(:last-child) {
|
|
|
+ border-right: 1px solid #f2f3f5;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .left {
|
|
|
+ width: 90px;
|
|
|
+ min-width: 90px;
|
|
|
+ position: sticky;
|
|
|
+ left: 0px;
|
|
|
+ z-index: 10;
|
|
|
+ }
|
|
|
+
|
|
|
+ .pro {
|
|
|
+ min-width: 142px;
|
|
|
+ flex-grow: 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.top {
|
|
|
+ position: sticky;
|
|
|
+ top: 0;
|
|
|
+ z-index: 20;
|
|
|
+ }
|
|
|
+ &.secondLevel {
|
|
|
+ .td {
|
|
|
+ background: #f5f7fa;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ border-top: 1px solid #f2f3f5;
|
|
|
+}
|
|
|
+
|
|
|
+.tags {
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ .tag {
|
|
|
+ font-size: 10px;
|
|
|
+ color: #565b66;
|
|
|
+ line-height: 18px;
|
|
|
+ padding: 0 3px;
|
|
|
+ border-radius: 2px;
|
|
|
+ border: 1px solid #dcdfe6;
|
|
|
+ margin-right: 4px;
|
|
|
+ margin-bottom: 4px;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.fixedLeft {
|
|
|
+ box-shadow: 2px 0px 2px 0px rgba(0, 0, 0, 0.08);
|
|
|
+}
|
|
|
+
|
|
|
+.fixedTop {
|
|
|
+ box-shadow: 0px 2px 2px 0px rgba(0, 0, 0, 0.08);
|
|
|
+}
|
|
|
+
|
|
|
+.name {
|
|
|
+ margin-right: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.product-list {
|
|
|
+ padding: 0 16px;
|
|
|
+ .product {
|
|
|
+ padding: 16px 0;
|
|
|
+ position: relative;
|
|
|
+ }
|
|
|
+ .product + .product {
|
|
|
+ &::after {
|
|
|
+ content: '';
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ left: 28px;
|
|
|
+ right: 0px;
|
|
|
+ height: 1px;
|
|
|
+ background: #f5f7fa;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+.title {
|
|
|
+ font-size: 16px;
|
|
|
+ height: 40px;
|
|
|
+ line-height: 40px;
|
|
|
+ padding: 0 20px;
|
|
|
+ font-weight: bold;
|
|
|
+}
|
|
|
+</style>
|