2025-03-23 09:29:40 +08:00
|
|
|
|
<template>
|
2025-05-28 11:46:27 +08:00
|
|
|
|
<view>
|
|
|
|
|
<view class="seach">
|
2025-09-23 16:26:35 +08:00
|
|
|
|
<view class="neibox"> 子点位 </view>
|
2025-05-28 11:46:27 +08:00
|
|
|
|
<view class="seach_i">
|
2025-09-23 16:26:35 +08:00
|
|
|
|
<view class="inputbox" @click="childNodeListVisible = true">
|
|
|
|
|
<view class="">
|
|
|
|
|
{{ selectedChildNodeName ? selectedChildNodeName : '请选择子点位' }}
|
|
|
|
|
</view>
|
|
|
|
|
<u-icon name="arrow-right" size="24rpx" color="#005bac"></u-icon>
|
|
|
|
|
</view>
|
2025-05-28 11:46:27 +08:00
|
|
|
|
</view>
|
|
|
|
|
<view class="neibox" @click="popShow = true"> 筛选 </view>
|
|
|
|
|
</view>
|
|
|
|
|
<view class="mainbox">
|
|
|
|
|
<view class="main_bottom">
|
|
|
|
|
<view
|
|
|
|
|
class="scoll_main"
|
|
|
|
|
ref="scrollMain"
|
2025-09-23 16:26:35 +08:00
|
|
|
|
@touchstart.prevent="handleTouchStart"
|
|
|
|
|
@touchmove.prevent="handleTouchMove"
|
2025-05-28 11:46:27 +08:00
|
|
|
|
@touchend="handleTouchEnd"
|
2025-09-23 16:26:35 +08:00
|
|
|
|
@dblclick="handleDoubleClick"
|
|
|
|
|
:style="containerStyle"
|
2025-05-28 11:46:27 +08:00
|
|
|
|
>
|
|
|
|
|
<TreeChart
|
|
|
|
|
:size="size"
|
|
|
|
|
:json="data"
|
|
|
|
|
:class="{ landscape: landscape.length }"
|
|
|
|
|
@click-node="clickNode"
|
|
|
|
|
/>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
<u-popup
|
|
|
|
|
:show="popShow"
|
|
|
|
|
mode="right"
|
|
|
|
|
@close="popShow = false"
|
|
|
|
|
:closeOnClickOverlay="false"
|
|
|
|
|
>
|
|
|
|
|
<view class="rightPopup">
|
|
|
|
|
<view class="popup_top">
|
|
|
|
|
<view
|
|
|
|
|
@click="
|
|
|
|
|
() => {
|
|
|
|
|
getDataList(), (popShow = false)
|
|
|
|
|
}
|
|
|
|
|
"
|
|
|
|
|
>筛选</view
|
|
|
|
|
>
|
|
|
|
|
<view class="top_red" @click="popShow = false">{{ '返回' }}</view>
|
|
|
|
|
</view>
|
|
|
|
|
<view class="typesBox">
|
2025-09-23 16:26:35 +08:00
|
|
|
|
<view class="typeTitle" @click="stageListVisible = true"> 阶段 </view>
|
2025-05-28 11:46:27 +08:00
|
|
|
|
<view class="choiceBox">
|
2025-09-23 16:26:35 +08:00
|
|
|
|
<view class="inputbox" @click="stageListVisible = true">
|
2025-05-28 11:46:27 +08:00
|
|
|
|
<view class="">
|
2025-09-23 16:26:35 +08:00
|
|
|
|
{{ stageName ? stageName : '请选择' }}
|
2025-05-28 11:46:27 +08:00
|
|
|
|
</view>
|
|
|
|
|
<u-icon name="arrow-right" size="24rpx" color="#090000"></u-icon>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
<view class="typesBox">
|
2025-09-23 16:26:35 +08:00
|
|
|
|
<view class="typeTitle" @click="statusListVisible = true">
|
|
|
|
|
状态
|
|
|
|
|
</view>
|
2025-05-28 11:46:27 +08:00
|
|
|
|
<view class="choiceBox">
|
2025-09-23 16:26:35 +08:00
|
|
|
|
<view class="inputbox" @click="statusListVisible = true">
|
|
|
|
|
<view class="">
|
|
|
|
|
{{ statusName ? statusName : '请选择' }}
|
|
|
|
|
</view>
|
|
|
|
|
<u-icon name="arrow-right" size="24rpx" color="#090000"></u-icon>
|
|
|
|
|
</view>
|
2025-05-28 11:46:27 +08:00
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
<view class="popup_bottom">
|
|
|
|
|
<view class="bottom_btn thebtn1" @click="clearAll">清空筛选条件</view>
|
|
|
|
|
<view
|
|
|
|
|
class="bottom_btn thebtn2"
|
|
|
|
|
@click="
|
|
|
|
|
() => {
|
2025-09-23 16:26:35 +08:00
|
|
|
|
handleSearch(), (popShow = false)
|
2025-05-28 11:46:27 +08:00
|
|
|
|
}
|
|
|
|
|
"
|
|
|
|
|
>{{ '确定' }}
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
<u-picker
|
2025-09-23 16:26:35 +08:00
|
|
|
|
@cancel="stageListVisible = false"
|
|
|
|
|
:show="stageListVisible"
|
2025-05-28 11:46:27 +08:00
|
|
|
|
ref="uPicker"
|
2025-09-23 16:26:35 +08:00
|
|
|
|
:columns="stageList"
|
|
|
|
|
@confirm="stagePickerHandleConfirm"
|
|
|
|
|
keyName="label"
|
|
|
|
|
></u-picker>
|
|
|
|
|
<u-picker
|
|
|
|
|
@cancel="statusListVisible = false"
|
|
|
|
|
:show="statusListVisible"
|
|
|
|
|
ref="uPicker"
|
|
|
|
|
:columns="statusList"
|
|
|
|
|
@confirm="statusPickerHandleConfirm"
|
|
|
|
|
keyName="label"
|
2025-05-28 11:46:27 +08:00
|
|
|
|
></u-picker>
|
|
|
|
|
</u-popup>
|
2025-09-23 16:26:35 +08:00
|
|
|
|
<!-- 子点位选择picker -->
|
|
|
|
|
<u-picker
|
|
|
|
|
@cancel="childNodeListVisible = false"
|
|
|
|
|
:show="childNodeListVisible"
|
|
|
|
|
ref="childNodePicker"
|
|
|
|
|
:columns="childNodeColumns"
|
|
|
|
|
@confirm="childNodePickerHandleConfirm"
|
|
|
|
|
keyName="childNode"
|
|
|
|
|
></u-picker>
|
|
|
|
|
|
2025-05-28 11:46:27 +08:00
|
|
|
|
<Eposter
|
|
|
|
|
width="750"
|
|
|
|
|
height="1334"
|
|
|
|
|
:list="list"
|
|
|
|
|
backgroundColor="rgb(255, 255, 255)"
|
|
|
|
|
@on-success="onSuccess"
|
|
|
|
|
ref="Eposter"
|
|
|
|
|
>
|
|
|
|
|
</Eposter>
|
|
|
|
|
</view>
|
2025-03-23 09:29:40 +08:00
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script>
|
2025-05-28 11:46:27 +08:00
|
|
|
|
import html2canvas from 'html2canvas'
|
|
|
|
|
import TreeChart from '@/components/architectures/resettleSO.vue'
|
|
|
|
|
import Eposter from '@/components/architectures/Poster.vue'
|
|
|
|
|
|
|
|
|
|
import * as arc from '@/config/architecture.js'
|
|
|
|
|
export default {
|
|
|
|
|
components: {
|
|
|
|
|
TreeChart,
|
|
|
|
|
Eposter,
|
|
|
|
|
},
|
|
|
|
|
data() {
|
|
|
|
|
return {
|
2025-09-23 16:26:35 +08:00
|
|
|
|
childNodeList: [],
|
|
|
|
|
childNodeColumns: [[]],
|
|
|
|
|
childNodeListVisible: false,
|
|
|
|
|
selectedChildNodeName: '',
|
2025-05-28 11:46:27 +08:00
|
|
|
|
treeData: [],
|
|
|
|
|
queryParams: {
|
2025-09-23 16:26:35 +08:00
|
|
|
|
childNode: '',
|
|
|
|
|
stage: 1,
|
|
|
|
|
status: 0,
|
2025-05-28 11:46:27 +08:00
|
|
|
|
},
|
2025-09-23 16:26:35 +08:00
|
|
|
|
stageList: [
|
|
|
|
|
[
|
|
|
|
|
{ value: 1, label: '阶段一' },
|
|
|
|
|
{ value: 2, label: '阶段二' },
|
|
|
|
|
{ value: 3, label: '阶段三' },
|
|
|
|
|
],
|
|
|
|
|
], //期数
|
|
|
|
|
statusList: [
|
|
|
|
|
[
|
|
|
|
|
{ value: 0, label: '已完成' },
|
|
|
|
|
{ value: 1, label: '未完成' },
|
|
|
|
|
],
|
|
|
|
|
], //期数
|
2025-05-28 11:46:27 +08:00
|
|
|
|
popShow: false,
|
2025-09-23 16:26:35 +08:00
|
|
|
|
stageListVisible: false,
|
|
|
|
|
statusListVisible: false,
|
|
|
|
|
stageName: '',
|
|
|
|
|
statusName: '',
|
2025-05-28 11:46:27 +08:00
|
|
|
|
data: {},
|
2025-09-23 16:26:35 +08:00
|
|
|
|
size: 0.5,
|
2025-05-28 11:46:27 +08:00
|
|
|
|
landscape: [],
|
|
|
|
|
popMould: {},
|
|
|
|
|
isPop: false,
|
|
|
|
|
touchStartPosition1: {
|
|
|
|
|
x: 0,
|
|
|
|
|
y: 0,
|
|
|
|
|
},
|
|
|
|
|
touchStartPosition2: {
|
|
|
|
|
x: 0,
|
|
|
|
|
y: 0,
|
|
|
|
|
},
|
|
|
|
|
initialDistance: 0,
|
2025-09-23 16:26:35 +08:00
|
|
|
|
initialSize: 0.4, // 记录缩放开始时的初始尺寸
|
|
|
|
|
minSize: 0.2, // 最小缩放值
|
|
|
|
|
maxSize: 3.0, // 最大缩放值
|
|
|
|
|
isZooming: false, // 是否正在缩放
|
|
|
|
|
isDragging: false, // 是否正在拖动
|
|
|
|
|
dragStartPosition: { x: 0, y: 0 }, // 拖动开始位置
|
|
|
|
|
containerTransform: { x: 0, y: 0 }, // 容器变换位置
|
|
|
|
|
lastTouchTime: 0, // 上次触摸时间,用于区分点击和拖动
|
|
|
|
|
lastTouchPosition: { x: 0, y: 0 }, // 上次触摸位置,用于计算速度
|
|
|
|
|
velocity: { x: 0, y: 0 }, // 拖动速度,用于惯性滚动
|
|
|
|
|
maxTransform: { x: 1000, y: 1000 }, // 最大变换距离限制
|
2025-05-28 11:46:27 +08:00
|
|
|
|
list: [],
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
onLoad() {
|
2025-09-23 16:26:35 +08:00
|
|
|
|
this.init()
|
|
|
|
|
this.getChildList().then(() => {
|
|
|
|
|
this.getDataList()
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
mounted() {
|
|
|
|
|
// 初始化容器变换
|
|
|
|
|
this.$nextTick(() => {
|
|
|
|
|
console.log('组件已挂载')
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
computed: {
|
|
|
|
|
containerStyle() {
|
|
|
|
|
return {
|
|
|
|
|
transform: `translate(${this.containerTransform.x}px, ${this.containerTransform.y}px) scale(${this.size})`,
|
|
|
|
|
transformOrigin: 'center center',
|
|
|
|
|
transition:
|
|
|
|
|
this.isDragging || this.isZooming
|
|
|
|
|
? 'none'
|
|
|
|
|
: 'transform 0.1s ease-out',
|
|
|
|
|
}
|
|
|
|
|
},
|
2025-05-28 11:46:27 +08:00
|
|
|
|
},
|
|
|
|
|
methods: {
|
2025-09-23 16:26:35 +08:00
|
|
|
|
init() {
|
|
|
|
|
this.stageName = this.stageList[0][0].label
|
|
|
|
|
this.statusName = this.statusList[0][0].label
|
|
|
|
|
this.queryParams.stage = this.stageList[0][0].value
|
|
|
|
|
this.queryParams.status = this.statusList[0][0].value
|
|
|
|
|
},
|
2025-05-28 11:46:27 +08:00
|
|
|
|
//复制文字
|
|
|
|
|
copyText() {
|
|
|
|
|
let self = this
|
|
|
|
|
let md = self.popMould
|
|
|
|
|
let text = `会员编号:${md.memberCode} \n会员姓名:${md.name}支付时间:${md.payDate} \n业绩 左区 右区 \n真实新增 ${md.leftRealNewPv} ${md.rightRealNewPv} \n首购新增 ${md.leftFirstPurchaseAdd} ${md.rightFirstPurchaseAdd} \n复购新增 ${md.leftRepeatPurchaseSurplus} ${md.rightRepeatPurchaseSurplus} \n真实累计 ${md.leftRealTotal} ${md.rightRealTotal} \n首购累计 ${md.leftFirstTotal} ${md.rightFirstTotal} \n复购累计 ${md.leftRepeatPurchaseTotal} ${md.rightRepeatPurchaseTotal} \n首购结余 ${md.leftFirstSurplus} ${md.rightFirstSurplus} \n复购结余 ${md.leftRepeatPurchaseSurplus} ${md.rightRepeatPurchaseSurplus} \n`
|
|
|
|
|
uni.setClipboardData({
|
|
|
|
|
data: text,
|
|
|
|
|
success: function (res) {
|
|
|
|
|
uni.getClipboardData({
|
|
|
|
|
success: function (res) {
|
|
|
|
|
uni.showToast({
|
|
|
|
|
title: '复制成功',
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
//下载图片
|
|
|
|
|
downImage(elClass) {
|
|
|
|
|
this.$refs.Eposter.createForElRect(elClass, false)
|
|
|
|
|
},
|
|
|
|
|
downloadImg() {
|
|
|
|
|
let self = this
|
|
|
|
|
let element = document.querySelector('.Poster1')
|
|
|
|
|
uni.showLoading({
|
|
|
|
|
title: '图片保存中',
|
|
|
|
|
})
|
|
|
|
|
html2canvas(element)
|
|
|
|
|
.then(function (canvas) {
|
|
|
|
|
let dataURL = canvas.toDataURL('image/jpeg')
|
|
|
|
|
let link = document.createElement('a')
|
|
|
|
|
link.style.display = 'none'
|
|
|
|
|
link.href = dataURL
|
|
|
|
|
link.download = 'image.jpg'
|
|
|
|
|
document.body.appendChild(link)
|
|
|
|
|
link.click()
|
|
|
|
|
document.body.removeChild(link)
|
|
|
|
|
uni.showToast({
|
|
|
|
|
icon: 'none',
|
|
|
|
|
title: '保存成功',
|
|
|
|
|
duration: 2000,
|
|
|
|
|
})
|
|
|
|
|
uni.hideLoading()
|
|
|
|
|
})
|
|
|
|
|
.catch(function (error) {
|
|
|
|
|
uni.hideLoading()
|
|
|
|
|
uni.showModal({
|
|
|
|
|
title: '保存失败',
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
onSuccess(val) {
|
|
|
|
|
// console.log('🌈val',val)
|
|
|
|
|
this.posterImg = val
|
|
|
|
|
this.downloadImg(this.posterImg)
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
handleTouchStart(event) {
|
2025-09-23 16:26:35 +08:00
|
|
|
|
console.log('handleTouchStart triggered', event.touches.length)
|
2025-05-28 11:46:27 +08:00
|
|
|
|
const touch1 = event.touches[0]
|
|
|
|
|
const touch2 = event.touches[1]
|
2025-09-23 16:26:35 +08:00
|
|
|
|
const currentTime = Date.now()
|
|
|
|
|
|
2025-05-28 11:46:27 +08:00
|
|
|
|
if (touch2) {
|
2025-09-23 16:26:35 +08:00
|
|
|
|
// 双指触摸 - 缩放模式
|
|
|
|
|
this.isZooming = true
|
|
|
|
|
this.isDragging = false
|
|
|
|
|
this.initialSize = this.size
|
|
|
|
|
|
2025-05-28 11:46:27 +08:00
|
|
|
|
this.touchStartPosition1 = {
|
2025-09-23 16:26:35 +08:00
|
|
|
|
x: touch1.clientX,
|
|
|
|
|
y: touch1.clientY,
|
2025-05-28 11:46:27 +08:00
|
|
|
|
}
|
|
|
|
|
this.touchStartPosition2 = {
|
2025-09-23 16:26:35 +08:00
|
|
|
|
x: touch2.clientX,
|
|
|
|
|
y: touch2.clientY,
|
2025-05-28 11:46:27 +08:00
|
|
|
|
}
|
|
|
|
|
this.initialDistance = Math.hypot(
|
2025-09-23 16:26:35 +08:00
|
|
|
|
touch2.clientX - touch1.clientX,
|
|
|
|
|
touch2.clientY - touch1.clientY
|
2025-05-28 11:46:27 +08:00
|
|
|
|
)
|
2025-09-23 16:26:35 +08:00
|
|
|
|
} else {
|
|
|
|
|
// 单指触摸 - 拖动模式
|
|
|
|
|
this.isZooming = false
|
|
|
|
|
this.isDragging = true
|
|
|
|
|
this.dragStartPosition = {
|
|
|
|
|
x: touch1.clientX,
|
|
|
|
|
y: touch1.clientY,
|
|
|
|
|
}
|
|
|
|
|
this.lastTouchTime = currentTime
|
2025-05-28 11:46:27 +08:00
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
handleTouchMove(event) {
|
|
|
|
|
const touch1 = event.touches[0]
|
|
|
|
|
const touch2 = event.touches[1]
|
2025-09-23 16:26:35 +08:00
|
|
|
|
|
|
|
|
|
if (touch2 && this.isZooming && this.initialDistance > 0) {
|
|
|
|
|
// 双指缩放处理
|
2025-05-28 11:46:27 +08:00
|
|
|
|
const currentDistance = Math.hypot(
|
2025-09-23 16:26:35 +08:00
|
|
|
|
touch2.clientX - touch1.clientX,
|
|
|
|
|
touch2.clientY - touch1.clientY
|
2025-05-28 11:46:27 +08:00
|
|
|
|
)
|
2025-09-23 16:26:35 +08:00
|
|
|
|
|
2025-05-28 11:46:27 +08:00
|
|
|
|
const scale = currentDistance / this.initialDistance
|
2025-09-23 16:26:35 +08:00
|
|
|
|
let newSize = this.initialSize * scale
|
|
|
|
|
|
|
|
|
|
// 应用边界限制
|
|
|
|
|
newSize = Math.max(this.minSize, Math.min(this.maxSize, newSize))
|
|
|
|
|
|
|
|
|
|
// 平滑缩放
|
|
|
|
|
const sizeDiff = newSize - this.size
|
|
|
|
|
this.size = this.size + sizeDiff * 0.3
|
|
|
|
|
} else if (!touch2 && this.isDragging) {
|
|
|
|
|
// 单指拖动处理
|
|
|
|
|
const deltaX = touch1.clientX - this.dragStartPosition.x
|
|
|
|
|
const deltaY = touch1.clientY - this.dragStartPosition.y
|
|
|
|
|
|
|
|
|
|
console.log('拖动中', {
|
|
|
|
|
deltaX,
|
|
|
|
|
deltaY,
|
|
|
|
|
touch: { x: touch1.clientX, y: touch1.clientY },
|
|
|
|
|
dragStart: this.dragStartPosition,
|
|
|
|
|
containerTransform: this.containerTransform,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// 计算拖动速度
|
|
|
|
|
this.velocity.x = deltaX * 0.1
|
|
|
|
|
this.velocity.y = deltaY * 0.1
|
|
|
|
|
|
|
|
|
|
// 更新容器变换位置(添加阻尼效果)
|
|
|
|
|
let newX = this.containerTransform.x + deltaX * 0.8
|
|
|
|
|
let newY = this.containerTransform.y + deltaY * 0.8
|
|
|
|
|
|
|
|
|
|
// 应用边界限制(根据缩放调整边界)
|
|
|
|
|
const scaledMaxX = this.maxTransform.x * this.size
|
|
|
|
|
const scaledMaxY = this.maxTransform.y * this.size
|
|
|
|
|
|
|
|
|
|
newX = Math.max(-scaledMaxX, Math.min(scaledMaxX, newX))
|
|
|
|
|
newY = Math.max(-scaledMaxY, Math.min(scaledMaxY, newY))
|
|
|
|
|
|
|
|
|
|
this.containerTransform.x = newX
|
|
|
|
|
this.containerTransform.y = newY
|
|
|
|
|
|
|
|
|
|
// 更新拖动起始位置
|
|
|
|
|
this.dragStartPosition.x = touch1.clientX
|
|
|
|
|
this.dragStartPosition.y = touch1.clientY
|
|
|
|
|
|
|
|
|
|
// 应用变换到DOM元素
|
|
|
|
|
this.updateContainerTransform()
|
2025-05-28 11:46:27 +08:00
|
|
|
|
}
|
|
|
|
|
},
|
2025-09-23 16:26:35 +08:00
|
|
|
|
handleTouchEnd(event) {
|
|
|
|
|
const currentTime = Date.now()
|
|
|
|
|
const touchDuration = currentTime - this.lastTouchTime
|
|
|
|
|
|
|
|
|
|
// 如果是拖动结束,启动惯性滚动
|
|
|
|
|
if (
|
|
|
|
|
this.isDragging &&
|
|
|
|
|
(Math.abs(this.velocity.x) > 1 || Math.abs(this.velocity.y) > 1)
|
|
|
|
|
) {
|
|
|
|
|
this.startInertiaScroll()
|
2025-05-28 11:46:27 +08:00
|
|
|
|
}
|
2025-09-23 16:26:35 +08:00
|
|
|
|
|
|
|
|
|
// 重置触摸状态
|
|
|
|
|
this.isZooming = false
|
|
|
|
|
this.isDragging = false
|
|
|
|
|
this.touchStartPosition1 = { x: 0, y: 0 }
|
|
|
|
|
this.touchStartPosition2 = { x: 0, y: 0 }
|
2025-05-28 11:46:27 +08:00
|
|
|
|
this.initialDistance = 0
|
2025-09-23 16:26:35 +08:00
|
|
|
|
this.initialSize = this.size
|
|
|
|
|
this.dragStartPosition = { x: 0, y: 0 }
|
2025-05-28 11:46:27 +08:00
|
|
|
|
},
|
2025-09-23 16:26:35 +08:00
|
|
|
|
|
|
|
|
|
// 惯性滚动
|
|
|
|
|
startInertiaScroll() {
|
|
|
|
|
const friction = 0.95 // 摩擦系数
|
|
|
|
|
const minVelocity = 0.1 // 最小速度阈值
|
|
|
|
|
|
|
|
|
|
const animateInertia = () => {
|
|
|
|
|
// 应用速度到位置
|
|
|
|
|
let newX = this.containerTransform.x + this.velocity.x
|
|
|
|
|
let newY = this.containerTransform.y + this.velocity.y
|
|
|
|
|
|
|
|
|
|
// 应用边界限制
|
|
|
|
|
const scaledMaxX = this.maxTransform.x * this.size
|
|
|
|
|
const scaledMaxY = this.maxTransform.y * this.size
|
|
|
|
|
|
|
|
|
|
newX = Math.max(-scaledMaxX, Math.min(scaledMaxX, newX))
|
|
|
|
|
newY = Math.max(-scaledMaxY, Math.min(scaledMaxY, newY))
|
|
|
|
|
|
|
|
|
|
this.containerTransform.x = newX
|
|
|
|
|
this.containerTransform.y = newY
|
|
|
|
|
|
|
|
|
|
// 减少速度
|
|
|
|
|
this.velocity.x *= friction
|
|
|
|
|
this.velocity.y *= friction
|
|
|
|
|
|
|
|
|
|
// 更新DOM
|
|
|
|
|
this.updateContainerTransform()
|
|
|
|
|
|
|
|
|
|
// 继续动画或停止
|
|
|
|
|
if (
|
|
|
|
|
Math.abs(this.velocity.x) > minVelocity ||
|
|
|
|
|
Math.abs(this.velocity.y) > minVelocity
|
|
|
|
|
) {
|
|
|
|
|
requestAnimationFrame(animateInertia)
|
|
|
|
|
}
|
2025-05-28 11:46:27 +08:00
|
|
|
|
}
|
2025-09-23 16:26:35 +08:00
|
|
|
|
|
|
|
|
|
requestAnimationFrame(animateInertia)
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 更新容器变换 - 现在使用响应式样式,这个方法可以简化
|
|
|
|
|
updateContainerTransform() {
|
|
|
|
|
// 使用响应式计算属性,无需手动更新DOM
|
|
|
|
|
console.log('容器变换更新', this.containerTransform, this.size)
|
2025-05-28 11:46:27 +08:00
|
|
|
|
},
|
2025-09-23 16:26:35 +08:00
|
|
|
|
// 重置缩放和位置到默认状态
|
|
|
|
|
resetZoom() {
|
|
|
|
|
this.size = 0.4
|
|
|
|
|
this.initialSize = 0.4
|
|
|
|
|
this.containerTransform = { x: 0, y: 0 }
|
|
|
|
|
this.updateContainerTransform()
|
2025-05-28 11:46:27 +08:00
|
|
|
|
},
|
2025-09-23 16:26:35 +08:00
|
|
|
|
|
|
|
|
|
// 双击重置缩放和位置
|
|
|
|
|
handleDoubleClick() {
|
|
|
|
|
this.resetZoom()
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
clickNode(e) {
|
|
|
|
|
return
|
|
|
|
|
},
|
|
|
|
|
stagePickerHandleConfirm(e) {
|
|
|
|
|
this.queryParams.memberSettlePeriodId = e.value[0].value
|
|
|
|
|
this.stageName = e.value[0].label
|
|
|
|
|
this.stageListVisible = false
|
|
|
|
|
},
|
|
|
|
|
statusPickerHandleConfirm(e) {
|
|
|
|
|
this.queryParams.status = e.value[0].value
|
|
|
|
|
this.statusName = e.value[0].label
|
|
|
|
|
this.statusListVisible = false
|
|
|
|
|
},
|
|
|
|
|
childNodePickerHandleConfirm(e) {
|
|
|
|
|
this.queryParams.memberCode = e.value[0].childNode
|
|
|
|
|
this.selectedChildNodeName = e.value[0].childNode
|
|
|
|
|
this.childNodeListVisible = false
|
|
|
|
|
// 选择子点位后自动获取数据
|
|
|
|
|
this.getDataList()
|
|
|
|
|
},
|
|
|
|
|
getChildList() {
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
arc.getChildList(this.queryParams).then(res => {
|
|
|
|
|
if (res.code === 200) {
|
|
|
|
|
this.childNodeList = res.data
|
|
|
|
|
// 格式化为picker需要的数据格式
|
|
|
|
|
this.childNodeColumns = [res.data]
|
|
|
|
|
this.queryParams.childNode = res.data[0].childNode
|
|
|
|
|
this.selectedChildNodeName = res.data[0].childNode
|
|
|
|
|
resolve()
|
|
|
|
|
}
|
|
|
|
|
})
|
2025-05-28 11:46:27 +08:00
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
getDataList() {
|
|
|
|
|
arc.getAzFramework(this.queryParams).then(res => {
|
|
|
|
|
this.data = res.data[0]
|
|
|
|
|
})
|
|
|
|
|
},
|
2025-09-23 16:26:35 +08:00
|
|
|
|
handleSearch() {
|
|
|
|
|
this.getChildList().then(() => {
|
|
|
|
|
this.getDataList()
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
|
2025-05-28 11:46:27 +08:00
|
|
|
|
clearAll() {
|
|
|
|
|
this.popShow = false
|
2025-09-23 16:26:35 +08:00
|
|
|
|
this.init()
|
2025-05-28 11:46:27 +08:00
|
|
|
|
this.queryParams = {
|
2025-09-23 16:26:35 +08:00
|
|
|
|
stage: this.stageList[0][0].value,
|
|
|
|
|
status: this.statusList[0][0].value,
|
2025-05-28 11:46:27 +08:00
|
|
|
|
}
|
2025-09-23 16:26:35 +08:00
|
|
|
|
this.handleSearch()
|
2025-05-28 11:46:27 +08:00
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
2025-03-23 09:29:40 +08:00
|
|
|
|
</script>
|
|
|
|
|
<style lang="scss" scoped>
|
2025-05-28 11:46:27 +08:00
|
|
|
|
.ispop_box {
|
|
|
|
|
padding: 27rpx;
|
|
|
|
|
padding-top: 60rpx;
|
|
|
|
|
width: 670rpx;
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
color: #333333;
|
|
|
|
|
|
|
|
|
|
.pop_top {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
|
|
.poster1 {
|
|
|
|
|
height: 88rpx;
|
|
|
|
|
width: 88rpx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.poster2 {
|
|
|
|
|
width: 88rpx;
|
|
|
|
|
height: 54rpx;
|
|
|
|
|
border-radius: 10rpx;
|
|
|
|
|
margin-left: 20rpx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.top_right {
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
align-items: center;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.pop_center {
|
|
|
|
|
.center_flex {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
margin-top: 20rpx;
|
|
|
|
|
|
|
|
|
|
.c1 {
|
|
|
|
|
width: 20%;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.c2 {
|
|
|
|
|
width: 80%;
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
align-items: center;
|
|
|
|
|
background: #f3f3f3;
|
|
|
|
|
border: 2rpx solid #eeeeee;
|
|
|
|
|
border-radius: 8rpx;
|
|
|
|
|
padding: 10rpx 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.pop_bottom {
|
|
|
|
|
margin: 20rpx 0;
|
|
|
|
|
border-top: 2rpx solid #eeeeee;
|
|
|
|
|
border-top: 2rpx solid #eeeeee;
|
|
|
|
|
|
|
|
|
|
.b_flex {
|
|
|
|
|
display: flex;
|
|
|
|
|
|
|
|
|
|
.bt1 {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
align-items: center;
|
|
|
|
|
margin-top: 22rpx;
|
|
|
|
|
flex: 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.bt2 {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
align-items: center;
|
|
|
|
|
margin-top: 22rpx;
|
|
|
|
|
flex: 1;
|
|
|
|
|
background: #f3f3f3;
|
|
|
|
|
border: 2rpx solid #eeeeee;
|
|
|
|
|
border-radius: 8rpx;
|
|
|
|
|
padding: 12rpx 0;
|
|
|
|
|
margin: 11rpx 18rpx;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.btn_box {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
|
|
|
|
.small-btn {
|
|
|
|
|
width: 312rpx;
|
|
|
|
|
height: 72rpx;
|
|
|
|
|
background: #005bac;
|
|
|
|
|
border-radius: 34rpx;
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
font-weight: 400;
|
|
|
|
|
color: #ffffff;
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
align-items: center;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.small-text-btn {
|
|
|
|
|
width: 312rpx;
|
|
|
|
|
height: 72rpx;
|
|
|
|
|
border: 1px solid #005bac;
|
|
|
|
|
border-radius: 34rpx;
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
align-items: center;
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
color: #005bac;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.operate-btnboxs {
|
|
|
|
|
padding: 29rpx 26rpx;
|
|
|
|
|
background-color: #ffffff;
|
|
|
|
|
|
|
|
|
|
.d-c-c {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
|
|
|
|
.operate-btn {
|
|
|
|
|
width: 64rpx;
|
|
|
|
|
height: 64rpx;
|
|
|
|
|
margin: 5rpx;
|
|
|
|
|
// background: #F2F2F2;
|
|
|
|
|
border-radius: 5rpx;
|
|
|
|
|
padding: 0;
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
align-items: center;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.rightPopup {
|
|
|
|
|
width: 645rpx;
|
|
|
|
|
height: 100%;
|
|
|
|
|
overflow: auto;
|
|
|
|
|
|
|
|
|
|
.popup_top {
|
|
|
|
|
padding: 25rpx;
|
|
|
|
|
background-color: rgba(176, 196, 222, 0.45);
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
align-items: center;
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
font-family: Source Han Sans CN;
|
|
|
|
|
font-weight: 400;
|
|
|
|
|
color: #333333;
|
|
|
|
|
|
|
|
|
|
.top_red {
|
|
|
|
|
color: #005bac;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.popup_bottom {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
position: absolute;
|
|
|
|
|
left: 0;
|
|
|
|
|
bottom: 0;
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
|
|
|
|
.bottom_btn {
|
|
|
|
|
flex: 1;
|
|
|
|
|
padding: 20rpx 0;
|
|
|
|
|
text-align: center;
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.thebtn1 {
|
|
|
|
|
background-color: rgba(176, 196, 222, 0.45);
|
|
|
|
|
color: #333333;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.thebtn2 {
|
|
|
|
|
background-color: #005bac;
|
|
|
|
|
color: #ffffff;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.typesBox {
|
|
|
|
|
margin-top: 40rpx;
|
|
|
|
|
|
|
|
|
|
.typeTitle {
|
|
|
|
|
padding: 0 24rpx;
|
|
|
|
|
font-size: 30rpx;
|
|
|
|
|
font-family: Source Han Sans CN;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
color: #333333;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.choiceBox {
|
|
|
|
|
padding: 0 12rpx;
|
|
|
|
|
display: flex;
|
|
|
|
|
margin-top: 17rpx;
|
|
|
|
|
align-items: center;
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
|
|
|
|
.inputbox {
|
|
|
|
|
font-size: 26rpx;
|
|
|
|
|
width: 100%;
|
|
|
|
|
padding: 20rpx 32rpx;
|
|
|
|
|
border-radius: 20rpx;
|
|
|
|
|
background-color: rgba(176, 196, 222, 0.45);
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
align-items: center;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.flex_btn {
|
|
|
|
|
background-color: rgba(176, 196, 222, 0.45);
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
padding: 14rpx 48rpx;
|
|
|
|
|
border-radius: 26rpx;
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
font-family: Source Han Sans CN;
|
|
|
|
|
font-weight: 400;
|
|
|
|
|
color: #333333;
|
|
|
|
|
margin: 17rpx 5rpx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.timesbtn {
|
|
|
|
|
flex: 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.selectbtn {
|
|
|
|
|
background-color: #005bac;
|
|
|
|
|
color: #ffffff;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.seach {
|
|
|
|
|
background: #fff;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
padding: 20rpx 23rpx;
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
align-items: center;
|
|
|
|
|
position: relative;
|
|
|
|
|
border-bottom: 2rpx solid #eee;
|
|
|
|
|
|
|
|
|
|
.these {
|
|
|
|
|
border: none;
|
|
|
|
|
padding: 10rpx 0 !important;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.seach_i {
|
|
|
|
|
padding: 0 20rpx;
|
|
|
|
|
border-radius: 34rpx;
|
|
|
|
|
background: #fff;
|
|
|
|
|
flex: 1;
|
|
|
|
|
background: #f5f6f8;
|
|
|
|
|
margin: 0 20rpx;
|
2025-09-23 16:26:35 +08:00
|
|
|
|
|
|
|
|
|
.inputbox {
|
|
|
|
|
font-size: 26rpx;
|
|
|
|
|
width: 100%;
|
|
|
|
|
padding: 15rpx 20rpx;
|
|
|
|
|
border-radius: 34rpx;
|
|
|
|
|
background-color: #f5f6f8;
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
align-items: center;
|
|
|
|
|
color: #333333;
|
|
|
|
|
|
|
|
|
|
&:active {
|
|
|
|
|
background-color: #e8e9eb;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-05-28 11:46:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.neibox {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
font-size: 26rpx;
|
|
|
|
|
font-family: PingFang SC;
|
|
|
|
|
font-weight: 400;
|
|
|
|
|
color: #999999;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.seatch_r {
|
|
|
|
|
background: #005bac;
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
padding: 8rpx;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.mainbox {
|
|
|
|
|
padding: 26rpx 22rpx;
|
2025-09-23 16:26:35 +08:00
|
|
|
|
height: 100%;
|
2025-05-28 11:46:27 +08:00
|
|
|
|
|
|
|
|
|
.main_bottom {
|
|
|
|
|
width: 100%;
|
2025-09-23 16:26:35 +08:00
|
|
|
|
height: 100%;
|
2025-05-28 11:46:27 +08:00
|
|
|
|
margin-top: 25rpx;
|
|
|
|
|
background-color: #ffffff;
|
|
|
|
|
padding: 38rpx 0;
|
|
|
|
|
|
|
|
|
|
border-radius: 20rpx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.scoll_main {
|
|
|
|
|
width: 700rpx;
|
|
|
|
|
|
2025-09-23 16:26:35 +08:00
|
|
|
|
transform-origin: center center; // 设置变换原点为中心
|
|
|
|
|
cursor: grab; // 显示可拖动光标
|
|
|
|
|
|
|
|
|
|
&:active {
|
|
|
|
|
cursor: grabbing; // 拖动时的光标
|
|
|
|
|
}
|
2025-05-28 11:46:27 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</style>
|