You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
741 lines
24 KiB
741 lines
24 KiB
<!-- @format -->
|
|
|
|
<template>
|
|
<div class="ns-table" :class="{ 'ns-table-no-search': !(formConfig?.schemas.length > 0) }">
|
|
<!-- tabletitle -->
|
|
<!-- <div
|
|
class="ns-table-title"
|
|
@click="
|
|
() => {
|
|
showBack ? navigateBack() : '';
|
|
}
|
|
"
|
|
v-if="tableTitle">
|
|
<ns-icon v-if="showBack" class="backIcon" name="left" />{{ tableTitle }}
|
|
</div> -->
|
|
<div class="ns-table-container">
|
|
<!-- todo drag -->
|
|
<div class="ns-part-tree" v-if="!isEmpty(treeConfig)">
|
|
<ns-tree-api v-bind="getTreeBindValue" @select="treeSelect" />
|
|
</div>
|
|
<div class="ns-part-table">
|
|
<a-spin :spinning="tableState.loading">
|
|
<div class="ns-table-search" v-if="!isEmpty(formConfig)">
|
|
<ns-form
|
|
ref="formElRef"
|
|
class="ns-table-form"
|
|
:showAction="true"
|
|
v-bind="formConfig"
|
|
:expand="expand"
|
|
:showExpand="showExpand"
|
|
:model="formModel"
|
|
@finish="formFinish" />
|
|
</div>
|
|
<a-row type="flex" class="ns-table-main">
|
|
<!-- <a-col :flex="getTreeWidth" v-if="!isEmpty(treeConfig)">
|
|
<ns-tree v-if="getTreeData.length" v-bind="getTreeBindValue" @select="treeSelect" />
|
|
</a-col> -->
|
|
<a-col flex="auto">
|
|
<ns-table-header
|
|
v-if="!isEmpty(headerActions) || tableTitle"
|
|
:headerActions="headerActions"
|
|
:searchData="formModel"
|
|
:tableTitle="tableTitle"
|
|
:data="tableState.selectedRows">
|
|
<template #header="data">
|
|
<slot name="header" v-bind="data || {}"></slot>
|
|
</template>
|
|
</ns-table-header>
|
|
<ns-basic-table ref="tableElRef" v-bind="getTableBindValues" :dataSource="tableData">
|
|
<template #emptyText>
|
|
<template v-if="tableState.loadError">
|
|
<div class="ns-table-content">
|
|
<div class="fetch-error">
|
|
<p>{{ tableState.loadErrorMessage }}</p>
|
|
<ns-button type="primary" ghost @click="reload">重新加载</ns-button></div
|
|
></div
|
|
>
|
|
</template>
|
|
<template v-else-if="tableState.loading"
|
|
><div class="ns-table-content"></div
|
|
></template>
|
|
<template v-else>
|
|
<div class="ns-table-content"> <a-empty /> </div>
|
|
</template>
|
|
</template>
|
|
|
|
<template #[item]="data" v-for="item in Object.keys($slots)" :key="item">
|
|
<slot :name="item" v-bind="data || {}"></slot>
|
|
<template v-if="item === 'bodyCell'">
|
|
<template v-if="data?.column?.textEllipsis">
|
|
<span
|
|
class="tool-tips"
|
|
:style="{ width: `${data.column.textWidth || data.column.width}px` }">
|
|
<ns-tooltip
|
|
placement="top"
|
|
v-if="
|
|
data.column.customRender
|
|
? data.column.customRender(data)
|
|
: data.record[data.column.dataIndex]
|
|
">
|
|
<template #title>
|
|
<span>{{
|
|
data.column.customRender
|
|
? data.column.customRender(data)
|
|
: data.record[data.column.dataIndex] || '-'
|
|
}}</span>
|
|
</template>
|
|
<span class="text-ellipsis">{{
|
|
data.column.customRender
|
|
? data.column.customRender(data)
|
|
: data.record[data.column.dataIndex] || '-'
|
|
}}</span>
|
|
</ns-tooltip>
|
|
<span class="text-ellipsis" v-else> - </span>
|
|
</span>
|
|
</template>
|
|
<template v-if="data.column.dataIndex === 'tableAction'">
|
|
<ns-table-action
|
|
:data="data.record"
|
|
:searchData="formModel"
|
|
:columnActions="getColumnActions" />
|
|
</template>
|
|
<template v-if="data.column.edit">
|
|
<ns-table-cell
|
|
:value="data.text"
|
|
:record="data.record"
|
|
:column="data.column"
|
|
:index="data.index" />
|
|
</template>
|
|
</template>
|
|
<template v-if="item === 'footer'">
|
|
<ns-table-footer :footerActions="footerActions" :data="ediRowData" />
|
|
</template>
|
|
</template>
|
|
|
|
<template #bodyCell="data" v-if="!Object.keys($slots).includes('bodyCell')">
|
|
<template v-if="data.column.textEllipsis">
|
|
<span
|
|
class="tool-tips"
|
|
:style="{ width: `${data.column.textWidth || data.column.width}px` }">
|
|
<ns-tooltip
|
|
placement="top"
|
|
v-if="
|
|
data.column.customRender
|
|
? data.column.customRender(data)
|
|
: data.record[data.column.dataIndex]
|
|
">
|
|
<template #title>
|
|
<span>{{
|
|
data.column.customRender
|
|
? data.column.customRender(data)
|
|
: data.record[data.column.dataIndex] || '-'
|
|
}}</span>
|
|
</template>
|
|
<span class="text-ellipsis">{{
|
|
data.column.customRender
|
|
? data.column.customRender(data)
|
|
: data.record[data.column.dataIndex] || '-'
|
|
}}</span>
|
|
</ns-tooltip>
|
|
<span class="text-ellipsis" v-else> - </span>
|
|
</span>
|
|
</template>
|
|
<template v-if="data.column.dataIndex === 'tableAction'">
|
|
<ns-table-action
|
|
:data="data.record"
|
|
:searchData="formModel"
|
|
:columnActions="getColumnActions" />
|
|
</template>
|
|
<template v-if="data.column.edit">
|
|
<ns-table-cell
|
|
:value="data.text"
|
|
:record="data.record"
|
|
:column="data.column"
|
|
:index="data.index" />
|
|
</template>
|
|
</template>
|
|
|
|
<template
|
|
#footer
|
|
v-if="!Object.keys($slots).includes('footer') && !isEmpty(footerActions)">
|
|
<ns-table-footer :footerActions="footerActions" :data="ediRowData" />
|
|
</template>
|
|
</ns-basic-table>
|
|
</a-col>
|
|
</a-row>
|
|
</a-spin>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { computed, defineComponent, provide, reactive, ref, unref, watch } from 'vue';
|
|
import { RequestParams } from '/nerv-lib/component/table/table';
|
|
import {
|
|
cloneDeep,
|
|
debounce,
|
|
throttle,
|
|
get,
|
|
isArray,
|
|
isEmpty,
|
|
isEqual,
|
|
isFunction,
|
|
isObject,
|
|
isString,
|
|
isUndefined,
|
|
} from 'lodash-es';
|
|
import NsTableAction from './table-action.vue';
|
|
import NsTableHeader from './table-header.vue';
|
|
import NsTableFooter from './table-footer.vue';
|
|
import NsTableCell from './edit/table-cell.vue';
|
|
import { useParams } from '/nerv-lib/use/use-params';
|
|
import { transformColumns } from '/nerv-lib/component/table/table-columns';
|
|
import NsBasicTable from '/nerv-lib/component/table/basic-table.vue';
|
|
import { tableProps } from '/nerv-lib/component/table/props';
|
|
import { AxiosRequestConfig } from 'axios';
|
|
import { useApi } from '/nerv-lib/use/use-api';
|
|
import { useRoute } from 'vue-router';
|
|
import { useTableEdit } from '/nerv-lib/component/table/use-table-edit';
|
|
import { Form } from 'ant-design-vue';
|
|
import { stringUtil } from '/nerv-lib/util/string-util';
|
|
import { useTableRefresh } from '/nerv-lib/component/table/use-table-refresh';
|
|
import { tableConfig } from '/nerv-base/config/table.config';
|
|
import { useTableSession } from '/nerv-lib/component/table/use-table-session';
|
|
import { useTableColumn } from '/nerv-lib/component/table/use-table-column';
|
|
import { useNavigate } from '/nerv-lib/use/use-navigate';
|
|
export default defineComponent({
|
|
name: 'NsTable',
|
|
components: {
|
|
NsBasicTable,
|
|
NsTableAction,
|
|
NsTableHeader,
|
|
NsTableFooter,
|
|
NsTableCell,
|
|
},
|
|
props: tableProps,
|
|
|
|
emits: ['cellChange', 'update:value', 'dataSourceChange', 'update:dataSource'],
|
|
setup(props, { attrs, emit }) {
|
|
const tableElRef = ref(null);
|
|
const formElRef = ref(null);
|
|
const dataRef = ref([]);
|
|
const treeParamsRef = ref({});
|
|
const formParamsRef = ref({});
|
|
const orderRef = ref({});
|
|
const formModel = reactive<Recordable>({});
|
|
const tableData = ref<Recordable[]>([]);
|
|
const tableState = reactive({
|
|
selectedRowKeys: [],
|
|
selectedRows: [],
|
|
loading: false,
|
|
loadError: false,
|
|
loadErrorMessage: '',
|
|
loadinterval: 0,
|
|
});
|
|
const route = useRoute();
|
|
const { getColumnActionWidth } = useTableColumn({
|
|
columnActions: Object.assign({}, tableConfig.columnActions, props.columnActions),
|
|
});
|
|
const { navigateBack } = useNavigate();
|
|
const defaultPageRef = ref(1 - props.pageFieldOffset);
|
|
|
|
const { setTableSession } = useTableSession(
|
|
formModel,
|
|
formParamsRef,
|
|
defaultPageRef,
|
|
treeParamsRef,
|
|
);
|
|
|
|
const { delayFetch } = useTableRefresh({ props, reload });
|
|
|
|
watch(
|
|
[() => props.value, () => props.dataSource],
|
|
() => {
|
|
tableData.value = props.value || props.dataSource || [];
|
|
},
|
|
{
|
|
immediate: true,
|
|
},
|
|
);
|
|
|
|
const formItemContext = Form.useInjectFormItemContext();
|
|
|
|
const getColumnActions = computed(() => {
|
|
const { actions } = props.columnActions as any;
|
|
const _tableConfig = cloneDeep(tableConfig);
|
|
if (actions) {
|
|
_tableConfig.columnActions.width = getColumnActionWidth(actions);
|
|
}
|
|
return Object.assign(_tableConfig.columnActions, props.columnActions);
|
|
});
|
|
|
|
const getColumns = computed(() => {
|
|
const columns = transformColumns(cloneDeep(props.columns || []));
|
|
const { title, width, dataIndex, fixed } = getColumnActions.value;
|
|
if (props.columnActions) {
|
|
columns.push({
|
|
title,
|
|
width,
|
|
dataIndex,
|
|
fixed,
|
|
});
|
|
}
|
|
return columns;
|
|
});
|
|
|
|
watch(
|
|
() => tableData.value,
|
|
(val) => {
|
|
// console.log(val, tableData.value);
|
|
|
|
if (isEqual(val, tableData.value)) return;
|
|
|
|
const data = cloneDeep(tableData.value);
|
|
if (props.editable) {
|
|
Object.keys(data).forEach((key) => {
|
|
delete data[key][props.rowKey];
|
|
});
|
|
}
|
|
// emit('update:value', data);
|
|
emit('dataSourceChange', data);
|
|
formItemContext.onFieldChange();
|
|
},
|
|
{
|
|
deep: true,
|
|
},
|
|
);
|
|
|
|
const tableEdit = useTableEdit({
|
|
dataSource: tableData,
|
|
columns: getColumns,
|
|
rowKey: props.rowKey,
|
|
editable: ref(props.editable),
|
|
});
|
|
provide('tableEdit', tableEdit);
|
|
|
|
const { getParams } = useParams();
|
|
|
|
const rowSelection = computed(() => {
|
|
const { rowSelection } = props;
|
|
if (rowSelection === false || rowSelection === null) {
|
|
return null;
|
|
}
|
|
return Object.assign(
|
|
{
|
|
fixed: true,
|
|
columnWidth: 48,
|
|
preserveSelectedRowKeys: true, // 跨页选中默认不清除选中key
|
|
selectedRowKeys: tableState.selectedRowKeys,
|
|
onChange: (selectedRowKeys: never[], selectedRows: never[]) => {
|
|
tableState.selectedRowKeys = selectedRowKeys;
|
|
tableState.selectedRows = selectedRows;
|
|
},
|
|
},
|
|
isFunction(rowSelection) ? rowSelection(tableState) : rowSelection,
|
|
);
|
|
});
|
|
|
|
const customizeRenderEmpty = computed(() => {
|
|
return () => '暂无数据';
|
|
});
|
|
|
|
const formFinish = debounce((data: object) => {
|
|
formParamsRef.value = data;
|
|
fetch({
|
|
page: 1,
|
|
});
|
|
}, 300);
|
|
|
|
function setLoading(loading: boolean) {
|
|
tableState.loading = loading;
|
|
}
|
|
|
|
const tableChangeEvent = (pagination: Props, filters: [], sorter: any) => {
|
|
console.log('params', pagination, filters, sorter);
|
|
if (sorter?.field) {
|
|
if (sorter.order) {
|
|
orderRef.value = {
|
|
[props.paramsOrderField]: stringUtil.toLine(
|
|
`${sorter.field} ${sorter.order.replace('end', '')}`,
|
|
),
|
|
};
|
|
} else {
|
|
orderRef.value = { [props.paramsOrderField]: '' }; //覆盖默认params
|
|
}
|
|
fetch({
|
|
page: pagination?.current || getPagination.value?.current || 1,
|
|
pageSize: pagination?.pageSize,
|
|
});
|
|
} else if (pagination?.current) {
|
|
fetch({
|
|
page: pagination?.current,
|
|
pageSize: pagination.pageSize,
|
|
});
|
|
}
|
|
};
|
|
|
|
// pagination
|
|
const getPagination: Recordable | Boolean = computed(() => {
|
|
const { pagination } = props;
|
|
const { getPageParams } = attrs;
|
|
|
|
if (pagination) {
|
|
const current = get(dataRef.value, props.pageField);
|
|
|
|
function getTotal() {
|
|
let total = 0;
|
|
if (isFunction(getPageParams)) {
|
|
total = getPageParams(dataRef)['total'];
|
|
} else {
|
|
total = get(dataRef.value, props.totalField);
|
|
}
|
|
return total;
|
|
}
|
|
|
|
return {
|
|
showQuickJumper: true,
|
|
showLessItems: true,
|
|
showSizeChanger: true,
|
|
showTotal: (total: number, range: Array<number>) => {
|
|
return `显示第${range[0]}到${range[1]}条记录 ,共 ${
|
|
get(dataRef.value, props.totalField) || total
|
|
} 条记录`;
|
|
},
|
|
...(pagination as Props),
|
|
total: getTotal(),
|
|
current: (current >= 0 ? current : 1) + props.pageFieldOffset, // 后端1 开始
|
|
pageSize: get(dataRef.value, props.sizeField),
|
|
};
|
|
}
|
|
return false;
|
|
});
|
|
|
|
console.log(getPagination.value);
|
|
|
|
const getTableBindValues = computed(() => {
|
|
const { params, dynamicParams } = props;
|
|
return {
|
|
...attrs,
|
|
...props,
|
|
rowSelection: rowSelection.value,
|
|
params: dynamicParams
|
|
? getParams({ ...route.params, ...route.query }, dynamicParams, params)
|
|
: params || {},
|
|
columns: getColumns.value,
|
|
pagination: getPagination.value,
|
|
onChange: tableChangeEvent,
|
|
};
|
|
});
|
|
|
|
watch(
|
|
() => getTableBindValues.value.api,
|
|
() => {
|
|
// console.log(getTableBindValues.value.api);
|
|
// fetch(); //路由切换导致api切换 导致发送请求
|
|
},
|
|
{
|
|
immediate: true,
|
|
},
|
|
);
|
|
|
|
// watch(
|
|
// () => getTableBindValues.value.params,
|
|
// () => {
|
|
// fetch();
|
|
// },
|
|
// {
|
|
// immediate: true,
|
|
// },
|
|
// );
|
|
|
|
/**
|
|
* 请求函数
|
|
* @param requestParams 主要是传入页面,部分变量闭包处理
|
|
* @param clearDelay 是否需要清除刷新时间(页面操作之后,自动刷新重新计算)
|
|
*/
|
|
|
|
function fetch(requestParams: RequestParams = {}, clearDelay = true) {
|
|
clearDelay && delayFetch();
|
|
if (tableState.loadinterval) {
|
|
clearTimeout(tableState.loadinterval);
|
|
}
|
|
if (tableState.loading) {
|
|
tableState.loadinterval = setTimeout(() => {
|
|
fetch(requestParams, clearDelay);
|
|
}, 500);
|
|
return;
|
|
}
|
|
const { api, pagination } = props;
|
|
const { page, pageSize } = requestParams;
|
|
if (api) {
|
|
let pageParams: Recordable = {};
|
|
|
|
if (pagination !== false) {
|
|
pageParams = {
|
|
[props.paramsPageField]: page ? page - props.pageFieldOffset : defaultPageRef.value, // 后端0 开始
|
|
[props.paramsPageSizeField]:
|
|
pageSize || getPagination.value?.pageSize || props.defaultPageSize,
|
|
};
|
|
} else {
|
|
pageParams = {
|
|
[props.paramsPageField]: defaultPageRef.value, // 后端0 开始
|
|
[props.paramsPageSizeField]:
|
|
pageSize || getPagination.value?.pageSize || props.defaultPageSize,
|
|
};
|
|
}
|
|
const httpParams = {
|
|
...getTableBindValues.value.params,
|
|
...pageParams,
|
|
...formParamsRef.value,
|
|
...treeParamsRef.value,
|
|
...orderRef.value,
|
|
};
|
|
if (!checkrequiredParams(httpParams)) {
|
|
console.log('check fail');
|
|
return;
|
|
}
|
|
|
|
setTableSession(pageParams[props.paramsPageField]);
|
|
|
|
clearDelay && setLoading(true);
|
|
|
|
const requestConfig: AxiosRequestConfig = { method: 'get' };
|
|
const { httpRequest } = useApi();
|
|
httpRequest({
|
|
api,
|
|
params: httpParams,
|
|
pathParams: { ...route.params, ...route.query },
|
|
requestConfig,
|
|
})
|
|
.then((res: any) => {
|
|
tableState.loadError = false;
|
|
tableState.loadErrorMessage = '';
|
|
dataRef.value = res;
|
|
console.log(props.listField);
|
|
tableData.value = get(unref(dataRef), props.listField);
|
|
//saas项目配置
|
|
if (attrs['getPageParams']) {
|
|
const getPageParams = attrs['getPageParams'];
|
|
let realPage = getPageParams(dataRef, pageParams.page)['page'];
|
|
if (realPage !== pageParams.page) {
|
|
fetch({ page: realPage });
|
|
}
|
|
}
|
|
emit('update:dataSource', tableData.value);
|
|
clearDelay && setLoading(false);
|
|
})
|
|
.catch((error: any) => {
|
|
const { response, code, message } = error || {};
|
|
let errMessage = response?.data?.msg;
|
|
const err: string = error?.toString?.() ?? '';
|
|
if (code === 'ECONNABORTED' && message.indexOf('timeout') !== -1) {
|
|
errMessage = '接口请求超时,请刷新页面重试!';
|
|
}
|
|
if (err?.includes('Network Error')) {
|
|
errMessage = '网络异常,请检查您的网络连接是否正常!';
|
|
}
|
|
|
|
// console.log(getPagination.value);
|
|
tableState.loadError = true;
|
|
tableState.loadErrorMessage = errMessage;
|
|
clearDelay && setLoading(false);
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 检测requiredParams是否全部获得数据
|
|
* @param params
|
|
*/
|
|
function checkrequiredParams(params: Recordable) {
|
|
const { params: dynamicParams } = getTableBindValues.value as any;
|
|
let { requiredParams } = props;
|
|
if (requiredParams) {
|
|
if (requiredParams === true) requiredParams = dynamicParams as any;
|
|
if (isFunction(requiredParams)) {
|
|
console.error(
|
|
'Property dynamicParams of props cannot set to Function when using requiredParams',
|
|
);
|
|
return false;
|
|
} else {
|
|
if (isString(requiredParams)) {
|
|
if (isUndefined(params[requiredParams])) return false;
|
|
} else if (isArray(requiredParams)) {
|
|
for (let i = 0, l = requiredParams.length; i < l; i++) {
|
|
if (isUndefined(params[requiredParams[i]])) return false;
|
|
}
|
|
} else if (isObject(requiredParams)) {
|
|
const keys = Object.keys(requiredParams);
|
|
for (let i = 0, l = keys.length; i < l; i++) {
|
|
if (isUndefined(params[keys[i]])) return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function treeSelect(
|
|
selectedKeys: never[],
|
|
e: {
|
|
selected: boolean;
|
|
selectedNodes: { props: { dataRef: any } }[];
|
|
node: any;
|
|
event: any;
|
|
},
|
|
) {
|
|
console.log(selectedKeys, e);
|
|
const { dataRef } = e.node;
|
|
treeParamsRef.value = getParams(dataRef, getTreeBindValue.value.dynamicParams);
|
|
fetch({
|
|
page: 1,
|
|
});
|
|
}
|
|
|
|
const getTreeData = computed(() => {
|
|
return props?.treeConfig?.treeData || [];
|
|
});
|
|
|
|
const getTreeWidth = computed(() => {
|
|
return props?.treeConfig?.width || '300px';
|
|
});
|
|
|
|
const getTreeBindValue = computed(() => ({
|
|
...props?.treeConfig,
|
|
}));
|
|
//todo 异步加载|| 树形接口
|
|
|
|
function reload(clearDelay = true) {
|
|
const pagination = unref(getPagination);
|
|
fetch(
|
|
{
|
|
page: pagination === false ? 1 : pagination.current,
|
|
},
|
|
clearDelay,
|
|
);
|
|
}
|
|
|
|
provide('reload', reload); //提供刷新功能
|
|
|
|
return {
|
|
navigateBack,
|
|
reload,
|
|
formElRef,
|
|
tableElRef,
|
|
getColumnActions,
|
|
getTableBindValues,
|
|
formModel,
|
|
tableState,
|
|
isEmpty,
|
|
formFinish,
|
|
tableChangeEvent,
|
|
treeSelect,
|
|
getTreeBindValue,
|
|
getTreeWidth,
|
|
getTreeData,
|
|
customizeRenderEmpty,
|
|
tableData,
|
|
treeParamsRef,
|
|
formParamsRef,
|
|
};
|
|
},
|
|
});
|
|
</script>
|
|
|
|
<style lang="less" scoped>
|
|
.backIcon {
|
|
cursor: pointer;
|
|
margin-right: 6px;
|
|
}
|
|
.ns-table-title {
|
|
text-align: left;
|
|
height: 46px;
|
|
line-height: 46px;
|
|
//font-size: 16px;
|
|
font-size: 18px;
|
|
font-weight: bold;
|
|
user-select: text;
|
|
padding-left: 16px;
|
|
background: #fff;
|
|
width: calc(100% + 32px);
|
|
margin-left: -16px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.ns-table-container {
|
|
display: flex;
|
|
.ns-part-tree {
|
|
width: 300px;
|
|
padding: 16px;
|
|
overflow-y: auto;
|
|
}
|
|
.ns-part-table {
|
|
flex: 1;
|
|
min-width: 0;
|
|
}
|
|
}
|
|
.ns-table-content {
|
|
// background: #e5ebf0;
|
|
margin: 16px;
|
|
}
|
|
|
|
:deep(.ant-spin-nested-loading > div > .ant-spin) {
|
|
max-height: none;
|
|
}
|
|
.ns-table-search {
|
|
padding-top: 16px;
|
|
}
|
|
:deep(.ant-form-item) {
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.ns-table {
|
|
position: relative;
|
|
// min-height: 400px;
|
|
// background: #e5ebf0;
|
|
.ant-spin-nested-loading {
|
|
height: 100%;
|
|
// min-height: 400px;
|
|
}
|
|
|
|
.ns-table-content {
|
|
min-height: 300px;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
}
|
|
|
|
.fetch-error {
|
|
p {
|
|
line-height: 40px;
|
|
padding: 0;
|
|
margin: 0;
|
|
font-size: 16px;
|
|
}
|
|
|
|
.ant-btn {
|
|
width: 88px;
|
|
}
|
|
}
|
|
}
|
|
|
|
.text-ellipsis {
|
|
display: inline-block;
|
|
vertical-align: top;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
max-width: 100%;
|
|
}
|
|
.tool-tips {
|
|
display: inline-block;
|
|
vertical-align: top;
|
|
padding: 0;
|
|
word-wrap: break-word;
|
|
word-break: break-word;
|
|
width: 100%;
|
|
}
|
|
</style>
|
|
|