349 lines
12 KiB
Vue
349 lines
12 KiB
Vue
<template>
|
||
<j-form class="table" ref="formTableRef" :model="modelRef">
|
||
<j-table
|
||
v-if="modelRef.dataSource.length !== 0"
|
||
:dataSource="modelRef.dataSource"
|
||
:columns="FormTableColumns"
|
||
:scroll="{ y: 580 }"
|
||
>
|
||
<template #headerCell="{ column }">
|
||
<template
|
||
v-if="column.key === 'nodeId' || column.key === 'action'"
|
||
>
|
||
<span> {{ column.title }} </span>
|
||
</template>
|
||
<template v-else>
|
||
<span> {{ column.title }} </span>
|
||
<span style="margin-left: 5px; color: red">*</span>
|
||
</template>
|
||
</template>
|
||
<template #bodyCell="{ column: { dataIndex }, record, index }">
|
||
<template v-if="dataIndex === 'name'">
|
||
<j-form-item
|
||
:name="['dataSource', index, 'name']"
|
||
:rules="[
|
||
{
|
||
required: true,
|
||
message: '请输入',
|
||
},
|
||
{
|
||
validator: checkLength,
|
||
trigger: 'change',
|
||
},
|
||
]"
|
||
>
|
||
<j-input
|
||
v-model:value="record[dataIndex]"
|
||
placeholder="请输入"
|
||
allowClear
|
||
></j-input>
|
||
</j-form-item>
|
||
</template>
|
||
<template v-if="dataIndex === 'id'">
|
||
<j-form-item
|
||
v-show="false"
|
||
:name="['dataSource', index, 'id']"
|
||
>
|
||
<j-input
|
||
v-model:value="record[dataIndex]"
|
||
disabled
|
||
:bordered="false"
|
||
></j-input>
|
||
</j-form-item>
|
||
<div
|
||
style="
|
||
margin: -24px 0 0 10px;
|
||
overflow: hidden;
|
||
white-space: nowrap;
|
||
text-overflow: ellipsis;
|
||
"
|
||
>
|
||
<j-tooltip>
|
||
<template #title>{{ record[dataIndex] }}</template>
|
||
{{ record[dataIndex] }}
|
||
</j-tooltip>
|
||
</div>
|
||
</template>
|
||
<template v-if="dataIndex === 'accessModes'">
|
||
<j-form-item
|
||
class="form-item"
|
||
:name="['dataSource', index, 'accessModes', 'value']"
|
||
:rules="[
|
||
{
|
||
required: true,
|
||
message: '请选择',
|
||
},
|
||
]"
|
||
>
|
||
<j-select
|
||
style="width: 75%"
|
||
v-model:value="record[dataIndex].value"
|
||
placeholder="请选择"
|
||
allowClear
|
||
mode="multiple"
|
||
:filter-option="filterOption"
|
||
:options="[
|
||
{ label: '读', value: 'read' },
|
||
{ label: '写', value: 'write' },
|
||
{ label: '订阅', value: 'subscribe' },
|
||
]"
|
||
:disabled="index !== 0 && record[dataIndex].check"
|
||
@change="changeValue(index, dataIndex)"
|
||
>
|
||
</j-select>
|
||
<j-checkbox
|
||
style="margin-left: 5px"
|
||
v-if="index !== 0"
|
||
v-model:checked="record[dataIndex].check"
|
||
@click="changeCheckbox(index, dataIndex)"
|
||
>同上</j-checkbox
|
||
>
|
||
</j-form-item>
|
||
</template>
|
||
<template v-if="dataIndex === 'interval'">
|
||
<j-form-item
|
||
class="form-item"
|
||
:name="[
|
||
'dataSource',
|
||
index,
|
||
'configuration',
|
||
'interval',
|
||
'value',
|
||
]"
|
||
:rules="[
|
||
{
|
||
validator: checkLength,
|
||
trigger: 'change',
|
||
},
|
||
{
|
||
pattern: regOnlyNumber,
|
||
message: '请输入0或者正整数',
|
||
},
|
||
]"
|
||
>
|
||
<j-input
|
||
style="width: 60%"
|
||
v-model:value="
|
||
record.configuration[dataIndex].value
|
||
"
|
||
placeholder="请输入"
|
||
allowClear
|
||
addon-after="ms"
|
||
:disabled="
|
||
index !== 0 &&
|
||
record.configuration[dataIndex].check
|
||
"
|
||
@blur="changeValue(index, dataIndex)"
|
||
></j-input>
|
||
<j-checkbox
|
||
style="margin-left: 5px; margin-top: 5px"
|
||
v-show="index !== 0"
|
||
v-model:checked="
|
||
record.configuration[dataIndex].check
|
||
"
|
||
@click="changeCheckbox(index, dataIndex)"
|
||
>同上</j-checkbox
|
||
>
|
||
</j-form-item>
|
||
</template>
|
||
<template v-if="dataIndex === 'features'">
|
||
<j-form-item
|
||
class="form-item"
|
||
:name="['dataSource', index, 'features', 'value']"
|
||
:rules="[
|
||
{
|
||
required: true,
|
||
message: '请选择',
|
||
},
|
||
]"
|
||
>
|
||
<j-select
|
||
style="width: 40%"
|
||
v-model:value="record[dataIndex].value"
|
||
placeholder="请选择"
|
||
allowClear
|
||
:filter-option="filterOption"
|
||
:options="[
|
||
{
|
||
label: '是',
|
||
value: true,
|
||
},
|
||
{
|
||
label: '否',
|
||
value: false,
|
||
},
|
||
]"
|
||
:disabled="index !== 0 && record[dataIndex].check"
|
||
@change="changeValue(index, dataIndex)"
|
||
>
|
||
</j-select>
|
||
|
||
<j-checkbox
|
||
style="margin-left: 5px"
|
||
v-show="index !== 0"
|
||
v-model:checked="record[dataIndex].check"
|
||
@click="changeCheckbox(index, dataIndex)"
|
||
>同上</j-checkbox
|
||
>
|
||
</j-form-item>
|
||
</template>
|
||
|
||
<template v-if="dataIndex === 'action'">
|
||
<j-tooltip title="删除">
|
||
<j-popconfirm
|
||
title="确认删除"
|
||
@confirm="clickDelete(record.id)"
|
||
>
|
||
<a style="color: red"
|
||
><AIcon type="DeleteOutlined"
|
||
/></a>
|
||
</j-popconfirm>
|
||
</j-tooltip>
|
||
</template>
|
||
</template>
|
||
</j-table>
|
||
<j-empty v-else style="margin-top: 10%" />
|
||
</j-form>
|
||
</template>
|
||
|
||
<script lang="ts" setup>
|
||
import { FormTableColumns, regOnlyNumber } from '../../data';
|
||
import { Rule } from 'ant-design-vue/lib/form';
|
||
|
||
const props = defineProps({
|
||
data: {
|
||
type: Array,
|
||
default: () => [],
|
||
},
|
||
});
|
||
const emits = defineEmits(['change']);
|
||
|
||
const formTableRef = ref();
|
||
const defaultType = ['accessModes', 'interval', 'features'];
|
||
const modelRef: any = reactive({
|
||
dataSource: [],
|
||
});
|
||
|
||
const checkLength = (_rule: Rule, value: string): Promise<any> =>
|
||
new Promise(async (resolve, reject) => {
|
||
if (value) {
|
||
return String(value).length > 64
|
||
? reject('最多可输入64个字符')
|
||
: resolve('');
|
||
} else {
|
||
reject('请输入');
|
||
}
|
||
});
|
||
|
||
const filterOption = (input: string, option: any) => {
|
||
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
|
||
};
|
||
|
||
const clickDelete = (value: string) => {
|
||
emits('change', value);
|
||
};
|
||
|
||
const getTargetData = (index: number, type: string) => {
|
||
const { dataSource } = modelRef;
|
||
const Interval = type === 'interval';
|
||
return !Interval
|
||
? dataSource[index][type]
|
||
: dataSource[index].configuration[type];
|
||
};
|
||
|
||
const changeValue = (index: number, type: string) => {
|
||
const { dataSource } = modelRef;
|
||
const originData = getTargetData(index, type);
|
||
for (let i = index + 1; i < dataSource.length; i++) {
|
||
const targetType = getTargetData(i, type);
|
||
if (!targetType.check) return;
|
||
targetType.value = originData.value;
|
||
}
|
||
};
|
||
|
||
const changeCheckbox = async (index: number, type: string) => {
|
||
//Dom未更新完成,需要用 setTimeout 或者 await nextTick() 处理
|
||
setTimeout(() => {
|
||
let startIndex = 0;
|
||
const { dataSource } = modelRef;
|
||
const currentCheck = getTargetData(index, type).check;
|
||
if (!currentCheck) return;
|
||
for (let i = index; i >= 0; i--) {
|
||
const preDataCheck = getTargetData(i, type).check;
|
||
if (!preDataCheck) {
|
||
startIndex = i;
|
||
break;
|
||
}
|
||
}
|
||
const originData = getTargetData(startIndex, type);
|
||
for (let i = startIndex; i < dataSource.length - 1; i++) {
|
||
const targetType = getTargetData(i + 1, type);
|
||
if (!targetType.check) return;
|
||
targetType.value = originData.value;
|
||
}
|
||
}, 0);
|
||
};
|
||
|
||
const validate = () => {
|
||
return new Promise((res, rej) => {
|
||
formTableRef.value
|
||
.validate()
|
||
.then(() => {
|
||
res(modelRef.dataSource);
|
||
})
|
||
.catch((err: any) => {
|
||
rej(err);
|
||
});
|
||
});
|
||
};
|
||
defineExpose({
|
||
validate,
|
||
});
|
||
watch(
|
||
() => props.data,
|
||
(value, preValue) => {
|
||
modelRef.dataSource = value;
|
||
|
||
// 有新增时同上数据
|
||
const vlength = value.length,
|
||
plength = preValue.length;
|
||
if (plength !== 0 && plength < vlength) {
|
||
defaultType.forEach((type) => {
|
||
vlength === 2
|
||
? changeValue(0, type)
|
||
: changeCheckbox(vlength - 1, type);
|
||
});
|
||
}
|
||
},
|
||
{ deep: true },
|
||
);
|
||
</script>
|
||
|
||
<style lang="less" scoped>
|
||
.table {
|
||
width: 100%;
|
||
min-width: 600px;
|
||
:deep(.ant-table-header) {
|
||
.ant-table-cell {
|
||
padding: 16px 5px;
|
||
}
|
||
}
|
||
|
||
:deep(.ant-table-tbody) {
|
||
.ant-table-cell {
|
||
padding: 24px 0 0 0;
|
||
}
|
||
.ant-table-cell-fix-right-first {
|
||
padding: 0 0 0 10px;
|
||
}
|
||
}
|
||
:deep(.ant-pagination) {
|
||
display: none;
|
||
}
|
||
}
|
||
|
||
.form-item {
|
||
display: flex;
|
||
}
|
||
</style>
|