<template>
<!--首次加载数据效果-->
<up-loading-page loadingText="" :loading="onloading" bgColor="#fff" iconSize="80px" zIndex="999"
image="https://m.nocexpo.com/statics/js/modules/h5/jinn/loading.gif">
</up-loading-page>
<!-- <root> -->
<root v-if="!onloading">
<gb :message="gbConfig.message"></gb>
<view class="container" :style="`height: ${screenArInfo.middleHeight}px;overflow:hidden;`">
<view scroll-y class="scroll-view">
<view class="head" :style="`width:${headSize.right}px`">
<view class="first">
<view class="lan"></view>
<view class="first-c">
<view>仅看差异</view>
<view class="switch-container">
<switch :checked="showOnlyDiff" @change="toggleDiffMode" color="rgba(16, 98, 202, 1)"
style="transform:scale(0.7)"></switch>
</view>
</view>
<view class="lan"></view>
</view>
<view class="data">
<view class="data-c">
<view class="item" v-for="(product, index) in products" :key="index"
:class="dingFlag && index === 0?'item_first':''">
<!--固定右侧的小白条-->
<view class="ding-right"></view>
<view :class="`item-c item-${index}`">
<view class="icon">
<view class="din" @click.stop="toggleDing(index)">
<pic v-if="dingFlag && index === 0" src="icon_ding_active.png"
prefix="image" cstyle="width:25.44rpx;height:25.42rpx" />
<pic v-else src="icon_ding.png" prefix="image"
cstyle="width:25rpx;height:25rpx" />
{{ dingFlag && index === 0 ? '钉住' : '钉在左侧' }}
</view>
<!-- 使用view包装pic组件以确保事件能正确触发 -->
<view @click.stop="removeProduct(index)" class="close">
<pic src="icon_close.png" prefix="image"
cstyle="width:16.45rpx;height:16.01rpx" />
</view>
</view>
<view class="title">
{{ product.seriesName }}
</view>
<view class="grey">
<!-- {{ product.brand }} -->
{{ product.name }}
</view>
</view>
</view>
<!-- <view class="last" @click="addProduct">
<view>添加机型</view>
<view class="i-img">
<pic src="icon_add.png" prefix="image" cstyle="width:34rpx;height:34rpx" />
</view>
</view>-->
</view>
</view>
</view>
<!-- <view class="hr"></view> -->
<view class="data-list">
<view class="datas">
<view class="group-name" :style="`width:${headSize.right-5}px`">
<view>参数</view>
</view>
<view class="group-data" :style="`width:${headSize.right-5}px`">
<view class="data">
<view class="item">
<view class="d">品牌</view>
<view class="d" v-for="(product, index) in products" :key="index"
:class="dingFlag && index==0?'item_first':''">
{{ product.brand }}
</view>
</view>
<view class="item">
<view class="d">价格</view>
<view class="d" v-for="(product, index) in products"
:class="dingFlag && index==0?'item_first':''">
{{ convertPrice(product) }}
</view>
</view>
</view>
</view>
</view>
<view class="datas" v-for="(group, groupIndex) in filteredAttributeGroups" :key="groupIndex">
<view class="group-name" :style="`width:${headSize.right-5}px`">
<view>{{ group.groupName }}</view>
</view>
<view class="group-data" :style="`width:${headSize.right-5}px`">
<view class="data">
<view class="item" v-for="(attr, attrIndex) in group.attributes" :key="attrIndex">
<view class="d">{{ attr.attrName }}</view>
<view class="d" v-for="(product, productIndex) in products" :key="productIndex"
:class="`${attr.isDiff?'diff':''} ${dingFlag && productIndex==0?'item_first':''}`">
{{ getProductAttributeValue(product, group.groupName, attr.attrName) }}
</view>
</view>
</view>
</view>
</view>
</view>
<view v-if="!screenArInfo.boolStripe" style="height: 20rpx;"></view>
</view>
</view>
</root>
</template>
<script setup>
import {
ref,
reactive,
computed,
onMounted
} from "vue"
import {
useStore
} from 'vuex';
import infoApi from '@/api/product/equipment/info.js';
import utilApi from "@/utils/util.js";
import classifyApi from '@/api/productseries.js';
const gbConfig = ref({
psize: {},
message: {
type: 1,
TitleText: "设备参数",
url: "pages/Choose/parameter/index"
}
})
const onloading = ref(true);
const dingFlag = ref(false);
const showOnlyDiff = ref(false); // 控制是否仅显示差异
const products = ref([]);
const attributeGroups = ref([]);
const screenArInfo = computed(() => {
return useStore().getters.getScreenInfo
})
const headSize = ref({});
const productIds = ref('');
// 计算属性,根据showOnlyDiff过滤属性组
const filteredAttributeGroups = computed(() => {
if (!showOnlyDiff.value) {
// 如果不显示差异,则返回所有属性组
return attributeGroups.value;
} else {
// 如果仅显示差异,则过滤掉isDiff为false的属性组和属性
return attributeGroups.value
.filter(group => group.isDiff) // 过滤属性组
.map(group => {
// 过滤属性
const filteredAttributes = group.attributes.filter(attr => attr.isDiff);
return {
...group,
attributes: filteredAttributes
};
})
.filter(group => group.attributes.length > 0); // 过滤掉没有属性的组
}
});
// 根据系列id获取所有型号id
const dataAll = ref([]);
const IDS = ref('');
const getSeriesId = async (id) => {
const params = {
seriesId: id,
}
try {
const res = await classifyApi.getAllId(params);
if (res.data.code === 0) {
console.log(res.data.list, 'res---');
// 检查数据结构,确保products正确赋值
if (Array.isArray(res.data.list)) {
// 假设res.data.list中的每个item需要映射到products的格式
// 创建一个临时数组存储转换后的数据
const formattedProducts = [];
// 遍历响应数据
res.data.list.forEach(item => {
// 检查item是否包含products数组
if (item.products && Array.isArray(item.products)) {
// 将每个product添加到formattedProducts中,并确保包含模板中使用的属性
item.products.forEach(product => {
// 确保产品对象包含必要的属性,如seriesName, name, brand等
formattedProducts.push({
id: product.id,
seriesName: product.seriesName || item.seriesName || '未知系列',
name: product.name || '未知型号',
brand: product.brand || '未知品牌',
quoted: product.quoted || 2, // 默认暂无报价
price: product.price || 0,
attributes: product.attributes || {}
});
});
} else {
// 如果item本身就是产品对象,则直接添加
formattedProducts.push({
id: item.id,
seriesName: item.seriesName || '未知系列',
name: item.name || '未知型号',
brand: item.brand || '未知品牌',
quoted: item.quoted || 2,
price: item.price || 0,
attributes: item.attributes || {}
});
}
});
// 赋值给products
products.value = formattedProducts;
// 重新生成attributeGroups
if (formattedProducts.length > 0) {
regenerateAttributeGroups();
}
console.log('处理后的产品数据:', products.value);
}
// 计算高度
setTimeout(() => {
getHeight()
}, 100);
}
onloading.value = false; // 加载完成后关闭加载状态
} catch (error) {
console.error('获取系列型号ID失败:', error);
onloading.value = false; // 出错时也关闭加载状态
}
}
/**
* 切换差异显示模式
*/
function toggleDiffMode(event) {
showOnlyDiff.value = event.detail.value;
}
/**
* 添加产品
*/
function addProduct() {
uni.navigateTo({
url: '/pages/product/equipment/list/list'
})
}
/**
* 删除指定索引的产品
*/
function removeProduct(index) {
// 检查产品数量是否大于1,否则不允许删除
if (products.value.length <= 1) {
console.log('至少保留一个设备');
// 这里可以添加用户提示,比如使用uni.showToast
uni.showToast({
title: '至少保留一个设备',
icon: 'none',
duration: 2000
});
return;
}
// 检查索引是否有效
if (index < 0 || index >= products.value.length) {
console.error('删除型号无效:', index);
return;
}
// 从products数组中删除指定索引的产品
products.value.splice(index, 1);
console.log('products after removal:', products.value);
// 重新生成attributeGroups数据
regenerateAttributeGroups();
// 确保onloading状态正确(在某些情况下可能需要)
onloading.value = false;
}
/**
* 钉住/取消钉住功能
* @param {Number} index - 要钉住的产品索引
*/
async function toggleDing(index) {
// 如果点击的是第一个产品(索引为0)
if (index === 0) {
// 切换钉住状态
dingFlag.value = !dingFlag.value;
// 如果钉住状态为true,确保该产品保持在第一位
if (dingFlag.value && products.value.length > 1) {
// 第一个产品已经是索引0,无需移动
console.log('产品已钉住');
}
} else {
// 如果点击的不是第一个产品,则需要将该产品移动到第一位并钉住
if (index >= 0 && index < products.value.length) {
// 获取要移动的产品
const productToMove = products.value[index];
// 从原位置删除并添加到第一位
products.value.splice(index, 1);
products.value.unshift(productToMove);
// 设置钉住状态
dingFlag.value = true;
// 重新生成属性组
regenerateAttributeGroups();
console.log('产品已移动到第一位并钉住');
}
}
}
/**
* 根据当前products重新生成attributeGroups
*/
function regenerateAttributeGroups() {
// 创建一个映射来存储所有属性组和属性
const attributeMap = new Map();
// 遍历所有产品,收集所有的属性组和属性
products.value.forEach(product => {
if (product.attributes) {
Object.keys(product.attributes).forEach(groupName => {
// 如果属性组不存在,则创建它
if (!attributeMap.has(groupName)) {
attributeMap.set(groupName, new Set());
}
// 将该组下的所有属性添加到集合中
const groupAttrs = product.attributes[groupName];
Object.keys(groupAttrs).forEach(attrName => {
attributeMap.get(groupName).add(attrName);
});
});
}
});
// 将Map转换为与原来格式相同的数组
const newAttributeGroups = [];
attributeMap.forEach((attrsSet, groupName) => {
const attributes = [];
attrsSet.forEach(attrName => {
// 检查该属性是否在所有产品中都有不同的值
let isDiff = checkAttributeIsDiff(groupName, attrName);
attributes.push({
attrName: attrName,
isDiff: isDiff
});
});
// 检查该属性组是否在不同产品中有不同的属性
let groupIsDiff = attributes.some(attr => attr.isDiff);
newAttributeGroups.push({
groupName: groupName,
attributes: attributes,
isDiff: groupIsDiff
});
});
// 更新attributeGroups
attributeGroups.value = newAttributeGroups;
// 重新计算高度
// setTimeout(() => {
// getHeight();
// }, 1000);
}
/**
* 检查指定属性在所有产品中是否具有不同值
*/
function checkAttributeIsDiff(groupName, attrName) {
let values = [];
// 收集所有产品的该属性值
products.value.forEach(product => {
if (product.attributes &&
product.attributes[groupName] &&
product.attributes[groupName][attrName]) {
values.push(product.attributes[groupName][attrName]);
} else {
values.push(undefined);
}
});
// 检查是否所有定义的值都相同
const firstValue = values[0];
return !values.every(value => value === firstValue);
}
/**
* 获取对比数据
*/
// async function fetchContrastData() {
// if (!productIds.value) return;
// try {
// const response = await infoApi.getproductcontrast(productIds.value)
// if (response.data.code === 0) {
// products.value = response.data.list[0].products || []
// attributeGroups.value = response.data.list[0].attributeGroups || []
// onloading.value = false; // 关闭加载动画
// // 计算高度
// setTimeout(() => {
// getHeight()
// }, 100);
// }
// } catch (error) {
// console.error('获取对比数据失败:', error)
// onloading.value = false; // 出错时也关闭加载动画
// }
// }
function convertPrice(item) {
if (item.quoted === 1) {
return "¥" + utilApi.handlePrice(item.price) + "起"
} else if (item.quoted === 0) {
return "询价"
} else {
return "暂无报价"
}
}
/**
* 此方法数据加载后执行,获取元素成开的高度
*/
function getHeight() {
const query = uni.createSelectorQuery();
// query.selectAll('.head').boundingClientRect(data => {
// headSize.value = data[0]
// }).exec();
// console.log(headSize.value.right, 2222222222, ".item-" + (products.value.length - 1));
if (!headSize.value.right) {
query.selectAll('.item-' + (products.value.length - 1)).boundingClientRect(data => {
headSize.value = data[0];
}).exec();
}
}
function getProductAttributeValue(product, groupName, attrName) {
if (product.attributes &&
product.attributes[groupName] &&
product.attributes[groupName][attrName] &&
product.attributes[groupName][attrName].length > 0) {
return product.attributes[groupName][attrName];
} else {
return '-';
}
}
// 存储页面参数
const pageOptions = ref({});
onMounted(() => {
// 获取URL参数
const pages = getCurrentPages()
const currentPage = pages[pages.length - 1]
pageOptions.value = currentPage.options || {}
productIds.value = pageOptions.value.productIds || ''
// 确保有seriesId参数再调用
if (pageOptions.value.seriesId) {
getSeriesId(pageOptions.value.seriesId);
} else {
console.warn('缺少seriesId参数');
onloading.value = false;
}
});
</script>
<style lang="scss" scoped>
.container {
background-color: #fff;
}
.scroll-view {
height: 100%;
overflow-y: auto;
.data-list {
padding-top: 10rpx;
padding-bottom: 2rpx;
.datas {
.group-name {
font-size: 28rpx;
line-height: 54rpx;
font-weight: 600;
display: flex;
view:first-child {
position: sticky;
left: 26rpx;
}
}
.group-data {
display: flex;
align-items: center;
padding-right: 16rpx;
position: relative;
box-shadow: 0px 4rpx 6rpx rgba(0, 0, 0, 0.1);
.data {
border-top: 2rpx solid rgba(209, 224, 255, 1);
.item {
display: flex;
padding-left: 26rpx;
.d {
display: flex;
justify-content: center;
align-items: center;
flex: 0 0 auto;
text-align: center;
width: 200rpx;
flex-shrink: 0;
padding: 10rpx 16rpx;
font-size: 24rpx;
min-height: 60rpx;
color: rgba(56, 56, 56, 1);
border-right: 2rpx solid rgba(209, 224, 255, 1);
border-bottom: 2rpx solid rgba(209, 224, 255, 1);
word-wrap: break-word;
word-break: break-word;
white-space: pre-wrap;
.ding-right {
display: none;
}
}
.d:last-child {
margin-right: 0px;
}
.d:first-child {
position: sticky;
left: 26rpx;
flex-shrink: 0;
width: 175rpx;
flex: 0 0 auto;
font-size: 28rpx;
z-index: 4;
color: rgba(0, 0, 0, 1);
background: rgba(239, 244, 255, 1);
border-left: 2rpx solid rgba(209, 224, 255, 1);
&:before {
position: absolute;
content: "";
z-index: 3;
top: -4%;
left: -28rpx;
height: 106%;
width: 26rpx;
background-color: #fff;
}
}
.d.diff {
background: rgba(255, 245, 242, 1);
color: rgba(16, 98, 202, 1);
}
}
.item_first {
position: sticky;
left: 233rpx;
background-color: #fff;
}
}
}
}
}
}
.hr {
box-shadow: 0px 4rpx 6rpx rgba(0, 0, 0, 0.1);
position: fixed;
left: 0px;
top: 363rpx;
width: 100%;
z-index: 10;
height: 2rpx;
background: #fff;
}
.head {
display: flex;
padding: 0rpx 0px 18rpx 0rpx;
position: sticky;
top: 0px;
z-index: 9;
height: 160rpx;
background-color: #fff;
box-shadow: 0px 4rpx 6rpx rgba(0, 0, 0, 0.1);
.first {
position: sticky;
left: 0rpx;
display: flex;
.lan {
width: 36rpx;
height: 165rpx;
position: relative;
z-index: 8;
background-color: #fff;
margin-right: -10rpx;
}
.lan:last-child {
width: 24rpx;
margin-left: -10rpx;
margin-right: 0px;
}
.first-c {
width: 200rpx;
height: 160rpx;
flex: 0 0 auto;
z-index: 9;
border-radius: 12rpx;
background: rgba(255, 245, 242, 1);
color: rgba(0, 0, 0, 1);
font-size: 24rpx;
text-align: center;
border: 2rpx solid rgba(255, 230, 224, 1);
view:first-child {
font-size: 24rpx;
padding: 36rpx 0px 0px;
}
view:last-child {
display: flex;
align-items: center;
justify-content: center;
height: 46rpx;
margin-top: 16rpx;
}
}
}
.data {
flex: 0 0 auto;
.data-c {
width: 100%;
display: flex;
align-items: center;
.item {
flex-shrink: 0;
margin: 0px 7rpx;
.ding-right {
display: none;
}
.item-c {
width: 208rpx;
height: 160rpx;
padding: 0px 0rpx 0rpx 10rpx;
display: inline-block;
border-radius: 12rpx;
background: rgba(239, 244, 255, 1);
border: 2rpx solid rgba(209, 224, 255, 1);
.icon {
display: flex;
justify-content: space-between;
.din {
display: flex;
align-items: center;
font-size: 20rpx;
gap: 10rpx;
color: rgba(97, 97, 97, 1);
}
.close {
padding: 15rpx;
}
}
.title {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: rgba(46, 45, 45, 1);
font-size: 24rpx;
font-weight: 600;
padding-right: 10rpx;
}
.grey {
word-wrap: break-word;
height: 70rpx;
word-break: normal;
font-size: 24rpx;
margin-top: 5rpx;
line-height: 35rpx;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
/* 限制最多显示3行 */
overflow: hidden;
text-overflow: ellipsis;
/* 可选,部分浏览器不生效 */
word-break: break-word;
color: rgba(56, 56, 56, 1);
padding-right: 10rpx;
}
}
}
.item:first-child {
margin-left: 0px;
}
.item_first {
position: sticky;
left: 242rpx;
margin-left: 0px;
.item-c {
position: relative;
z-index: 4;
}
.ding-right {
position: absolute;
width: 16rpx;
height: 100%;
right: -10rpx;
top: 0px;
z-index: 3;
display: block;
background: #fff;
}
}
}
}
}
.param-title {
color: rgba(0, 0, 0, 1);
font-size: 28rpx;
font-weight: 555;
padding: 20rpx 26rpx;
}
</style>在安卓正常显示 在ios会出现横向滚动时纵向也会滚动的情况 分析代码 找出什么原因
最新发布