Browse Source

添加互动图

master
xh-pan1 9 months ago
parent
commit
99692adf3a
  1. 21
      src/api/interactionDiagram.js
  2. 6
      src/components/canvasShow/config/mixin/funMixin.js
  3. 10
      src/router/index.js
  4. 10
      src/util/server.js
  5. 239
      src/views/interactionDiagram/components/interactionDiagramImage.vue
  6. 196
      src/views/interactionDiagram/interactionDiagramDetail.vue

21
src/api/interactionDiagram.js

@ -0,0 +1,21 @@
import request from '@/util/server.js'
// 获取动态图详情
export function getInteractionDiagramDetail (params) {
return request({
url: '/cereInteractionDiagram/getById',
method: 'get',
params
})
}
// 查询商品
export function getProducts (params) {
return request({
url: '/canvas/getProducts',
method: 'get',
params
})
}

6
src/components/canvasShow/config/mixin/funMixin.js

@ -40,6 +40,12 @@ export const tool = {
query: {shopId: linkObj.data.shopId}
});
break
case '互动图':
router.push({
path: '/interactionDiagramDetail',
query: {interactionDiagramId: linkObj.data.interactionDiagramId}
});
break
case '商品':
// this.setCurrentPro(linkObj.data)
// router.push("/productDetail");

10
src/router/index.js

@ -363,6 +363,16 @@ const router = new Router({
searchVisible: false
}
},
// 互动图详情
{
path: '/interactionDiagramDetail',
name: 'interactionDiagramDetail',
component: () => import('@/views/interactionDiagram/interactionDiagramDetail'),
meta: {
logoText: '',
searchVisible: false
}
},
// 商品详情
{
path: '/productDetail',

10
src/util/server.js

@ -2,6 +2,7 @@
import Vue from 'vue'
import promise from 'es6-promise'
import axios from 'axios'
import qs from 'qs'
import store from '@/store/index'
import router from '../router'
// import localStorage from '../storage/localStorage'
@ -29,10 +30,17 @@ service.interceptors.request.use(config => {
// if (localStorage.get('token')) {
// config.headers['x-auth-token'] = localStorage.get('token')
// }
if (Cookie.get('token')) {
config.headers['Authorization'] = Cookie.get('token')
}
config.headers['language'] = localStorage.getItem("language") || 'zh'
config.paramsSerializer = function(params) {
let result = qs.stringify(params, { arrayFormat: 'repeat' })
return result
}
var fullUrl = window.location.search;
if (fullUrl.indexOf("?") != -1) {
fullUrl = fullUrl.substring(1);
@ -48,7 +56,7 @@ service.interceptors.request.use(config => {
}else{
config.headers['project'] = '0'
}
config.headers['language'] = localStorage.getItem("language") || 'zh'
return config
}, error => {
return Promise.reject(error)

239
src/views/interactionDiagram/components/interactionDiagramImage.vue

@ -0,0 +1,239 @@
<template>
<div class="mainContent">
<div class="canvasContent" ref="canvasContent" :style="{ width: `${canvasWidth}px`, height: `${canvasHeight}px` }"
v-if="interactionDiagramDetailData.interactionDiagramImage">
<img class="img-bg" ref="canvasBgContent" :src="interactionDiagramDetailData.interactionDiagramImage" />
<div class="drap-container-item" v-for="(point, index) in pointList" :key="index"
:style="{ top: `${canvasHeight * point.pointY}px`, left: `${canvasWidth * point.pointX}px` }"
@click="handleClick(point, index)">
<div :class="showPoint == point ? 'point_source_active' : 'point_source'" />
<div class="product-detail" @click="toProductDetail" v-if="showPoint == point && (point.product && point.product.productName)">
<div class="product-name">{{ (point.product && point.product.productName) ? point.product.productName : '' }}</div>
<div class="product-price">{{ (point.product && point.product.price) ? point.product.price : '' }}</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data () {
return {
interactionDiagramDetailData:{},
showPoint: {},
pointList: [],
canvasWidth: 0,
canvasHeight: 0
}
},
methods: {
toProductDetail () {
this.$emit('clickProductDetail', {
productId: this.productData.productId
})
},
//
handleClick(row, index) {
console.log("handleClick");
if(this.showPoint == row){
this.showPoint = null
}else{
this.showPoint = row
}
},
setParams (data, pointList) {
this.interactionDiagramDetailData = data
this.pointList = pointList
const position = {
height: 650,
width: 900
}
//
var naturalWidth = this.interactionDiagramDetailData.imageWidth;
var naturalHeight = this.interactionDiagramDetailData.imageHeight;
//
var showHeight = position.height;
var showWidth = naturalWidth * showHeight / naturalHeight;
if (showWidth > position.width) {
showWidth = position.width;
showHeight = naturalHeight * showWidth / naturalWidth;
}
this.canvasWidth = showWidth;
this.canvasHeight = showHeight;
}
}
}
</script>
<style lang="scss" scoped>
.point_source_active{
align-items: center;
background: hsla(0,0%,47%,.5);
border: 2px solid transparent;
border-radius: 50%;
display: flex;
height: 32px;
justify-content: center;
opacity: 1;
padding: 0;
transition: border-color .25s ease-in-out,opacity .25s ease-in-out,visibility .25s ease-in-out;
width: 32px;
&:after {
background: #fff;
border-radius: 50%;
box-shadow: 0 1px 4px #0000008c;
content: "";
display: block;
height: 12px;
position: relative;
transition: transform .25s ease-in-out;
width: 12px;
transform: scale(.667);
}
}
.point_source {
align-items: center;
background: hsla(0,0%,47%,.5);
border: 2px solid transparent;
border-radius: 50%;
display: flex;
height: 32px;
justify-content: center;
opacity: 1;
padding: 0;
transition: border-color .25s ease-in-out,opacity .25s ease-in-out,visibility .25s ease-in-out;
width: 32px;
&:after {
background: #fff;
border-radius: 50%;
box-shadow: 0 1px 4px #0000008c;
content: "";
display: block;
height: 12px;
position: relative;
transition: transform .25s ease-in-out;
width: 12px;
}
}
.mainContent {
margin: 0 auto;
width: 900px;
height: 650px;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-content: center;
justify-content: center;
align-items: center;
.canvasContent {
width: 100%;
height: 100%;
position: relative;
.img-bg {
width: 100%;
height: 100%;
object-fit: contain;
}
.drap-container-item {
-webkit-user-select: none;
-moz-user-select: none;
-o-user-select: none;
user-select: none;
position: absolute;
user-select: none;
cursor: pointer;
border: 1px solid transparent;
.drap-item-img {
width: 40px;
height: 40px;
object-fit: contain;
}
.drap-item-name {
text-align: center;
}
.product-detail-top{
position: relative;
top: -100px;
}
.product-detail-bottom{
}
.product-detail-left{
position: relative;
left: -100px;
}
.product-detail-right{
}
.product-detail-centerv{
margin-top: -25%;
margin-bottom: 25%;
}
.product-detail-centerh{
margin-left: -25%;
margin-right: 25%;
}
.product-detail{
display: flex;
flex-direction: column;
flex-wrap: nowrap;
align-content: flex-start;
justify-content: center;
align-items: flex-start;
background: white;
padding-left: 10px;
padding-right: 10px;
padding-top: 8px;
padding-bottom: 8px;
border-radius: 4px;
margin-left: -25%;
margin-right: 25%;
.product-name{
width: 100%;
height: auto;
font-size: 16px;
font-family: Source Han Sans CN;
font-weight: bold;
color: #252744;
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
line-height: 20px;
text-align: left;
}
.product-price{
width: auto;
height: 20px;
line-height: 20px;
font-size: 14px;
font-family: Source Han Sans CN;
font-weight: bold;
color: #252744;
}
}
}
.drap-container-item-active {
border: 1px solid skyblue;
}
}
}
</style>

196
src/views/interactionDiagram/interactionDiagramDetail.vue

@ -0,0 +1,196 @@
<template>
<div class="interactionDiagramPage">
<div class="left">
<!-- 互动图 -->
<InteractionDiagramImage ref="interactionDiagramImage" @clickProductDetail="clickProductDetail"
v-loading="pageloading">
</InteractionDiagramImage>
</div>
<div class="right">
<!-- 商品信息列表 -->
<div class="productList">
<div class="product-detail" @click="clickProductDetail(point)" v-for="(point, index) in showPointList"
:key="index">
<div class="image-container">
<img class="product-image" v-if="point.product.image" :src="point.product.image" />
</div>
<div class="product-info">
<div class="product-name">{{ (point.product && point.product.productName) ? point.product.productName : '' }}
</div>
<div class="product-price">{{ (point.product && point.product.price) ? point.product.price : '' }}</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { getInteractionDiagramDetail, getProducts } from '@/api/interactionDiagram.js'
import InteractionDiagramImage from '@/views/interactionDiagram/components/interactionDiagramImage.vue'
export default {
name: 'interactionDiagramDetail',
components: {
InteractionDiagramImage
},
data() {
return {
pageloading: false,
interactionDiagramDetailData: {},
pointList: [],
showPointList: []
}
},
created() {
this.interactionDiagramId = JSON.parse(this.$route.query.interactionDiagramId)
this.getInteractionDiagramDetail()
},
methods: {
//
async getInteractionDiagramDetail() {
this.pageloading = true
const response = await getInteractionDiagramDetail({
interactionDiagramId: this.interactionDiagramId
})
const res = response.data
if (res.code === '200') {
this.interactionDiagramDetailData = res.data
if (this.interactionDiagramDetailData.pointData) {
this.pointList = JSON.parse(this.interactionDiagramDetailData.pointData);
}
this.showPointList = this.pointList.filter(item => item.product)
let productIdList = this.showPointList.map(item => item.product.productId)
const getProductsResponse = await getProducts({
ids: productIdList,
page: 1,
pageSize: productIdList.length
})
if (getProductsResponse.data.code === '200') {
let productList = getProductsResponse.data.data.list
if (productList) {
this.pointList.forEach(item => {
if (item.product) {
let newProduct = productList.find(newItem => newItem.productId == item.product.productId)
if (newProduct) {
item.product = newProduct
}
}
})
}
}
this.$refs.interactionDiagramImage.setParams(this.interactionDiagramDetailData, this.pointList)
this.pageloading = false
} else {
this.$message.error(res.message || '请求失败!')
}
},
clickProductDetail(prointData) {
console.log(prointData)
if (prointData.product) {
let data = {
productId: prointData.product.productId,
skuId: prointData.product.skuId,
shopId: prointData.product.shopId
}
this.$router.push({
path: "/productDetail",
query: {
proData: JSON.stringify(data)
}
})
}
}
}
}
</script>
<style lang="scss" scoped>
.interactionDiagramPage {
background-color: #F5F5F5;
padding: 50px 0 50px 0;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-content: flex-start;
justify-content: center;
align-items: flex-start;
.left {
flex: 1;
margin-right: 5px;
}
.right {
flex: 1;
margin-left: 5px;
.productList {
.product-detail {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-content: flex-start;
justify-content: flex-start;
align-items: flex-start;
margin-bottom: 15px;
.image-container {
width: 80px;
height: 80px;
.product-image {
width: 100%;
height: 100%;
object-fit: contain;
}
}
.product-info {
margin-left: 8px;
display: flex;
flex-direction: column;
flex-wrap: nowrap;
align-content: flex-start;
justify-content: flex-start;
align-items: flex-start;
}
.product-name {
width: 100%;
height: auto;
font-size: 16px;
font-family: Source Han Sans CN;
font-weight: bold;
color: #252744;
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
line-height: 20px;
text-align: left;
}
.product-price {
width: auto;
height: 20px;
line-height: 20px;
font-size: 14px;
font-family: Source Han Sans CN;
font-weight: bold;
color: #252744;
margin-top: 6px;
}
}
}
}
}
</style>
Loading…
Cancel
Save