热区图功能:
<template>
<div class="img-intercept-content" :style="hotStyle">
<div class="imgContainer" :style="hotStyle" ref="imgContainer">
<canvas
ref="refInterceptCanvas"
class="canvasClass"
:width="divWidth"
:height="divHeight"
@mousedown="canvasMouseDown"
@mouseup="canvasMouseUp"
@mousemove="canvasMouseMove"
@mouseleave="canvasMouseLeave"
></canvas>
<img
:id="'image'"
:src="imageSrc"
ref="refInterceptImage"
class="imgClass"
@load="uploadImgLoad"
v-show="false"
/>
</div>
</div>
</template>
<script>
export default {
name: 'imageIntercept',
data() {
return {
divWidth: 0,
divHeight: 0,
// canvas的配置部分
canvasObj: '',
cxt: '',
canvasImg: '',
imgWidth: 0, // img框的宽度
imgHeight: 0, // img框的高度
targetMarkIndex: -1, // 目标标注index
params: {
currentX: 0,
currentY: 0,
flag: false, // 用来判断在canvas上是否有鼠标down的事件,
editFlag: false,
editIndex: -1
},
// 目标类别list
imageCategoryList: [],
targetMarkArray: [],
allPosition: [],
hotStyle: {
height: (window.innerHeight - 130 > 300 ? window.innerHeight - 130 : 400) + 'px',
overflow: 'auto'
},
deleteSubIndex: -1,
editSubIndex: -1
}
},
props: {
imageSrc: {
type: String,
default: ''
},
positionList: {
type: Array,
default: ()=>{
return []
}
},
change: {
type: Function,
default: ()=>{
}
},
editHotNumber: {
type: Number,
default: -1
}
},
computed: {},
watch: {
},
mounted() {
this.initCanvas()
},
methods: {
// 初始化canvas
initCanvas() {
try {
this.canvasObj = this.$refs.refInterceptCanvas;
this.canvasImg = this.$refs.refInterceptImage;
this.cxt = this.canvasObj.getContext('2d');
this.divWidth = this.$refs.imgContainer.offsetWidth;
this.divHeight = this.$refs.imgContainer.offsetHeight;
} catch (err) {
console.log(err);
}
try {
this.canvasOnDraw(this.imgWidth, this.imgHeight);
} catch (err) {
console.log(err);
}
},
// 鼠标down事件
canvasMouseDown(e) {
if (this.editHotNumber === -1){
return
}
this.params.flag = true;
if (!e) {
e = window.event;
// 防止IE文字选中
this.$refs.refInterceptCanvas.onselectstart = function () {
return false;
};
}
// 这里先判断一下,看是否是在有效数据,并且初始化参数
if ((this.params.flag === true) && (this.params.editFlag === false)) {
this.params.currentX = 0;
this.params.currentY = 0;
this.params.currentX = e.layerX;
this.params.currentY = e.layerY;
const dict1 = {
x1: this.params.currentX, // 开始的x坐标
y1: this.params.currentY, // 开始的y坐标
x2: this.params.currentX, // 结束的x坐标
y2: this.params.currentY, // 结束的y坐标
flag: false, // 图片区域是否高亮,
targetMarkValue: '', // 目标类别值
wid: 0, // 矩形宽度
hei: 0, // 矩形高度
// final 是最终的框选的坐标值
left: this.params.currentX,
top: this.params.currentY,
width: 0, // 矩形宽度
height: 0, // 矩形高度
finalX1: this.params.currentX,
finalY1: this.params.currentY,
finalX2: this.params.currentX,
finalY2: this.params.currentY
};
this.targetMarkIndex = this.targetMarkIndex + 1;
if (this.editHotNumber !== -1) {
dict1.hotNumber = this.editHotNumber
}
this.targetMarkArray.push(dict1);
}
// 执行渲染操作
try {
this.canvasOnDraw(this.imgWidth, this.imgHeight);
} catch (err) {
console.log(err);
}
},
canvasMouseUp(e) {
if (this.editHotNumber === -1){
return
}
this.params.flag = false;
try {
// 数据去重
let oldDataLength = this.targetMarkArray.length
this.targetMarkArray = this.uniqueArrByObj(this.targetMarkArray, 'hotNumber')
if (oldDataLength !== this.targetMarkArray.length) {
this.refreshCanvas()
return
}
let isOriginalPoint = false
this.targetMarkArray = this.targetMarkArray.filter((mark) => {
// 如果x1>x2,调换x1和x2的值
if (mark.x1 >= mark.x2) {
let x1 = mark.x1
mark.x1 = mark.x2
mark.x2 = x1
}
// 如果y1>y2,调换y1和y2的值
if (mark.y1 >= mark.y2) {
let y1 = mark.y1
mark.y1 = mark.y2
mark.y2 = y1
}
if (mark.x2 - mark.x1 < 5 || mark.y2 - mark.y1 < 5) {
isOriginalPoint = true
return false
} else {
return true
}
})
// 判断是否原点,宽高均为0或宽高小于5, 重绘
if (isOriginalPoint) {
this.refreshCanvas()
return
}
// 矩形重叠判断
let changeData = {
tempNumber: this.deleteSubIndex !== -1 ? this.deleteSubIndex : (this.editSubIndex !== -1 ? this.editSubIndex : this.targetMarkIndex),
position: {}
}
this.targetMarkArray.filter(row=>{
if (this.editHotNumber === row.hotNumber) {
changeData.position = row
}
})
// console.log('当前坐标:' + JSON.stringify(changeData.position))
let repeatList = this.judgePositionRepeat(this.targetMarkArray)
if ((!repeatList || !repeatList.length) && Object.keys(changeData.position).length) {
this.$emit('change', changeData)
} else if (repeatList && repeatList.length) {
let repeatIndexMap = {}
repeatList.filter(row => {
let repeatIndex = null
Array.isArray(row) && row.filter((item) => {
this.targetMarkArray.filter((mark, markIndex) => {
if (item.x1 === mark.x1 && item.x2 === mark.x2 && item.y1 === mark.y1 && item.y2 === mark.y2) {
repeatIndex = repeatIndex == null ? markIndex : (repeatIndex > markIndex ? repeatIndex : markIndex)
}
})
})
if (repeatIndex != null) {
repeatIndexMap[repeatIndex] = repeatIndex
}
})
this.targetMarkArray = this.targetMarkArray.filter((row, index) => {
if (index === repeatIndexMap[index]) {
return false
} else {
return true
}
})
this.refreshCanvas()
this.$message.error('选择的区域不能重叠')
}
} catch (err) {
console.log(err);
}
},
canvasMouseMove(e) {
if (this.editHotNumber === -1){
return
}
if (e === null) {
e = window.event;
}
if ((this.params.flag === true) && (this.params.editFlag === false)) {
this.params.currentX = e.layerX;
this.params.currentY = e.layerY;
this.targetMarkArray[this.targetMarkIndex].x2 = this.params.currentX; // x1 值
this.targetMarkArray[this.targetMarkIndex].y2 = this.params.currentY; // y1 值
this.targetMarkArray[this.targetMarkIndex].wid = this.params.currentX - this.targetMarkArray[this.targetMarkIndex].x1; // 宽度值
this.targetMarkArray[this.targetMarkIndex].hei = this.params.currentY - this.targetMarkArray[this.targetMarkIndex].y1; // 高度
}
// 执行渲染操作
try {
this.canvasOnDraw(this.imgWidth, this.imgHeight);
} catch (err) {
console.log(err);
}
},
canvasMouseLeave(e){
this.canvasMouseUp(e)
},
uploadImgLoad(e) {
try {
this.imgWidth = e.path[0].naturalWidth;
this.imgHeight = e.path[0].naturalHeight;
let timeout = setTimeout(()=>{
this.positionListChange()
this.canvasOnDraw(this.imgWidth, this.imgHeight)
clearTimeout(timeout)
}, 200)
this.canvasOnDraw(this.imgWidth, this.imgHeight);
} catch (err) {
console.log(err);
}
},
positionListChange () {
let targetMarkArray = []
if (Array.isArray(this.positionList)) {
this.positionList.filter(row => {
if (row.position && Object.keys(row.position).length) {
if (row.hotNumber || row.hotNumber === 0) {
row.position.hotNumber = row.hotNumber
}
targetMarkArray.push(row.position)
}
})
this.targetMarkArray = targetMarkArray
this.targetMarkIndex = this.targetMarkArray.length - 1
}
},
// 输入两个坐标值,判断哪个坐标值离左上角最近,其中特殊情况需要进行坐标查找工作
findWhichIsFirstPoint(x1, y1, x2, y2) {
// 首先判断x轴的距离谁更近
if (x1 <= x2) {
// 说明x1 比较小,接下来判断y谁更近
if (y1 <= y2) {
// 说明第一个坐标离得更近,直接顺序return就好
return [x1, y1, x2, y2];
} else {
// 这里遇见一个奇葩问题,需要进行顶角变换
return [x1, y2, x2, y1];
}
} else {
// 这里是x1 大于 x2 的情况
if (y2 <= y1) {
return [x2, y2, x1, y1];
} else {
// y2 大于 y1 的情况, 这里需要做顶角变换工作
return [x2, y1, x1, y2];
}
}
},
// canvas绘图部分
canvasOnDraw(imgW = this.imgWidth, imgH = this.imgHeight) {
if (!imgW) {
return
}
const imgWidth = imgW;
const imgHeight = imgH;
this.divWidth = imgW;
this.divHeight = imgH;
this.cxt.clearRect(0, 0, this.canvasObj.width, this.canvasObj.height);
// 当前的图片和现有的canvas容器之前的一个关系,是否有必要,我们后续做讨论
var resPointList = this.changeOldPointToNewPoint(
imgWidth,
imgHeight,
this.divWidth,
this.divHeight
);
this.cxt.drawImage(
this.canvasImg,
0,
0,
imgWidth,
imgHeight,
0,
0,
resPointList[0],
resPointList[1]
);
for (const index in this.targetMarkArray) {
let markItem = this.targetMarkArray[index]
const x1 = markItem.x1;
const y1 = markItem.y1;
const x2 = markItem.x2;
const y2 = markItem.y2;
const wid = markItem.wid;
const hei = markItem.hei;
const FinalPointList = this.findWhichIsFirstPoint(
(x1 * this.imgWidth) / resPointList[0],
(y1 * this.imgHeight) / resPointList[1],
(x2 * this.imgWidth) / resPointList[0],
(y2 * this.imgHeight) / resPointList[1]
);
markItem.finalX1 = FinalPointList[0];
markItem.finalY1 = FinalPointList[1];
markItem.finalX2 = FinalPointList[2];
markItem.finalY2 = FinalPointList[3];
// 必须要有的字段
markItem.left = markItem.finalX1;
markItem.top = markItem.finalY1;
markItem.width = markItem.finalX2 - markItem.finalX1;
markItem.height = markItem.finalY2 - markItem.finalY1;
// 调整四个顶角的函数,为了能让整体框选区域更好看
const FinalPointListNow = this.findWhichIsFirstPoint(
x1,
y1,
x2,
y2
);
const tmpX1 = FinalPointListNow[0];
const tmpY1 = FinalPointListNow[1];
const tmpX2 = FinalPointListNow[2];
const tmpY2 = FinalPointListNow[3];
this.cxt.strokeStyle = '#ff6600';
this.cxt.strokeRect(tmpX1, tmpY1, tmpX2 - tmpX1, tmpY2 - tmpY1);
this.cxt.fillStyle = 'red';
this.cxt.font = '30px Arial bold';
// canvas的标题部分
let number = (markItem.hotNumber || markItem.hotNumber === 0) ? markItem.hotNumber : parseInt(index) + 1
this.cxt.fillText(number, parseInt((tmpX1 + tmpX2) / 2) - 4, parseInt((tmpY1 + tmpY2) / 2) + 10);
// 矩形背景色
this.cxt.fillStyle = 'rgba(255, 0, 0, 0.1)';
this.cxt.fillRect(tmpX1, tmpY1, wid, hei);
// 说明被点击了
this.canvasDrowBorder(
'#FF6600',
tmpX1,
tmpY1,
tmpX2 - tmpX1,
tmpY2 - tmpY1
);
this.canvasDrowInnerColor(
'rgba(255, 0, 0, 0.2)',
tmpX1,
tmpY1,
tmpX2 - tmpX1,
tmpY2 - tmpY1
);
}
},
// canvas框选区域的内容颜色
canvasDrowInnerColor(color, x, y, w, h) {
this.cxt.fillStyle = color;
this.cxt.fillRect(x, y, w, h);
},
// canvas框选区域的边框颜色
canvasDrowBorder(color, x, y, w, h) {
this.cxt.strokeStyle = color;
this.cxt.strokeRect(x, y, w, h);
},
// 尺寸变换函数
changeOldPointToNewPoint(imgw, imgH, canvasW, canvasH) {
// 这里有个要求,先以宽度为准,然后再一步步调整高度
var tmpW = canvasW;
var tmpH = (tmpW * imgH) / imgw;
// 如果转换之后的高度正好小于框的高度,则直接进行显示
if (tmpH <= canvasH) {
// 尺寸完美匹配
return [tmpW, tmpH];
} else {
// 高度超出框了,需要重新调整高度部分
tmpW = canvasW;
tmpH = (tmpW * imgH) / imgw;
var count = 1;
var raise = 0.05;
while (tmpH > canvasH || tmpW > canvasW) {
tmpW = tmpW * (1 - raise * count);
tmpH = (tmpW * imgH) / imgw;
}
return [tmpW, tmpH];
}
},
// 判断多个矩线框是否重叠
judgePositionRepeat(layers) {
let repeatList = [] // 重复矩形列表
let formatLayers = [];
for (let i = 0, j = layers.length; i < j; i++) {
formatLayers.push({
// x 和 y 就是矩形框 左上角的位置的点
x: (layers[i].x1 <= layers[i].x2 ? layers[i].x1 : layers[i].x2) + layers[i].width / 2,
y: (layers[i].y1 <= layers[i].y2 ? layers[i].y1 : layers[i].y2) + layers[i].height / 2,
x1: layers[i].x1,
x2: layers[i].x2,
y1: layers[i].y1,
y2: layers[i].y2,
width: layers[i].width,
height: layers[i].height
});
}
for (let i = 0; i < formatLayers.length; i++) {
for (let j = i + 1; j < formatLayers.length; j++) {
if (i >= 0 && i < formatLayers.length - 1) {
if (intersects(formatLayers[i], formatLayers[j])) {
// 走到这里 就说明 已经有交叉的线框了, 你可以做错误的提示了
repeatList.push([formatLayers[i], formatLayers[j]])
}
}
}
}
//判断是否有交叉的矩形框
function intersects(first, second) {
if (Math.abs(first.x - second.x) < first.width / 2 + second.width / 2 && Math.abs(first.y - second.y) < first
.height / 2 + second.height / 2) {
return true;
}
return false;
}
return repeatList
},
deleteIntercept(index, hotNumber){
this.deleteSubIndex = index
this.editSubIndex = -1
if (!this.imgWidth || index === -1) {
return
}
try {
let editIdx = -1
Array.isArray(this.targetMarkArray) && this.targetMarkArray.filter((row, rowIndex)=>{
if (hotNumber != undefined && hotNumber === row.hotNumber) {
editIdx = rowIndex
}
})
index = editIdx !== -1 ? editIdx : index
if (this.targetMarkArray[index]) {
this.targetMarkArray.splice(index, 1)
}
// todo 加这行代码防止vue视图不更新
this.targetMarkArray = JSON.parse(JSON.stringify(this.targetMarkArray))
this.refreshCanvas()
} catch (err) {
console.log(err);
}
},
editIntercept(index, hotNumber){
this.deleteSubIndex = -1
this.editSubIndex = index
if (!this.imgWidth || index === -1) {
return
}
// 重绘矩形
try {
let editIdx = -1
Array.isArray(this.targetMarkArray) && this.targetMarkArray.filter((row, rowIndex)=>{
if (hotNumber != undefined && hotNumber === row.hotNumber) {
editIdx = rowIndex
}
})
let curMark = editIdx !== -1 ? this.targetMarkArray[editIdx] : {}
if (curMark && (curMark.width || curMark.height)) {
this.targetMarkArray.splice(editIdx, 1)
// todo 加这行代码防止vue视图不更新
this.targetMarkArray = JSON.parse(JSON.stringify(this.targetMarkArray))
this.refreshCanvas()
}
} catch (err) {
console.log(err);
}
},
// 更新canvas视图
refreshCanvas () {
// 执行渲染操作
try {
this.targetMarkIndex = this.targetMarkArray.length - 1
this.canvasOnDraw(this.imgWidth, this.imgHeight);
} catch (err) {
console.log('canvas绘制异常', err);
}
},
/** 对象数组去重
* @param {Object} oldArr 需要去重的数组
* @param {String} key 需要去重的对象属性
*/
uniqueArrByObj (oldArr, key) {
var newArr = [];
var obj = {};
for(var i =0; i<oldArr.length; i++){
if(!obj[oldArr[i][key]]){
newArr.push(oldArr[i]);
obj[oldArr[i][key]] = true;
}
}
return newArr;
}
}
}
</script>
<style scoped lang="scss">
.img-intercept-content {
width: 750px;
min-width: 750px;
max-width: 750px;
min-height: 480px;
}
.imgContainer {
position: relative;
width: 750px;
height: 480px;
}
.canvasClass {
position: absolute;
width: 750px;
height: auto;
//border: 1px solid #e4e4e4;
}
.imgClass {
width: 750px;
height: auto;
}
::-webkit-scrollbar {
/*滚动条整体样式*/
width : 8px; /*高宽分别对应横竖滚动条的尺寸*/
height: 0;
border-radius: 4px;
}
::-webkit-scrollbar-thumb {
/*滚动条里面小方块*/
box-shadow: inset 0 0 8px rgba(0, 0, 0, 0.07);
background: #c1c1c1;
border-radius: 4px;
}
::-webkit-scrollbar-track {
/*滚动条里面轨道*/
box-shadow: inset 0 0 8px rgba(0, 0, 0, 0.07);
background: #f1f1f1;
}
</style>
运营后台热区图组件
<template>
<div>
<div class="hot-zone-item-content">
<div class="hot-card-title">
<h4>热区</h4>
<el-upload
v-if="hotItem.icon"
class="change-hot-img"
:action="imgAction"
:accept="accept"
:show-file-list="false"
:on-success="(res, file)=>{uploadImgSuccess(res, file, 'hot_list_icon')}"
:on-error="(res, file)=>{uploadImgError(res, file, 'hot_list_icon')}"
:before-upload="(file)=>{return beforeImgUpload(file, 'hot_list_icon')}">
<el-button type="primary">更换热区图片</el-button>
</el-upload>
<el-button
class="del-hot-btn"
type="danger"
@click="delItem()"
>删除
</el-button>
</div>
<el-form
:model="hotItem"
:ref="`refHotItem${refIndex}`"
label-width="120px"
label-position="right"
class="hot-form-main"
:validate-on-rule-change="false"
>
<div class="hot-form-content">
<div class="float-left hot-left">
<imageIntercept
:ref="`refImageIntercept${refIndex}`"
v-if="hotItem.icon"
:imageSrc="hotItem.icon"
:positionList="hotItem.subItems"
:editHotNumber="editHotNumber"
@change="(data)=>{changeHotSubItems(data)}"
/>
<el-form-item
label="图片"
prop="icon"
:rules="{
required: true,
message: '请上传图片',
trigger: 'blur'
}"
v-if="!hotItem.icon"
>
<el-upload
class="hot-upload-btn"
:action="imgAction"
:accept="accept"
:show-file-list="false"
:on-success="(res, file)=>{uploadImgSuccess(res, file, 'hot_list_icon')}"
:on-error="(res, file)=>{uploadImgError(res, file, 'hot_list_icon')}"
:before-upload="(file)=>{return beforeImgUpload(file, 'hot_list_icon')}">
<img v-if="hotItem.icon" :src="hotItem.icon" class="hot-avatar"/>
<span v-if="hotItem.icon" class="content-img-close el-icon-circle-close"
@click="hotItem.icon=''"></span>
<i v-else class="el-icon-plus avatar-uploader-icon"/>
</el-upload>
<div class="el-upload__tip">只能上传.jpg,.jpeg,.png,.gif文件,且不超过300kb</div>
</el-form-item>
</div>
<div class="float-left hot-right" :style="hotStyle">
<div v-for="(sub, index) in hotItem.subItems" :key="index">
<div>
<el-form-item
label="热区编号"
class="is-required"
style="margin-bottom:30px;"
>
<el-input
class="hot-no-input"
:disabled="true"
v-model="sub.hotNumber"
></el-input>
<label class="batch-no-oprbtn">
<el-button type="text" class="color-blue" @click="editSubItem(index)">{{sub.position && Object.keys(sub.position).length ? '重绘矩形' : '编辑'}}</el-button>
<el-button type="text" @click="addSubItem(index)">添加</el-button>
<el-button v-if="index !== 0" type="text" class="color-red" @click="delSubItem(index)">删除</el-button>
</label>
</el-form-item>
<el-form-item
:label="`券批次号${batchIndex + 1}`"
:prop="'subItems.' + index + '.hdActivityId'"
:rules="{
required: false,
message: sub.url ? '请填写活动券码':' ',
trigger: 'blur'
}"
style="margin-bottom:30px;"
v-for="(batch, batchIndex) in sub.hdActivityIdList"
:key="batchIndex"
>
<el-input
class="batch-no-input"
v-model="batch.hdActivityId"
:disabled="!(!sub.url)"
@blur="verifyCouponFun(index, batchIndex)"
:placeholder="`请填写券批次号${batchIndex + 1}`"
></el-input>
<label class="batch-no-oprbtn">
<el-button v-if="sub.hdActivityIdList && sub.hdActivityIdList.length === (batchIndex + 1)" type="text" @click="addBatch(index, batchIndex)">添加</el-button>
<el-button v-if="sub.hdActivityIdList && sub.hdActivityIdList.length !== (batchIndex + 1)" type="text" class="del-btn" @click="delBatch(index, batchIndex)">删除</el-button>
</label>
</el-form-item>
<div v-if="sub.showMaxQtyAndQuantity">
<el-form-item
:label="'活动优惠券总数'"
:prop="'subItems.' + index + '.maxQty'"
:rules="{
required: sub.showMaxQtyAndQuantity || sub.getQuantity,
trigger: 'blur',
validator: maxQtyValidator
}"
style="margin-bottom:30px;"
>
<el-input
v-model="sub.maxQty"
:disabled="!(!sub.url)"
type="text"
:min="0"
placeholder="请填写活动优惠券总数"
></el-input>
</el-form-item>
<el-form-item
:label="'每人可领券数量'"
:prop="'subItems.' + index + '.getQuantity'"
:rules="{
required: sub.showMaxQtyAndQuantity || sub.maxQty,
trigger: 'blur',
validator: getQuantityValidator
}"
style="margin-bottom:30px;"
>
<el-input
v-model="sub.getQuantity"
:disabled="!(!sub.url)"
type="text"
:min="0"
placeholder="请填写每人可领券数量"
></el-input>
</el-form-item>
</div>
</div>
<el-form-item
style="margin-bottom:30px;"
:label="'小程序内链接'"
:prop="'subItems.' + index + '.url'"
:rules="{
required: false,
message: sub.showMaxQtyAndQuantity ? '请填写链接' : ' ',
trigger: 'blur'
}"
>
<el-input
v-model="sub.url"
:disabled="!(!sub.showMaxQtyAndQuantity)"
placeholder="请填写小程序内链接"
></el-input>
</el-form-item>
<el-form-item
:label="'订阅消息'"
:prop="'subItems.' + index + '.wxTemplateIds'"
:rules="{
required: sub.mustSubscribe == 1,
validator: (_, value, callback)=>{testTemplateIds(index, value, callback)},
trigger: 'blur'
}"
style="margin-bottom:30px;"
>
<el-input
v-model="sub.wxTemplateIds"
placeholder="请填写模板ID,最多三个用英文逗号隔开"
></el-input>
</el-form-item>
<el-form-item
:label="'订阅'"
:prop="'subItems.' + index + '.mustSubscribe'"
style="margin-bottom:30px;"
>
<el-checkbox v-model="sub.mustSubscribe" :true-label="1" :false-label="0" @change="changeMustSubscribe(index)">是否强制订阅</el-checkbox>
</el-form-item>
</div>
</div>
</div>
</el-form>
</div>
</div>
</template>
<script>
import imgUpload from "@/mixins/upload";
import RequestLoading from "@/utils/global-loading";
import {verifyBatchIds} from "@/api/couponActivitypage";
import imageIntercept from '@/components/image-intercept/image-intercept'
const loadingInstance = new RequestLoading();
function showLoading() {
loadingInstance.showFullScreenLoading();
}
function hideLoading() {
loadingInstance.hideFullScreenLoading();
}
let indexSubItems = {
hotId: 1,
hotNumber: 1,
canvas: '',
sort: 1,
pit: 1,
name: '',
icon: '',
url: '',
hdActivityIdList: [{hdActivityId: ''}],
hdActivityId: '',
showMaxQtyAndQuantity: '',
getQuantity: '',
maxQty: '',
wxTemplateIds: '',
mustSubscribe: 0,
position: {}
}
export default {
name: 'hotZoneItem',
mixins: [imgUpload],
data() {
return {
hotItem: {},
imgConfig: {
// 没规定
noRules: {
maxSize: 300
},
hot_list_icon: {
width: 750,
maxSize: 300
}
},
accept: ".jpg,.jpeg,.png,.gif",
imgAction: "/operation-service/upload/uploadPic",
fileActicon: "/operation-service/operation/content/excel",
loading: false,
uploadLoading1: false,
uploadLoading2: false,
uploadLoading3: false,
incidentNameLength: 50,
colorNoLength: 30,
moduleNameLength: 8,
editHotNumber: -1,
hotStyle: {
height: (window.innerHeight - 130 > 300 ? window.innerHeight - 130 : 400) + 'px',
overflow: 'auto'
},
};
},
props: {
hotData: {
type: Object,
default: () => {
return {}
}
},
refIndex: {
type: Number,
default: 0
},
},
components: {
imageIntercept
},
watch: {
'hotItem': {
handler(val) {
this.hotItem && Array.isArray(this.hotItem.subItems) && this.hotItem.subItems.filter(sub => {
let showMaxQtyAndQuantity = false
sub.hdActivityIdList && sub.hdActivityIdList.filter(batch => {
// 如果填写了券批次号,显示活动优惠券总数和每人可领券数量
if (batch.hdActivityId && String(batch.hdActivityId).trim()) {
showMaxQtyAndQuantity = true
}
})
sub.showMaxQtyAndQuantity = showMaxQtyAndQuantity
})
},
deep: true
},
'hotData': {
handler(val) {
this.hotItem = JSON.parse(JSON.stringify(this.hotData))
},
deep: true
}
},
mounted() {
let dataList = JSON.parse(JSON.stringify(this.hotData))
let subItems = dataList.subItems
if(!subItems || (Array.isArray(subItems) && !subItems.length)) {
subItems = [JSON.parse(JSON.stringify(indexSubItems))]
} else if (subItems.length && (!subItems[0].hotNumber && subItems[0].hotNumber !== 0)){
subItems[0].hotNumber = 1
}
this.hotItem = JSON.parse(JSON.stringify(dataList))
},
methods: {
changeUrl(val) {
this.hotItem.url
this.$emit(this.hotItem, 'url', val)
},
delItem() {
this.$emit('delItem')
},
changeHotSubItems({tempNumber, position}, index) {
this.editHotNumber = -1
let subItems = this.hotItem.subItems || []
if (subItems[tempNumber]) {
subItems[tempNumber].position = position
} else {
let subObj = JSON.parse(JSON.stringify(indexSubItems))
subObj.tempNumber = tempNumber
subObj.position = position
subObj.sort = subItems.length + 1
subItems.push(subObj)
}
this.$set(this.hotItem, 'subItems', subItems)
},
addSubItem(index) {
let subItems = this.hotItem.subItems || []
let subObj = JSON.parse(JSON.stringify(indexSubItems))
subObj.sort = subItems.length + 1
let copySubItems = JSON.parse(JSON.stringify(subItems))
copySubItems.sort((a, b) => {
return a.hotNumber - b.hotNumber;
})
subObj.hotNumber = copySubItems.length ? Number(copySubItems[copySubItems.length - 1].hotNumber) + 1 : subItems.length + 1
subItems.push(subObj)
},
editSubItem(index) {
let sub = this.hotItem.subItems[index]
this.editHotNumber = sub.hotNumber
if (sub.position && Object.keys(sub.position).length) {
sub.position = {}
}
let refImageIntercept = this.$refs[`refImageIntercept${this.refIndex}`]
refImageIntercept && refImageIntercept.editIntercept(index, sub.hotNumber)
},
delSubItem(index) {
let sub = this.hotItem.subItems[index]
this.editHotNumber = -1
this.hotItem.subItems.splice(index, 1)
let refImageIntercept = this.$refs[`refImageIntercept${this.refIndex}`]
refImageIntercept && refImageIntercept.deleteIntercept(index, sub.hotNumber)
},
maxQtyValidator(_, val, cb) {
if (!val) {
return cb(new Error("请输入活动优惠券总数"))
}
let regPos = /^[1-9]+[0-9]*]*$/; // 正整数
if (!regPos.test(val)) {
return cb(new Error("只支持正整数"))
}
cb()
},
getQuantityValidator(_, val, cb) {
if (!val) {
return cb(new Error("请输入每人可领券数量"))
}
let regPos = /^[1-9]+[0-9]*]*$/; // 正整数
if (!regPos.test(val)) {
return cb(new Error("只支持正整数"))
}
cb()
},
changeMustSubscribe(index) {
if (this.hotItem.subItems[index].mustSubscribe != 1) {
this.$refs[`refHotItem${this.refIndex}`] && this.$refs[`refHotItem${this.refIndex}`].clearValidate()
}
},
testTemplateIds(index, value, callback) {
if (value && value.match(/[^\x00-\xff]/ig)) {
return callback(new Error("模板ID只允许输入英文逗号隔开"));
} else if (this.hotItem.subItems[index].mustSubscribe == 1 && !value) {
return callback(new Error("请填写模板ID"));
} else {
callback();
}
},
// 校验券批次号是否有用
verifyCouponFun(index, batchIndex) {
let subObj = this.hotItem.subItems[index]
let batchObj = subObj.hdActivityIdList[batchIndex]
let hdActivityId = batchObj.hdActivityId
if (hdActivityId) {
verifyBatchIds({batchIds: [hdActivityId]}).then(res => {
if (typeof res.data === 'object' && Object.keys(res.data).length) {
this.$message.error(res.data[hdActivityId] ? res.data[hdActivityId] : '券批次号有误')
subObj.hdActivityId = ''
batchObj.hdActivityId = ''
this.$forceUpdate()
}
}).catch(() => {
// this.$message.error('券批次号有误')
subObj.hdActivityId = ''
batchObj.hdActivityId = ''
this.$forceUpdate()
})
}
},
// 添加券批次号
addBatch(index, batchIndex) {
this.hotItem.subItems[index].hdActivityIdList.push({
hdActivityId: ''
})
},
// 删除券批次号
delBatch(index, batchIndex) {
let hdActivityIdList = this.hotItem.subItems[index].hdActivityIdList
if (hdActivityIdList && hdActivityIdList.length === 1) {
return
}
hdActivityIdList.splice(batchIndex, 1)
},
// 图片上传前
beforeImgUpload(file, type) {
let imgAccept = ['image/jpeg', 'image/png', 'image/gif']
if (!file.type || (file.type && imgAccept.indexOf(file.type) === -1)) {
this.$message.warning('请上传.jpg,.jpeg,.png,.gif等格式的图片')
return false
}
let value = this.beforeUploadCheck(file, this.imgConfig[type] || this.imgConfig.noRules);
if (type && type === 'hot_list_icon') {
this.$set(this.hotItem, 'uploadLoading', value)
}
return value
},
// 上传图片成功
uploadImgSuccess(res, file, type, rowIndex) {
if (type && type === 'hot_list_icon') {
this.$set(this.hotItem, 'uploadLoading', false)
}
if (res.code === 200 && res.data && res.data.pictUrl) {
let url = res.data.pictUrl;
if (type && type === 'hot_list_icon') {
if (this.hotItem.icon) {
this.initHotData()
}
this.hotItem.icon = url
}
} else {
this.$message.error(res.msg);
}
},
// 上传失败
uploadImgError(res, file, type, rowIndex) {
if (type && type === 'list_icon') {
this.$set(this.hotItem, 'uploadLoading', false)
}
},
initHotData(){
Array.isArray(this.hotItem.subItems) && this.hotItem.subItems.filter(row => {
row.position = {}
row.canvas = ''
})
let refImageIntercept = this.$refs[`refImageIntercept${this.refIndex}`] || {}
refImageIntercept.targetMarkArray = []
refImageIntercept.targetMarkIndex = -1
refImageIntercept.deleteSubIndex = -1
refImageIntercept.editSubIndex = -1
refImageIntercept.editHotNumber = -1
}
}
};
</script>
<style lang="scss" scoped>
.batch-no-input {
width: calc(100% - 70px);
}
.batch-no-oprbtn {
button{
margin-left: 15px;
}
.del-btn {
color: red;
}
}
.float-left {
float: left;
}
.hot-zone-item-content {
background: #ffffff;
.hot-card-title {
height: 50px;
line-height: 50px;
border-bottom: 1px solid rgb(220, 223, 230);
background: #ffffff;
z-index: 1;
h4 {
padding: 0;
margin: 0;
display: inline-block;
line-height: 40px;
font-size: 18px;
float: left;
}
.change-hot-img {
display: inline-block;
position: absolute;
top: 10px;
right: 110px;
}
.del-hot-btn {
display: inline-block;
position: absolute;
top: 15px;
right: 20px;
}
}
.hot-form-content {
margin: 20px 0 0 0;
width: 100%;
min-width: 1185px;
background: #ffffff;
overflow: auto;
.hot-right {
/deep/ .el-form-item__content{
width: calc(100vw - 1310px);
min-width: 250px;
}
}
}
.hot-left {
}
.hot-right {
padding: 0 20px;
}
.hot-upload-btn {
font-size: 28px;
font-weight: 500;
color: #ccc;
width: 250px;
height: 250px;
border: 1px dashed #999;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
margin-right: 20px;
position: relative;
.avatar-uploader-icon {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
display: flex;
align-items: center;
justify-content: center;
}
.content-img-close {
position: absolute;
top: -1px;
right: -1px;
font-size: 24px;
cursor: pointer;
color: #666666;
}
}
.hot-avatar {
width: 130px;
height: auto;
max-height: 130px;
}
.hot-no-input {
width: 60px;
text-align: center;
}
.color-blue {
color: #2d8cf0;
}
.color-red {
color: red;
}
}
::-webkit-scrollbar {
/*滚动条整体样式*/
width : 8px; /*高宽分别对应横竖滚动条的尺寸*/
height: 8px;
border-radius: 4px;
}
::-webkit-scrollbar-thumb {
/*滚动条里面小方块*/
box-shadow: inset 0 0 8px rgba(0, 0, 0, 0.07);
background: #c1c1c1;
border-radius: 4px;
}
::-webkit-scrollbar-track {
/*滚动条里面轨道*/
box-shadow: inset 0 0 8px rgba(0, 0, 0, 0.07);
background: #f1f1f1;
}
</style>
小程序端热区图组件
import Taro, {getCurrentInstance} from '@tarojs/taro'
import React, {Component} from 'react'
import {View, Image} from '@tarojs/components'
import {clearStorageBy401, loginLoading, needRegisterByUrl, newLogin, safeNavigateTo} from '@/utils/shop_utils/util'
import {godPolicyBuriedPoint, getCouponTypeZh} from '@/utils/shop_utils/godpolicy'
import LoginBtn from "@/components/store_components/loginBtn/index"
import {baseUrl} from "@/utils/conf.js";
import classnames from "classnames";
import request from "@/utils/request";
import {getJsonHead} from "@/utils/header";
import {tip} from "@/utils/util";
import {statReport} from "@/utils/report";
import SubscribePopup from '@/components/store_components/SubscribePopup/index'
import checkAddGroup from '@/utils/shop_utils/checkAddGroup'
import {globalNearestStore} from '@/utils/global-data/store-address/index';
import {sleep} from "@/utils/common/time/sleep";
import './hotZone.scss'
export default class HotZone extends Component {
static defaultProps = {
userInfo: Taro.getStorageSync('memberInfo') || {},
couponInfo: {},
imgIndex: '0',
hotSource: '首页',
activityId: '',
receiveCouponSuccess: () => {
},
updateUserInfo: () => {
}
}
state = {
imageRect: {},
getImageRectError: false,
rpxRate: 2,
isAcquire: false,
isReject: false,
showSubscribe: false,
subscribeData: {},
newHotItem: {},
hotClickData: {}
}
componentDidMount() {
let sysinfo = Taro.getSystemInfoSync()
sysinfo = sysinfo || {}
sysinfo.screenWidth = sysinfo.screenWidth || 375
let rpxRate = 750 / sysinfo.screenWidth
this.setState({
rpxRate: rpxRate
})
}
componentWillReceiveProps() {
// 如果图片宽高获取失败,重新获取
if (this.state.getImageRectError) {
this.setImageRect(this.props.imgIndex)
}
}
onLogined() {
this.props.updateUserInfo('hotZone', this.state.hotClickData)
}
setImageRect(imgIndex, e){
this[`hotImg${imgIndex}Timeout`] = setTimeout(() => {
let query = Taro.createSelectorQuery();
let that = this;
let classname = '.hot-img-' + imgIndex
query.select(classname).boundingClientRect(function (rect) {
// console.log('热区图rect:', rect)
if (!rect) {
that.setState({
getImageRectError: true
})
return
}
that.setState({
imageRect: rect,
getImageRectError: false
})
}).exec();
clearTimeout(this[`hotImg${imgIndex}Timeout`])
}, 150)
}
imageLoad = (imgIndex, e) => {
this.setImageRect(imgIndex, e)
}
acquireCouponIndex(hdActivityId, id) {
if (this.state.isAcquire) {
this.closeTabLoading()
return
}
this.setState.isAcquire = true
let {userInfo} = this.props
let memberInfo = userInfo && (userInfo.phone || userInfo.mobile) ? userInfo : (Taro.getStorageSync('memberInfo') || {})
let data = {
id: id,
hdActivityId: hdActivityId,
// storeId: globalNearestStore.storeId,
// memberPhone: memberInfo.phone || memberInfo.mobile || '',
// openId: memberInfo.openid || memberInfo.openId || ''
}
request(
{
url: baseUrl + `/member-service/coupon/activity/getHomePageCouponLocation`,
method: 'POST',
header: {
...getJsonHead(),
"through": "true"
},
data: data
},
{outDate: false, showLoad: true}
)
.then((res) => {
res = Array.isArray(res) ? res : []
res.forEach(item => {
item = item || {}
godPolicyBuriedPoint('getCoupon', {
coupon_id: item.batchId,
coupon_name: item.couponName,
coupon_amount: item.faceValue,
coupon_type: getCouponTypeZh(item.couponType)
})
})
this.setState.isAcquire = false
this.props.receiveCouponSuccess()
Taro.showModal({
title: '',
content: '你已经领取成功,现在就去购物吧',
confirmText: '立即使用',
success: (modalRes) => {
if (modalRes.confirm) {
Taro.navigateTo({
url: '/pages/couponList/couponList'
})
} else if (modalRes.cancel) {
console.log('用户点击取消')
}
this.closeTabLoading()
}
})
})
.catch((err) => {
this.setState.isAcquire = false
this.closeTabLoading()
if (err.code == 401) {
clearStorageBy401()
} else {
tip(err.message || '领券失败')
}
})
}
async acquireCouponGetCoupons(hdActivityId, id) {
if (this.state.isAcquire) {
this.closeTabLoading()
return
}
let {userInfo, activityId} = this.props
const isAddGroup = await checkAddGroup(getCurrentInstance().router.params.id)
if(!isAddGroup){
this.tabLoading = false;
return Taro.showToast({
title: '您还没有进群哦,请进群后再来领取优惠券吧',
icon: 'none'
})
}
this.setState.isAcquire = true
let memberInfo = userInfo && (userInfo.phone || userInfo.mobile) ? userInfo : (Taro.getStorageSync('memberInfo') || {})
let locationAddress = Taro.getStorageSync('locationAddress') || {}
let data = {
id: activityId || getCurrentInstance().router.params.id,
hdActivityId: hdActivityId,
detailId: id,
storeId: globalNearestStore.storeId,
memberPhone: memberInfo.phone || memberInfo.mobile || '',
openId: memberInfo.openid || memberInfo.openId || '',
longitude: locationAddress.longitude || '',
latitude: locationAddress.latitude || ''
}
request(
{
url: baseUrl + `/member-service/coupon/activity/getCouponLocation`,
method: 'POST',
header: {
...getJsonHead(),
"through": "true"
},
data: data
},
{outDate: false, showLoad: true}
)
.then((res) => {
res = Array.isArray(res) ? res : []
res.forEach(item => {
item = item || {}
godPolicyBuriedPoint('getCoupon', {
coupon_id: item.batchId,
coupon_name: item.couponName,
coupon_amount: item.faceValue,
coupon_type: getCouponTypeZh(item.couponType)
})
})
this.setState.isAcquire = false
Taro.showModal({
title: '',
content: '你已经领取成功,现在就去购物吧',
confirmText: '立即使用',
success: (modalRes) => {
if (modalRes.confirm) {
Taro.switchTab({
url: '/shop/index/index'
})
} else if (modalRes.cancel) {
console.log('用户点击取消')
}
this.closeTabLoading()
}
})
})
.catch((err) => {
this.setState.isAcquire = false
this.closeTabLoading()
if (err.code == 401) {
clearStorageBy401()
} else {
tip(err.message || '领券失败')
}
})
}
showSubscribe = () => {
this.closeTabLoading()
this.setState({
showSubscribe: true
})
}
// 最外层热区组件点击事件,防止未注册时热区点击事件不触发获取不到点击位置
async hotZoneClick(item, imgIndex, e) {
let newItem = {}
if (!this.dealHasTempIds(item, imgIndex, e)) { // 没有消息模板的情况下直接获取图片信息,防止计算的点击位置不精准
let rect = await this.getRectPromise(imgIndex)
if (rect && rect !== 'fail') {
newItem = this.getClickPosition(item, imgIndex, e, rect)
} else {
newItem = this.getClickPosition(item, imgIndex, e)
}
} else { // 有消息模板的情况下,不能直接获取图片信息,小程序createSelectorQuery方法有延迟,会导致之后调用订阅相关接口报错(微信订阅相关接口需要tab点击事件触发后立马调用)。
newItem = this.getClickPosition(item, imgIndex, e)
}
this.setState({
hotClickData: {item, imgIndex, e, newItem}
})
}
async hotImgClick(item, imgIndex, e) {
if (!this.dealHasTempIds(item, imgIndex, e)) { // 没有消息模板的情况下直接获取图片信息,防止计算的点击位置不精准
let rect = await this.getRectPromise(imgIndex)
if (rect && rect !== 'fail') {
this.addSubscribe(item, imgIndex, e, rect)
} else {
this.addSubscribe(item, imgIndex, e)
}
} else { // 有消息模板的情况下,不能直接获取图片信息,小程序createSelectorQuery方法有延迟,会导致之后调用订阅相关接口报错(微信订阅相关接口需要tab点击事件触发后立马调用)。
this.addSubscribe(item, imgIndex, e)
}
}
// 判断是否有消息订阅模板
dealHasTempIds(item, imgIndex, e) {
let {rpxRate} = this.state
let tabPosition = e && e.touches && e.touches.length ? JSON.parse(JSON.stringify(e.touches[0])) : {}
tabPosition.x = tabPosition.clientX * rpxRate
let hasTempIds = false // 判断是否有订阅模板
let hasCanvas = false
if (Array.isArray(item.subItems) && item.subItems.length) {
item.subItems.filter(row => {
let canvas = {}
try {
canvas = typeof row.canvas === 'string' && row.canvas ? JSON.parse(row.canvas) : {}
} catch (err) {
}
// 如果x1>x2,调换x1和x2的值
if (canvas.x1 >= canvas.x2) {
let x1 = canvas.x1
canvas.x1 = canvas.x2
canvas.x2 = x1
}
if (tabPosition.x >= canvas.x1 && tabPosition.x <= canvas.x2) {
hasCanvas = true
hasTempIds = !!row.wxTemplateIds ? true : hasTempIds
}
})
}
return hasTempIds = !hasCanvas && item.wxTemplateIds ? true : hasTempIds
}
// 计算点击位置
getClickPosition(item, imgIndex, e, rect){
let newItem = {}
let imageRect = rect || this.state.imageRect
let tabPosition = {}
if (e) {
let {rpxRate} = this.state
console.log('图片信息:', imageRect)
// if (rect) {
tabPosition = e.touches && e.touches.length ? JSON.parse(JSON.stringify(e.touches[0])) : {}
console.log('原先点击位置:', e)
tabPosition.y = tabPosition.clientY - imageRect.top
tabPosition.x = tabPosition.clientX * rpxRate
tabPosition.y = Math.abs(tabPosition.y * rpxRate)
// } else {
// tabPosition = e.detail ? JSON.parse(JSON.stringify(e.detail)) : {}
// console.log('原先点击位置:', e)
// tabPosition.y = tabPosition.y - imageRect.top
// tabPosition.x = tabPosition.x * rpxRate
// tabPosition.y = Math.abs(tabPosition.y * rpxRate)
// }
console.log('计算后的点击位置:', tabPosition)
let hasCanvas = false
// 根据点击位置获取跳转路径,如果全部的canvas为空,拿默认路径
if (Array.isArray(item.subItems) && item.subItems.length) {
let newSubItems = JSON.parse(JSON.stringify(item.subItems))
item.subItems.filter(row => {
let canvas = {}
try {
canvas = typeof row.canvas === 'string' && row.canvas ? JSON.parse(row.canvas) : {}
if (Object.keys(canvas).length) {
hasCanvas = true
}
} catch (err) {
}
// 如果x1>x2,调换x1和x2的值
if (canvas.x1 >= canvas.x2) {
let x1 = canvas.x1
canvas.x1 = canvas.x2
canvas.x2 = x1
}
// 如果y1>y2,调换y1和y2的值
if (canvas.y1 >= canvas.y2) {
let y1 = canvas.y1
canvas.y1 = canvas.y2
canvas.y2 = y1
}
if (tabPosition.x >= canvas.x1 && tabPosition.x <= canvas.x2
&& tabPosition.y >= canvas.y1 && tabPosition.y <= canvas.y2) {
newItem = JSON.parse(JSON.stringify(row))
newItem.subItems = newSubItems
}
})
console.log('点击位置Item:', newItem)
}
// 如果newItem为空对象且canvas也是空对象(图片未框选矩形),默认取第一个对象的值
if (!Object.keys(newItem).length && !hasCanvas) {
newItem = JSON.parse(JSON.stringify(item))
}
} else {
newItem = this.state.newHotItem
}
return newItem
}
async addSubscribe(item, imgIndex, e, rect) {
if (this.tabLoading) {
return false
}
this.tabLoading = true
let newItem = this.getClickPosition(item, imgIndex, e, rect)
this.setState({
subscribeData: newItem,
showSubscribe: false,
newHotItem: newItem
})
/**
* wxTemplateIds:消息id
* mustSubscribe:是否强制
*/
let {wxTemplateIds, mustSubscribe, id} = newItem
if (wxTemplateIds) {
const tempIds = wxTemplateIds.split(',')
if (this.props.registered == 0) {
return false
}
const hasItemSettings = await this.checkOpenSetting(
tempIds,
mustSubscribe
)
Taro.requestSubscribeMessage({
tmplIds: tempIds
})
.then(async (res) => {
console.log('【requestSubscribeMessage】:', res)
const filterTmplId = tempIds.filter((v) => res[v] === 'accept')
if (res.errMsg && res.errMsg === 'requestSubscribeMessage:ok' && filterTmplId && filterTmplId.length) {
// 非强制||强制订阅
const result = await this.subscribeSend(tempIds, id)
const settings = await this.checkOpenSetting(tempIds)
console.log(settings, 'settings')
if (
result === 'success' &&
(settings === 'fail' ||
hasItemSettings === 'fail')
) {
// tip('订阅成功')
// await sleep(2500)
}
this.handleForward(newItem)
} else {
// 拒绝条件
if (mustSubscribe === 0) {
this.handleForward(newItem)
} else {
this.toOpenSetting(tempIds)
}
}
})
.catch((e) => {
console.log('【requestSubscribeMessage】fail:', e)
if (mustSubscribe === 1) {
if (e && e.errCode && e.errCode == 20001) {
tip('订阅失败,模板ID无效')
this.closeTabLoading()
return
}
tip('订阅消息内容获取异常,请检查是否已打开接收开关')
this.showSubscribe()
} else {
this.handleForward(newItem)
}
})
} else {
console.log('不需要订阅')
this.handleForward(newItem)
}
}
getRectPromise(imgIndex) {
return new Promise((resolve) => {
let query = Taro.createSelectorQuery();
let classname = '.hot-img-' + imgIndex
query.select(classname).boundingClientRect((rect) => {
if (!rect) {
this.closeTabLoading()
return resolve('fail')
} else {
return resolve(rect)
}
}).exec();
})
}
checkOpenSetting(tempIds, mustSubscribe) {
return new Promise((resolve) => {
Taro.getSetting({
withSubscriptions: true,
success: (settings) => {
const subSet = settings.subscriptionsSetting
console.log('checkopen settings', settings)
if (subSet) {
const itemSettings = subSet.itemSettings || {}
let hasSettings = true
if (mustSubscribe === 1) {
hasSettings = tempIds.every((v) => itemSettings[v] === 'accept')
} else {
hasSettings = tempIds.some((v) => itemSettings[v] === 'accept')
}
console.log('itemSettings', itemSettings, hasSettings)
return resolve(hasSettings ? 'success' : 'fail')
} else {
return resolve('fail')
}
}
})
})
}
toOpenSetting(tempIds) {
// 获取小程序设置
const tipsText = '必须全部勾选订阅才能继续操作'
this.setState({
isReject: false
})
Taro.getSetting({
withSubscriptions: true,
success: (res1) => {
const subSet = res1.subscriptionsSetting
console.log('【getSetting】:', res1)
if (subSet) {
const itemSettings = subSet.itemSettings || {}
const rejectTmplId = tempIds.filter(
(v) => itemSettings[v] === undefined
)
// 没有勾选不再询问,点取消或者不勾全
if (rejectTmplId.length > 0) {
this.showSubscribe()
this.setState({
isReject: true
})
return false
}
if (!subSet.itemSettings || !subSet.mainSwitch) {
this.showSubscribe()
tip(tipsText)
} else {
const hasSettings = tempIds.every(
(v) => itemSettings[v] === 'accept'
)
if (!hasSettings) {
this.showSubscribe()
tip(tipsText)
} else {
// 防止:当模版标题相同requestSubscribeMessage返回filter时
this.subscribeSend(tempIds)
}
}
}
this.closeTabLoading()
},
fail: () => {
this.closeTabLoading()
}
})
}
handleForward(item) {
// 神策埋点-资源位点击
if((item.url || item.hdActivityId) && this.props.hotSource == '首页' ){
godPolicyBuriedPoint('rcesourceClick',{
hot_zone_number : item.hotNumber,
Jump_the_link : item.url,
coupon_lot_number : item.hdActivityId,
mkt_name : this.props.incidentName,
mkt_type : '热区'
})
}
// 跳转还是领券判断
let {hdActivityId, id} = item
if (hdActivityId) {
if (this.props.hotSource === '自定义页面') {
this.acquireCouponGetCoupons(hdActivityId, id)
} else {
this.acquireCouponIndex(hdActivityId, id)
}
} else {
this.onJump(item.url, item)
}
}
subscribeSend(ids, activityDetailId) {
return new Promise((resolve) => {
const {userInfo} = this.props
const data = {
mobile: userInfo.mobile,
templateIds: ids
}
console.log('【/member-service/subscribe/add】data:', data)
request({
url: `${baseUrl}/member-service/subscribe/add`,
method: 'POST',
header: getJsonHead(),
data
}).then((res) => {
const subData = {
activityDetailId: activityDetailId,
phone: userInfo.mobile,
templateIds: ids
}
this.activitySubscribe(subData)
this.closeTabLoading()
return resolve('success')
}).catch(()=>{
this.closeTabLoading()
})
})
}
activitySubscribe(data) {
request({
url: `${baseUrl}/member-service/wx/subscribe/locations?codes=8`,
method: 'POST',
header: getJsonHead(),
data
}).then((res) => {
})
}
onJump = (url, item) => { //地址跳转
let registered = Taro.getStorageSync('registered')
if (registered == undefined || registered === '') {
if (loginLoading) {
Taro.showToast({
title: '登录中,请稍等...',
icon: 'none',
duration: 1500
})
this.closeTabLoading()
} else {
newLogin().then(res => {
this.onJump(url)
}).catch(() => {
this.closeTabLoading()
})
}
return
}
// 根据跳转的页面路径判断是否需要跳转注册页
if (needRegisterByUrl(url)) {
this.closeTabLoading()
return
}
if (getCurrentInstance().router.path.indexOf('shop/index/index') !== -1 && item) {
statReport({url: 'wowcolour_10008.txt', immediate: true}, {
report_name: '首页-自定义模块',
active_id: item && item.id ? item.id : '',
})
}
if (url && url.indexOf('pages/goodsDetail/goodsDetail') !== -1 && item) { // 神策埋点-存储首页资源位
Taro.setStorageSync('indexModuleData', {
moduleName: '热区',
hot_zone_number: item.hotNumber,
Jump_the_link: item.url
})
}
this.closeTabLoading()
safeNavigateTo(url)
};
closeTabLoading(time) {
sleep(typeof time === "number" ? time : 500).then(() => {
this.tabLoading = false
})
}
render() {
const {registered, couponInfo, imgIndex} = this.props
return (
<View className='hot-img-view' onClick={this.hotZoneClick.bind(this, couponInfo, imgIndex)}>
<LoginBtn
customName='auth-btn'
registered={registered}
onLogined={this.onLogined.bind(this)}
>
<Image
className={classnames('hot-coupon-img', 'hot-img-' + imgIndex)}
mode='widthFix'
onClick={this.hotImgClick.bind(this, couponInfo, imgIndex)}
onLoad={this.imageLoad.bind(this, imgIndex)}
src={couponInfo.icon || couponInfo.url[0]}
/>
</LoginBtn>
<SubscribePopup
show={this.state.showSubscribe}
clickPic={this.addSubscribe.bind(this, this.state.subscribeData)}
reject={this.state.isReject}
/>
</View>
)
}
}