From a1d7e81859f554f3a53680cc35f0f49bf1f77098 Mon Sep 17 00:00:00 2001
From: wwf <1971391498@qq.com>
Date: 星期四, 14 五月 2026 14:37:02 +0800
Subject: [PATCH] 导入项目

---
 src/components/bpmnProcessDesigner/package/penal/task/task-components/ServiceTask.vue |  396 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 396 insertions(+), 0 deletions(-)

diff --git a/src/components/bpmnProcessDesigner/package/penal/task/task-components/ServiceTask.vue b/src/components/bpmnProcessDesigner/package/penal/task/task-components/ServiceTask.vue
new file mode 100644
index 0000000..c07e80b
--- /dev/null
+++ b/src/components/bpmnProcessDesigner/package/penal/task/task-components/ServiceTask.vue
@@ -0,0 +1,396 @@
+<template>
+  <div>
+    <el-form-item label="鎵ц绫诲瀷" key="executeType">
+      <el-select v-model="serviceTaskForm.executeType" @change="handleExecuteTypeChange">
+        <el-option label="Java绫�" value="class" />
+        <el-option label="琛ㄨ揪寮�" value="expression" />
+        <el-option label="浠g悊琛ㄨ揪寮�" value="delegateExpression" />
+        <el-option label="HTTP 璋冪敤" value="http" />
+      </el-select>
+    </el-form-item>
+    <el-form-item
+      v-if="serviceTaskForm.executeType === 'class'"
+      label="Java绫�"
+      prop="class"
+      key="execute-class"
+    >
+      <el-input v-model="serviceTaskForm.class" clearable @change="updateElementTask" />
+    </el-form-item>
+    <el-form-item
+      v-if="serviceTaskForm.executeType === 'expression'"
+      label="琛ㄨ揪寮�"
+      prop="expression"
+      key="execute-expression"
+    >
+      <el-input v-model="serviceTaskForm.expression" clearable @change="updateElementTask" />
+    </el-form-item>
+    <el-form-item
+      v-if="serviceTaskForm.executeType === 'delegateExpression'"
+      label="浠g悊琛ㄨ揪寮�"
+      prop="delegateExpression"
+      key="execute-delegate"
+    >
+      <el-input
+        v-model="serviceTaskForm.delegateExpression"
+        clearable
+        @change="updateElementTask"
+      />
+    </el-form-item>
+    <template v-if="serviceTaskForm.executeType === 'http'">
+      <el-form-item label="璇锋眰鏂规硶" key="http-method">
+        <el-radio-group v-model="httpTaskForm.requestMethod">
+          <el-radio-button label="GET" value="GET" />
+          <el-radio-button label="POST" value="POST" />
+          <el-radio-button label="PUT" value="PUT" />
+          <el-radio-button label="DELETE" value="DELETE" />
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item label="璇锋眰鍦板潃" key="http-url" prop="requestUrl">
+        <el-input v-model="httpTaskForm.requestUrl" clearable />
+      </el-form-item>
+      <el-form-item label="璇锋眰澶�" key="http-headers">
+        <div style="display: flex; gap: 8px; align-items: flex-start; width: 100%">
+          <el-input
+            v-model="httpTaskForm.requestHeaders"
+            type="textarea"
+            resize="vertical"
+            :autosize="{ minRows: 4, maxRows: 8 }"
+            readonly
+            placeholder="鐐瑰嚮鍙充晶缂栬緫鎸夐挳娣诲姞璇锋眰澶�"
+            style="flex: 1; min-width: 0"
+          />
+          <el-button
+            type="primary"
+            :icon="Edit"
+            @click="showHeaderEditor = true"
+            style="flex-shrink: 0"
+          >
+            缂栬緫
+          </el-button>
+        </div>
+      </el-form-item>
+      <el-form-item label="绂佹閲嶅畾鍚�" key="http-disallow-redirects">
+        <el-switch v-model="httpTaskForm.disallowRedirects" />
+      </el-form-item>
+      <el-form-item label="蹇界暐寮傚父" key="http-ignore-exception">
+        <el-switch v-model="httpTaskForm.ignoreException" />
+      </el-form-item>
+      <el-form-item label="淇濆瓨杩斿洖鍙橀噺" key="http-save-response">
+        <el-switch v-model="httpTaskForm.saveResponseParameters" />
+      </el-form-item>
+      <el-form-item label="鏄惁鐬棿鍙橀噺" key="http-save-transient">
+        <el-switch v-model="httpTaskForm.saveResponseParametersTransient" />
+      </el-form-item>
+      <el-form-item label="杩斿洖鍙橀噺鍓嶇紑" key="http-result-variable-prefix">
+        <el-input v-model="httpTaskForm.resultVariablePrefix" />
+      </el-form-item>
+      <el-form-item label="鏍煎紡鍖栬繑鍥炰负JSON" key="http-save-json">
+        <el-switch v-model="httpTaskForm.saveResponseVariableAsJson" />
+      </el-form-item>
+    </template>
+
+    <!-- 璇锋眰澶寸紪杈戝櫒 -->
+    <HttpHeaderEditor
+      v-model="showHeaderEditor"
+      :headers="httpTaskForm.requestHeaders"
+      @save="handleHeadersSave"
+    />
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { Edit } from '@element-plus/icons-vue'
+import { updateElementExtensions } from '@/components/bpmnProcessDesigner/package/utils'
+import HttpHeaderEditor from './HttpHeaderEditor.vue'
+
+defineOptions({ name: 'ServiceTask' })
+const props = defineProps({
+  id: String,
+  type: String
+})
+
+const prefix = (inject('prefix', 'flowable') || 'flowable') as string
+const flowableTypeKey = `${prefix}:type`
+const flowableFieldType = `${prefix}:Field`
+
+const HTTP_FIELD_NAMES = [
+  'requestMethod',
+  'requestUrl',
+  'requestHeaders',
+  'disallowRedirects',
+  'ignoreException',
+  'saveResponseParameters',
+  'resultVariablePrefix',
+  'saveResponseParametersTransient',
+  'saveResponseVariableAsJson'
+]
+const HTTP_BOOLEAN_FIELDS = new Set([
+  'disallowRedirects',
+  'ignoreException',
+  'saveResponseParameters',
+  'saveResponseParametersTransient',
+  'saveResponseVariableAsJson'
+])
+
+const DEFAULT_TASK_FORM = {
+  executeType: '',
+  class: '',
+  expression: '',
+  delegateExpression: ''
+}
+
+const DEFAULT_HTTP_FORM = {
+  requestMethod: 'GET',
+  requestUrl: '',
+  requestHeaders: 'Content-Type: application/json',
+  resultVariablePrefix: '',
+  disallowRedirects: false,
+  ignoreException: false,
+  saveResponseParameters: false,
+  saveResponseParametersTransient: false,
+  saveResponseVariableAsJson: false
+}
+
+const serviceTaskForm = ref({ ...DEFAULT_TASK_FORM })
+const httpTaskForm = ref({ ...DEFAULT_HTTP_FORM })
+const bpmnElement = ref()
+const httpInitializing = ref(false)
+const showHeaderEditor = ref(false)
+
+const bpmnInstances = () => (window as any)?.bpmnInstances
+
+// 鍒ゆ柇瀛楃涓叉槸鍚﹀寘鍚〃杈惧紡
+const isExpression = (value: string): boolean => {
+  if (!value) return false
+  // 妫�娴� ${...} 鎴� #{...} 鏍煎紡鐨勮〃杈惧紡
+  return /\${[^}]+}/.test(value) || /#{[^}]+}/.test(value)
+}
+
+const collectHttpExtensionInfo = () => {
+  const businessObject = bpmnElement.value?.businessObject
+  const extensionElements = businessObject?.extensionElements
+  const httpFields = new Map<string, string>()
+  const httpFieldTypes = new Map<string, 'string' | 'expression'>()
+  const otherExtensions: any[] = []
+
+  extensionElements?.values?.forEach((item: any) => {
+    if (item?.$type === flowableFieldType && HTTP_FIELD_NAMES.includes(item.name)) {
+      const value = item.string ?? item.stringValue ?? item.expression ?? ''
+      const fieldType = item.expression ? 'expression' : 'string'
+      httpFields.set(item.name, value)
+      httpFieldTypes.set(item.name, fieldType)
+    } else {
+      otherExtensions.push(item)
+    }
+  })
+
+  return { httpFields, httpFieldTypes, otherExtensions }
+}
+
+const resetHttpDefaults = () => {
+  httpInitializing.value = true
+  httpTaskForm.value = { ...DEFAULT_HTTP_FORM }
+  nextTick(() => {
+    httpInitializing.value = false
+  })
+}
+
+const resetHttpForm = () => {
+  httpInitializing.value = true
+  const { httpFields } = collectHttpExtensionInfo()
+  const nextForm = { ...DEFAULT_HTTP_FORM }
+
+  HTTP_FIELD_NAMES.forEach((name) => {
+    const stored = httpFields.get(name)
+    if (stored !== undefined) {
+      nextForm[name] = HTTP_BOOLEAN_FIELDS.has(name) ? stored === 'true' : stored
+    }
+  })
+
+  httpTaskForm.value = nextForm
+  nextTick(() => {
+    httpInitializing.value = false
+    updateHttpExtensions(true)
+  })
+}
+
+const resetServiceTaskForm = () => {
+  const businessObject = bpmnElement.value?.businessObject
+  const nextForm = { ...DEFAULT_TASK_FORM }
+
+  if (businessObject) {
+    if (businessObject.class) {
+      nextForm.class = businessObject.class
+      nextForm.executeType = 'class'
+    }
+    if (businessObject.expression) {
+      nextForm.expression = businessObject.expression
+      nextForm.executeType = 'expression'
+    }
+    if (businessObject.delegateExpression) {
+      nextForm.delegateExpression = businessObject.delegateExpression
+      nextForm.executeType = 'delegateExpression'
+    }
+    if (businessObject.$attrs?.[flowableTypeKey] === 'http') {
+      nextForm.executeType = 'http'
+    } else {
+      // 鍏滃簳锛氬缂哄皯 flowable:type=http锛屼絾鎵╁睍閲屽凡鏈� HTTP 鐨勫瓧娈碉紝涔熻涓烘槸 HTTP
+      const { httpFields } = collectHttpExtensionInfo()
+      if (httpFields.size > 0) {
+        nextForm.executeType = 'http'
+      }
+    }
+  }
+
+  serviceTaskForm.value = nextForm
+
+  if (nextForm.executeType === 'http') {
+    resetHttpForm()
+  } else {
+    resetHttpDefaults()
+  }
+}
+
+const shouldPersistField = (name: string, value: any) => {
+  if (HTTP_BOOLEAN_FIELDS.has(name)) return true
+  if (name === 'requestMethod') return true
+  if (name === 'requestUrl') return !!value
+  return value !== undefined && value !== ''
+}
+
+const updateHttpExtensions = (force = false) => {
+  if (!bpmnElement.value) return
+  if (!force && (httpInitializing.value || serviceTaskForm.value.executeType !== 'http')) {
+    return
+  }
+
+  const {
+    httpFields: existingFields,
+    httpFieldTypes: existingTypes,
+    otherExtensions
+  } = collectHttpExtensionInfo()
+
+  const desiredEntries: [string, string][] = []
+  HTTP_FIELD_NAMES.forEach((name) => {
+    const rawValue = httpTaskForm.value[name]
+    if (!shouldPersistField(name, rawValue)) {
+      return
+    }
+
+    const persisted = HTTP_BOOLEAN_FIELDS.has(name)
+      ? String(!!rawValue)
+      : rawValue === undefined
+        ? ''
+        : String(rawValue)
+
+    desiredEntries.push([name, persisted])
+  })
+
+  // 妫�鏌ユ槸鍚︽湁鍙樺寲锛氫笉浠呮瘮杈冨�硷紝杩樿姣旇緝瀛楁绫诲瀷锛坰tring vs expression锛�
+  if (!force && desiredEntries.length === existingFields.size) {
+    let noChange = true
+    for (const [name, value] of desiredEntries) {
+      const existingValue = existingFields.get(name)
+      const existingType = existingTypes.get(name)
+      const currentType = isExpression(value) ? 'expression' : 'string'
+      if (existingValue !== value || existingType !== currentType) {
+        noChange = false
+        break
+      }
+    }
+    if (noChange) {
+      return
+    }
+  }
+
+  const moddle = bpmnInstances().moddle
+  const httpFieldElements = desiredEntries.map(([name, value]) => {
+    // 鏍规嵁鍊兼槸鍚﹀寘鍚〃杈惧紡鏉ュ喅瀹氫娇鐢� string 杩樻槸 expression 灞炴��
+    const isExpr = isExpression(value)
+    return moddle.create(flowableFieldType, {
+      name,
+      ...(isExpr ? { expression: value } : { string: value })
+    })
+  })
+
+  updateElementExtensions(bpmnElement.value, [...otherExtensions, ...httpFieldElements])
+}
+
+const removeHttpExtensions = () => {
+  if (!bpmnElement.value) return
+  const { httpFields, otherExtensions } = collectHttpExtensionInfo()
+  if (!httpFields.size) {
+    return
+  }
+
+  if (!otherExtensions.length) {
+    bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
+      extensionElements: null
+    })
+    return
+  }
+
+  updateElementExtensions(bpmnElement.value, otherExtensions)
+}
+
+const updateElementTask = () => {
+  if (!bpmnElement.value) return
+
+  const taskAttr: Record<string, any> = {
+    class: null,
+    expression: null,
+    delegateExpression: null,
+    [flowableTypeKey]: null
+  }
+
+  const type = serviceTaskForm.value.executeType
+  if (type === 'class' || type === 'expression' || type === 'delegateExpression') {
+    taskAttr[type] = serviceTaskForm.value[type] || null
+  } else if (type === 'http') {
+    taskAttr[flowableTypeKey] = 'http'
+  }
+
+  bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), taskAttr)
+
+  if (type === 'http') {
+    updateHttpExtensions(true)
+  } else {
+    removeHttpExtensions()
+  }
+}
+
+const handleExecuteTypeChange = (value: string) => {
+  serviceTaskForm.value.executeType = value
+  if (value === 'http') {
+    resetHttpForm()
+  }
+  updateElementTask()
+}
+
+const handleHeadersSave = (headersStr: string) => {
+  httpTaskForm.value.requestHeaders = headersStr
+}
+
+onBeforeUnmount(() => {
+  bpmnElement.value = null
+})
+
+watch(
+  () => props.id,
+  () => {
+    bpmnElement.value = bpmnInstances().bpmnElement
+    nextTick(() => {
+      resetServiceTaskForm()
+    })
+  },
+  { immediate: true }
+)
+
+watch(
+  () => httpTaskForm.value,
+  () => {
+    updateHttpExtensions()
+  },
+  { deep: true }
+)
+</script>

--
Gitblit v1.8.0