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.

283 lines
7.7 KiB

7 months ago
<template>
<div class="ns-view">
<a-spin class="ns-view-spinning" :spinning="isLoading" :key="'addForm_' + $route.name">
<ns-page-header class="ns-page-header" :sticky="sticky">
<template #title>
<div class="title" @click="onBack" v-if="showBack">
<!-- <left-outlined style="color: rgba(0, 0, 0, 0.4)" /> {{ title }} -->
<ns-icon name="left" /> <div class="text">{{ title }}</div>
</div>
<div class="title" v-else>
{{ title }}
</div>
</template>
<template #extra>
<ns-button v-if="okText" type="primary" @click="submit" :disabled="!validateResult">{{
okText
}}</ns-button>
<template v-for="item in getActions" :key="item.name">
<template v-if="item.children">
<template v-if="getDropdownActions(item.children).length > 0">
<a-dropdown :trigger="['hover']" :dropMenuList="item.children">
<a class="ant-dropdown-link" @click.prevent>
{{ item.label }}
<CaretDownOutlined />
</a>
<template #overlay>
<a-menu>
<a-menu-item
style="padding: 2px 5px"
v-for="itemChild in getDropdownActions(item.children)"
:key="itemChild.name"
@click="itemChild.finalHandle(data, itemChild.name)">
<a-button type="link" :disabled="itemChild.dynamicDisabled">
{{ itemChild.label }}
</a-button>
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</template>
</template>
<template v-else>
<ns-button
:type="item.type || 'default'"
:disabled="item.dynamicDisabled"
@click="item.finalHandle(data, item.name)">
<ns-v-node :content="item.label" />
</ns-button>
</template>
</template>
<ns-button v-if="cancelText" @click="navigateBack">{{ cancelText }}</ns-button>
</template>
</ns-page-header>
<div class="ns-add-form">
<ns-form ref="nsFormElRef" v-bind="getBindValue">
<template #[item]="data" v-for="item in Object.keys($slots)">
<slot :name="item" v-bind="data || {}"></slot>
</template>
</ns-form>
<slot name="nsCustomFormItem"></slot>
</div>
</a-spin>
</div>
</template>
<script lang="ts">
import { computed, defineComponent, PropType, ref } from 'vue';
import { http } from '/nerv-lib/util/http';
import { NsMessage } from '/nerv-lib/component/message';
import { useNavigate } from '/nerv-lib/use/use-navigate';
import { cloneDeep } from 'lodash-es';
import { Action, useAction } from '/nerv-lib/use';
import { useRoute } from 'vue-router';
import { CaretDownOutlined, LeftOutlined } from '@ant-design/icons-vue';
import { useApi, HttpRequestConfig } from '/nerv-lib/use/use-api';
interface ColumnActions {
back: Boolean;
actions: Action[];
}
export default defineComponent({
name: 'NsViewAddForm',
components: {
CaretDownOutlined,
LeftOutlined,
},
props: {
api: {
type: String,
required: true,
},
showBack: {
type: Boolean,
default: true,
},
detailApi: {
type: String,
required: true,
},
sticky: {
type: Boolean,
default: true,
},
title: String,
params: {
type: Object,
default: () => ({}),
},
data: {
type: Object,
default: () => ({}),
},
dataHandle: Function,
okText: {
type: String,
default: '确 定',
},
cancelText: {
type: String,
default: '取 消',
},
headActions: {
type: Object as PropType<ColumnActions>,
default: () => ({
actions: [],
}),
},
customBack: {
type: String || Function,
},
},
setup(props, { attrs }) {
const nsFormElRef = ref(null);
const isLoading = ref(false);
const { navigateBackV2: navigateBack } = useNavigate();
const route = useRoute();
const { httpRequest } = useApi();
const getData = computed(() => {
return {
...route.query,
...route.params,
formRef: nsFormElRef.value,
};
});
const getBindValue = computed(() => ({
...attrs,
...props,
title: '',
}));
const validateResult = computed(() => {
return nsFormElRef.value?.validateResult;
});
function submit() {
nsFormElRef.value
.triggerSubmit()
.then((data: any) => {
isLoading.value = true;
data = props.dataHandle ? props.dataHandle(data) : data;
const { api } = props;
const requestConfig: HttpRequestConfig = { method: 'POST' };
const { params } = route;
httpRequest({ api, params: data, pathParams: params, requestConfig })
.then(() => {
NsMessage.success('操作成功', 1, () => {
isLoading.value = false;
navigateBack();
});
})
.catch(() => {
isLoading.value = false;
});
})
.catch(() => {});
}
const { transformAction } = useAction();
const getActions = computed(() => {
let actions = cloneDeep(props.headActions.actions);
actions = actions.map((action) => {
return transformAction(action, getData.value);
});
return actions;
});
const getDropdownActions = (actions) => {
actions = actions.map((action) => {
return transformAction(action, getData.value);
});
return actions;
};
return {
nsFormElRef,
validateResult,
submit,
getBindValue,
isLoading,
navigateBack,
getActions,
getDropdownActions,
};
},
methods: {
onBack() {
//debugger;
if (this.customBack) {
this.customBack();
} else {
this.navigateBack();
}
// this.$router.go(-1);
},
},
});
</script>
<style lang="less" scoped>
.ns-view {
min-height: 100%;
height: 100%;
background: #e5ebf0;
}
:deep(.ant-spin-nested-loading) {
min-height: 100%;
height: 100%;
}
:deep(.ant-spin-container) {
min-height: 100%;
height: 100%;
}
:deep(.ant-divider) {
display: none;
}
.ns-page-header {
margin-bottom: 0 !important;
padding: 7px 16px !important;
width: calc(100% + 32px);
margin-left: -16px;
.title {
cursor: pointer;
font-size: 18px !important;
display: flex;
align-items: center;
.text {
margin-left: 6px;
}
}
}
.ns-add-form {
border-top: 16px solid #e5ebf0;
padding: 16px 21px;
background: #fff;
height: calc(100% - 47px);
:deep(.ns-form) {
.ns-form-item .ns-form-body .ns-child-form-title {
padding-top: 0;
}
&:after {
display: none;
}
}
:deep(.ns-child-form-title) {
&:after {
content: '';
width: 75px;
height: 7px;
display: block;
background: linear-gradient(90deg, @primary-color 0%, #fff 82.67%);
margin-left: 2px;
margin-top: -7px;
}
}
}
:deep(.ns-form.ns-vertical-form) {
padding-top: 16px !important;
}
</style>