feat: 明细表中的组织架构选择器支持将文本表示存储在独立字段,以改善显示性能
This commit is contained in:
@ -422,6 +422,13 @@
|
|||||||
</template>
|
</template>
|
||||||
</a-input>
|
</a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<template v-if="data.isSubFormChild">
|
||||||
|
<a-form-item v-if="hasKey('sepTextField')" label="文本存储字段">
|
||||||
|
<a-select v-model:value="data.options.sepTextField" :allow-clear="true" :placeholder="t('请选择文本字段')" size="mini">
|
||||||
|
<a-select-option v-for="fItem in findTableFields(data)" :key="fItem.key" :value="fItem.bindField">{{ fItem.label }}</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
</template>
|
||||||
<!-- 响应式布局只对主表字段生效 -->
|
<!-- 响应式布局只对主表字段生效 -->
|
||||||
<template v-if="!data.isSubFormChild">
|
<template v-if="!data.isSubFormChild">
|
||||||
<a-form-item v-if="hasKey('responsive')" label="响应式">
|
<a-form-item v-if="hasKey('responsive')" label="响应式">
|
||||||
@ -1560,6 +1567,18 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function findTableFields(obj) {
|
||||||
|
if (!props.widgetForm?.list) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const bTable = obj.bindTable;
|
||||||
|
const pTable = props.widgetForm.list.find((item) => item.type === 'form' && item.bindTable === bTable);
|
||||||
|
if (!pTable) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return pTable.children;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data,
|
data,
|
||||||
hasKey,
|
hasKey,
|
||||||
@ -1617,7 +1636,8 @@
|
|||||||
handleIsSave,
|
handleIsSave,
|
||||||
buttonTableOptions,
|
buttonTableOptions,
|
||||||
t,
|
t,
|
||||||
imageUrl
|
imageUrl,
|
||||||
|
findTableFields
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1164,6 +1164,7 @@ export const infoComponents = [
|
|||||||
labelFixWidth: 120,
|
labelFixWidth: 120,
|
||||||
parentNode: '',
|
parentNode: '',
|
||||||
responsive: false,
|
responsive: false,
|
||||||
|
sepTextField: '',
|
||||||
span: '',
|
span: '',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
defaultValue: undefined,
|
defaultValue: undefined,
|
||||||
@ -1184,6 +1185,7 @@ export const infoComponents = [
|
|||||||
labelWidthMode: 'fix',
|
labelWidthMode: 'fix',
|
||||||
labelFixWidth: 120,
|
labelFixWidth: 120,
|
||||||
responsive: false,
|
responsive: false,
|
||||||
|
sepTextField: '',
|
||||||
span: '',
|
span: '',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
defaultValue: '',
|
defaultValue: '',
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div style="width: 100%" @click="show" class="depart-select">
|
<div class="depart-select" style="width: 100%" @click="show">
|
||||||
<a-input v-model:value="departNames" :bordered="bordered" :disabled="disabled" :placeholder="placeholder"
|
<a-input v-model:value="departNames" :bordered="bordered" :disabled="disabled" :placeholder="placeholder" :size="size" readonly>
|
||||||
:size="size" readonly>
|
|
||||||
<template v-if="prefix" #prefix>
|
<template v-if="prefix" #prefix>
|
||||||
<Icon :icon="prefix" />
|
<Icon :icon="prefix" />
|
||||||
</template>
|
</template>
|
||||||
@ -9,35 +8,37 @@
|
|||||||
<Icon :icon="suffix" />
|
<Icon :icon="suffix" />
|
||||||
</template>
|
</template>
|
||||||
</a-input>
|
</a-input>
|
||||||
<ModalPanel :visible="visible" :width="800" :title="t('选择部门')" @submit="submit" @close="close" class="depart-select-dialog">
|
<ModalPanel :title="t('选择部门')" :visible="visible" :width="800" class="depart-select-dialog" @close="close" @submit="submit">
|
||||||
<div class="choose-dep-box">
|
<div class="choose-dep-box">
|
||||||
<div class="choose-dep">
|
<div class="choose-dep">
|
||||||
<a-spin class="loading-box" :spinning="loading" />
|
<a-spin :spinning="loading" class="loading-box" />
|
||||||
<SelectDepartmentTreeV2 v-if="visible" @changeValue="departChange" :value="props.value"
|
<SelectDepartmentTreeV2 v-if="visible" :parentNode="parentNode" :value="props.value" @changeValue="departChange" @queryCompleted="queryCompleted"></SelectDepartmentTreeV2>
|
||||||
@queryCompleted="queryCompleted" :parentNode="parentNode"></SelectDepartmentTreeV2>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="choosen-dep">
|
<div class="choosen-dep">
|
||||||
<div class="choosen-item" v-for="item in selectedNodes">
|
<div v-for="item in selectedNodes" class="choosen-item">
|
||||||
<div class="choosen-label">{{ item.name }}</div>
|
<div class="choosen-label">{{ item.name }}</div>
|
||||||
<close-outlined class="close" @click="deleteItem" />
|
<close-outlined class="close" @click="deleteItem" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</ModalPanel>
|
</ModalPanel>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script setup>
|
||||||
import { onMounted, ref, watch } from 'vue';
|
import { onMounted, ref, watch } from 'vue';
|
||||||
import SelectDepartmentTreeV2 from './SelectDepartmentTreeV2.vue'
|
import SelectDepartmentTreeV2 from './SelectDepartmentTreeV2.vue';
|
||||||
import { useI18n } from '/@/hooks/web/useI18n';
|
import { useI18n } from '/@/hooks/web/useI18n';
|
||||||
import { ModalPanel } from '/@/components/ModalPanel/index';
|
import { ModalPanel } from '/@/components/ModalPanel/index';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const emits = defineEmits(['change', 'changeNames', 'close', 'options-change', 'update:value']);
|
const emits = defineEmits(['change', 'changeNames', 'close', 'options-change', 'update:value']);
|
||||||
import { getDepartmentTrees } from '/@/api/system/department';
|
import { getDepartmentTrees } from '/@/api/system/department';
|
||||||
import { CloseOutlined } from '@ant-design/icons-vue';
|
import { CloseOutlined } from '@ant-design/icons-vue';
|
||||||
const visible = ref(false)
|
import { camelCaseString } from '/@/utils/event/design';
|
||||||
const departNames = ref<string>();
|
|
||||||
|
const visible = ref(false);
|
||||||
|
const departNames = ref();
|
||||||
|
const valChanged = ref(false);
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
value: String,
|
value: String,
|
||||||
@ -59,43 +60,52 @@ const props = defineProps({
|
|||||||
componentProps: {
|
componentProps: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: {}
|
default: {}
|
||||||
}
|
},
|
||||||
|
sepTextField: '', // 将文字描述存在独立字段,增加首次渲染速度
|
||||||
|
row: Object
|
||||||
});
|
});
|
||||||
const selectedNodes = ref([])
|
const selectedNodes = ref([]);
|
||||||
const loading = ref(true)
|
const loading = ref(true);
|
||||||
|
|
||||||
// Embedded in the form, just use the hook binding to perform form verification
|
// Embedded in the form, just use the hook binding to perform form verification
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {});
|
||||||
});
|
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.value,
|
() => props.value,
|
||||||
(val: any) => {
|
(val) => {
|
||||||
if (val) {
|
if (val) {
|
||||||
getDefaultList(val)
|
if (props.sepTextField && !valChanged.value) {
|
||||||
|
departNames.value = props.row[camelCaseString(props.sepTextField, true)];
|
||||||
|
} else {
|
||||||
|
getDefaultList(val);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
immediate: true,
|
immediate: true
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
async function getDefaultList(id) {
|
async function getDefaultList(id) {
|
||||||
let param = {
|
let param = {
|
||||||
id: id,
|
id: id,
|
||||||
code: '',
|
code: '',
|
||||||
name: '',
|
name: '',
|
||||||
parentNode: false
|
parentNode: false
|
||||||
}
|
};
|
||||||
let list = resetTreeList(await getDepartmentTrees(param))
|
let list = resetTreeList(await getDepartmentTrees(param));
|
||||||
selectedNodes.value = list
|
selectedNodes.value = list;
|
||||||
let nameList = selectedNodes.value.map(item => item.name)
|
let nameList = selectedNodes.value.map((item) => item.name);
|
||||||
const names = nameList.join(',')
|
const names = nameList.join(',');
|
||||||
departNames.value = names;
|
departNames.value = names;
|
||||||
// handleSelectedNodes()
|
if (props.sepTextField) {
|
||||||
|
props.row[camelCaseString(props.sepTextField, true)] = names;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function resetTreeList(list) {
|
function resetTreeList(list) {
|
||||||
const result = list.map(item => {
|
const result = list.map((item) => {
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
...{
|
...{
|
||||||
@ -103,41 +113,52 @@ function resetTreeList(list) {
|
|||||||
children: resetTreeList(item.children),
|
children: resetTreeList(item.children),
|
||||||
title: item.name
|
title: item.name
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
})
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
function queryCompleted() {
|
function queryCompleted() {
|
||||||
loading.value = false
|
loading.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function departChange(nodes) {
|
function departChange(nodes) {
|
||||||
selectedNodes.value = nodes
|
selectedNodes.value = nodes;
|
||||||
|
valChanged.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function show() {
|
function show() {
|
||||||
visible.value = true
|
visible.value = true;
|
||||||
loading.value = true
|
loading.value = true;
|
||||||
if (props.value) {
|
if (props.value) {
|
||||||
getDefaultList(props.value)
|
getDefaultList(props.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSelectedNodes() {
|
function handleSelectedNodes() {
|
||||||
let nameList = selectedNodes.value.map(item => item.name)
|
let nameList = selectedNodes.value.map((item) => item.name);
|
||||||
let idList = selectedNodes.value.map(item => item.id)
|
let idList = selectedNodes.value.map((item) => item.id);
|
||||||
const names = nameList.join(',')
|
const names = nameList.join(',');
|
||||||
const ids = idList.join(',')
|
const ids = idList.join(',');
|
||||||
emits('update:value', ids);
|
emits('update:value', ids);
|
||||||
departNames.value = names;
|
departNames.value = names;
|
||||||
|
if (props.sepTextField) {
|
||||||
|
props.row[camelCaseString(props.sepTextField, true)] = names;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function deleteItem() {
|
function deleteItem() {
|
||||||
selectedNodes.value = []
|
selectedNodes.value = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
function submit() {
|
function submit() {
|
||||||
handleSelectedNodes()
|
handleSelectedNodes();
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
function close() {
|
function close() {
|
||||||
visible.value = false;
|
visible.value = false;
|
||||||
selectedNodes.value = []
|
selectedNodes.value = [];
|
||||||
emits('close');
|
emits('close');
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@ -189,7 +210,7 @@ function close() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.close {
|
.close {
|
||||||
visibility: hidden
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,7 +218,7 @@ function close() {
|
|||||||
background-color: #eaeaea;
|
background-color: #eaeaea;
|
||||||
|
|
||||||
.close {
|
.close {
|
||||||
visibility: visible
|
visibility: visible;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
{{ t('新增') }}
|
{{ t('新增') }}
|
||||||
</a-button>
|
</a-button>
|
||||||
</div>
|
</div>
|
||||||
<a-table :bordered="showFormBorder" :columns="headColums.length > 0 ? headColums : columns" :data-source="data" :pagination="showPagination ? { defaultPageSize: 10 } : false" :scroll="{ x: 'max-content' }">
|
<a-table :bordered="showFormBorder" :columns="headColums.length > 0 ? headColums : columns" :data-source="addDataKey(data)" :pagination="showPagination ? { defaultPageSize: 10 } : false" :scroll="{ x: 'max-content' }">
|
||||||
<template #summary>
|
<template #summary>
|
||||||
<a-table-summary-row v-if="columns.some((x) => x.componentProps?.subTotal)">
|
<a-table-summary-row v-if="columns.some((x) => x.componentProps?.subTotal)">
|
||||||
<a-table-summary-cell v-for="(column, idx) in columns" :key="idx">
|
<a-table-summary-cell v-for="(column, idx) in columns" :key="idx">
|
||||||
@ -66,6 +66,8 @@
|
|||||||
:bordered="showComponentBorder"
|
:bordered="showComponentBorder"
|
||||||
:index="index"
|
:index="index"
|
||||||
:mainKey="mainKey"
|
:mainKey="mainKey"
|
||||||
|
:key="column.dataIndex + record['_key_']"
|
||||||
|
:row="record"
|
||||||
v-bind="getComponentsProps(column.componentProps, column.dataIndex, record, index)"
|
v-bind="getComponentsProps(column.componentProps, column.dataIndex, record, index)"
|
||||||
@blur="onFieldBlur(column, record, index)"
|
@blur="onFieldBlur(column, record, index)"
|
||||||
@change="onFieldChange(column, record, index)"
|
@change="onFieldChange(column, record, index)"
|
||||||
@ -225,6 +227,15 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addDataKey(rows) {
|
||||||
|
rows.forEach((row) => {
|
||||||
|
if (!row['_key_']) {
|
||||||
|
row['_key_'] = Math.random();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
data.value = cloneDeep(props.value);
|
data.value = cloneDeep(props.value);
|
||||||
|
|
||||||
@ -261,23 +272,7 @@
|
|||||||
watch(
|
watch(
|
||||||
() => props.value,
|
() => props.value,
|
||||||
(v) => {
|
(v) => {
|
||||||
// console.log('watch props.value', props.value);
|
|
||||||
data.value = v;
|
data.value = v;
|
||||||
// const rangeComponents = props.columns.filter((column) =>
|
|
||||||
// column.componentType?.includes('Range'),
|
|
||||||
// );
|
|
||||||
// if (rangeComponents.length && formModel) {
|
|
||||||
// rangeComponents.forEach((item) => {
|
|
||||||
// data.value.forEach((x) => {
|
|
||||||
// if (x[(item.dataIndex as string)?.split(',')[0]]) {
|
|
||||||
// x[item.dataIndex as string] = [
|
|
||||||
// x[(item.dataIndex as string)?.split(',')[0]],
|
|
||||||
// x[(item.dataIndex as string)?.split(',')[1]],
|
|
||||||
// ];
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
//要保证在预加载之后在emit 不然预加载数据不会绑定到表单数据中
|
//要保证在预加载之后在emit 不然预加载数据不会绑定到表单数据中
|
||||||
emit('change', unref(data));
|
emit('change', unref(data));
|
||||||
|
|||||||
@ -27,8 +27,11 @@ export function changeToPinyin(label: string, isUpper?: boolean) {
|
|||||||
|
|
||||||
/* 如果没有下划线,不需要处理
|
/* 如果没有下划线,不需要处理
|
||||||
如果有下划线,用下划线切割,第一个下划线左边的全部小写,后面的首字母大写,首字母后面的全部小写 */
|
如果有下划线,用下划线切割,第一个下划线左边的全部小写,后面的首字母大写,首字母后面的全部小写 */
|
||||||
export function camelCaseString(string: string) {
|
export function camelCaseString(string: string, skipNoUnderline = false) {
|
||||||
if (!string) return;
|
if (!string) return;
|
||||||
|
if (skipNoUnderline && string.indexOf('_') < 0) {
|
||||||
|
return string;
|
||||||
|
}
|
||||||
const stringLower = string.toLowerCase();
|
const stringLower = string.toLowerCase();
|
||||||
const len = stringLower.length;
|
const len = stringLower.length;
|
||||||
let str = '';
|
let str = '';
|
||||||
|
|||||||
Reference in New Issue
Block a user