398 lines
11 KiB
Vue
398 lines
11 KiB
Vue
<template>
|
||
<NavBar />
|
||
<view class="container">
|
||
<view class="title">
|
||
<PageTitle :title="$t('ib.fundSetting')" />
|
||
</view>
|
||
<template v-if="!loading && allJunior">
|
||
<view style="height: 56upx; margin-bottom: 20upx" v-if="allJunior && allJunior.power == 'children'">
|
||
{{ $t('fundSetting.childrenMaxHierarchy') }}
|
||
<text style="font-size: 36upx">{{ selectedRow.hierarchy_value }}</text>
|
||
</view>
|
||
<view style="height: 80upx; margin-bottom: 20upx; position: relative" v-if="allJunior && allJunior.power == 'all'">
|
||
<view class="searchWrapper">
|
||
<uni-data-select :clear="false" :localdata="searchTypeOptions" v-model="searchType"></uni-data-select>
|
||
<uni-easyinput primaryColor="#29BBE4" v-model="searchValue" />
|
||
<button class="primaryButton searchBtn" @click="query">{{ $t('form.search') }}</button>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
</view>
|
||
<uni-popup ref="resultDialog" :isMaskClick="false">
|
||
<view style="width: 600upx">
|
||
<view class="tableSection">
|
||
<uni-table :emptyText="$t('common.noData')" @click="hideSearchDialog">
|
||
<uni-tr v-for="row in searchResult" :key="row.rowKey ?? row.id" @click="handleRow(row)">
|
||
<uni-td class="columnItem">
|
||
<view style="width: 100%">
|
||
<view>{{ row?.['text'] ?? '-' }}</view>
|
||
</view>
|
||
</uni-td>
|
||
</uni-tr>
|
||
</uni-table>
|
||
</view>
|
||
</view>
|
||
</uni-popup>
|
||
<view>
|
||
<template v-if="!loading">
|
||
<view v-if="allJunior" style="width: 100%; padding: 0 20upx; box-sizing: border-box">
|
||
<scroll-view :style="{ height: contentHeight }" scroll-y scroll-x scroll-with-animation="true" @scroll="handleScroll" :scroll-top="scrollTop">
|
||
<BaseTree ref="tree" class="mtl-tree" treeLine v-model="treeNodes">
|
||
<template #default="{ node, stat }">
|
||
<image
|
||
src="@/static/partner/collapse.png"
|
||
mode="aspectFill"
|
||
class="tree-node-icon"
|
||
v-if="stat.open && stat.children.length"
|
||
@click.native="stat.open = false"
|
||
></image>
|
||
<image
|
||
src="@/static/partner/unfold.png"
|
||
mode="aspectFill"
|
||
class="tree-node-icon"
|
||
v-else-if="!stat.open && stat.children.length"
|
||
@click.native="stat.open = true"
|
||
></image>
|
||
<view class="tree-node" :id="'refN' + node.id">
|
||
<text class="level">{{ stat.level }}</text>
|
||
<text class="label">{{ node.text }}</text>
|
||
<uni-easyinput
|
||
type="digit"
|
||
inputmode="decimal"
|
||
:readonly="node.readonly"
|
||
:disabled="node.readonly"
|
||
:clearable="false"
|
||
:primaryColor="(stat.level == 1 ? selectedRow.hierarchy_value : stat.parent.data.val) < node.val ? 'red' : '#29BBE4'"
|
||
style="min-width: 100upx; margin-left: 10upx; flex-grow: 0"
|
||
:class="{ 't-input-error': (stat.level == 1 ? selectedRow.hierarchy_value : stat.parent.data.val) < node.val && !node.readonly }"
|
||
v-model="node.val"
|
||
/>
|
||
<text class="diff" :class="{ 'error-diff': (stat.parent.data.val ? stat.parent.data.val : 0) < node.val }" v-if="stat.level != 1">
|
||
{{ $t('partner.difference', { n: (stat.parent.data.val ? stat.parent.data.val : 0) - (node.val ? node.val : 0) }) }}
|
||
</text>
|
||
</view>
|
||
</template>
|
||
</BaseTree>
|
||
</scroll-view>
|
||
<view>
|
||
<!-- 保存和返回 -->
|
||
<button class="primaryButton" style="margin-top: 20upx" :disabled="saveLoading" @click="save">
|
||
<image v-show="saveLoading" src="/static/loadingCircle.svg" mode="aspectFit" style="width: 16px; height: 16px"></image>
|
||
{{ $t('form.save') }}
|
||
</button>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
<Spin v-show="loading" />
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import { useUserStore } from '@/stores/user';
|
||
import { getAllJunior, saveRebateSet } from '@/services/partner/myClient.ts';
|
||
import BaseTree, { walkTreeData } from '@/pages/components/baseTree/baseTree.vue';
|
||
import '@/pages/components/baseTree/style/default.css';
|
||
import '@/pages/components/baseTree/style/material-design.css';
|
||
|
||
export default {
|
||
components: { BaseTree },
|
||
data() {
|
||
return {
|
||
scrollTop: 0,
|
||
curScrollTop: 0,
|
||
contentHeight: 'auto',
|
||
loading: true,
|
||
saveLoading: false,
|
||
searchTypeOptions: [
|
||
{ text: this.$t('fundSetting.account'), value: 'n' },
|
||
{ text: this.$t('fundSetting.value'), value: 'v' }
|
||
],
|
||
searchType: 'n',
|
||
searchValue: null,
|
||
searchResult: null,
|
||
allJunior: null,
|
||
bigAgentId: null,
|
||
selectedRow: null,
|
||
treeNodes: []
|
||
};
|
||
},
|
||
methods: {
|
||
async loadData(currentRow) {
|
||
this.loading = true;
|
||
const resp = await getAllJunior({ rebate_id: currentRow.id });
|
||
this.loading = false;
|
||
if (resp.code == 0) {
|
||
this.allJunior = resp.data;
|
||
if (resp.data.power === 'all') {
|
||
this.loadTree(currentRow);
|
||
} else if (resp.data.power === 'children') {
|
||
this.loadChildren(currentRow);
|
||
}
|
||
}
|
||
},
|
||
/**
|
||
* 加载所有下级
|
||
*/
|
||
loadTree(currentRow) {
|
||
const { tree, listAll, listVal } = this.allJunior;
|
||
let valueMap = new Map();
|
||
if (listVal && listVal.length) {
|
||
for (let i = 0; i < listVal.length; i++) {
|
||
let val = listVal[i].hierarchy_value;
|
||
let if_fixed = listVal[i].if_fixed;
|
||
if (val == null || val == '' || isNaN(val)) {
|
||
val = 0;
|
||
}
|
||
valueMap.set(listVal[i].user_id, { val: val, if_fixed: if_fixed });
|
||
}
|
||
}
|
||
let node0 = [];
|
||
if (tree && tree.length) {
|
||
this.bigAgentId = listAll[0].id;
|
||
node0.push({
|
||
level: 0,
|
||
levelNum: listAll[0].level,
|
||
id: listAll[0].id,
|
||
text: listAll[0].user_code + '(' + listAll[0].id + ')',
|
||
// 大代理的值时默认的,不允许修改
|
||
readonly: true,
|
||
pid: 0,
|
||
val: currentRow.hierarchy_value
|
||
});
|
||
}
|
||
node0[0].children = this.getTree(tree, valueMap, 0);
|
||
this.treeNodes = node0;
|
||
valueMap.clear();
|
||
},
|
||
/**
|
||
* 加载直属下级
|
||
*/
|
||
loadChildren(currentRow) {
|
||
const { listAll, noChangeUserMap } = this.allJunior;
|
||
let nodes = [];
|
||
for (let i = 0; i < listAll.length; i++) {
|
||
let readonly = false;
|
||
if (noChangeUserMap != null && !this.isEmpty(noChangeUserMap[listAll[i].id])) {
|
||
readonly = true;
|
||
}
|
||
let item = listAll[i];
|
||
nodes.push({
|
||
level: 0,
|
||
readonly: readonly,
|
||
id: item.id,
|
||
text: item.user_code + '(' + item.id + ')',
|
||
val: this.returnFloat(item.hierarchy_value),
|
||
children: []
|
||
});
|
||
}
|
||
this.treeNodes = nodes;
|
||
},
|
||
getTree(tree, valueMap, level) {
|
||
if (!tree) {
|
||
return [];
|
||
}
|
||
let nodes = [];
|
||
const { noChangeUserMap } = this.allJunior;
|
||
for (let i = 0; i < tree.length; i++) {
|
||
let readonly = false;
|
||
if (noChangeUserMap != null && !this.isEmpty(noChangeUserMap[tree[i].id])) {
|
||
readonly = true;
|
||
}
|
||
let val = 0;
|
||
let if_fixed = 0;
|
||
if (valueMap && valueMap.get(tree[i].id)) {
|
||
val = valueMap.get(tree[i].id).val;
|
||
if_fixed = valueMap.get(tree[i].id).if_fixed;
|
||
}
|
||
nodes.push({
|
||
readonly: readonly,
|
||
levelNum: tree[i].level,
|
||
id: tree[i].id,
|
||
text: tree[i].user_code + '(' + tree[i].id + ')',
|
||
val: val,
|
||
if_fixed: if_fixed,
|
||
level: level + 1,
|
||
children: this.getTree(tree[i].child, valueMap, level + 1)
|
||
});
|
||
}
|
||
return nodes;
|
||
},
|
||
getData(nodes, result, maxValue) {
|
||
if (nodes && nodes.length) {
|
||
for (var j = 0; j < nodes.length; j++) {
|
||
let i = nodes[j];
|
||
if (!i.readonly) {
|
||
result.push({
|
||
user_id: i.id,
|
||
hierarchy_value: i.val
|
||
});
|
||
if (maxValue < i.val) {
|
||
return false;
|
||
}
|
||
}
|
||
if (i.children && i.children.length) {
|
||
if (!this.getData(i.children, result, i.val)) {
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return true;
|
||
},
|
||
async save() {
|
||
let data = {
|
||
rebate_id: this.selectedRow.id
|
||
};
|
||
let tmp = [];
|
||
if (!this.getData(this.treeNodes, tmp, this.selectedRow.hierarchy_value)) {
|
||
return;
|
||
}
|
||
data.json = JSON.stringify(tmp);
|
||
this.saveLoading = true;
|
||
const resp = await saveRebateSet(data);
|
||
this.saveLoading = false;
|
||
if (resp.code == 0) {
|
||
this.$cusModal.showModal({
|
||
type: 'message',
|
||
status: 'success',
|
||
contentText: this.$t('common.success.action')
|
||
});
|
||
} else {
|
||
this.$cusModal.showModal({
|
||
type: 'message',
|
||
status: 'warning',
|
||
contentText: resp.msg ?? this.$t('common.error.sysError')
|
||
});
|
||
}
|
||
},
|
||
isEmpty(str) {
|
||
if (typeof value === 'number' && !isNaN(str)) str = str + '';
|
||
if (str == 'undefined' || str == 'null' || str == null || str == '' || str == undefined) {
|
||
return true;
|
||
} else {
|
||
return false;
|
||
}
|
||
},
|
||
returnFloat(value) {
|
||
if (this.isEmpty(value)) return '0.00';
|
||
var value = Math.round(parseFloat(value) * 100) / 100;
|
||
var s = value.toString().split('.');
|
||
if (s.length == 1) {
|
||
value = value.toString() + '.00';
|
||
return value;
|
||
}
|
||
if (s.length > 1) {
|
||
if (s[1].length < 2) {
|
||
value = value.toString() + '0';
|
||
}
|
||
return value;
|
||
}
|
||
},
|
||
/**
|
||
* searchType n=按名字,v=按值
|
||
*/
|
||
query() {
|
||
this.searchResult = null;
|
||
let str = this.searchValue;
|
||
if (this.isEmpty(str)) {
|
||
this.searchResult = null;
|
||
} else {
|
||
let tmp = [];
|
||
walkTreeData(
|
||
this.treeNodes,
|
||
(node, index, parent) => {
|
||
if (this.searchType == 'n') {
|
||
if (node.text.indexOf(str) >= 0) {
|
||
tmp.push(node);
|
||
}
|
||
} else if (this.searchType == 'v') {
|
||
str = parseFloat(str);
|
||
let ibvalue = node.val;
|
||
if (this.isEmpty(ibvalue)) {
|
||
ibvalue = 0;
|
||
} else {
|
||
ibvalue = parseFloat(ibvalue);
|
||
}
|
||
if (ibvalue == str) {
|
||
tmp.push(node);
|
||
}
|
||
}
|
||
},
|
||
{
|
||
childrenKey: 'children',
|
||
reverse: false,
|
||
childFirst: false
|
||
}
|
||
);
|
||
this.searchResult = tmp;
|
||
this.$refs.resultDialog.open();
|
||
}
|
||
},
|
||
handleRow(rowData) {
|
||
this.closeSearchDialog();
|
||
this.$refs.tree.openNodeAndParents(rowData);
|
||
const query = uni.createSelectorQuery();
|
||
query.select('#refN' + rowData.id).boundingClientRect();
|
||
query.select('.container').boundingClientRect();
|
||
query.exec((res) => {
|
||
this.scrollTop = this.curScrollTop + res[0].top - res[1].height - res[1].top;
|
||
});
|
||
},
|
||
hideSearchDialog() {
|
||
if (!this.searchResult || !this.searchResult.length) {
|
||
this.closeSearchDialog()
|
||
}
|
||
},
|
||
closeSearchDialog() {
|
||
this.$refs.resultDialog.close();
|
||
},
|
||
handleScroll(e) {
|
||
this.curScrollTop = e.detail.scrollTop;
|
||
}
|
||
},
|
||
created() {
|
||
const userStore = useUserStore();
|
||
this.selectedRow = userStore.currentRow;
|
||
this.loadData(this.selectedRow);
|
||
},
|
||
mounted() {
|
||
this.$nextTick(() => {
|
||
const query = uni.createSelectorQuery().in(this);
|
||
query
|
||
.select('.container')
|
||
.boundingClientRect((data) => {
|
||
if (data) {
|
||
this.contentHeight = `calc(100vh - ${data.height + 100}px - 200upx)`;
|
||
}
|
||
})
|
||
.exec();
|
||
});
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
@import './tree.scss';
|
||
</style>
|
||
|
||
<style lang="scss">
|
||
.tree-node {
|
||
.uni-easyinput__content-input {
|
||
height: 50upx !important;
|
||
}
|
||
}
|
||
|
||
.t-input-error {
|
||
border: 1px solid red;
|
||
}
|
||
|
||
.diff {
|
||
padding-left: 16upx;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.error-diff {
|
||
color: red;
|
||
}
|
||
</style>
|