Remove unused legacy monitor helpers
This commit is contained in:
@@ -39,46 +39,6 @@ export namespace WebSocketApi {
|
|||||||
heartbeatInterval?: number;
|
heartbeatInterval?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 监控数据类型 */
|
|
||||||
export interface MonitorMessage {
|
|
||||||
type:
|
|
||||||
| 'get_overview'
|
|
||||||
| 'get_realtime'
|
|
||||||
| 'set_interval'
|
|
||||||
| 'start_monitor'
|
|
||||||
| 'stop_monitor'
|
|
||||||
| 'test_connection';
|
|
||||||
interval?: number;
|
|
||||||
timestamp?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 服务器监控数据 */
|
|
||||||
export interface ServerMonitorData {
|
|
||||||
basic_info?: any;
|
|
||||||
cpu_info?: any;
|
|
||||||
memory_info?: any;
|
|
||||||
disk_info?: any;
|
|
||||||
network_info?: any;
|
|
||||||
process_info?: any;
|
|
||||||
system_load?: any;
|
|
||||||
boot_time?: any;
|
|
||||||
users_info?: any;
|
|
||||||
timestamp?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Redis监控数据 */
|
|
||||||
export interface RedisMonitorData {
|
|
||||||
connection_id?: string;
|
|
||||||
connection_name?: string;
|
|
||||||
status?: string;
|
|
||||||
info?: any;
|
|
||||||
memory?: any;
|
|
||||||
stats?: any;
|
|
||||||
keyspace?: any[];
|
|
||||||
clients?: any[];
|
|
||||||
slow_log?: any[];
|
|
||||||
timestamp?: string;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -430,7 +390,7 @@ export function createWebSocket(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建测试WebSocket连接
|
* Create test WebSocket connection
|
||||||
*/
|
*/
|
||||||
export function createTestWebSocket(
|
export function createTestWebSocket(
|
||||||
callbacks?: WebSocketApi.WebSocketCallbacks,
|
callbacks?: WebSocketApi.WebSocketCallbacks,
|
||||||
@@ -439,7 +399,7 @@ export function createTestWebSocket(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建通知WebSocket连接
|
* Create notification WebSocket connection
|
||||||
*/
|
*/
|
||||||
export function createNotificationWebSocket(
|
export function createNotificationWebSocket(
|
||||||
callbacks?: WebSocketApi.WebSocketCallbacks,
|
callbacks?: WebSocketApi.WebSocketCallbacks,
|
||||||
@@ -448,197 +408,10 @@ export function createNotificationWebSocket(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建服务器监控WebSocket连接
|
* Create chat WebSocket connection
|
||||||
*/
|
|
||||||
export function createServerMonitorWebSocket(
|
|
||||||
callbacks?: WebSocketApi.WebSocketCallbacks,
|
|
||||||
): WebSocketManager {
|
|
||||||
return createWebSocket('/ws/server-monitor/', callbacks);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建Redis监控WebSocket连接
|
|
||||||
*/
|
|
||||||
export function createRedisMonitorWebSocket(
|
|
||||||
callbacks?: WebSocketApi.WebSocketCallbacks,
|
|
||||||
): WebSocketManager {
|
|
||||||
return createWebSocket('/ws/redis-monitor/', callbacks);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建数据库监控WebSocket连接
|
|
||||||
*/
|
|
||||||
export function createDatabaseMonitorWebSocket(
|
|
||||||
callbacks?: WebSocketApi.WebSocketCallbacks,
|
|
||||||
): WebSocketManager {
|
|
||||||
return createWebSocket('/ws/database-monitor/', callbacks);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 监控WebSocket管理器类
|
|
||||||
*/
|
|
||||||
export class MonitorWebSocketManager extends WebSocketManager {
|
|
||||||
/**
|
|
||||||
* 获取概览信息
|
|
||||||
*/
|
|
||||||
getOverview(): boolean {
|
|
||||||
return this.send({
|
|
||||||
type: 'get_overview',
|
|
||||||
timestamp: new Date().toISOString(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取实时统计
|
|
||||||
*/
|
|
||||||
getRealtime(): boolean {
|
|
||||||
return this.send({
|
|
||||||
type: 'get_realtime',
|
|
||||||
timestamp: new Date().toISOString(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 开始监控
|
|
||||||
*/
|
|
||||||
startMonitoring(): boolean {
|
|
||||||
return this.send({
|
|
||||||
type: 'start_monitor',
|
|
||||||
timestamp: new Date().toISOString(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 停止监控
|
|
||||||
*/
|
|
||||||
stopMonitoring(): boolean {
|
|
||||||
return this.send({
|
|
||||||
type: 'stop_monitor',
|
|
||||||
timestamp: new Date().toISOString(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测试连接(适用于Redis监控)
|
|
||||||
*/
|
|
||||||
testConnection(): boolean {
|
|
||||||
return this.send({
|
|
||||||
type: 'test_connection',
|
|
||||||
timestamp: new Date().toISOString(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建服务器监控WebSocket管理器
|
|
||||||
*/
|
|
||||||
export function createServerMonitorManager(
|
|
||||||
callbacks?: WebSocketApi.WebSocketCallbacks,
|
|
||||||
): MonitorWebSocketManager {
|
|
||||||
const wsManager = createServerMonitorWebSocket(callbacks);
|
|
||||||
// 创建增强版管理器
|
|
||||||
return Object.setPrototypeOf(wsManager, MonitorWebSocketManager.prototype);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建Redis监控WebSocket管理器
|
|
||||||
*/
|
|
||||||
export function createRedisMonitorManager(
|
|
||||||
callbacks?: WebSocketApi.WebSocketCallbacks,
|
|
||||||
): MonitorWebSocketManager {
|
|
||||||
const wsManager = createRedisMonitorWebSocket(callbacks);
|
|
||||||
// 创建增强版管理器
|
|
||||||
return Object.setPrototypeOf(wsManager, MonitorWebSocketManager.prototype);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 数据库监控WebSocket管理器类
|
|
||||||
*/
|
|
||||||
export class DatabaseMonitorWebSocketManager extends WebSocketManager {
|
|
||||||
/**
|
|
||||||
* 获取数据库配置列表
|
|
||||||
*/
|
|
||||||
getConfigs(): boolean {
|
|
||||||
return this.send({
|
|
||||||
type: 'get_configs',
|
|
||||||
timestamp: new Date().toISOString(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取概览信息
|
|
||||||
*/
|
|
||||||
getOverview(dbName: string): boolean {
|
|
||||||
return this.send({
|
|
||||||
type: 'get_overview',
|
|
||||||
db_name: dbName,
|
|
||||||
timestamp: new Date().toISOString(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取实时统计
|
|
||||||
*/
|
|
||||||
getRealtime(dbName: string): boolean {
|
|
||||||
return this.send({
|
|
||||||
type: 'get_realtime',
|
|
||||||
db_name: dbName,
|
|
||||||
timestamp: new Date().toISOString(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 开始监控
|
|
||||||
*/
|
|
||||||
startMonitoring(dbName: string): boolean {
|
|
||||||
return this.send({
|
|
||||||
type: 'start_monitor',
|
|
||||||
db_name: dbName,
|
|
||||||
timestamp: new Date().toISOString(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 停止监控
|
|
||||||
*/
|
|
||||||
stopMonitoring(): boolean {
|
|
||||||
return this.send({
|
|
||||||
type: 'stop_monitor',
|
|
||||||
timestamp: new Date().toISOString(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测试连接
|
|
||||||
*/
|
|
||||||
testConnection(dbName: string): boolean {
|
|
||||||
return this.send({
|
|
||||||
type: 'test_connection',
|
|
||||||
db_name: dbName,
|
|
||||||
timestamp: new Date().toISOString(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建聊天WebSocket连接
|
|
||||||
*/
|
*/
|
||||||
export function createChatWebSocket(
|
export function createChatWebSocket(
|
||||||
callbacks?: WebSocketApi.WebSocketCallbacks,
|
callbacks?: WebSocketApi.WebSocketCallbacks,
|
||||||
): WebSocketManager {
|
): WebSocketManager {
|
||||||
return createWebSocket('/ws/chat/', callbacks);
|
return createWebSocket('/ws/chat/', callbacks);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建数据库监控WebSocket管理器
|
|
||||||
*/
|
|
||||||
export function createDatabaseMonitorManager(
|
|
||||||
callbacks?: WebSocketApi.WebSocketCallbacks,
|
|
||||||
): DatabaseMonitorWebSocketManager {
|
|
||||||
const wsManager = createDatabaseMonitorWebSocket(callbacks);
|
|
||||||
// 创建增强版管理器
|
|
||||||
return Object.setPrototypeOf(
|
|
||||||
wsManager,
|
|
||||||
DatabaseMonitorWebSocketManager.prototype,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,531 +0,0 @@
|
|||||||
import type {
|
|
||||||
DataSourceParamConfig,
|
|
||||||
FormLifecycleHook,
|
|
||||||
FormLifecycleMode,
|
|
||||||
} from '#/components/form-design/store/formDesignStore';
|
|
||||||
|
|
||||||
import { ElMessage } from 'element-plus/es/components/message/index';
|
|
||||||
|
|
||||||
import { getWorkflowDetailApi, runWorkflowApi } from '#/api/ai-platform/ai-platform';
|
|
||||||
import { requestClient } from '#/api/request';
|
|
||||||
|
|
||||||
export interface FormLifecycleContext {
|
|
||||||
formCode: string;
|
|
||||||
formData: Record<string, any>;
|
|
||||||
editId?: string;
|
|
||||||
routeQuery?: Record<string, any>;
|
|
||||||
savedId?: string;
|
|
||||||
error?: any;
|
|
||||||
payload?: { main: Record<string, any>; sub_tables?: Record<string, any> };
|
|
||||||
response?: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface FormLifecycleResult {
|
|
||||||
blocked: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface FormLoadPipelineOptions {
|
|
||||||
hooks?: FormLifecycleHook[];
|
|
||||||
mode: FormLifecycleMode;
|
|
||||||
formCode: string;
|
|
||||||
formData: Record<string, any>;
|
|
||||||
editId?: string;
|
|
||||||
routeQuery?: Record<string, any>;
|
|
||||||
initForm: () => void;
|
|
||||||
applyDefaults?: () => void;
|
|
||||||
fetchDetail?: () => Promise<void>;
|
|
||||||
onBlocked: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const WORKFLOW_TYPES = ['data_process', 'automation'] as const;
|
|
||||||
|
|
||||||
const BLOCKING_EVENTS = new Set<FormLifecycleHook['event']>([
|
|
||||||
'beforeLoad',
|
|
||||||
'beforeSubmit',
|
|
||||||
]);
|
|
||||||
|
|
||||||
function isBlockingEvent(event: FormLifecycleHook['event']) {
|
|
||||||
return BLOCKING_EVENTS.has(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function replaceLifecycleVariables(
|
|
||||||
template: string,
|
|
||||||
formData: Record<string, any>,
|
|
||||||
savedId?: string,
|
|
||||||
): string {
|
|
||||||
if (!template) return '';
|
|
||||||
let result = template.replaceAll(/\{id\}/g, savedId ? String(savedId) : '{id}');
|
|
||||||
result = result.replaceAll(/\{(\w+)\}/g, (match, key) => {
|
|
||||||
if (key === 'id') {
|
|
||||||
return savedId === undefined ? match : String(savedId);
|
|
||||||
}
|
|
||||||
return formData[key] === undefined ? match : String(formData[key]);
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function createScriptHelpers(rootData: Record<string, any>) {
|
|
||||||
const $setValue = (field: string, value: any) => {
|
|
||||||
if (field.includes('.')) {
|
|
||||||
const [table, subField] = field.split('.');
|
|
||||||
if (Array.isArray(rootData[table!])) {
|
|
||||||
rootData[table!].forEach((row: any) => {
|
|
||||||
row[subField!] = value;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rootData[field] = value;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const $setValues = (obj: Record<string, any>) => {
|
|
||||||
for (const [field, value] of Object.entries(obj)) {
|
|
||||||
$setValue(field, value);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const $getValue = (field: string) => {
|
|
||||||
if (field.includes('.')) {
|
|
||||||
const [table, subField] = field.split('.');
|
|
||||||
if (Array.isArray(rootData[table!])) {
|
|
||||||
return rootData[table!].map((row: any) => row[subField!]);
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
return rootData[field];
|
|
||||||
};
|
|
||||||
|
|
||||||
const $getSubTable = (field: string) => rootData[field] || [];
|
|
||||||
|
|
||||||
const $setSubTable = (field: string, rows: any[]) => {
|
|
||||||
rootData[field] = rows;
|
|
||||||
};
|
|
||||||
|
|
||||||
const $addRow = (field: string, row: any) => {
|
|
||||||
if (!Array.isArray(rootData[field])) {
|
|
||||||
rootData[field] = [];
|
|
||||||
}
|
|
||||||
rootData[field].push({ _id: `${Date.now()}_${Math.random()}`, ...row });
|
|
||||||
};
|
|
||||||
|
|
||||||
const $removeRow = (field: string, index: number) => {
|
|
||||||
if (Array.isArray(rootData[field])) {
|
|
||||||
rootData[field].splice(index, 1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const $updateRow = (field: string, index: number, data: any) => {
|
|
||||||
if (Array.isArray(rootData[field]) && rootData[field][index]) {
|
|
||||||
Object.assign(rootData[field][index], data);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const $clearSubTable = (field: string) => {
|
|
||||||
rootData[field] = [];
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
$setValue,
|
|
||||||
$setValues,
|
|
||||||
$getValue,
|
|
||||||
$getSubTable,
|
|
||||||
$setSubTable,
|
|
||||||
$addRow,
|
|
||||||
$removeRow,
|
|
||||||
$updateRow,
|
|
||||||
$clearSubTable,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildDataSourceParams(
|
|
||||||
params: DataSourceParamConfig[] | undefined,
|
|
||||||
formData: Record<string, any>,
|
|
||||||
): Record<string, any> {
|
|
||||||
const result: Record<string, any> = {};
|
|
||||||
for (const p of params || []) {
|
|
||||||
if (p.valueSource === 'fixed') {
|
|
||||||
result[p.name] = p.fixedValue ?? p.default ?? '';
|
|
||||||
} else if (p.valueSource === 'field' && p.sourceField) {
|
|
||||||
result[p.name] = formData[p.sourceField] ?? '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildWorkflowInputs(
|
|
||||||
hook: FormLifecycleHook,
|
|
||||||
context: FormLifecycleContext,
|
|
||||||
): Record<string, any> {
|
|
||||||
const inputs: Record<string, any> = {
|
|
||||||
form_code: context.formCode,
|
|
||||||
};
|
|
||||||
const dataId = context.savedId || context.editId;
|
|
||||||
if (dataId) {
|
|
||||||
inputs.form_data_id = dataId;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const mapping of hook.actionConfig.workflowInputs || []) {
|
|
||||||
if (mapping.valueSource === 'field' && mapping.sourceField) {
|
|
||||||
inputs[mapping.name] = context.formData[mapping.sourceField] ?? '';
|
|
||||||
} else {
|
|
||||||
inputs[mapping.name] = mapping.fixedValue ?? mapping.default ?? '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return inputs;
|
|
||||||
}
|
|
||||||
|
|
||||||
function appendLoadScriptArgs(
|
|
||||||
hook: FormLifecycleHook,
|
|
||||||
context: FormLifecycleContext,
|
|
||||||
argNames: string[],
|
|
||||||
argValues: any[],
|
|
||||||
) {
|
|
||||||
if (hook.event === 'beforeLoad' || hook.event === 'afterLoadSuccess') {
|
|
||||||
argNames.push('$editId', '$query');
|
|
||||||
argValues.push(context.editId, context.routeQuery || {});
|
|
||||||
}
|
|
||||||
if (hook.event === 'afterLoadSuccess') {
|
|
||||||
argNames.push('$savedId');
|
|
||||||
argValues.push(context.savedId || context.editId);
|
|
||||||
}
|
|
||||||
if (hook.event === 'afterLoadFail' || hook.event === 'afterSubmitFail') {
|
|
||||||
argNames.push('$error');
|
|
||||||
argValues.push(context.error);
|
|
||||||
}
|
|
||||||
if (hook.event === 'afterSubmitSuccess') {
|
|
||||||
argNames.push('$savedId', '$response');
|
|
||||||
argValues.push(context.savedId, context.response);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function executeScriptHook(
|
|
||||||
hook: FormLifecycleHook,
|
|
||||||
context: FormLifecycleContext,
|
|
||||||
mode: FormLifecycleMode,
|
|
||||||
): Promise<boolean | void> {
|
|
||||||
const script = hook.actionConfig.script;
|
|
||||||
if (!script?.trim()) return;
|
|
||||||
|
|
||||||
const rootData = context.formData;
|
|
||||||
const helpers = createScriptHelpers(rootData);
|
|
||||||
const argNames = [
|
|
||||||
'model',
|
|
||||||
'$root',
|
|
||||||
'$mode',
|
|
||||||
'$event',
|
|
||||||
'$setValue',
|
|
||||||
'$setValues',
|
|
||||||
'$getValue',
|
|
||||||
'$getSubTable',
|
|
||||||
'$setSubTable',
|
|
||||||
'$addRow',
|
|
||||||
'$removeRow',
|
|
||||||
'$updateRow',
|
|
||||||
'$clearSubTable',
|
|
||||||
];
|
|
||||||
const argValues: any[] = [
|
|
||||||
rootData,
|
|
||||||
rootData,
|
|
||||||
mode,
|
|
||||||
hook.event,
|
|
||||||
helpers.$setValue,
|
|
||||||
helpers.$setValues,
|
|
||||||
helpers.$getValue,
|
|
||||||
helpers.$getSubTable,
|
|
||||||
helpers.$setSubTable,
|
|
||||||
helpers.$addRow,
|
|
||||||
helpers.$removeRow,
|
|
||||||
helpers.$updateRow,
|
|
||||||
helpers.$clearSubTable,
|
|
||||||
];
|
|
||||||
|
|
||||||
appendLoadScriptArgs(hook, context, argNames, argValues);
|
|
||||||
|
|
||||||
const fn = new Function(...argNames, script);
|
|
||||||
return fn(...argValues);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function executeDataSourceHook(
|
|
||||||
hook: FormLifecycleHook,
|
|
||||||
context: FormLifecycleContext,
|
|
||||||
mode: FormLifecycleMode,
|
|
||||||
): Promise<any> {
|
|
||||||
const dsCode = hook.actionConfig.dataSourceCode;
|
|
||||||
if (!dsCode) return;
|
|
||||||
|
|
||||||
const params = buildDataSourceParams(
|
|
||||||
hook.actionConfig.dataSourceParams,
|
|
||||||
context.formData,
|
|
||||||
);
|
|
||||||
const response = await requestClient.get(
|
|
||||||
`/api/core/data-source/execute/${dsCode}`,
|
|
||||||
{ params },
|
|
||||||
);
|
|
||||||
|
|
||||||
const callbackScript = hook.actionConfig.callbackScript;
|
|
||||||
if (callbackScript?.trim()) {
|
|
||||||
const rootData = context.formData;
|
|
||||||
const helpers = createScriptHelpers(rootData);
|
|
||||||
const argNames = [
|
|
||||||
'model',
|
|
||||||
'$root',
|
|
||||||
'$result',
|
|
||||||
'$mode',
|
|
||||||
'$event',
|
|
||||||
'$setValue',
|
|
||||||
'$setValues',
|
|
||||||
'$getValue',
|
|
||||||
'$getSubTable',
|
|
||||||
'$setSubTable',
|
|
||||||
'$addRow',
|
|
||||||
'$removeRow',
|
|
||||||
'$updateRow',
|
|
||||||
'$clearSubTable',
|
|
||||||
];
|
|
||||||
const argValues: any[] = [
|
|
||||||
rootData,
|
|
||||||
rootData,
|
|
||||||
response,
|
|
||||||
mode,
|
|
||||||
hook.event,
|
|
||||||
helpers.$setValue,
|
|
||||||
helpers.$setValues,
|
|
||||||
helpers.$getValue,
|
|
||||||
helpers.$getSubTable,
|
|
||||||
helpers.$setSubTable,
|
|
||||||
helpers.$addRow,
|
|
||||||
helpers.$removeRow,
|
|
||||||
helpers.$updateRow,
|
|
||||||
helpers.$clearSubTable,
|
|
||||||
];
|
|
||||||
appendLoadScriptArgs(hook, context, argNames, argValues);
|
|
||||||
|
|
||||||
const fn = new Function(...argNames, callbackScript);
|
|
||||||
const callbackResult = fn(...argValues);
|
|
||||||
if (isBlockingEvent(hook.event) && callbackResult === false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
function executeRedirectHook(
|
|
||||||
hook: FormLifecycleHook,
|
|
||||||
context: FormLifecycleContext,
|
|
||||||
) {
|
|
||||||
const savedId = context.savedId || context.editId;
|
|
||||||
const url = replaceLifecycleVariables(
|
|
||||||
hook.actionConfig.url || '',
|
|
||||||
context.formData,
|
|
||||||
savedId,
|
|
||||||
);
|
|
||||||
if (!url) return;
|
|
||||||
|
|
||||||
if (hook.actionConfig.openInNewTab) {
|
|
||||||
window.open(url, '_blank');
|
|
||||||
} else {
|
|
||||||
window.location.href = url;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function executeMessageHook(
|
|
||||||
hook: FormLifecycleHook,
|
|
||||||
context: FormLifecycleContext,
|
|
||||||
) {
|
|
||||||
const savedId = context.savedId || context.editId;
|
|
||||||
const message = replaceLifecycleVariables(
|
|
||||||
hook.actionConfig.message || '',
|
|
||||||
context.formData,
|
|
||||||
savedId,
|
|
||||||
);
|
|
||||||
if (!message) return;
|
|
||||||
|
|
||||||
const messageType = hook.actionConfig.messageType || 'success';
|
|
||||||
ElMessage[messageType](message);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function executeWorkflowHook(
|
|
||||||
hook: FormLifecycleHook,
|
|
||||||
context: FormLifecycleContext,
|
|
||||||
) {
|
|
||||||
const workflowId = hook.actionConfig.workflowId;
|
|
||||||
if (!workflowId) return;
|
|
||||||
|
|
||||||
const run = async () => {
|
|
||||||
const workflow = await getWorkflowDetailApi(workflowId);
|
|
||||||
if (
|
|
||||||
workflow.status !== 'published' ||
|
|
||||||
!WORKFLOW_TYPES.includes(
|
|
||||||
workflow.workflow_type as (typeof WORKFLOW_TYPES)[number],
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
throw new Error('Workflow is not published or type not allowed');
|
|
||||||
}
|
|
||||||
|
|
||||||
const inputs = buildWorkflowInputs(hook, context);
|
|
||||||
const result = await runWorkflowApi(workflowId, inputs);
|
|
||||||
if (result.status === 'failed') {
|
|
||||||
throw new Error(result.error_message || 'Workflow execution failed');
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (hook.actionConfig.async) {
|
|
||||||
run().catch((error) => {
|
|
||||||
console.warn('[FormLifecycleHook] async workflow failed:', error);
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await run();
|
|
||||||
}
|
|
||||||
|
|
||||||
async function executeSingleHook(
|
|
||||||
hook: FormLifecycleHook,
|
|
||||||
context: FormLifecycleContext,
|
|
||||||
mode: FormLifecycleMode,
|
|
||||||
): Promise<{ blocked: boolean }> {
|
|
||||||
switch (hook.actionType) {
|
|
||||||
case 'script': {
|
|
||||||
const result = await executeScriptHook(hook, context, mode);
|
|
||||||
if (isBlockingEvent(hook.event) && result === false) {
|
|
||||||
return { blocked: true };
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'dataSource': {
|
|
||||||
const result = await executeDataSourceHook(hook, context, mode);
|
|
||||||
if (isBlockingEvent(hook.event) && result === false) {
|
|
||||||
return { blocked: true };
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'redirect': {
|
|
||||||
executeRedirectHook(hook, context);
|
|
||||||
if (hook.event === 'beforeLoad') {
|
|
||||||
return { blocked: true };
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'message': {
|
|
||||||
executeMessageHook(hook, context);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'workflow': {
|
|
||||||
await executeWorkflowHook(hook, context);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return { blocked: false };
|
|
||||||
}
|
|
||||||
|
|
||||||
function getActiveHooks(
|
|
||||||
hooks: FormLifecycleHook[] | undefined,
|
|
||||||
event: FormLifecycleHook['event'],
|
|
||||||
mode: FormLifecycleMode,
|
|
||||||
): FormLifecycleHook[] {
|
|
||||||
return (hooks || [])
|
|
||||||
.filter(
|
|
||||||
(hook) =>
|
|
||||||
hook.enabled &&
|
|
||||||
hook.event === event &&
|
|
||||||
Array.isArray(hook.modes) &&
|
|
||||||
hook.modes.includes(mode),
|
|
||||||
)
|
|
||||||
.sort((a, b) => (a.sort ?? 0) - (b.sort ?? 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
function getBlockErrorMessage(event: FormLifecycleHook['event']) {
|
|
||||||
if (event === 'beforeLoad') {
|
|
||||||
return '表单加载被阻止';
|
|
||||||
}
|
|
||||||
return '提交前校验未通过';
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function executeFormLifecycleHooks(
|
|
||||||
hooks: FormLifecycleHook[] | undefined,
|
|
||||||
event: FormLifecycleHook['event'],
|
|
||||||
mode: FormLifecycleMode,
|
|
||||||
context: FormLifecycleContext,
|
|
||||||
): Promise<FormLifecycleResult> {
|
|
||||||
const activeHooks = getActiveHooks(hooks, event, mode);
|
|
||||||
|
|
||||||
for (const hook of activeHooks) {
|
|
||||||
try {
|
|
||||||
const result = await executeSingleHook(hook, context, mode);
|
|
||||||
if (result.blocked) {
|
|
||||||
return { blocked: true };
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.warn(`[FormLifecycleHook] ${hook.id} failed:`, error);
|
|
||||||
if (isBlockingEvent(hook.event) && hook.blockOnError) {
|
|
||||||
ElMessage.error(
|
|
||||||
error instanceof Error ? error.message : getBlockErrorMessage(hook.event),
|
|
||||||
);
|
|
||||||
return { blocked: true };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return { blocked: false };
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function runFormLoadPipeline(
|
|
||||||
opts: FormLoadPipelineOptions,
|
|
||||||
): Promise<{ loaded: boolean }> {
|
|
||||||
const {
|
|
||||||
hooks,
|
|
||||||
mode,
|
|
||||||
formCode,
|
|
||||||
formData,
|
|
||||||
editId,
|
|
||||||
routeQuery,
|
|
||||||
initForm,
|
|
||||||
applyDefaults,
|
|
||||||
fetchDetail,
|
|
||||||
onBlocked,
|
|
||||||
} = opts;
|
|
||||||
|
|
||||||
const baseContext: FormLifecycleContext = {
|
|
||||||
formCode,
|
|
||||||
formData,
|
|
||||||
editId,
|
|
||||||
routeQuery,
|
|
||||||
};
|
|
||||||
|
|
||||||
const beforeResult = await executeFormLifecycleHooks(
|
|
||||||
hooks,
|
|
||||||
'beforeLoad',
|
|
||||||
mode,
|
|
||||||
baseContext,
|
|
||||||
);
|
|
||||||
if (beforeResult.blocked) {
|
|
||||||
onBlocked();
|
|
||||||
return { loaded: false };
|
|
||||||
}
|
|
||||||
|
|
||||||
initForm();
|
|
||||||
applyDefaults?.();
|
|
||||||
|
|
||||||
if (fetchDetail) {
|
|
||||||
try {
|
|
||||||
await fetchDetail();
|
|
||||||
} catch (error) {
|
|
||||||
await executeFormLifecycleHooks(hooks, 'afterLoadFail', mode, {
|
|
||||||
...baseContext,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await executeFormLifecycleHooks(hooks, 'afterLoadSuccess', mode, {
|
|
||||||
...baseContext,
|
|
||||||
savedId: editId,
|
|
||||||
});
|
|
||||||
|
|
||||||
return { loaded: true };
|
|
||||||
}
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
import type {
|
|
||||||
FormItemSchema,
|
|
||||||
ReverseAutoFillConfig,
|
|
||||||
} from '#/components/form-design/store/formDesignStore';
|
|
||||||
|
|
||||||
export interface ReverseAutoFillContext {
|
|
||||||
cfg: ReverseAutoFillConfig;
|
|
||||||
formCode?: string;
|
|
||||||
kind: 'form-selector' | 'select';
|
|
||||||
valueField: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 是否可在设计器配置关联自动填充 */
|
|
||||||
export function canConfigureReverseAutoFill(
|
|
||||||
item: { dataSource?: { type?: string }; type?: string } | null | undefined,
|
|
||||||
): boolean {
|
|
||||||
if (!item) return false;
|
|
||||||
if (item.type === 'form-selector') return true;
|
|
||||||
return item.type === 'select' && item.dataSource?.type === 'formData';
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 是否已启用关联自动填充(含未完整配置) */
|
|
||||||
export function hasReverseAutoFillEnabled(
|
|
||||||
item: FormItemSchema | null | undefined,
|
|
||||||
): boolean {
|
|
||||||
if (!item) return false;
|
|
||||||
if (item.type === 'form-selector') {
|
|
||||||
return !!item.formSelectorConfig?.reverseAutoFill?.enabled;
|
|
||||||
}
|
|
||||||
if (item.type === 'select' && item.dataSource?.type === 'formData') {
|
|
||||||
return !!item.dataSource.reverseAutoFill?.enabled;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 读取关联自动填充配置(设计器用) */
|
|
||||||
export function getReverseAutoFillConfig(
|
|
||||||
item: FormItemSchema | null | undefined,
|
|
||||||
): ReverseAutoFillConfig | undefined {
|
|
||||||
if (!item) return undefined;
|
|
||||||
if (item.type === 'form-selector') {
|
|
||||||
return item.formSelectorConfig?.reverseAutoFill;
|
|
||||||
}
|
|
||||||
if (item.type === 'select' && item.dataSource?.type === 'formData') {
|
|
||||||
return item.dataSource.reverseAutoFill;
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 运行时:获取已启用的关联自动填充上下文 */
|
|
||||||
export function getReverseAutoFillContext(
|
|
||||||
item: FormItemSchema | null | undefined,
|
|
||||||
): ReverseAutoFillContext | null {
|
|
||||||
if (!item) return null;
|
|
||||||
|
|
||||||
if (item.type === 'form-selector') {
|
|
||||||
const cfg = item.formSelectorConfig?.reverseAutoFill;
|
|
||||||
if (!cfg?.enabled || !cfg.sourceField) return null;
|
|
||||||
return {
|
|
||||||
cfg,
|
|
||||||
formCode: item.formSelectorConfig?.formCode,
|
|
||||||
valueField: item.formSelectorConfig?.valueField || 'id',
|
|
||||||
kind: 'form-selector',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.type === 'select' && item.dataSource?.type === 'formData') {
|
|
||||||
const cfg = item.dataSource.reverseAutoFill;
|
|
||||||
if (!cfg?.enabled || !cfg.sourceField) return null;
|
|
||||||
return {
|
|
||||||
cfg,
|
|
||||||
formCode: item.dataSource.formCode,
|
|
||||||
valueField: item.dataSource.formValueField || 'id',
|
|
||||||
kind: 'select',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createDefaultReverseAutoFillConfig(): ReverseAutoFillConfig {
|
|
||||||
return {
|
|
||||||
enabled: false,
|
|
||||||
sourceField: '',
|
|
||||||
targetField: 'b_id',
|
|
||||||
filterType: 'eq',
|
|
||||||
pageSize: 500,
|
|
||||||
clearWhenEmpty: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user