提交 4eb69ac1 编写于 作者: Mosher's avatar Mosher

update:更新表单保存逻辑

上级 24440741
......@@ -13,6 +13,9 @@
{{/if}}
paramItem="{{#if item.paramItem}}{{item.paramItem}}{{else}}srfkey{{/if}}"
deCodeName="{{lowerCase ctrl.appEntity.codeName}}"
{{#if item.refreshItems}}
refreshItems="{{item.refreshItems}}"
{{/if}}
:context="context"
:viewParams="viewParams"
{{#if item.psNavigateContexts}}
......
<script setup lang="ts">
import { deepCopy, IActionParam, ILayoutOpts, IParam, RouteUtil, UIUtil } from '@core';
import { context } from 'ant-design-vue/lib/vc-image/src/PreviewGroup';
import { deepCopy, IActionParam, ILayoutOpts, IParam, isExistAndNotEmpty, RouteUtil, UIUtil } from '@core';
import { Subject, Subscription } from 'rxjs';
import { Ref } from 'vue';
interface FormDruipartProps {
......@@ -36,8 +35,6 @@ interface FormDruipartProps {
formSubject: Subject<any>;
// 视图路由参数
parameters: any[];
// 是否忽略表单项值变化
ignoreFieldValueChange?: boolean;
// 是否显示
visible?: boolean;
// 关系视图标识
......@@ -68,17 +65,28 @@ let druipartContext: Ref<any> = ref({});
// 关秀界面视图参数
let druipartViewParams: Ref<any> = ref({});
// 是否是刷新状态
let isRefreshStatus: boolean = false;
onBeforeMount(() => {
watch(
() => props.data,
(newVal: any, oldVal: any) => {
if (props.ignoreFieldValueChange) {
return;
}
if (Object.is(newVal, oldVal)) {
return;
}
let refreshFlag: boolean = false;
// 存在刷新项时刷新
if (isExistAndNotEmpty(props.refreshItems)) {
props.refreshItems?.split(';').some((item: string) => {
if (!Object.is(newVal[item], oldVal[item])) {
refreshFlag = true;
}
})
}
if (refreshFlag && !isRefreshStatus) {
refreshDRUIPart();
}
},
);
druipartInit();
......@@ -92,16 +100,17 @@ const druipartInit = () => {
// 视图事件
});
// formSubjectEvent = props.formSubject.subscribe(({ type, data }) => {
// // 表单加载完成
// if (type && Object.is(type, 'load')) {
// refreshDRUIPart(data);
// }
// })
formSubjectEvent = props.formSubject.subscribe(({ type, data }) => {
// 表单加载完成
if (type && Object.is(type, 'load')) {
refreshDRUIPart(data);
}
})
};
// 刷新关系界面
const refreshDRUIPart = (data?: any) => {
isRefreshStatus = true;
const formData: any = data ? data : props.data;
const paramItem = formData[props.paramItem];
// 应用上下文
......@@ -147,11 +156,12 @@ const refreshDRUIPart = (data?: any) => {
Object.assign(druipartContext.value, tempContext);
Object.assign(druipartViewParams.value, tempParams);
nextTick(() => {
isRefreshStatus = false;
// 设置局部上下文
if (props.viewSubject) {
props.viewSubject.next({ tag: props.viewCodeName, action: 'viewRefresh', data: [] });
}
})
});
};
const viewEvent = (action:any) => {
......@@ -163,7 +173,7 @@ const viewEvent = (action:any) => {
<AppCol noRoot :visible="visible" :layoutOpts="layoutOpts" :class="['app-form-druipart', `app-form-druipart-${name}`]">
<template #default="{slotStyle, slotClass}">
<a-card :class="slotClass" :style="slotStyle" :bordered="false">
<template #title>
<template v-if="title" #title>
<p :class="['app-form-druipart-title']">
<AppIconText :text="title" />
</p>
......
......@@ -37,6 +37,13 @@ export interface FormControlState extends MainControlState {
*/
detailsModel: IParam;
/**
* @description 错误信息
* @type {string[]}
* @memberof FormControlState
*/
errorMessage: string[];
/**
* @description 表单通讯对象
* @type {Subject<any>}
......
......@@ -5,6 +5,7 @@ import {
deepCopy,
FormControlProps,
FormControlState,
hasFunction,
IActionParam,
IParam,
MainControl,
......@@ -536,28 +537,30 @@ export class FormControl extends MainControl {
const save = async (opt: any = {}) => {
try {
// 获取需要的状态变量
const { controlService, context, viewParams, showBusyIndicator, data } = this.state;
// TODO 值规则校验处理
// 判断实体行为
const { updateAction, createAction } = this.state.controlAction;
const saveAction: any = data.srfuf == '1' ? updateAction : createAction;
const saveFunName = data.srfuf == '1' ? 'update' : 'create';
if (!saveAction) {
const { controlService, context, viewParams, showBusyIndicator, data, formSubject } = this.state;
if (!(await this.formValidateStatus())) {
this.showErrorMessage();
return;
}
// 处理请求参数
let _context = deepCopy(context);
let _viewParams = deepCopy(viewParams);
const arg: any = { ...opt };
Object.assign(arg, data.getDo());
Object.assign(arg, _viewParams);
// 拷贝模式
if (_viewParams && _viewParams.copyMode) {
data.srfuf = '0';
}
// TODO 关系界面保存通知处理,做成异步。
// TODO 拷贝相关。
// 判断实体行为
const { updateAction, createAction } = this.state.controlAction;
const saveAction: any = data.srfuf == '1' ? updateAction : createAction;
const saveFunName = data.srfuf == '1' ? 'update' : 'create';
if (!saveAction) {
App.getNotificationService().warning({ message: '', description: '未配置SaveAction' });
return;
}
// 发起请求处理与解析请求
const response = await controlService[saveFunName](_context, arg, {
action: saveAction,
......@@ -567,14 +570,19 @@ export class FormControl extends MainControl {
// TODO 统一Error格式
return;
}
// TODO 取消拷贝模式
const { data: _data } = toRefs(this.state);
// 请求后处理
this.state.data = response.data;
// TODO 表单onFormLoad
} catch (error) {
_data.value = response.data;
this.emit('ctrlEvent', { tag: this.props.name, action: 'save', data: [response.data] });
this.afterFormAction('save');
nextTick(() => {
formSubject.next({ type: 'save', data: _data.value });
})
} catch (error: any) {
App.getNotificationService().error({ message: '保存失败', description: error?.message || '' });
// TODO 错误异常处理
console.log(error);
}
};
......@@ -800,6 +808,53 @@ export class FormControl extends MainControl {
App.getAppActionService().execute(data, inputParam);
}
/**
* @description 表单值规则校验状态
* @private
* @return {*} {Promise<boolean>}
* @memberof FormControl
*/
private async formValidateStatus(): Promise<boolean> {
const form = this.getXDataCtrl()?.value;
let result: boolean = true;
if (form && hasFunction(form, 'validate')) {
try {
await form.validate();
} catch (error: any) {
result = false;
if (error.errorFields && error.errorFields.length) {
const { detailsModel } = this.state;
this.state.errorMessage = [];
error.errorFields.forEach((field: IParam) => {
const caption = detailsModel[field.name[0]]?.caption;
this.state.errorMessage.push(`${caption}: ${field.errors?.join('、')}`);
});
}
}
}
return result;
}
/**
* @description 展示错误信息
* @private
* @memberof FormControl
*/
private showErrorMessage() {
const errorMessage = this.state.errorMessage;
if (errorMessage && errorMessage.length) {
const getMessage = () => {
const messages: any[] = [];
errorMessage.forEach((message: string) => {
messages.push(h('span', {}, message));
});
return messages;
}
const content = h('div', { class: 'error-messages', style: { 'display': 'flex', 'flex-direction': 'column' } }, getMessage());
App.getNotificationService().error({ message: '值规则错误', description: content });
}
}
/**
* @description 安装部件所有功能模块的方法
* @return {*}
......
import { ControlBase, IParam, MainControlProps, MainControlState, UIUtil } from '@core';
import { ControlBase, IParam, MainControlState } from '@core';
/**
* @description 实体部件
......@@ -15,6 +15,14 @@ export class MainControl extends ControlBase {
*/
public declare state: MainControlState;
/**
* @description 数据部件组件
* @private
* @type {IParam}
* @memberof MainControl
*/
private declare xData: IParam;
/**
* 界面行为服务
*
......@@ -47,6 +55,27 @@ export class MainControl extends ControlBase {
}
}
/**
* @description 使用设置数据部件模块
* @private
* @return {*}
* @memberof MainControl
*/
private useSetXDataCtrl() {
const xData = ref(null);
this.xData = xData;
return xData;
}
/**
* @description 获取数据部件
* @return {*}
* @memberof MainControl
*/
public getXDataCtrl() {
return this.xData;
}
/**
* @description 安装部件所有功能模块的方法
* @return {*}
......@@ -57,7 +86,8 @@ export class MainControl extends ControlBase {
// 使用UI服务
this.useUIService();
return {
...superParams
...superParams,
xDataCtrl: this.useSetXDataCtrl()
};
}
}
......@@ -69,7 +69,7 @@ const { state, grid, searchForm, quickSearchForm, onCtrlEvent, onToolbarEvent, o
<template v-slot:quickSearch>
<div class='app-quick-search'>
<a-input-search v-if="state.enableQuickSearch" @search="onQuickSearchEvent" allowClear/>
<a-popover v-if="state.expandSearchForm" trigger="click" :overlayStyle="{width: '50%'}" placement="bottom">
<a-popover v-show="state.expandSearchForm" trigger="click" :overlayStyle="{width: '50%'}" placement="bottom">
<template #content>
<{{codeName}}SearchForm
ref="searchForm"
......@@ -88,7 +88,7 @@ const { state, grid, searchForm, quickSearchForm, onCtrlEvent, onToolbarEvent, o
{{else}}
<template v-slot:searchForm>
<{{codeName}}SearchForm
v-if="state.expandSearchForm"
v-show="state.expandSearchForm"
ref="searchForm"
name="{{name}}"
:context="state.context"
......
......@@ -57,6 +57,7 @@ export const ctrlState = {
appDeKeyFieldName: '{{#if ctrl.appEntity.keyPSAppDEField}}{{ctrl.appEntity.keyPSAppDEField.codeName}}{{/if}}',
appDeMajorFieldName: '{{#if ctrl.appEntity.majorPSAppDEField}}{{ctrl.appEntity.majorPSAppDEField.codeName}}{{/if}}',
enableAutoSave: {{ctrl.enableAutoSave}},
errorMessage: [],
// 新建默认值
createDefaultItems: [
{{#each ctrl.psDEFormItems as | formItem |}}
......
......@@ -40,13 +40,20 @@ interface CtrlEmit {
const emit = defineEmits <CtrlEmit> ();
// 安装功能模块,提供状态和能力方法
const { name, state, load, loadDraft, save, remove, refresh, onEditorEvent, onComponentEvent, getData } = new FormControl(ctrlState, props, emit).moduleInstall();
const { name, state, load, loadDraft, save, remove, refresh, onEditorEvent, onComponentEvent, getData, xDataCtrl } = new FormControl(ctrlState, props, emit).moduleInstall();
// 暴露内部状态及能力
defineExpose({ name, state, load, loadDraft, save, remove, refresh, getData });
</script>
<template>
<a-form name="{{ctrl.codeName}}" class="app-form{{#if ctrl.psSysCss}} {{ctrl.psSysCss.cssName}}{{/if}}{{#if ctrl.infoFormMode}} app-info-form{{/if}}" style="{{#if ctrl.formWidth}}width: {{ctrl.formWidth}}px;{{/if}}" :model="state.data" :rules="state.rules">
<a-form
name="{{ctrl.codeName}}"
class="app-form{{#if ctrl.psSysCss}} {{ctrl.psSysCss.cssName}}{{/if}}{{#if ctrl.infoFormMode}} app-info-form{{/if}}"
style="{{#if ctrl.formWidth}}width: {{ctrl.formWidth}}px;{{/if}}"
:model="state.data"
:rules="state.rules"
ref="xDataCtrl"
>
{{#if ctrl.noTabHeader}}
{{#each ctrl.psDEFormPages as | ctrlPage | }}
{{#each ctrlPage.psDEFormDetails as | formDetail | }}
......
Markdown 格式
0% or
您添加了 0 到此讨论。请谨慎行事。
先完成此消息的编辑!
想要评论请 注册