import urllib.request
import urllib.parse
import json
import time

API_BASE = 'http://localhost:8080/jeecg-boot'
TOKEN = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiY2xpZW50VHlwZSI6IlBDIiwiZXhwIjoxNzc1ODYwNDQ3fQ.CwbbFH-7jlKA_q48KSikeqP7opSGC16AijhC2EI3YKM'

ts = str(int(time.time() * 1000))
process_key = f'process_{ts}'
process_name = '员工请假流程审批'

# 构造BPMN XML
bpmn_xml = f'''<?xml version="1.0" encoding="UTF-8"?>
<bpmn2:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd" id="sample-diagram" targetNamespace="http://bpmn.io/schema/bpmn">
  <bpmn2:process id="{process_key}" name="{process_name}" isExecutable="true">
    <bpmn2:startEvent id="startEvent" name="开始">
      <bpmn2:outgoing>flow1</bpmn2:outgoing>
    </bpmn2:startEvent>
    <bpmn2:userTask id="task_apply" name="员工提交" flowable:assignee="${{applyUserId}}">
      <bpmn2:extensionElements>
        <flowable:taskExtendJson value='{{"sameMode":2,"isShowAssignee":false,"isAllowEdit":true,"isAllowDelete":false,"isAllowWithdraw":true,"isAllowSave":true,"isAllowPrint":true,"isAllowDelegate":false,"isAllowAddSign":false,"isAllowCopy":false,"isAllowAssign":false,"isAllowTurn":false,"isAllowComment":true,"isAllowCounterSign":false,"isAllowReturn":false,"isAllowBack":false,"isAllowViewComment":true,"isAllowViewHistory":true,"isAllowViewTask":true,"isAllowViewTrack":true,"isAllowViewForm":true,"isAllowViewAssignee":false,"isAllowViewDelegate":false,"isAllowViewAddSign":false,"isAllowViewCopy":false,"isAllowViewAssign":false,"isAllowViewTurn":false,"isAllowViewCommentHistory":true,"isAllowViewAttachment":true,"isAllowAddAttachment":true,"isAllowDeleteAttachment":true,"isAllowViewImage":true,"isAllowViewVideo":true,"isAllowViewAudio":true,"isAllowViewFile":true,"isAllowDownload":true,"isAllowUpload":true,"isAllowShare":false,"isAllowPrintForm":true,"isAllowExportForm":true,"isAllowImportForm":false,"isAllowSaveForm":true,"isAllowResetForm":false,"isAllowSubmitForm":true,"isAllowCancelSubmit":true,"isAllowDraft":true,"isAllowPreview":true,"isAllowTest":false,"isAllowDebug":false,"isAllowMonitor":false,"isAllowDeploy":false,"isAllowUndeploy":false,"isAllowSuspend":false,"isAllowActivate":false,"isAllowDeleteProcess":false,"isAllowEditProcess":false,"isAllowCopyProcess":false,"isAllowExportProcess":true,"isAllowImportProcess":false,"isAllowViewProcess":true,"isAllowViewInstance":true,"isAllowViewTaskList":true,"isAllowViewTaskDetail":true,"isAllowViewTaskHistory":true,"isAllowViewTaskTrack":true,"isAllowViewTaskForm":true,"isAllowViewTaskAssignee":false,"isAllowViewTaskDelegate":false,"isAllowViewTaskAddSign":false,"isAllowViewTaskCopy":false,"isAllowViewTaskAssign":false,"isAllowViewTaskTurn":false,"isAllowViewTaskComment":true,"isAllowViewTaskCommentHistory":true,"isAllowViewTaskAttachment":true,"isAllowViewTaskImage":true,"isAllowViewTaskVideo":true,"isAllowViewTaskAudio":true,"isAllowViewTaskFile":true,"isAllowViewTaskDownload":true,"isAllowViewTaskUpload":true,"isAllowViewTaskShare":false,"isAllowViewTaskPrintForm":true,"isAllowViewTaskExportForm":true,"isAllowViewTaskImportForm":false,"isAllowViewTaskSaveForm":true,"isAllowViewTaskResetForm":false,"isAllowViewTaskSubmitForm":true,"isAllowViewTaskCancelSubmit":true,"isAllowViewTaskDraft":true,"isAllowViewTaskPreview":true,"isAllowViewTaskTest":false,"isAllowViewTaskDebug":false,"isAllowViewTaskMonitor":false,"isAllowViewTaskDeploy":false,"isAllowViewTaskUndeploy":false,"isAllowViewTaskSuspend":false,"isAllowViewTaskActivate":false,"isAllowViewTaskDeleteProcess":false,"isAllowViewTaskEditProcess":false,"isAllowViewTaskCopyProcess":false,"isAllowViewTaskExportProcess":true,"isAllowViewTaskImportProcess":false}}' />
        <flowable:taskListener event="create" class="org.jeecg.modules.bpm.listener.TaskCreateListener" />
      </bpmn2:extensionElements>
      <bpmn2:incoming>flow1</bpmn2:incoming>
      <bpmn2:outgoing>flow2</bpmn2:outgoing>
    </bpmn2:userTask>
    <bpmn2:userTask id="task_manager" name="部门经理审批" flowable:candidateGroups="manager" flowable:groupType="role">
      <bpmn2:extensionElements>
        <flowable:taskExtendJson value='{{"sameMode":0,"isShowAssignee":true,"isAllowEdit":false,"isAllowDelete":false,"isAllowWithdraw":false,"isAllowSave":true,"isAllowPrint":true,"isAllowDelegate":true,"isAllowAddSign":true,"isAllowCopy":true,"isAllowAssign":true,"isAllowTurn":true,"isAllowComment":true,"isAllowCounterSign":false,"isAllowReturn":true,"isAllowBack":true,"isAllowViewComment":true,"isAllowViewHistory":true,"isAllowViewTask":true,"isAllowViewTrack":true,"isAllowViewForm":true,"isAllowViewAssignee":true,"isAllowViewDelegate":true,"isAllowViewAddSign":true,"isAllowViewCopy":true,"isAllowViewAssign":true,"isAllowViewTurn":true,"isAllowViewCommentHistory":true,"isAllowViewAttachment":true,"isAllowAddAttachment":true,"isAllowDeleteAttachment":true,"isAllowViewImage":true,"isAllowViewVideo":true,"isAllowViewAudio":true,"isAllowViewFile":true,"isAllowDownload":true,"isAllowUpload":true,"isAllowShare":false,"isAllowPrintForm":true,"isAllowExportForm":true,"isAllowImportForm":false,"isAllowSaveForm":true,"isAllowResetForm":false,"isAllowSubmitForm":true,"isAllowCancelSubmit":true,"isAllowDraft":false,"isAllowPreview":true,"isAllowTest":false,"isAllowDebug":false,"isAllowMonitor":false,"isAllowDeploy":false,"isAllowUndeploy":false,"isAllowSuspend":false,"isAllowActivate":false,"isAllowDeleteProcess":false,"isAllowEditProcess":false,"isAllowCopyProcess":false,"isAllowExportProcess":true,"isAllowImportProcess":false,"isAllowViewProcess":true,"isAllowViewInstance":true,"isAllowViewTaskList":true,"isAllowViewTaskDetail":true,"isAllowViewTaskHistory":true,"isAllowViewTaskTrack":true,"isAllowViewTaskForm":true,"isAllowViewTaskAssignee":true,"isAllowViewTaskDelegate":true,"isAllowViewTaskAddSign":true,"isAllowViewTaskCopy":true,"isAllowViewTaskAssign":true,"isAllowViewTaskTurn":true,"isAllowViewTaskComment":true,"isAllowViewTaskCommentHistory":true,"isAllowViewTaskAttachment":true,"isAllowViewTaskImage":true,"isAllowViewTaskVideo":true,"isAllowViewTaskAudio":true,"isAllowViewTaskFile":true,"isAllowViewTaskDownload":true,"isAllowViewTaskUpload":true,"isAllowViewTaskShare":false,"isAllowViewTaskPrintForm":true,"isAllowViewTaskExportForm":true,"isAllowViewTaskImportForm":false,"isAllowViewTaskSaveForm":true,"isAllowViewTaskResetForm":false,"isAllowViewTaskSubmitForm":true,"isAllowViewTaskCancelSubmit":true,"isAllowViewTaskDraft":false,"isAllowViewTaskPreview":true,"isAllowViewTaskTest":false,"isAllowViewTaskDebug":false,"isAllowViewTaskMonitor":false,"isAllowViewTaskDeploy":false,"isAllowViewTaskUndeploy":false,"isAllowViewTaskSuspend":false,"isAllowViewTaskActivate":false,"isAllowViewTaskDeleteProcess":false,"isAllowViewTaskEditProcess":false,"isAllowViewTaskCopyProcess":false,"isAllowViewTaskExportProcess":true,"isAllowViewTaskImportProcess":false}}' />
        <flowable:taskListener event="create" class="org.jeecg.modules.bpm.listener.TaskCreateListener" />
      </bpmn2:extensionElements>
      <bpmn2:incoming>flow2</bpmn2:incoming>
      <bpmn2:outgoing>flow3</bpmn2:outgoing>
    </bpmn2:userTask>
    <bpmn2:userTask id="task_general_manager" name="总经理审批" flowable:candidateGroups="general_manager" flowable:groupType="role">
      <bpmn2:extensionElements>
        <flowable:taskExtendJson value='{{"sameMode":0,"isShowAssignee":true,"isAllowEdit":false,"isAllowDelete":false,"isAllowWithdraw":false,"isAllowSave":true,"isAllowPrint":true,"isAllowDelegate":true,"isAllowAddSign":true,"isAllowCopy":true,"isAllowAssign":true,"isAllowTurn":true,"isAllowComment":true,"isAllowCounterSign":false,"isAllowReturn":true,"isAllowBack":true,"isAllowViewComment":true,"isAllowViewHistory":true,"isAllowViewTask":true,"isAllowViewTrack":true,"isAllowViewForm":true,"isAllowViewAssignee":true,"isAllowViewDelegate":true,"isAllowViewAddSign":true,"isAllowViewCopy":true,"isAllowViewAssign":true,"isAllowViewTurn":true,"isAllowViewCommentHistory":true,"isAllowViewAttachment":true,"isAllowAddAttachment":true,"isAllowDeleteAttachment":true,"isAllowViewImage":true,"isAllowViewVideo":true,"isAllowViewAudio":true,"isAllowViewFile":true,"isAllowDownload":true,"isAllowUpload":true,"isAllowShare":false,"isAllowPrintForm":true,"isAllowExportForm":true,"isAllowImportForm":false,"isAllowSaveForm":true,"isAllowResetForm":false,"isAllowSubmitForm":true,"isAllowCancelSubmit":true,"isAllowDraft":false,"isAllowPreview":true,"isAllowTest":false,"isAllowDebug":false,"isAllowMonitor":false,"isAllowDeploy":false,"isAllowUndeploy":false,"isAllowSuspend":false,"isAllowActivate":false,"isAllowDeleteProcess":false,"isAllowEditProcess":false,"isAllowCopyProcess":false,"isAllowExportProcess":true,"isAllowImportProcess":false,"isAllowViewProcess":true,"isAllowViewInstance":true,"isAllowViewTaskList":true,"isAllowViewTaskDetail":true,"isAllowViewTaskHistory":true,"isAllowViewTaskTrack":true,"isAllowViewTaskForm":true,"isAllowViewTaskAssignee":true,"isAllowViewTaskDelegate":true,"isAllowViewTaskAddSign":true,"isAllowViewTaskCopy":true,"isAllowViewTaskAssign":true,"isAllowViewTaskTurn":true,"isAllowViewTaskComment":true,"isAllowViewTaskCommentHistory":true,"isAllowViewTaskAttachment":true,"isAllowViewTaskImage":true,"isAllowViewTaskVideo":true,"isAllowViewTaskAudio":true,"isAllowViewTaskFile":true,"isAllowViewTaskDownload":true,"isAllowViewTaskUpload":true,"isAllowViewTaskShare":false,"isAllowViewTaskPrintForm":true,"isAllowViewTaskExportForm":true,"isAllowViewTaskImportForm":false,"isAllowViewTaskSaveForm":true,"isAllowViewTaskResetForm":false,"isAllowViewTaskSubmitForm":true,"isAllowViewTaskCancelSubmit":true,"isAllowViewTaskDraft":false,"isAllowViewTaskPreview":true,"isAllowViewTaskTest":false,"isAllowViewTaskDebug":false,"isAllowViewTaskMonitor":false,"isAllowViewTaskDeploy":false,"isAllowViewTaskUndeploy":false,"isAllowViewTaskSuspend":false,"isAllowViewTaskActivate":false,"isAllowViewTaskDeleteProcess":false,"isAllowViewTaskEditProcess":false,"isAllowViewTaskCopyProcess":false,"isAllowViewTaskExportProcess":true,"isAllowViewTaskImportProcess":false}}' />
        <flowable:taskListener event="create" class="org.jeecg.modules.bpm.listener.TaskCreateListener" />
      </bpmn2:extensionElements>
      <bpmn2:incoming>flow3</bpmn2:incoming>
      <bpmn2:outgoing>flow4</bpmn2:outgoing>
    </bpmn2:userTask>
    <bpmn2:endEvent id="endEvent" name="结束">
      <bpmn2:incoming>flow4</bpmn2:incoming>
    </bpmn2:endEvent>
    <bpmn2:sequenceFlow id="flow1" sourceRef="startEvent" targetRef="task_apply" />
    <bpmn2:sequenceFlow id="flow2" sourceRef="task_apply" targetRef="task_manager" />
    <bpmn2:sequenceFlow id="flow3" sourceRef="task_manager" targetRef="task_general_manager" />
    <bpmn2:sequenceFlow id="flow4" sourceRef="task_general_manager" targetRef="endEvent" />
    <bpmn2:extensionElements>
      <flowable:executionListener event="end" class="org.jeecg.modules.bpm.listener.ProcessEndListener" />
    </bpmn2:extensionElements>
  </bpmn2:process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_1">
    <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="{process_key}">
      <bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="startEvent">
        <dc:Bounds x="100" y="100" width="36" height="36" />
        <bpmndi:BPMNLabel>
          <dc:Bounds x="109" y="142" width="18" height="14" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="_BPMNShape_UserTask_1" bpmnElement="task_apply">
        <dc:Bounds x="200" y="80" width="100" height="80" />
        <bpmndi:BPMNLabel>
          <dc:Bounds x="230" y="165" width="40" height="14" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="_BPMNShape_UserTask_2" bpmnElement="task_manager">
        <dc:Bounds x="350" y="80" width="100" height="80" />
        <bpmndi:BPMNLabel>
          <dc:Bounds x="360" y="165" width="80" height="14" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="_BPMNShape_UserTask_3" bpmnElement="task_general_manager">
        <dc:Bounds x="500" y="80" width="100" height="80" />
        <bpmndi:BPMNLabel>
          <dc:Bounds x="510" y="165" width="80" height="14" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="_BPMNShape_EndEvent_1" bpmnElement="endEvent">
        <dc:Bounds x="650" y="100" width="36" height="36" />
        <bpmndi:BPMNLabel>
          <dc:Bounds x="660" y="142" width="18" height="14" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="_BPMNEdge_SequenceFlow_1" bpmnElement="flow1">
        <di:waypoint x="136" y="118" />
        <di:waypoint x="200" y="120" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="_BPMNEdge_SequenceFlow_2" bpmnElement="flow2">
        <di:waypoint x="300" y="120" />
        <di:waypoint x="350" y="120" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="_BPMNEdge_SequenceFlow_3" bpmnElement="flow3">
        <di:waypoint x="450" y="120" />
        <di:waypoint x="500" y="120" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="_BPMNEdge_SequenceFlow_4" bpmnElement="flow4">
        <di:waypoint x="600" y="120" />
        <di:waypoint x="650" y="118" />
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</bpmn2:definitions>'''

# 构造nodes参数
nodes_str = 'id=task_apply###nodeName=员工提交@@@id=task_manager###nodeName=部门经理审批@@@id=task_general_manager###nodeName=总经理审批@@@'

data = {
    'processDefinitionId': '0',
    'processName': process_name,
    'processkey': process_key,
    'typeid': 'oa',
    'lowAppId': '',
    'params': '',
    'nodes': nodes_str,
    'processDescriptor': bpmn_xml,
    'realProcDefId': '',
    'startType': 'manual'
}

encoded_data = urllib.parse.urlencode(data).encode('utf-8')

req = urllib.request.Request(
    f'{API_BASE}/bpm/process/save',
    data=encoded_data,
    headers={
        'X-Access-Token': TOKEN,
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
    },
    method='POST'
)

try:
    resp = urllib.request.urlopen(req)
    result = json.loads(resp.read().decode('utf-8'))
    print(json.dumps(result, ensure_ascii=False, indent=2))
    print(f'\nProcess Key: {process_key}')
except urllib.error.HTTPError as e:
    print(f'HTTP Error: {e.code} - {e.reason}')
    print(f'Error details: {e.read().decode("utf-8")}')
except Exception as e:
    print(f'Error: {e}')
