feat(arch): 阶段架构方案一功能实现

This commit is contained in:
woody 2025-09-23 16:26:35 +08:00
parent 4b26ae1ab7
commit 01586fb27d
7 changed files with 857 additions and 754 deletions

View File

@ -1,326 +1,433 @@
<template> <template>
<view class="table pr" :style="'zoom:'+size+';'"> <view class="table pr" :style="'zoom:' + size + ';'">
<view class="v-tr" style="display: flex;"> <view class="v-tr" style="display: flex">
<view class="v-td" :class="{ <view
colspan: Array.isArray(treeData.children) ? treeData.children.length * 2 : 1, class="v-td"
parentLevel: Array.isArray(treeData.children) && treeData.children.length, :class="{
extend: Array.isArray(treeData.children) && treeData.children.length && treeData.extend colspan: Array.isArray(treeData.children)
}"> ? treeData.children.length * 2
<view :class="{ node: true }"> : 1,
<view class="person" :class="Array.isArray(treeData.class) ? treeData.class : []"> parentLevel:
<image @click.stop="clickNode(treeData)" class="person-ava" :src="treeData.avatarUrl" mode=""></image> Array.isArray(treeData.children) && treeData.children.length,
</view> extend:
</view> Array.isArray(treeData.children) &&
</view> treeData.children.length &&
</view> treeData.extend,
<view class="v-tr" v-if="Array.isArray(treeData.children) && treeData.children.length && treeData.extend"> }"
<view v-for="(children, index) in treeData.children" :key="index" colspan="2" class="childLevel v-td"> >
<TreeChart :json="children" :left="0" :top="0" @click-node="clickNode" /> <view :class="{ node: true }">
</view> <view
</view> class="person"
</view> :class="Array.isArray(treeData.class) ? treeData.class : []"
>
<view class="frame-text">
<view style="font-weight: bold">{{
treeData.nodeCode === '0-root' ? '' : treeData.nodeCode
}}</view>
<view v-if="treeData.memberCode && treeData.memberName">
<view> {{ treeData.memberCode }}</view>
<view>{{ treeData.memberName }}</view>
</view>
<view v-else> 空点位 </view>
</view>
</view>
</view>
</view>
</view>
<view
class="v-tr"
v-if="
Array.isArray(treeData.children) &&
treeData.children.length &&
treeData.extend
"
>
<view
v-for="(children, index) in treeData.children"
:key="index"
colspan="2"
class="childLevel v-td"
>
<TreeChart
:json="children"
:left="0"
:top="0"
@click-node="clickNode"
@click-top="clickTop"
/>
</view>
</view>
</view>
</template> </template>
<script> <script>
export default { export default {
name: 'TreeChart', name: 'TreeChart',
props: ['json', 'size'], props: ['json', 'size'],
data() { data() {
return { return {
treeData: {} treeData: {},
}; }
}, },
watch: { watch: {
json: { json: {
handler: function(Props) { handler: function (Props) {
let extendKey = function(jsonData) { let extendKey = function (jsonData) {
jsonData.extend = jsonData.extend === void 0 ? true : !!jsonData.extend; jsonData.extend =
if (Array.isArray(jsonData.children)) { jsonData.extend === void 0 ? true : !!jsonData.extend
jsonData.children.forEach(c => { if (Array.isArray(jsonData.children)) {
extendKey(c); jsonData.children.forEach(c => {
}); extendKey(c)
} })
return jsonData; }
}; return jsonData
if (Props) { }
this.treeData = extendKey(Props); if (Props) {
} this.treeData = extendKey(Props)
}, }
immediate: true },
} immediate: true,
}, },
methods: { },
toggleExtend: function(treeData) { methods: {
treeData.extend = !treeData.extend; toggleExtend: function (treeData) {
this.$forceUpdate(); treeData.extend = !treeData.extend
}, this.$forceUpdate()
clickNode(e){ },
this.$emit('click-node',e) clickNode(e) {
} this.$emit('click-node', e)
} },
}; clickTop(e) {
this.$emit('click-top', e)
},
},
}
</script> </script>
<style scoped> <style scoped>
.f18 { .f18 {
font-size: 18rpx; font-size: 18rpx;
} }
.pv-btn { .pv-btn {
width: 200rpx; width: 200rpx;
height: 50rpx; height: 50rpx;
background-color: #b2821e; background: #007bff;
color: #fff; color: #fff;
font-size: 20rpx; font-size: 20rpx;
line-height: 50rpx; line-height: 50rpx;
display: flex; display: flex;
align-items: center; align-items: center;
margin: auto; margin: auto;
margin-top: 12rpx; margin-top: 12rpx;
margin-bottom: 12rpx; margin-bottom: 12rpx;
} border-radius: 8rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 123, 255, 0.2);
transition: all 0.3s ease;
}
.next-btn { .pv-btn:hover {
border-radius: 50%; background: #0056b3;
background: none; transform: translateY(-1rpx);
width: 40rpx; box-shadow: 0 4rpx 12rpx rgba(0, 123, 255, 0.3);
height: 40rpx; }
margin: auto;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
}
.table { .next-btn {
border-collapse: separate !important; border-radius: 50%;
border-spacing: 0 !important; background: #6c757d;
width: 100%; width: 40rpx;
} height: 40rpx;
margin: auto;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
box-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
}
.v-tr { .next-btn:hover {
background: #495057;
display: inline-flex; transform: scale(1.05);
justify-content: center; box-shadow: 0 4rpx 8rpx rgba(0, 0, 0, 0.15);
align-items: flex-start; }
/* width: 100%; */
} .table {
border-collapse: separate !important;
border-spacing: 0 !important;
width: 100%;
/* background: #f8f9fa; */
padding: 40rpx 0;
}
.v-td { .v-tr {
position: relative; display: inline-flex;
vertical-align: top; justify-content: center;
padding: 0 0 100rpx 0; align-items: flex-start;
text-align: center; width: 100%;
} }
.extend_handle { .v-td {
position: absolute; position: relative;
left: 50%; vertical-align: top;
bottom: 30rpx; padding: 0 0 130rpx 0;
width: 10rpx; text-align: center;
height: 10rpx; }
padding: 10rpx;
transform: translate3d(-30rpx, 0, 0);
cursor: pointer;
}
.extend_handle:before { .extend_handle {
content: ''; position: absolute;
display: block; left: 50%;
width: 100%; bottom: 30rpx;
height: 100%; width: 10rpx;
box-sizing: border-box; height: 10rpx;
border: 4rpx solid; padding: 10rpx;
border-color: #f2f2f2 #f2f2f2 transparent transparent; transform: translate3d(-30rpx, 0, 0);
transform: rotateZ(135deg); cursor: pointer;
transform-origin: 50% 50% 0; transition: all 0.3s ease;
transition: transform ease 300ms; }
}
.extend_handle:hover:before { .extend_handle:before {
border-color: #f2f2f2 #f2f2f2 transparent transparent; content: '';
} display: block;
width: 100%;
height: 100%;
box-sizing: border-box;
border: 4rpx solid;
border-color: #6c757d #6c757d transparent transparent;
transform: rotateZ(135deg);
transform-origin: 50% 50% 0;
transition: all 0.3s ease;
}
.extend .extend_handle:before { .extend_handle:hover:before {
transform: rotateZ(-45deg); border-color: #495057 #495057 transparent transparent;
} transform: rotateZ(135deg) scale(1.1);
}
.extend::after { .extend .extend_handle:before {
content: ''; transform: rotateZ(-45deg);
position: absolute; }
left: 50%;
bottom: 84rpx;
height: 84rpx;
border-left: 4rpx solid #f2f2f2;
transform: translate3d(-2rpx, 0, 0);
}
.childLevel::before { .extend .extend_handle:hover:before {
content: ''; transform: rotateZ(-45deg) scale(1.1);
position: absolute; }
left: 50%;
bottom: 100%;
height: 84rpx;
border-left: 4rpx solid #f2f2f2;
transform: translate3d(-2rpx, 0, 0);
}
.childLevel::after { .extend::after {
content: ''; content: '';
position: absolute; position: absolute;
left: 0; left: 50%;
right: 0; bottom: 84rpx;
top: -88rpx; height: 84rpx;
border-top: 4rpx solid #f2f2f2; border-left: 4rpx solid #dee2e6;
} transform: translate3d(-2rpx, 0, 0);
}
.childLevel:first-child:before, .childLevel::before {
.childLevel:last-child:before { content: '';
display: none; position: absolute;
} left: 50%;
bottom: 100%;
height: 84rpx;
border-left: 4rpx solid #dee2e6;
transform: translate3d(-2rpx, 0, 0);
}
.childLevel:first-child:after { .childLevel::after {
left: 50%; content: '';
height: 84rpx; position: absolute;
border: 4rpx solid; left: 0;
border-color: #f2f2f2 transparent transparent #f2f2f2; right: 0;
border-radius: 6rpx 0 0 0; top: -88rpx;
transform: translate3d(2rpx, 0, 0); border-top: 4rpx solid #dee2e6;
} }
.childLevel:last-child:after { .childLevel:first-child:before,
right: 50%; .childLevel:last-child:before {
height: 84rpx; display: none;
border: 4rpx solid; }
border-color: #f2f2f2 #f2f2f2 transparent transparent;
border-radius: 0 6rpx 0 0;
transform: translate3d(-2rpx, 0, 0);
}
.childLevel:first-child.childLevel:last-child::after { .childLevel:first-child:after {
left: auto; left: 50%;
border-radius: 0; height: 84rpx;
border-color: transparent #f2f2f2 transparent transparent; border: 4rpx solid;
transform: translate3d(2rpx, 0, 0); border-color: #dee2e6 transparent transparent #dee2e6;
} border-radius: 8rpx 0 0 0;
transform: translate3d(2rpx, 0, 0);
}
.node { .childLevel:last-child:after {
position: relative; right: 50%;
display: inline-block; height: 84rpx;
margin: 0 10rpx; border: 4rpx solid;
box-sizing: border-box; border-color: #dee2e6 #dee2e6 transparent transparent;
text-align: center; border-radius: 0 8rpx 0 0;
} transform: translate3d(-2rpx, 0, 0);
}
.node .person { .childLevel:first-child.childLevel:last-child::after {
position: relative; left: auto;
display: inline-block; border-radius: 0;
z-index: 2; border-color: transparent #dee2e6 transparent transparent;
width: 104rpx; transform: translate3d(2rpx, 0, 0);
height: 104rpx; }
}
.node .person .person-ava { .node {
width: 104rpx; position: relative;
height: 104rpx; display: inline-block;
} margin: 0 10rpx;
box-sizing: border-box;
text-align: center;
}
.node .person .avat { .node .person {
display: block; position: relative;
width: 4em; display: inline-block;
height: 4em; z-index: 2;
margin: auto; width: fit-content;
overflow: hidden; padding: 20rpx;
background: #fff; background: #ffffff;
border: 4px solid #f2f2f2; box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1);
box-sizing: border-box; border-radius: 16rpx;
border-radius: 0.5em; border: 2rpx solid #e9ecef;
} transition: all 0.3s ease;
cursor: pointer;
}
.node .person .avat img { .node .person:hover {
width: 100%; transform: translateY(-4rpx);
height: 100%; box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.15);
} border-color: #6c757d;
}
.node .person .name { .node .person:active {
display: block; transform: translateY(-2rpx);
margin: auto; box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
overflow: hidden; }
box-sizing: border-box;
overflow: hidden;
font-size: 20rpx;
line-height: 1.5;
padding-top: 24rpx;
}
.node .person .name-bottom { .node .person .person-ava {
display: block; width: 88rpx;
margin: auto; height: 53rpx;
overflow: hidden; border-radius: 15rpx;
border-top: none; box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
box-sizing: border-box; }
overflow: hidden;
}
.node .person .operation {} .frame-text {
border-radius: 8rpx;
font-size: 22rpx;
margin: 0 auto;
color: #495057;
font-weight: 500;
line-height: 1.4;
}
.node.hasMate::after { .frame-text view:first-child {
content: ''; font-weight: 600;
position: absolute; font-size: 24rpx;
left: 2em; margin-bottom: 4rpx;
right: 2em; color: #212529;
top: 2em; }
border-top: 4px solid #f2f2f2;
z-index: 1;
}
/* 横板 */ .frame-text view:not(:first-child) {
.landscape { font-size: 20rpx;
transform: translate(-100%, 0) rotate(-90deg); color: #6c757d;
transform-origin: 100% 0; margin-bottom: 2rpx;
} }
.landscape .node { .node .person .avat {
text-align: left; display: block;
height: 8em; width: 4em;
width: 8em; height: 4em;
} margin: auto;
overflow: hidden;
background: #f8f9fa;
border: 4px solid #e9ecef;
box-sizing: border-box;
border-radius: 1em;
}
.landscape .person { .node .person .avat img {
position: relative; width: 100%;
transform: rotate(90deg); height: 100%;
padding-left: 4.5em; border-radius: inherit;
height: 4em; }
top: 4em;
left: -1em;
}
.landscape .person .avat { .node .person .name {
position: absolute; display: block;
left: 0; margin: auto;
} overflow: hidden;
box-sizing: border-box;
font-size: 20rpx;
line-height: 1.5;
padding-top: 24rpx;
color: #495057;
font-weight: 500;
}
.landscape .person .name { .node .person .name-bottom {
height: 4em; display: block;
line-height: 4em; margin: auto;
} overflow: hidden;
border-top: none;
box-sizing: border-box;
color: #6c757d;
}
.landscape .hasMate { .node.hasMate::after {
position: relative; content: '';
} position: absolute;
left: 2em;
right: 2em;
top: 2em;
border-top: 4px solid #dee2e6;
z-index: 1;
}
.landscape .hasMate .person { /* 横板 */
position: absolute; .landscape {
} transform: translate(-100%, 0) rotate(-90deg);
transform-origin: 100% 0;
}
.landscape .hasMate .person:first-child { .landscape .node {
left: auto; text-align: left;
right: -4em; height: 8em;
} width: 8em;
}
.landscape .hasMate .person:last-child { .landscape .person {
left: -4em; position: relative;
margin-left: 0; transform: rotate(90deg);
} padding-left: 4.5em;
</style> height: 4em;
top: 4em;
left: -1em;
}
.landscape .person .avat {
position: absolute;
left: 0;
}
.landscape .person .name {
height: 4em;
line-height: 4em;
}
.landscape .hasMate {
position: relative;
}
.landscape .hasMate .person {
position: absolute;
}
.landscape .hasMate .person:first-child {
left: auto;
right: -4em;
}
.landscape .hasMate .person:last-child {
left: -4em;
margin-left: 0;
}
</style>

View File

@ -1,17 +1,25 @@
const http = uni.$u.http const http = uni.$u.http
//架构上方会员等级图标 //架构上方会员等级图标
export const getAvarerInfo = (params) => http.get('/member/api/member-structure/get-avatar-info', {params}) export const getAvarerInfo = params =>
http.get('/member/api/member-structure/get-avatar-info', { params })
//结算期数下拉选 //结算期数下拉选
export const getMemberSettlePeriod = (params) => http.get('/member/api/member-structure/get-member-settle-period', {params}) export const getMemberSettlePeriod = params =>
http.get('/member/api/member-structure/get-member-settle-period', { params })
//安置架构 //安置架构
export const getAzFramework = (params) => http.get('/member/api/member-structure/az-framework', {params}) export const getAzFramework = params =>
http.get('/member/api/member-structure/three-framework', { params })
// 查询会员子节点
export const getChildList = params =>
http.get('/member/api/member-structure/childList', { params })
//推荐架构 //推荐架构
export const getTjFramework = (params) => http.get('/member/api/member-structure/tj-framework', {params}) export const getTjFramework = params =>
http.get('/member/api/member-structure/tj-framework', { params })
//转换为base64格式用于图片下载 //转换为base64格式用于图片下载
export const getUrlBase = (data) => http.post('/member/manage/member-structure/get-url-base64', data) export const getUrlBase = data =>
http.post('/member/manage/member-structure/get-url-base64', data)

View File

@ -20,7 +20,7 @@ module.exports = vm => {
//#ifdef DEV_SERVER //#ifdef DEV_SERVER
console.log('DEV_SERVER') console.log('DEV_SERVER')
config.baseURL = 'http://192.168.0.86:8080' config.baseURL = 'https://t-zk.beida666.com/prod-api'
//#endif //#endif
//#ifdef QA_SERVER //#ifdef QA_SERVER

View File

@ -739,7 +739,7 @@
{ {
"path": "pages/architecture/resettleArchite/resettle1", "path": "pages/architecture/resettleArchite/resettle1",
"style": { "style": {
"navigationBarTitleText": "安置方案一", "navigationBarTitleText": "方案一",
"enablePullDownRefresh": false "enablePullDownRefresh": false
} }
}, },

View File

@ -1,117 +1,128 @@
<template> <template>
<view class="content"> <view class="content">
<view class="theflex"> <view class="theflex">
<view @click="goRouter(item.path)" class="kuaibox" v-for="(item,index) in kuaiList" <view
:key="index"> @click="goRouter(item.path)"
<view class=""> class="kuaibox"
{{item.name}} v-for="(item, index) in menus"
</view> :key="index"
<image class="kuaiimg" :src="item.url" mode=""></image> >
</view> <view class="">
</view> {{ item.name }}
</view>
</view> <image class="kuaiimg" :src="item.url" mode=""></image>
</view>
</view>
</view>
</template> </template>
<script> <script>
import * as mar from "@/config/market.js" import * as mar from '@/config/market.js'
export default { export default {
data() { data() {
return { return {
kuaiList: [{ menus: [
name:'安置方案一', {
url: "../../static/images/my_icon14.png", name: '方案一',
path: "/pages/architecture/resettleArchite/resettle1", url: '../../static/images/my_icon14.png',
value: "marketDynamics", path: '/pages/architecture/resettleArchite/resettle1',
isShow: false, value: 'marketDynamics',
}, { isShow: false,
name: '安置方案二', },
url: "../../static/images/my_icon14.png", // {
path: "/pages/architecture/resettleArchite/resettle2", // name: '',
value: 'incomeDetail', // url: '../../static/images/my_icon14.png',
isShow: false, // path: '/pages/architecture/resettleArchite/resettle2',
}, { // value: 'incomeDetail',
name: '安置方案三', // isShow: false,
url: "../../static/images/my_icon14.png", // },
path: "/pages/architecture/resettleArchite/resettle3", // {
value: 'bonusSource', // name: '',
isShow: false, // url: '../../static/images/my_icon14.png',
}, { // path: '/pages/architecture/resettleArchite/resettle3',
name: '安置方案四', // value: 'bonusSource',
url: "../../static/images/my_icon14.png", // isShow: false,
path: "/pages/architecture/resettleArchite/resettle4", // },
isShow: false, // {
value: 'appraisal', // name: '',
}, { // url: '../../static/images/my_icon14.png',
name: '推荐方案一', // path: '/pages/architecture/resettleArchite/resettle4',
url: "../../static/images/my_icon14.png", // isShow: false,
path: "/pages/architecture/recommendArchite/recommend1", // value: 'appraisal',
isShow: false, // },
value: 'registration', // {
}, { // name: '',
name: '推荐方案二', // url: '../../static/images/my_icon14.png',
url: "../../static/images/my_icon14.png", // path: '/pages/architecture/recommendArchite/recommend1',
path: "/pages/architecture/recommendArchite/recommend2", // isShow: false,
isShow: false, // value: 'registration',
// value: 'investment', // },
}, { // {
name: '推荐方案三', // name: '',
url: "../../static/images/my_icon14.png", // url: '../../static/images/my_icon14.png',
path: "/pages/architecture/recommendArchite/recommend3", // path: '/pages/architecture/recommendArchite/recommend2',
isShow: false, // isShow: false,
value: 'activeZone', // // value: 'investment',
}, { // },
name: '推荐方案四', // {
url: "../../static/images/my_icon14.png", // name: '',
path: "/pages/architecture/recommendArchite/recommend4", // url: '../../static/images/my_icon14.png',
isShow: false, // path: '/pages/architecture/recommendArchite/recommend3',
value: 'activeZone', // isShow: false,
}] // value: 'activeZone',
} // },
}, // {
// name: '',
// url: '../../static/images/my_icon14.png',
// path: '/pages/architecture/recommendArchite/recommend4',
// isShow: false,
// value: 'activeZone',
// },
],
}
},
methods: { methods: {
goRouter(path) { goRouter(path) {
uni.navigateTo({ uni.navigateTo({
url: path url: path,
}) })
}, },
},
} }
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.content { .content {
background-color: #F2F2F2; background-color: #f2f2f2;
height: 100vh; height: 100vh;
padding: 4rpx 21rpx 500rpx 21rpx; padding: 4rpx 21rpx 500rpx 21rpx;
.theflex { .theflex {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: space-between; justify-content: space-between;
} }
.kuaibox { .kuaibox {
width: 40%; width: 40%;
// height: 150rpx; // height: 150rpx;
border-radius: 20rpx; border-radius: 20rpx;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
padding: 60rpx 40rpx 60rpx 22rpx; padding: 60rpx 40rpx 60rpx 22rpx;
margin: 13rpx 0rpx; margin: 13rpx 0rpx;
background-color: #FFFFFF; background-color: #ffffff;
font-size: 24rpx; font-size: 24rpx;
font-family: Source Han Sans CN; font-family: Source Han Sans CN;
font-weight: 400; font-weight: 400;
color: #666666; color: #666666;
.kuaiimg { .kuaiimg {
width: 52rpx; width: 52rpx;
height: 53rpx; height: 53rpx;
} }
} }
} }
</style> </style>

View File

@ -1,42 +1,27 @@
<template> <template>
<view> <view>
<view class="seach"> <view class="seach">
<view class="neibox"> 会员编号 </view> <view class="neibox"> 子点位 </view>
<view class="seach_i"> <view class="seach_i">
<u--input class="these" v-model="queryParams.memberCode"> <view class="inputbox" @click="childNodeListVisible = true">
<template slot="suffix"> <view class="">
<view class="seatch_r"> {{ selectedChildNodeName ? selectedChildNodeName : '请选择子点位' }}
<u-icon </view>
@click="getDataList" <u-icon name="arrow-right" size="24rpx" color="#005bac"></u-icon>
name="search" </view>
size="22"
color="#fff"
></u-icon>
</view>
</template>
</u--input>
</view> </view>
<view class="neibox" @click="popShow = true"> 筛选 </view> <view class="neibox" @click="popShow = true"> 筛选 </view>
</view> </view>
<view class="mainbox"> <view class="mainbox">
<view class="main_top">
<view
class="top_flex"
v-for="(item, index) in avaerInfoList"
:key="index"
>
<img class="theimg" :src="item.value" alt="" />
<view class="fle2">{{ item.name }}</view>
</view>
</view>
<view class="main_bottom"> <view class="main_bottom">
<view <view
class="scoll_main" class="scoll_main"
ref="scrollMain" ref="scrollMain"
@touchstart="handleTouchStart" @touchstart.prevent="handleTouchStart"
@touchmove="handleTouchMove" @touchmove.prevent="handleTouchMove"
@touchend="handleTouchEnd" @touchend="handleTouchEnd"
@dblclick="handleDoubleClick"
:style="containerStyle"
> >
<TreeChart <TreeChart
:size="size" :size="size"
@ -66,29 +51,27 @@
<view class="top_red" @click="popShow = false">{{ '返回' }}</view> <view class="top_red" @click="popShow = false">{{ '返回' }}</view>
</view> </view>
<view class="typesBox"> <view class="typesBox">
<view class="typeTitle" @click="listShow = true"> 结算期数 </view> <view class="typeTitle" @click="stageListVisible = true"> 阶段 </view>
<view class="choiceBox"> <view class="choiceBox">
<view class="inputbox" @click="listShow = true"> <view class="inputbox" @click="stageListVisible = true">
<view class=""> <view class="">
{{ settleName ? settleName : '请选择' }} {{ stageName ? stageName : '请选择' }}
</view> </view>
<u-icon name="arrow-right" size="24rpx" color="#090000"></u-icon> <u-icon name="arrow-right" size="24rpx" color="#090000"></u-icon>
</view> </view>
</view> </view>
</view> </view>
<view class="typesBox"> <view class="typesBox">
<view class="typeTitle"> 代数 </view> <view class="typeTitle" @click="statusListVisible = true">
状态
</view>
<view class="choiceBox"> <view class="choiceBox">
<u--input <view class="inputbox" @click="statusListVisible = true">
v-model="queryParams.level" <view class="">
style=" {{ statusName ? statusName : '请选择' }}
background-color: rgba(176, 196, 222, 0.45); </view>
border-color: rgba(176, 196, 222, 0.45) !important; <u-icon name="arrow-right" size="24rpx" color="#090000"></u-icon>
" </view>
placeholder="请输入"
border="surround"
shape="circle"
></u--input>
</view> </view>
</view> </view>
@ -98,7 +81,7 @@
class="bottom_btn thebtn2" class="bottom_btn thebtn2"
@click=" @click="
() => { () => {
getDataList(), (popShow = false) handleSearch(), (popShow = false)
} }
" "
>{{ '确定' }} >{{ '确定' }}
@ -106,128 +89,32 @@
</view> </view>
</view> </view>
<u-picker <u-picker
@cancel="listShow = false" @cancel="stageListVisible = false"
:show="listShow" :show="stageListVisible"
ref="uPicker" ref="uPicker"
:columns="memberSettlePeriodList" :columns="stageList"
@confirm="confirm" @confirm="stagePickerHandleConfirm"
keyName="settleDate" keyName="label"
></u-picker>
<u-picker
@cancel="statusListVisible = false"
:show="statusListVisible"
ref="uPicker"
:columns="statusList"
@confirm="statusPickerHandleConfirm"
keyName="label"
></u-picker> ></u-picker>
</u-popup> </u-popup>
<u-popup <!-- 子点位选择picker -->
:show="isPop" <u-picker
closeable @cancel="childNodeListVisible = false"
mode="center" :show="childNodeListVisible"
round="10" ref="childNodePicker"
@close="isPop = false" :columns="childNodeColumns"
> @confirm="childNodePickerHandleConfirm"
<view class="ispop_box"> keyName="childNode"
<view class="Poster1"> ></u-picker>
<view class="pop_top">
<view class="pop_top">
<view>
<image
crossorigin="anonymous"
data-etype="image"
:data-enode="popMould.avatarUrl"
:src="'data:image/png;base64,' + popMould.avatarUrlBase64"
mode="aspectFit"
class="poster1"
></image>
</view>
<view>
<image
crossorigin="anonymous"
data-etype="image"
:data-enode="popMould.countryUrl2"
:src="'data:image/png;base64,' + popMould.countryUrl2Base64"
mode="aspectFit"
class="poster2"
></image>
</view>
</view>
<view class="top_right">
<image
crossorigin="anonymous"
data-etype="image"
:data-enode="popMould.settleCountryUrl2"
:src="
'data:image/png;base64,' + popMould.settleCountryUrl2Base64
"
mode="aspectFit"
class="poster2"
></image>
<view style="margin-top: 18rpx"> 结算国家 </view>
</view>
</view>
<view class="pop_center">
<view class="center_flex">
<view class="c1">会员编号</view>
<view class="c2">{{ popMould.memberCode }}</view>
</view>
<view class="center_flex">
<view class="c1">会员姓名</view>
<view class="c2">{{ popMould.name }}</view>
</view>
<view class="center_flex">
<view class="c1">支付时间</view>
<view class="c2">{{ popMould.payDate }}</view>
</view>
</view>
<view class="pop_bottom">
<view class="b_flex">
<view class="bt1">业绩</view>
<view class="bt1">左区</view>
<view class="bt1">右区</view>
</view>
<view class="b_flex">
<view class="bt2">真实新增</view>
<view class="bt2">{{ popMould.leftRealNewPv }}</view>
<view class="bt2">{{ popMould.rightRealNewPv }}</view>
</view>
<view class="b_flex">
<view class="bt2">首购新增</view>
<view class="bt2">{{ popMould.leftFirstPurchaseAdd }}</view>
<view class="bt2">{{ popMould.rightFirstPurchaseAdd }}</view>
</view>
<view class="b_flex">
<view class="bt2">复购新增</view>
<view class="bt2">{{ popMould.leftRepeatPurchaseSurplus }}</view>
<view class="bt2">{{ popMould.rightRepeatPurchaseSurplus }}</view>
</view>
<view class="b_flex">
<view class="bt2">真实累计</view>
<view class="bt2">{{ popMould.leftRealTotal }}</view>
<view class="bt2">{{ popMould.rightRealTotal }}</view>
</view>
<view class="b_flex">
<view class="bt2">首购累计</view>
<view class="bt2">{{ popMould.leftFirstTotal }}</view>
<view class="bt2">{{ popMould.rightFirstTotal }}</view>
</view>
<view class="b_flex">
<view class="bt2">复购累计</view>
<view class="bt2">{{ popMould.leftRepeatPurchaseTotal }}</view>
<view class="bt2">{{ popMould.rightRepeatPurchaseTotal }}</view>
</view>
<view class="b_flex">
<view class="bt2">首购结余</view>
<view class="bt2">{{ popMould.leftFirstSurplus }}</view>
<view class="bt2">{{ popMould.rightFirstSurplus }}</view>
</view>
<view class="b_flex">
<view class="bt2">复购结余</view>
<view class="bt2">{{ popMould.leftRepeatPurchaseSurplus }}</view>
<view class="bt2">{{ popMould.rightRepeatPurchaseSurplus }}</view>
</view>
</view>
</view>
<view class="btn_box">
<view class="small-btn" @click="downImage('Poster1')">下载图片</view>
<view class="small-text-btn" @click="copyText()">复制文字</view>
</view>
</view>
</u-popup>
<Eposter <Eposter
width="750" width="750"
height="1334" height="1334"
@ -253,20 +140,36 @@ export default {
}, },
data() { data() {
return { return {
avaerInfoList: [], childNodeList: [],
childNodeColumns: [[]],
childNodeListVisible: false,
selectedChildNodeName: '',
treeData: [], treeData: [],
queryParams: { queryParams: {
memberSettlePeriodId: '', // childNode: '',
memberCode: '', // stage: 1,
level: 6, // status: 0,
type: 1,
}, },
memberSettlePeriodList: [], // stageList: [
[
{ value: 1, label: '阶段一' },
{ value: 2, label: '阶段二' },
{ value: 3, label: '阶段三' },
],
], //
statusList: [
[
{ value: 0, label: '已完成' },
{ value: 1, label: '未完成' },
],
], //
popShow: false, popShow: false,
listShow: false, stageListVisible: false,
settleName: '', statusListVisible: false,
stageName: '',
statusName: '',
data: {}, data: {},
size: 0.3, size: 0.5,
landscape: [], landscape: [],
popMould: {}, popMould: {},
isPop: false, isPop: false,
@ -279,14 +182,53 @@ export default {
y: 0, y: 0,
}, },
initialDistance: 0, initialDistance: 0,
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 }, //
list: [], list: [],
} }
}, },
onLoad() { onLoad() {
this.getAvarerInfo() this.init()
this.getDataList() 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',
}
},
}, },
methods: { methods: {
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
},
// //
copyText() { copyText() {
let self = this let self = this
@ -346,75 +288,210 @@ export default {
}, },
handleTouchStart(event) { handleTouchStart(event) {
console.log('handleTouchStart triggered', event.touches.length)
const touch1 = event.touches[0] const touch1 = event.touches[0]
const touch2 = event.touches[1] const touch2 = event.touches[1]
const currentTime = Date.now()
if (touch2) { if (touch2) {
// -
this.isZooming = true
this.isDragging = false
this.initialSize = this.size
this.touchStartPosition1 = { this.touchStartPosition1 = {
x: touch1.pageX, x: touch1.clientX,
y: touch1.pageY, y: touch1.clientY,
} }
this.touchStartPosition2 = { this.touchStartPosition2 = {
x: touch2.pageX, x: touch2.clientX,
y: touch2.pageY, y: touch2.clientY,
} }
this.initialDistance = Math.hypot( this.initialDistance = Math.hypot(
touch2.pageX - touch1.pageX, touch2.clientX - touch1.clientX,
touch2.pageY - touch1.pageY touch2.clientY - touch1.clientY
) )
} else {
// -
this.isZooming = false
this.isDragging = true
this.dragStartPosition = {
x: touch1.clientX,
y: touch1.clientY,
}
this.lastTouchTime = currentTime
} }
}, },
handleTouchMove(event) { handleTouchMove(event) {
const touch1 = event.touches[0] const touch1 = event.touches[0]
const touch2 = event.touches[1] const touch2 = event.touches[1]
if (touch2) {
if (touch2 && this.isZooming && this.initialDistance > 0) {
//
const currentDistance = Math.hypot( const currentDistance = Math.hypot(
touch2.pageX - touch1.pageX, touch2.clientX - touch1.clientX,
touch2.pageY - touch1.pageY touch2.clientY - touch1.clientY
) )
const scale = currentDistance / this.initialDistance const scale = currentDistance / this.initialDistance
this.size = this.size * scale 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()
} }
}, },
handleTouchEnd() { handleTouchEnd(event) {
this.touchStartPosition1 = { const currentTime = Date.now()
x: 0, const touchDuration = currentTime - this.lastTouchTime
y: 0,
} //
this.touchStartPosition2 = { if (
x: 0, this.isDragging &&
y: 0, (Math.abs(this.velocity.x) > 1 || Math.abs(this.velocity.y) > 1)
) {
this.startInertiaScroll()
} }
//
this.isZooming = false
this.isDragging = false
this.touchStartPosition1 = { x: 0, y: 0 }
this.touchStartPosition2 = { x: 0, y: 0 }
this.initialDistance = 0 this.initialDistance = 0
this.initialSize = this.size
this.dragStartPosition = { x: 0, y: 0 }
}, },
clickNode(e) {
let self = this //
if (e) { startInertiaScroll() {
arc const friction = 0.95 //
.getUrlBase({ const minVelocity = 0.1 //
countryUrl2: e.countryUrl2,
settleCountryUrl2: e.settleCountryUrl2, const animateInertia = () => {
avatarUrl: e.avatarUrl, //
}) let newX = this.containerTransform.x + this.velocity.x
.then(res => { let newY = this.containerTransform.y + this.velocity.y
self.popMould = e
self.popMould.countryUrl2Base64 = res.countryUrl2Base64 //
self.popMould.settleCountryUrl2Base64 = res.settleCountryUrl2Base64 const scaledMaxX = this.maxTransform.x * this.size
self.popMould.avatarUrlBase64 = res.avatarUrlBase64 const scaledMaxY = this.maxTransform.y * this.size
self.isPop = true
}) 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)
}
} }
requestAnimationFrame(animateInertia)
}, },
confirm(e) {
this.queryParams.memberSettlePeriodId = e.value[0].pkId // - 使
this.settleName = e.value[0].settleDate updateContainerTransform() {
this.listShow = false // 使DOM
console.log('容器变换更新', this.containerTransform, this.size)
}, },
getAvarerInfo() { //
arc.getAvarerInfo().then(res => { resetZoom() {
this.avaerInfoList = res.data this.size = 0.4
}) this.initialSize = 0.4
arc.getMemberSettlePeriod().then(res => { this.containerTransform = { x: 0, y: 0 }
this.memberSettlePeriodList = [res.data] this.updateContainerTransform()
},
//
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()
}
})
}) })
}, },
getDataList() { getDataList() {
@ -422,15 +499,20 @@ export default {
this.data = res.data[0] this.data = res.data[0]
}) })
}, },
handleSearch() {
this.getChildList().then(() => {
this.getDataList()
})
},
clearAll() { clearAll() {
this.popShow = false this.popShow = false
this.settleName = '' this.init()
this.queryParams = { this.queryParams = {
memberSettlePeriodId: '', // stage: this.stageList[0][0].value,
memberCode: '', // status: this.statusList[0][0].value,
level: '', //
} }
this.getDataList() this.handleSearch()
}, },
}, },
} }
@ -701,6 +783,22 @@ export default {
flex: 1; flex: 1;
background: #f5f6f8; background: #f5f6f8;
margin: 0 20rpx; margin: 0 20rpx;
.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;
}
}
} }
.neibox { .neibox {
@ -721,40 +819,11 @@ export default {
.mainbox { .mainbox {
padding: 26rpx 22rpx; padding: 26rpx 22rpx;
height: 100%;
.main_top {
background: #ffffff;
border-radius: 20rpx;
padding: 20rpx 4rpx;
display: flex;
flex-wrap: wrap;
.top_flex {
display: flex;
flex-direction: column;
align-items: center;
margin: 15rpx 20rpx;
// justify-content: center;
width: 98rpx;
.theimg {
width: 92rpx;
height: 92rpx;
border-radius: 50%;
}
.flex2 {
font-size: 26rpx;
font-family: Source Han Sans CN;
font-weight: 400;
color: #666666;
}
}
}
.main_bottom { .main_bottom {
width: 100%; width: 100%;
height: calc(100vh - 600rpx); height: 100%;
margin-top: 25rpx; margin-top: 25rpx;
background-color: #ffffff; background-color: #ffffff;
padding: 38rpx 0; padding: 38rpx 0;
@ -764,11 +833,13 @@ export default {
.scoll_main { .scoll_main {
width: 700rpx; width: 700rpx;
height: calc(100vh - 600rpx);
overflow: auto;
// overflow: scroll; transform-origin: center center; //
// overflow-x: auto; cursor: grab; //
&:active {
cursor: grabbing; //
}
} }
} }
</style> </style>

View File

@ -88,49 +88,6 @@
</view> </view>
</view> </view>
<!-- 收益区域 -->
<view class="my_order" v-if="regionInfoVisible">
<view class="my_title">
<text class="thetitle">收益区域</text>
</view>
<template
v-if="
regionInfo.provinceVal || regionInfo.cityVal || regionInfo.countyVal
"
>
<view class="region-info-box">
<view class="region-info-item">
<text class="region-info-label">{{ '省' }}</text>
<text class="region-info-value">{{
regionInfo.provinceVal || '-'
}}</text>
</view>
<view class="region-info-item">
<text class="region-info-label">{{ '市' }}</text>
<text class="region-info-value">{{
regionInfo.cityVal || '-'
}}</text>
</view>
<view class="region-info-item">
<text class="region-info-label">{{ '区' }}</text>
<text class="region-info-value">{{
regionInfo.countyVal || '-'
}}</text>
</view>
</view>
</template>
<template v-else>
<view class="region-select-action">
<u-button
@click="openRegionSelect"
color="#005BAC"
shape="circle"
text="选择区域"
></u-button>
</view>
</template>
</view>
<view class="my_order"> <view class="my_order">
<view class="order_flex"> <view class="order_flex">
<template v-for="(item, index) in otherMenuList"> <template v-for="(item, index) in otherMenuList">
@ -144,47 +101,9 @@
<view class="order_text">{{ item.name }}</view> <view class="order_text">{{ item.name }}</view>
</view> </view>
</template> </template>
<!-- <view
class="theorderflex1"
@click="goTo('/pages/mine/feedBack/feedBack')"
>
<image class="order_img" src="../../static/images/my_icon12.png" />
<view class="order_text">{{ '意见反馈' }}</view>
</view> -->
<!-- <picker
:range="getLanguageList"
:value="index"
range-key="label"
@change="bindPickerChange"
>
<view class="theorderflex1" @click="goTo('')">
<image class="order_img" src="../../static/images/mark6.png" />
<view class="order_text">{{ '多语言切换' }}</view>
</view>
</picker> -->
<!-- <view
class="theorderflex1"
@click="goTo('/pages/mine/branchAddress/branchAddress')"
>
<image class="order_img" src="../../static/images/my_icon9.png" />
<view class="order_text"
>{{ '分公司' }}{{ '地址' }}</view
>
</view> -->
<!-- <view class="theorderflex1" @click="goYear">
<image class='order_img' src="../../static/images/my_icon12.png" />
<view class="order_text">{{ '年度奖衔' }}</view>
</view> -->
<!-- <view class="theorderflex1" @click="goTo('')">
<image class='order_img' src="../../static/images/my_icon12.png" />
<view class="order_text">关于我们</view>
</view> -->
</view> </view>
</view> </view>
<!-- 会员中心 -->
<view class="btnbox"> <view class="btnbox">
<u-button <u-button
shape="circle" shape="circle"
@ -220,12 +139,6 @@
</u-button> </u-button>
</view> </view>
</u-popup> </u-popup>
<!-- <RegionSelect
v-if="isNormal"
ref="regionSelect"
@success="getRegionSelect"
/> -->
<!-- <talentList :drShow="drShow" @closeShow="closeShow"></talentList> -->
</view> </view>
</template> </template>
@ -286,13 +199,6 @@ export default {
menuKey: 'selfHelp', menuKey: 'selfHelp',
ifshow: true, ifshow: true,
}, },
// {
// url: '/pages/mine/share/index',
// name: '广',
// imgurl: '../../static/images/list.svg',
// menuKey: 'share',
// ifshow: false,
// },
{ {
url: '/pages/userSecure/index', url: '/pages/userSecure/index',
name: '账号安全', name: '账号安全',
@ -321,13 +227,13 @@ export default {
menuKey: 'bankInfo', menuKey: 'bankInfo',
ifshow: true, ifshow: true,
}, },
// { {
// url: '/pages/mine/addNewPv/index', url: '/pages/architecture/architecture',
// name: '', name: '架构管理',
// imgurl: '../../static/images/mark9.png', imgurl: '../../static/images/my_icon14.png',
// menuKey: 'iNewAchievement', menuKey: 'recommend',
// ifshow: false, ifshow: false,
// }, },
], ],
drShow: false, drShow: false,
actMenu: false, actMenu: false,