Browse Source

选择组织控件支持多选,支持限制数据范围

qin_26
liwenxuan 2 months ago
parent
commit
b73be65def
  1. 2
      src/components/DesignForm/assembly/index.ts
  2. 72
      src/components/DesignForm/formControlPropertiNew.vue
  3. 240
      src/components/DesignForm/public/expand/org.vue
  4. 110
      src/widget/org/cont.vue

2
src/components/DesignForm/assembly/index.ts

@ -1063,6 +1063,8 @@ export default [
icon: 'sliders',
iconFont: 'fa-sliders',
control: {
range:[],
multiple: '',
},
config: {},
styles: {

72
src/components/DesignForm/formControlPropertiNew.vue

@ -13,6 +13,8 @@ import validateInt from "./validateInt";
import { ValidateTextTypes } from "@/components/DesignForm/validateText";
import { ElMessage } from "element-plus";
import { formatNumber } from "@/api/DesignForm/utils";
import { getOrgTreeList } from "@/api/hr/org/index";
import { orgInfo } from "@/api/hr/org/type";
import {
PublicAtrr,
formStruct,
@ -833,6 +835,22 @@ const attrList = computed(() => {
vIf: state.isSearch,
vShow: ["lowcodeImage"],
},
{
label: "数据范围",
value: config.orgCentent,
path: "config.orgCentent",
type: "orgCentent_range",
vIf: state.isSearch,
vShow: ["orgCentent"],
},
{
label: "是否多选",
value: config.orgCentent,
path: "config.orgCentent",
type: "orgCentent_Multiple",
vIf: state.isSearch,
vShow: ["orgCentent"],
},
/* {
label: "添加时间水印",
value: config.lowcodeImage,
@ -2048,6 +2066,8 @@ watch(
controlData.value.control.fillRoles.child[0].id = uuidv4()
.replaceAll("-", "")
.toString();
}else if(controlData.value.type === "orgCentent"){
haveOrgTreeInfo()
}
// start
// console.log(controlData.value.name)
@ -2086,6 +2106,34 @@ watch(
// end
}
);
const orgTreeProps = {
children: "child",
label: "name",
}; //
const orgCententRange = ref<orgInfo[]>();
function haveOrgTreeInfo() {
//orgTreeLoading.value = true;
getOrgTreeList({ orgid: 309 })
.then(({ data }) => {
console.log("行政组织树对照值", data);
orgCententRange.value = data;
console.log(orgCententRange.value)
})
.finally(() => {
//orgTreeLoading.value = false;
});
}
//
function carouselImgUploadSuccess(
response: any,
@ -4404,6 +4452,30 @@ const aiAgentList = ref([
</el-row>
<el-row v-else-if="item.type === 'orgCentent_range'">
<!-- {{ controlData.control.range }} -->
<el-tree-select
v-model="controlData.control.range"
node-key="id"
:props="orgTreeProps"
:data="orgCententRange"
:render-after-expand="false"
show-checkbox
multiple
style="width: 200px"
/>
</el-row>
<el-row v-else-if="item.type === 'orgCentent_Multiple'">
<el-radio-group v-model="controlData.control.multiple">
<el-radio value="1"></el-radio>
<el-radio value=""></el-radio>
</el-radio-group>
</el-row>

240
src/components/DesignForm/public/expand/org.vue

@ -11,6 +11,7 @@ const props = withDefaults(
defineProps<{
modelValue?: string;
disabled?: boolean;
data?: Object;
}>(),
{}
);
@ -20,13 +21,33 @@ const emits = defineEmits<{
const value = computed({
get: () => {
if (props.modelValue != "" && props.modelValue != undefined) {
return props.modelValue * 1;
if(hasComma(props.modelValue)||multiple){
return commaStringToNumberArray(props.modelValue)
}else{
return props.modelValue * 1;
}
} else {
return props.modelValue;
}
},
set: (newVal: any) => {
emits("update:modelValue", newVal);
//console.log(newVal)
if(isArray(newVal)){
let str = arrayToCommaString(newVal)
//console.log(2)
//console.log(str)
emits("update:modelValue", str);
}else{
//console.log(1)
//console.log(newVal)
emits("update:modelValue", newVal);
}
// let newValJson:criteriaForPeopleList[] = JSON.parse(newVal)
// if(newValJson.length > 0){
// let userAry = new Array
@ -43,6 +64,62 @@ const value = computed({
// }
},
});
function hasComma(str: any) {
//
if (typeof str !== 'string') {
return false
}
// 使indexOf
// truefalse
return str.indexOf(',') !== -1;
}
function commaStringToNumberArray(str: string) {
//
if (typeof str !== 'string') {
throw new Error('输入必须是字符串');
}
//
if (str.trim() === '') {
return [];
}
//
return str.split(',').map(item => {
//
const trimmed = item.trim();
//
const number = Number(trimmed);
//
if (isNaN(number)) {
throw new Error(`无法将 "${trimmed}" 转换为有效数字`);
}
return number;
});
}
function isArray(variable: any) {
// 使
if (typeof Array.isArray === 'function') {
return Array.isArray(variable);
} else {
//
return Object.prototype.toString.call(variable) === '[object Array]';
}
}
function arrayToCommaString(numbers: any[]) {
//
if (!Array.isArray(numbers)) {
throw new Error('输入必须是一个数组');
}
// 使join
return numbers.join(',');
}
const orgTreeList = ref<orgInfo[]>();
const orgTreeLoading = ref(false); //
const orgTreeProps = {
@ -55,7 +132,21 @@ function haveOrgTreeInfo() {
getOrgTreeList({ orgid: 309 })
.then(({ data }) => {
console.log("行政组织树对照值", data);
orgTreeList.value = data;
//liwenxuan 250916 start
// IDIDididid
const targetIds = props.data.control.range
//
const filteredTree = filterOrganizationTree(data, targetIds);
orgTreeList.value = filteredTree
//liwenxuan 250916 end
//orgTreeList.value = data;
})
.finally(() => {
orgTreeLoading.value = false;
@ -72,6 +163,145 @@ onMounted(() => {
haveOrgTreeInfo();
});
});
/**
* 过滤组织架构树仅保留顶层目标ID节点其所有祖先节点和子孙节点
* 顶层目标ID目标数组中无其他ID是其祖先的ID子节点ID会被自动忽略
* @param {Array} originalTree - 原始组织架构树形结构顶层为数组
* @param {Array<number>} targetIds - 目标节点ID数组可能包含子节点ID
* @returns {Array} 过滤后的组织架构树
*/
function filterOrganizationTree(originalTree: orgInfo[], targetIds: any) {
// 1. ID便/
const nodeMap = new Map();
buildNodeMap(originalTree, nodeMap);
// 2. IDIDIDID
const topTargetIds = filterChildTargetIds(targetIds, nodeMap);
if (topTargetIds.length === 0) {
console.warn("警告:所有目标ID无效或均为其他目标ID的子节点,返回空树");
return [];
}
// 3. IDID + ID + ID
const keepIds = collectKeepIds(topTargetIds, nodeMap);
// 4.
const filteredTree = filterTreeNodes(originalTree, keepIds);
return filteredTree;
}
/**
* 辅助函数1遍历树形结构构建节点ID节点映射表
* @param {Array} nodes - 当前层级的节点数组顶层/子节点数组
* @param {Map} nodeMap - 待构建的节点映射表
*/
function buildNodeMap(nodes: any[], nodeMap: Map<any, any>) {
if (!nodes || !Array.isArray(nodes)) return;
nodes.forEach(node => {
nodeMap.set(node.id, node);
// childnull
buildNodeMap(Array.isArray(node.child) ? node.child : [], nodeMap);
});
}
/**
* 辅助函数2预处理目标ID数组过滤掉是其他目标ID子节点的ID
* @param {Array<number>} targetIds - 原始目标ID数组
* @param {Map} nodeMap - 节点映射表
* @returns {Array<number>} 仅包含顶层目标ID的数组无父节点在目标数组内
*/
function filterChildTargetIds(targetIds: any[], nodeMap: Map<any, any>) {
if (!targetIds || !Array.isArray(targetIds)) return [];
// ID
const validTargetIds = targetIds.filter(id => nodeMap.has(id));
if (validTargetIds.length <= 1) return validTargetIds; // 1ID
// IDIDID
return validTargetIds.filter(currentId => {
let parentId = nodeMap.get(currentId).superior;
// ID
while (parentId !== undefined && nodeMap.has(parentId)) {
if (validTargetIds.includes(parentId)) {
console.log(`提示:ID ${currentId} 是目标ID ${parentId} 的子节点,已忽略`);
return false; // ID
}
parentId = nodeMap.get(parentId).superior; //
}
return true; // ID
});
}
/**
* 辅助函数3收集所有需保留的节点ID顶层目标ID + 所有祖先ID + 所有子孙ID
* @param {Array<number>} topTargetIds - 预处理后的顶层目标ID数组
* @param {Map} nodeMap - 节点映射表
* @returns {Set<number>} 需保留的节点ID集合去重
*/
function collectKeepIds(topTargetIds: any[], nodeMap: Map<any, any>) {
const keepIds = new Set();
topTargetIds.forEach((targetId: unknown) => {
const targetNode = nodeMap.get(targetId);
// 1.
keepIds.add(targetId);
// 2.
let parentId = targetNode.superior;
while (parentId !== undefined && nodeMap.has(parentId)) {
keepIds.add(parentId);
parentId = nodeMap.get(parentId).superior;
}
// 3. ...
collectDescendants(targetNode.child, nodeMap, keepIds);
});
return keepIds;
}
/**
* 辅助函数4递归收集某个节点的所有子孙节点ID
* @param {Array} childNodes - 当前节点的子节点数组
* @param {Map} nodeMap - 节点映射表
* @param {Set<number>} keepIds - 需保留的ID集合
*/
function collectDescendants(childNodes: any[], nodeMap: any, keepIds: Set<unknown>) {
if (!Array.isArray(childNodes)) return;
childNodes.forEach(childNode => {
keepIds.add(childNode.id);
collectDescendants(childNode.child, nodeMap, keepIds); //
});
}
/**
* 辅助函数5递归过滤树形节点仅保留在keepIds中的节点
* @param {Array} nodes - 当前层级的节点数组
* @param {Set<number>} keepIds - 需保留的节点ID集合
* @returns {Array} 过滤后的节点数组
*/
function filterTreeNodes(nodes: any[], keepIds: Set<unknown>) {
if (!Array.isArray(nodes) || !keepIds) return [];
return nodes.reduce((filtered, node) => {
if (keepIds.has(node.id)) {
//
const clonedNode = { ...node };
clonedNode.child = filterTreeNodes(Array.isArray(clonedNode.child) ? clonedNode.child : [], keepIds);
filtered.push(clonedNode);
}
return filtered;
}, []);
}
const multiple = props.data.control.multiple=='1'
</script>
<template>
<el-tree-select
@ -81,9 +311,11 @@ onMounted(() => {
node-key="id"
:props="orgTreeProps"
:data="orgTreeList"
check-strictly
:render-after-expand="false"
clearable
:show-checkbox="multiple"
:multiple="multiple"
:check-strictly="!multiple"
/>
<div></div>
</template>

110
src/widget/org/cont.vue

@ -12,21 +12,115 @@ const props = defineProps({
}
})
const orgName = ref("")
/* const orgName = computed(()=>{
return str.value
}) */
//let str = ref("")
//
const pickOrgVal = (val:any) => {
if(val != "" && val != null){
getgovcont({id:val*1,idstr:val})
.then(({data}) =>{
// console.log("-3->",data,data.name)
if(hasComma(val)){
let arr = commaStringToNumberArray(val)
let str= ''
arr.forEach((element, index, array) => {
//
const isLast = index === array.length - 1;
str = ''
let item = element+""
getgovcont({id:element*1,idstr:item})
.then(({data}) =>{
str+=data.name+","
})
.finally(()=>{
if(isLast){
//alert(1)
str = removeLastChar(str)
orgName.value = str
}
})
});
}else{
getgovcont({id:val*1,idstr:val})
.then(({data}) =>{
// console.log("-3->",data,data.name)
orgName.value = data.name
})
.finally(()=>{
})
})
.finally(()=>{})
}
}
}
function removeLastChar(str: string | any[]) {
//
if (typeof str !== 'string') {
throw new Error('输入必须是字符串类型');
}
//
if (str.length === 0) {
return str; //
}
//
return str.slice(0, -1);
}
function hasComma(str: any) {
//
if (typeof str !== 'string') {
return false
}
// 使indexOf
// truefalse
return str.indexOf(',') !== -1;
}
function commaStringToNumberArray(str: string) {
//
if (typeof str !== 'string') {
throw new Error('输入必须是字符串');
}
//
if (str.trim() === '') {
return [];
}
//
return str.split(',').map(item => {
//
const trimmed = item.trim();
//
const number = Number(trimmed);
//
if (isNaN(number)) {
throw new Error(`无法将 "${trimmed}" 转换为有效数字`);
}
return number;
});
}
onBeforeMount(() => {
pickOrgVal(props.orgid)
})

Loading…
Cancel
Save