|
|
|
|
import { reactive, Ref, toRaw } from "vue";
|
|
|
|
|
import {} from "noob-mengyxu";
|
|
|
|
|
import * as Element from "../element";
|
|
|
|
|
import { clearAndAssign, deepCopy } from "../util/objectUtil";
|
|
|
|
|
|
|
|
|
|
const { showMessage } = Element;
|
|
|
|
|
|
|
|
|
|
export interface FormProp {
|
|
|
|
|
code: string;
|
|
|
|
|
name?: string;
|
|
|
|
|
i18n?: string;
|
|
|
|
|
dict?: string;
|
|
|
|
|
slot?: boolean;
|
|
|
|
|
|
|
|
|
|
[others: string]: any;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface Options {
|
|
|
|
|
props?: FormProp[];
|
|
|
|
|
formRef?: Ref<any>;
|
|
|
|
|
handleAdd?: (value) => Promise<void>;
|
|
|
|
|
handleEdit?: (value) => Promise<void>;
|
|
|
|
|
handleCancel?: () => Promise<void>;
|
|
|
|
|
handleError?: (kind: "validation" | "internal", err?) => void;
|
|
|
|
|
init?: any;
|
|
|
|
|
extraProps?: string[] | "any" | ((code: string) => boolean);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function useModifyForm(options: Options) {
|
|
|
|
|
const { formRef, handleAdd, handleEdit, handleCancel, init, extraProps } = options;
|
|
|
|
|
const initValue = init ?? {};
|
|
|
|
|
const props = options.props ?? [];
|
|
|
|
|
const propMap = Object.fromEntries(props.map((prop) => [prop.code, prop]));
|
|
|
|
|
|
|
|
|
|
let isValidProp: (code: string) => boolean;
|
|
|
|
|
|
|
|
|
|
if (typeof extraProps === "function") {
|
|
|
|
|
isValidProp = (code: string) => extraProps(code) as boolean;
|
|
|
|
|
} else if (Array.isArray(extraProps)) {
|
|
|
|
|
isValidProp = (code: string) => extraProps.includes(code);
|
|
|
|
|
} else {
|
|
|
|
|
isValidProp = (_code: string) => extraProps === "any";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const normalizeValue = (code: string, value: any) => {
|
|
|
|
|
const prop = propMap[code];
|
|
|
|
|
if (!prop && !isValidProp(code)) return null;
|
|
|
|
|
if (prop?.dict) {
|
|
|
|
|
const parsed = parseInt(value);
|
|
|
|
|
return isNaN(parsed) ? value : parsed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return value;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const normalizeModel = (newModel: Record<string, any>) =>
|
|
|
|
|
Object.fromEntries(
|
|
|
|
|
Object.entries(newModel).flatMap(([code, value]) => {
|
|
|
|
|
const normalized = normalizeValue(code, value);
|
|
|
|
|
return normalized != null ? [[code, normalized]] : [];
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const handleError =
|
|
|
|
|
options.handleError ??
|
|
|
|
|
((kind, err) => {
|
|
|
|
|
if (kind === "validation") {
|
|
|
|
|
showMessage("error", "Validation Error");
|
|
|
|
|
} else if (kind === "internal") {
|
|
|
|
|
const msg = `Internal Error: ${err}`;
|
|
|
|
|
showMessage("error", msg);
|
|
|
|
|
console.error(msg);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
flagOnClose: null,
|
|
|
|
|
flagOnAdd: "add",
|
|
|
|
|
flagOnEdit: "edit",
|
|
|
|
|
|
|
|
|
|
data: reactive<{ dialog: any; model: Record<string, any> }>({
|
|
|
|
|
dialog: null,
|
|
|
|
|
model: { ...initValue },
|
|
|
|
|
}),
|
|
|
|
|
|
|
|
|
|
clearModel() {
|
|
|
|
|
clearAndAssign(this.data.model, initValue);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
assignModel(newModel: Record<string, any>) {
|
|
|
|
|
const normalized = normalizeModel(newModel);
|
|
|
|
|
this.clearModel();
|
|
|
|
|
Object.assign(this.data.model, normalized);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
openAdd() {
|
|
|
|
|
this.clearModel();
|
|
|
|
|
formRef?.value?.clearValidate();
|
|
|
|
|
this.data.dialog = this.flagOnAdd;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
openEdit(toEdit: Record<string, any>) {
|
|
|
|
|
this.assignModel(toEdit);
|
|
|
|
|
formRef?.value?.clearValidate();
|
|
|
|
|
this.data.dialog = this.flagOnEdit;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
close() {
|
|
|
|
|
this.data.dialog = this.flagOnClose;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
async onConfirm() {
|
|
|
|
|
const value = deepCopy(toRaw(this.data.model));
|
|
|
|
|
try {
|
|
|
|
|
if (this.data.dialog === this.flagOnAdd) {
|
|
|
|
|
await handleAdd?.(value);
|
|
|
|
|
} else if (this.data.dialog === this.flagOnEdit) {
|
|
|
|
|
await handleEdit?.(value);
|
|
|
|
|
}
|
|
|
|
|
} catch (err) {
|
|
|
|
|
handleError?.("internal", err);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.close();
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
async onCancel() {
|
|
|
|
|
await handleCancel?.();
|
|
|
|
|
this.close();
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|