<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>