logologo
البدء
الدليل
التطوير
الإضافات
API
English
简体中文
日本語
한국어
Deutsch
Français
Español
Português
Русский
Italiano
Türkçe
Українська
Tiếng Việt
Bahasa Indonesia
ไทย
Polski
Nederlands
Čeština
العربية
עברית
हिन्दी
Svenska
البدء
الدليل
التطوير
الإضافات
API
logologo
سير العمل
نظرة عامة
بدء سريع

المشغلات

نظرة عامة
أحداث جدول البيانات
المهام المجدولة
حدث ما قبل الإجراء
حدث ما بعد الإجراء
حدث الإجراء المخصص
الموافقة
Webhook

العقدة

نظرة عامة

AI

LLM

التحكم في التدفق

الشرط
تفرع متعدد الشروط
التكرار
المتغيرات
تفرع متوازي
استدعاء سير العمل
مخرجات التدفق
ربط متغيرات JSON
تأخير
إنهاء

حساب

حساب
حساب التاريخ
حساب JSON

عمليات البيانات

إضافة بيانات
تحديث البيانات
استعلام البيانات
حذف البيانات
عمليات SQL

معالجة يدوية

معالجة يدوية
الموافقة
نسخة كربونية

أنواع ممتدة

طلب HTTP
سكريبت JavaScript
إشعار
إرسال بريد إلكتروني
استجابة
رسالة الاستجابة
المتغيرات
سجل التنفيذ
إدارة الإصدارات
خيارات متقدمة

تطوير الإضافات

نظرة عامة
توسيع أنواع المشغلات
توسيع أنواع العقد
مرجع API
Previous Pageتوسيع أنواع المشغلات
Next Pageمرجع API
إشعار الترجمة بالذكاء الاصطناعي

تمت ترجمة هذه الوثائق تلقائيًا بواسطة الذكاء الاصطناعي.

#توسيع أنواع العقد

نوع العقدة هو في الأساس تعليمات تشغيلية. تمثل التعليمات المختلفة عمليات مختلفة يتم تنفيذها في سير العمل.

على غرار المشغلات، ينقسم توسيع أنواع العقد أيضًا إلى جزأين: جانب الخادم وجانب العميل. يحتاج جانب الخادم إلى تنفيذ منطق التعليمات المسجلة، بينما يحتاج جانب العميل إلى توفير تهيئة الواجهة للمعلمات الخاصة بالعقدة التي توجد بها التعليمات.

#جانب الخادم

#أبسط تعليمات العقدة

المحتوى الأساسي للتعليمات هو دالة، مما يعني أن طريقة run في فئة التعليمات يجب أن تُنفذ لتشغيل منطق التعليمات. يمكن للدالة تنفيذ أي عمليات ضرورية، مثل عمليات قاعدة البيانات، عمليات الملفات، استدعاء واجهات برمجة تطبيقات الطرف الثالث، وما إلى ذلك.

يجب أن تشتق جميع التعليمات من الفئة الأساسية Instruction. أبسط تعليمات تحتاج فقط إلى تنفيذ دالة run:

import { Instruction, JOB_STATUS } from '@nocobase/plugin-workflow';

export class MyInstruction extends Instruction {
  run(node, input, processor) {
    console.log('my instruction runs!');
    return {
      status: JOB_STATUS.RESOVLED,
    };
  }
}

وسجل هذه التعليمات في إضافة سير العمل:

export default class MyPlugin extends Plugin {
  load() {
    // get workflow plugin instance
    const workflowPlugin = this.app.getPlugin<WorkflowPlugin>(WorkflowPlugin);

    // register instruction
    workflowPlugin.registerInstruction('my-instruction', MyInstruction);
  }
}

قيمة الحالة (status) في كائن الإرجاع للتعليمات إلزامية ويجب أن تكون قيمة من الثابت JOB_STATUS. تحدد هذه القيمة مسار المعالجة اللاحقة لهذه العقدة في سير العمل. عادةً ما يتم استخدام JOB_STATUS.RESOVLED، مما يشير إلى أن العقدة قد نُفذت بنجاح وسيستمر التنفيذ إلى العقد التالية. إذا كانت هناك قيمة نتيجة تحتاج إلى حفظ مسبقًا، يمكنك أيضًا استدعاء طريقة processor.saveJob وإرجاع كائن الإرجاع الخاص بها. سيقوم المنفذ بإنشاء سجل نتيجة التنفيذ بناءً على هذا الكائن.

#قيمة نتيجة العقدة

إذا كانت هناك نتيجة تنفيذ محددة، خاصة البيانات المُجهزة للاستخدام بواسطة العقد اللاحقة، فيمكن إرجاعها عبر خاصية result وحفظها في كائن مهمة العقدة:

import { Instruction, JOB_STATUS } from '@nocobase/plugin-workflow';

export class RandomStringInstruction extends Instruction {
  run(node, input, processor) {
    // customized config from node
    const { digit = 1 } = node.config;
    const result = `${Math.round(10 ** digit * Math.random())}`.padStart(
      digit,
      '0',
    );
    return {
      status: JOB_STATUS.RESOVLED,
      result,
    };
  },
};

هنا، node.config هو عنصر تهيئة العقدة، والذي يمكن أن يكون أي قيمة مطلوبة. سيتم حفظه كحقل من نوع JSON في سجل العقدة المقابل في قاعدة البيانات.

#معالجة أخطاء التعليمات

إذا كان من المحتمل حدوث استثناءات أثناء التنفيذ، يمكنك التقاطها مسبقًا وإرجاع حالة فشل:

import { JOB_STATUS } from '@nocobase/plugin-workflow';

export const errorInstruction = {
  run(node, input, processor) {
    try {
      throw new Error('exception');
    } catch (error) {
      return {
        status: JOB_STATUS.ERROR,
        result: error,
      };
    }
  },
};

إذا لم يتم التقاط الاستثناءات المتوقعة، فسيقوم محرك سير العمل بالتقاطها تلقائيًا وإرجاع حالة خطأ لمنع الاستثناءات غير الملتقطة من التسبب في تعطل البرنامج.

#العقد غير المتزامنة

عند الحاجة إلى التحكم في سير العمل أو عمليات الإدخال/الإخراج غير المتزامنة (المستهلكة للوقت)، يمكن لطريقة run إرجاع كائن بحالة status تساوي JOB_STATUS.PENDING، مما يوجه المنفذ للانتظار (التعليق) حتى تكتمل بعض العمليات الخارجية غير المتزامنة، ثم إخطار محرك سير العمل لمواصلة التنفيذ. إذا تم إرجاع قيمة حالة معلقة في دالة run، فيجب أن تُنفذ هذه التعليمات طريقة resume؛ وإلا، لا يمكن استئناف تنفيذ سير العمل:

import { Instruction, JOB_STATUS } from '@nocobase/plugin-workflow';

export class PayInstruction extends Instruction {
  async run(node, input, processor) {
    // job could be create first via processor
    const job = await processor.saveJob({
      status: JOB_STATUS.PENDING,
    });

    const { workflow } = processor;
    // do payment asynchronously
    paymentService.pay(node.config, (result) => {
      // notify processor to resume the job
      return workflow.resume(job.id, result);
    });

    // return created job instance
    return job;
  }

  resume(node, job, processor) {
    // check payment status
    job.set('status', job.result.status === 'ok' ? JOB_STATUS.RESOVLED : JOB_STATUS.REJECTED);
    return job;
  },
};

يشير paymentService هنا إلى خدمة دفع معينة. في رد نداء الخدمة، يتم تشغيل سير العمل لاستئناف تنفيذ المهمة المقابلة، ويخرج السير الحالي أولاً. بعد ذلك، يقوم محرك سير العمل بإنشاء معالج جديد وتمريره إلى طريقة resume الخاصة بالعقدة لمواصلة تنفيذ العقدة التي كانت معلقة سابقًا.

تلميح

"العملية غير المتزامنة" المذكورة هنا لا تشير إلى دوال async في JavaScript، بل إلى عمليات غير فورية الإرجاع عند التفاعل مع أنظمة خارجية أخرى، مثل خدمة الدفع التي قد تحتاج إلى انتظار إشعار آخر لمعرفة النتيجة.

#حالة نتيجة العقدة

تؤثر حالة تنفيذ العقدة على نجاح أو فشل سير العمل بأكمله. عادةً، في غياب الفروع، يؤدي فشل عقدة معينة مباشرة إلى فشل سير العمل بأكمله. السيناريو الأكثر شيوعًا هو أنه إذا نُفذت العقدة بنجاح، فإنها تنتقل إلى العقدة التالية في جدول العقد، حتى لا توجد عقد لاحقة، وعندئذ يكتمل تنفيذ سير العمل بأكمله بحالة نجاح.

إذا أرجعت عقدة ما حالة تنفيذ فاشلة أثناء التنفيذ، فسيتعامل المحرك معها بشكل مختلف اعتمادًا على الحالتين التاليتين:

  1. العقدة التي تُرجع حالة فشل تقع في سير العمل الرئيسي، أي أنها ليست ضمن أي سير عمل فرعي بدأته عقدة سابقة. في هذه الحالة، يُحكم على سير العمل الرئيسي بأكمله بالفشل، ويتم إنهاء السير.

  2. العقدة التي تُرجع حالة فشل تقع ضمن سير عمل فرعي. في هذه الحالة، تُنقل مسؤولية تحديد حالة الخطوة التالية لسير العمل إلى العقدة التي بدأت الفرع. يحدد المنطق الداخلي لتلك العقدة حالة سير العمل اللاحق، وينتشر هذا القرار بشكل متكرر صعودًا إلى سير العمل الرئيسي.

في النهاية، يتم تحديد حالة الخطوة التالية لسير العمل بأكمله عند عقد سير العمل الرئيسي. إذا أرجعت عقدة في سير العمل الرئيسي حالة فشل، ينتهي سير العمل بأكمله بحالة فشل.

إذا أرجعت أي عقدة حالة "معلقة" بعد التنفيذ، فسيتم مقاطعة عملية التنفيذ بأكملها وتعليقها مؤقتًا، في انتظار حدث تحدده العقدة المقابلة لتشغيل استئناف تنفيذ سير العمل. على سبيل المثال، عقدة التدخل اليدوي، عند تنفيذها، ستتوقف عند تلك العقدة بحالة "معلقة"، في انتظار تدخل يدوي لتقرير ما إذا كان سيتم الموافقة. إذا كانت الحالة المدخلة يدويًا هي الموافقة، فستستمر عقد سير العمل اللاحقة؛ وإلا، فسيتم التعامل معها وفقًا لمنطق الفشل المذكور سابقًا.

لمزيد من حالات إرجاع التعليمات، يرجى الرجوع إلى قسم مرجع واجهة برمجة تطبيقات سير العمل.

#الخروج المبكر

في بعض سير العمل الخاصة، قد يكون من الضروري إنهاء سير العمل مباشرة ضمن عقدة معينة. يمكنك إرجاع null، مما يشير إلى الخروج من سير العمل الحالي، ولن يتم تنفيذ العقد اللاحقة.

هذا الموقف شائع في العقد من نوع التحكم في سير العمل، مثل عقدة الفرع المتوازي (مرجع الكود)، حيث يخرج سير عمل العقدة الحالية، ولكن يتم بدء سير عمل جديدة لكل فرع فرعي وتستمر في التنفيذ.

:::warn{title=تحذير} جدولة سير عمل الفروع باستخدام العقد الموسعة تتسم ببعض التعقيد، وتتطلب معالجة دقيقة واختبارًا شاملاً. :::

#لمعرفة المزيد

للاطلاع على تعريفات المعلمات المختلفة لتحديد أنواع العقد، راجع قسم مرجع واجهة برمجة تطبيقات سير العمل.

#جانب العميل

على غرار المشغلات، يجب تنفيذ نموذج تهيئة التعليمات (نوع العقدة) في الواجهة الأمامية.

#أبسط تعليمات العقدة

يجب أن تشتق جميع التعليمات من الفئة الأساسية Instruction. تُستخدم الخصائص والأساليب ذات الصلة لتهيئة العقدة واستخدامها.

على سبيل المثال، إذا أردنا توفير واجهة تهيئة لعقدة نوع سلسلة الأرقام العشوائية (randomString) المحددة في جانب الخادم أعلاه، والتي تحتوي على عنصر تهيئة digit يمثل عدد خانات الرقم العشوائي، فسنستخدم مربع إدخال رقمي في نموذج التهيئة لاستقبال إدخال المستخدم.

import WorkflowPlugin, { Instruction, VariableOption } from '@nocobase/workflow/client';

class MyInstruction extends Instruction {
  title = 'Random number string';
  type = 'randomString';
  group = 'extended';
  fieldset = {
    'digit': {
      type: 'number',
      title: 'Digit',
      name: 'digit',
      'x-decorator': 'FormItem',
      'x-component': 'InputNumber',
      'x-component-props': {
        min: 1,
        max: 10,
      },
      default: 6,
    },
  };
  useVariables(node, options): VariableOption {
    return {
      value: node.key,
      label: node.title,
    };
  }
}

export default class MyPlugin extends Plugin {
  load() {
    // get workflow plugin instance
    const workflowPlugin = this.app.getPlugin<WorkflowPlugin>(WorkflowPlugin);

    // register instruction
    workflowPlugin.registerInstruction('randomString', MyInstruction);
  }
}
تلميح

يجب أن يكون معرف نوع العقدة المسجل في جانب العميل متطابقًا مع المعرف الموجود في جانب الخادم، وإلا سيؤدي ذلك إلى حدوث أخطاء.

#توفير نتائج العقد كمتغيرات

قد تلاحظ طريقة useVariables في المثال أعلاه. إذا كنت بحاجة إلى استخدام نتيجة العقدة (جزء result) كمتغير للعقد اللاحقة، فيجب عليك تنفيذ هذه الطريقة في فئة التعليمات الموروثة وإرجاع كائن يتوافق مع نوع VariableOption. يعمل هذا الكائن كوصف هيكلي لنتيجة تنفيذ العقدة، ويوفر تعيينًا لأسماء المتغيرات، ليتم اختيارها واستخدامها في العقد اللاحقة.

يتم تعريف نوع VariableOption على النحو التالي:

export type VariableOption = {
  value?: string;
  label?: string;
  children?: VariableOption[] | null;
  [key: string]: any;
};

الخاصية الأساسية هي value، والتي تمثل قيمة المسار المجزأ لاسم المتغير. تُستخدم label للعرض في الواجهة، وتُستخدم children لتمثيل بنية المتغير متعددة المستويات، ويتم استخدامها عندما تكون نتيجة العقدة كائنًا متداخلاً بعمق.

يتم تمثيل المتغير القابل للاستخدام داخليًا في النظام كسلسلة قالب مسار مفصولة بـ .، على سبيل المثال، {{jobsMapByNodeKey.2dw92cdf.abc}}. هنا، يمثل jobsMapByNodeKey مجموعة نتائج جميع العقد (مُعرفة داخليًا، لا تحتاج إلى معالجة)، و2dw92cdf هو key العقدة، وabc هي خاصية مخصصة في كائن نتيجة العقدة.

بالإضافة إلى ذلك، نظرًا لأن نتيجة العقدة قد تكون أيضًا قيمة بسيطة، عند توفير متغيرات العقدة، يجب أن تكون الطبقة الأولى بالضرورة وصفًا للعقدة نفسها:

{
  value: node.key,
  label: node.title,
}

أي أن الطبقة الأولى هي key العقدة وعنوانها. على سبيل المثال، في مرجع الكود لعقدة الحساب، عند استخدام نتيجة عقدة الحساب، تكون خيارات الواجهة كما يلي:

نتيجة عقدة الحساب

عندما تكون نتيجة العقدة كائنًا معقدًا، يمكنك استخدام children لمواصلة وصف الخصائص المتعمقة. على سبيل المثال، قد تُرجع تعليمات مخصصة بيانات JSON التالية:

{
  "message": "ok",
  "data": {
    "id": 1,
    "name": "test",
  }
}

ثم يمكنك إرجاعها عبر طريقة useVariables على النحو التالي:

useVariables(node, options): VariableOption {
  return {
    value: node.key,
    label: node.title,
    children: [
      {
        value: 'message',
        label: 'Message',
      },
      {
        value: 'data',
        label: 'Data',
        children: [
          {
            value: 'id',
            label: 'ID',
          },
          {
            value: 'name',
            label: 'Name',
          },
        ],
      },
    ],
  };
}

بهذه الطريقة، في العقد اللاحقة، يمكنك استخدام الواجهة التالية لاختيار المتغيرات منها:

المتغيرات الناتجة المخططة

تلميح

عندما يكون أحد الهياكل في النتيجة عبارة عن مصفوفة من الكائنات المتداخلة بعمق، يمكنك أيضًا استخدام children لوصف المسار، ولكن لا يمكن أن يتضمن فهارس المصفوفة. وذلك لأنه في معالجة المتغيرات في سير عمل NocoBase، يتم تسطيح وصف مسار المتغير لمصفوفة الكائنات تلقائيًا إلى مصفوفة من القيم المتعمقة عند الاستخدام، ولا يمكنك الوصول إلى قيمة معينة عن طريق فهرسها.

#توفر العقدة

افتراضيًا، يمكن إضافة أي عقدة إلى سير العمل. ومع ذلك، في بعض الحالات، قد لا تكون العقدة قابلة للتطبيق في أنواع معينة من سير العمل أو الفروع. في مثل هذه الحالات، يمكنك تهيئة توفر العقدة باستخدام isAvailable:

// تعريف النوع
export abstract class Instruction {
  isAvailable?(ctx: NodeAvailableContext): boolean;
}

export type NodeAvailableContext = {
  // مثيل إضافة سير العمل
  engine: WorkflowPlugin;
  // مثيل سير العمل
  workflow: object;
  // العقدة السابقة
  upstream: object;
  // هل هي عقدة فرعية (رقم الفرع)
  branchIndex: number;
};

تُرجع طريقة isAvailable القيمة true إذا كانت العقدة متاحة، وfalse إذا لم تكن كذلك. يحتوي المعامل ctx على معلومات سياق العقدة الحالية، والتي يمكن استخدامها لتحديد توفر العقدة.

في حالة عدم وجود متطلبات خاصة، لا تحتاج إلى تنفيذ طريقة isAvailable، حيث تكون العقد متاحة افتراضيًا. السيناريو الأكثر شيوعًا الذي يتطلب التهيئة هو عندما تكون العقدة عملية تستغرق وقتًا طويلاً وغير مناسبة للتنفيذ في سير عمل متزامن. يمكنك استخدام طريقة isAvailable لتقييد استخدام العقدة. على سبيل المثال:

isAvailable({ engine, workflow, upstream, branchIndex }) {
  return !engine.isWorkflowSync(workflow);
}

#لمعرفة المزيد

للاطلاع على تعريفات المعلمات المختلفة لتحديد أنواع العقد، راجع قسم مرجع واجهة برمجة تطبيقات سير العمل.