<!-- @format --> <template> <div class="edittable-contain"> <div class="operation"> <a-button type="primary" @click="operation('get')" v-if="api">获取数据</a-button> <a-button type="primary" @click="operation('clear')">清除数据</a-button> </div> <NsBasicTable :columns="columns" :data-source="dataSource" align="center" rowKey="familyUuid" @change="change" :scroll="{ x: '800px' }" > <template #headerCell="{ title, column }"> <template v-if="column.required"> <div class="mainColum">{{ title }}</div> </template> </template> <template #bodyCell="{ column, text, record, index }"> <template v-if="column.dataIndex !== 'action'"> <div> <component style="min-width: 120px" v-model:value="record[column.dataIndex]" :is="column.component" :record="record" v-bind="column.formProps || column.componentProps" /> <p v-if="column.validator" style="color: red"> {{ column.validator(record) === 'error' ? column.errorTitle : '' }} </p> </div> </template> <template v-if="column.dataIndex === 'action'"> <div style="min-width: 120px" class="column-operation"> <span style="cursor: pointer; color: rgb(27, 182, 182)" @click="remove(index)" >移除</span > <span style="cursor: pointer; color: rgb(27, 182, 182)" @click="setOptions('down', index)" >向下插入</span > <span style="cursor: pointer; color: rgb(27, 182, 182)" @click="setOptions('up', index)" >向上插入</span > </div> </template> </template> <template #footer v-if="!readonly"> <span style="cursor: pointer; color: rgb(27, 182, 182)" @click="add"> 添加</span> </template> </NsBasicTable> </div> </template> <script lang="ts"> import { defineComponent, ref, PropType, nextTick, watch, unref, computed } from 'vue'; import { cloneDeep, get, isArray, isEqual, isFunction, isString, isUndefined } from 'lodash-es'; import { HttpRequestConfig, useApi } from '/nerv-lib/use/use-api'; import { useParams } from '/nerv-lib/use/use-params'; export default defineComponent({ name: 'NsCustomEditTable', props: { api: { type: [String, Object, Function] as PropType<string | Function | HttpRequestConfig>, required: true, }, params: { type: Object, default: () => ({}), }, resultField: { type: String, default: 'data.data', }, columns: { type: Array, default: () => [], }, initData: { type: Array, default: () => [], }, readonly: { type: Boolean, default: () => false, }, value: { type: Array, default: () => [], }, formModel: { type: Object as PropType<Recordable>, default: () => ({}), }, scroll: { type: Object, default: () => ({ x: '800px' }), }, }, emits: ['change', 'validateChange'], setup(props, { emit }) { // const components = inject("components"); const columns = ref([]); const dataSource = ref([]); const { getParams } = useParams(); columns.value = props.columns; dataSource.value = props.initData; const add = () => { // let info = JSON.parse(JSON.stringify(props.initItem)); // if ( // dataSource.value.length === 0 // ) { dataSource.value.push({}); // } console.log(dataSource.value); }; const pagination = ref({ current: 1, pageSize: 10, }); const remove = (i: number) => { let pagebase = (pagination.value.current - 1) * 10; dataSource.value.splice(i + pagebase, 1); }; const change = (pag, filters, sorter, { currentDataSource }) => { pagination.value = pag; }; /** * 获取数据 */ const fetch = () => { const requestConfig: HttpRequestConfig = { method: 'get' }; const { api, params: _params, resultField, filterData, dynamicParams } = props; let params: Recordable = cloneDeep(_params); // if (props.filterFiled && filterFiledRef.value) { // params[props.filterFiled] = filterFiledRef.value; // } // let data; if (dynamicParams) { params = getParams(props.formModel, dynamicParams, { ...params }); // console.log('getParams', data); } const { httpRequest } = useApi(); httpRequest({ api, params, requestConfig }) .then((res: Recordable) => { emit('validateChange', { help: undefined }); if (resultField) { // debugger; let data = get(res, resultField) || []; // data = data.splice(Math.floor(Math.random() * 3), Math.floor(Math.random() * 5 + 5)); if (isFunction(filterData)) { dataSource.value = data.filter(filterData); } else { dataSource.value = data; } emit('change', dataSource.value); } }) .catch((error: any) => { if (error?.response?.status === 403) { emit('validateChange', { help: '暂无权限', validateStatus: 'error' }); } dataSource.value = []; }); }; const operation = (name) => { if (name === 'get') { fetch(); } if (name === 'clear') { dataSource.value.splice(0); emit('change', dataSource.value); } }; const setOptions = (name, i) => { let pagebase = (pagination.value.current - 1) * 10; let index = i + pagebase; if (name === 'up') { if (index === 0) { dataSource.value.unshift({}); } else { dataSource.value.splice(index, 0, {}); } } if (name === 'down') { dataSource.value.splice(index + 1, 0, {}); } emit('change', dataSource.value); }; watch( () => props.value, (val) => { dataSource.value = props.value; emit('change', val); }, { deep: true, immediate: true } ); return { remove, add, dataSource, columns, operation, setOptions, change, }; }, // watch: { // dataSource: { // handler(val) { // console.log(val); // this.$emit('change', val); // }, // deep: true, // }, // }, }); </script> <style lang="less" scoped> :deep(.ant-table-thead) > tr > th:not(:last-child):not(.ant-table-selection-column):not(.ant-table-row-expand-icon-cell):not([colspan])::before { display: none; } .mainColum { &::before { display: inline-block; margin-right: 4 px; color: #ff4d4f; font-size: 12px; font-family: SimSun, sans-serif; line-height: 1; content: '*'; } } :deep(.ant-form-item-explain.ant-form-item-explain-error) { display: flex; min-width: 130px !important; width: 140px !important; } .operation { padding-bottom: 8px; .ant-btn { margin-right: 16px; } } .column-operation { span { margin-right: 8px; } } </style>