amis 展示 camunda zeebe task

 整体架构如上图所示,通过nginx反向代理amis-editor、zeebe和keycloak,docker可以通过以下compose文件安装:

# While the Docker images themselves are supported for production usage,
# this docker-compose.yaml is designed to be used by developers to run
# an environment locally. It is not designed to be used in production.
# We recommend to use Kubernetes in production with our Helm Charts:
# https://docs.camunda.io/docs/self-managed/platform-deployment/kubernetes-helm/
# For local development, we recommend using KIND instead of `docker-compose`:
# https://docs.camunda.io/docs/self-managed/platform-deployment/kubernetes-helm/#installing-the-camunda-helm-chart-locally-using-kind

# This is a full configuration with Zeebe, Operate, Tasklist, Optimize, Identity, Keycloak, and Elasticsearch
# See docker-compose-core.yml for a lightweight configuration that does not include Optimize, Identity, and Keycloak.

services:

  zeebe: # https://docs.camunda.io/docs/self-managed/platform-deployment/docker/#zeebe
    image: camunda/zeebe:${CAMUNDA_PLATFORM_VERSION:-8.0.5}
    container_name: zeebe
    ports:
      - "26500:26500"
      - "9600:9600"
    environment: # https://docs.camunda.io/docs/self-managed/zeebe-deployment/configuration/environment-variables/
      - ZEEBE_BROKER_EXPORTERS_ELASTICSEARCH_CLASSNAME=io.camunda.zeebe.exporter.ElasticsearchExporter
      - ZEEBE_BROKER_EXPORTERS_ELASTICSEARCH_ARGS_URL=http://elasticsearch:9200
      - ZEEBE_BROKER_EXPORTERS_ELASTICSEARCH_ARGS_BULK_SIZE=1
      # allow running with low disk space
      - ZEEBE_BROKER_DATA_DISKUSAGECOMMANDWATERMARK=0.998
      - ZEEBE_BROKER_DATA_DISKUSAGEREPLICATIONWATERMARK=0.999
      - "JAVA_TOOL_OPTIONS=-Xms512m -Xmx512m"
    restart: always
    volumes:
      - zeebe:/usr/local/zeebe/data
    networks:
      - camunda-platform
    depends_on:
      - elasticsearch

  operate: # https://docs.camunda.io/docs/self-managed/platform-deployment/docker/#operate
    image: camunda/operate:${CAMUNDA_PLATFORM_VERSION:-8.0.5}
    container_name: operate
    ports:
      - "8081:8080"
    environment: # https://docs.camunda.io/docs/self-managed/operate-deployment/configuration/
      - CAMUNDA_OPERATE_ZEEBE_GATEWAYADDRESS=zeebe:26500
      - CAMUNDA_OPERATE_ELASTICSEARCH_URL=http://elasticsearch:9200
      - CAMUNDA_OPERATE_ZEEBEELASTICSEARCH_URL=http://elasticsearch:9200
      # For more information regarding configuration with Identity see:
      # https://docs.camunda.io/docs/self-managed/operate-deployment/authentication/#identity
      - SPRING_PROFILES_ACTIVE=identity-auth
      - CAMUNDA_OPERATE_IDENTITY_ISSUER_URL=http://localhost:18080/auth/realms/camunda-platform
      - CAMUNDA_OPERATE_IDENTITY_ISSUER_BACKEND_URL=http://keycloak:8080/auth/realms/camunda-platform
      - CAMUNDA_OPERATE_IDENTITY_CLIENTID=operate
      - CAMUNDA_OPERATE_IDENTITY_CLIENTSECRET=XALaRPl5qwTEItdwCMiPS62nVpKs7dL7
      - CAMUNDA_OPERATE_IDENTITY_AUDIENCE=operate-api
      - SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI=http://localhost:18080/auth/realms/camunda-platform
      - SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_JWK_SET_URI=http://localhost:18080/auth/realms/camunda-platform/protocol/openid-connect/certs
    networks:
      - camunda-platform
      - identity-network
    depends_on:
      - zeebe
      - identity
      - elasticsearch

  tasklist: # https://docs.camunda.io/docs/self-managed/platform-deployment/docker/#tasklist
    image: camunda/tasklist:${CAMUNDA_PLATFORM_VERSION:-8.0.5}
    container_name: tasklist
    ports:
      - "8082:8080"
    environment: # https://docs.camunda.io/docs/self-managed/tasklist-deployment/configuration/
      - CAMUNDA_TASKLIST_ZEEBE_GATEWAYADDRESS=zeebe:26500
      - CAMUNDA_TASKLIST_ELASTICSEARCH_URL=http://elasticsearch:9200
      - CAMUNDA_TASKLIST_ZEEBEELASTICSEARCH_URL=http://elasticsearch:9200
      # For more information regarding configuration with Identity see:
      # https://docs.camunda.io/docs/self-managed/tasklist-deployment/authentication/#identity
      - SPRING_PROFILES_ACTIVE=identity-auth
      - CAMUNDA_TASKLIST_IDENTITY_ISSUER_URL=http://localhost:18080/auth/realms/camunda-platform
      - CAMUNDA_TASKLIST_IDENTITY_ISSUER_BACKEND_URL=http://keycloak:8080/auth/realms/camunda-platform
      - CAMUNDA_TASKLIST_IDENTITY_CLIENTID=tasklist
      - CAMUNDA_TASKLIST_IDENTITY_CLIENTSECRET=XALaRPl5qwTEItdwCMiPS62nVpKs7dL7
      - CAMUNDA_TASKLIST_IDENTITY_AUDIENCE=tasklist-api
      - SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI=http://localhost:18080/auth/realms/camunda-platform
      - SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_JWK_SET_URI=http://localhost:18080/auth/realms/camunda-platform/protocol/openid-connect/certs
    networks:
      - camunda-platform
      - identity-network
    depends_on:
      - zeebe
      - identity
      - elasticsearch

  optimize: # https://docs.camunda.io/docs/self-managed/platform-deployment/docker/#optimize
    image: camunda/optimize:${CAMUNDA_OPTIMIZE_VERSION:-3.8.5}
    container_name: optimize
    ports:
      - "8083:8090"
    environment: # https://docs.camunda.io/docs/self-managed/optimize-deployment/setup/installation/#available-environment-variables
      - OPTIMIZE_ELASTICSEARCH_HOST=elasticsearch
      - OPTIMIZE_ELASTICSEARCH_HTTP_PORT=9200
      - SPRING_PROFILES_ACTIVE=ccsm
      - CAMUNDA_OPTIMIZE_ZEEBE_ENABLED=true
      - CAMUNDA_OPTIMIZE_ENTERPRISE=false
      - CAMUNDA_OPTIMIZE_IDENTITY_ISSUER_URL=http://localhost:18080/auth/realms/camunda-platform
      - CAMUNDA_OPTIMIZE_IDENTITY_ISSUER_BACKEND_URL=http://keycloak:8080/auth/realms/camunda-platform
      - CAMUNDA_OPTIMIZE_IDENTITY_CLIENTID=optimize
      - CAMUNDA_OPTIMIZE_IDENTITY_CLIENTSECRET=XALaRPl5qwTEItdwCMiPS62nVpKs7dL7
      - CAMUNDA_OPTIMIZE_IDENTITY_AUDIENCE=optimize-api
      - CAMUNDA_OPTIMIZE_SECURITY_AUTH_COOKIE_SAME_SITE_ENABLED=false
      - CAMUNDA_OPTIMIZE_UI_LOGOUT_HIDDEN=true
    restart: on-failure
    networks:
      - camunda-platform
      - identity-network
    depends_on:
      - identity
      - elasticsearch

  identity: # https://docs.camunda.io/docs/self-managed/platform-deployment/docker/#identity
    container_name: identity
    image: camunda/identity:${CAMUNDA_PLATFORM_VERSION:-8.0.5}
    ports:
      - "8084:8084"
    environment: # https://docs.camunda.io/docs/self-managed/identity/deployment/configuration-variables/
      SERVER_PORT: 8084
      KEYCLOAK_URL: http://keycloak:8080/auth
      IDENTITY_AUTH_PROVIDER_BACKEND_URL: http://keycloak:8080/auth/realms/camunda-platform
      KEYCLOAK_INIT_OPERATE_SECRET: XALaRPl5qwTEItdwCMiPS62nVpKs7dL7
      KEYCLOAK_INIT_OPERATE_ROOT_URL: http://localhost:8081
      KEYCLOAK_INIT_TASKLIST_SECRET: XALaRPl5qwTEItdwCMiPS62nVpKs7dL7
      KEYCLOAK_INIT_TASKLIST_ROOT_URL: http://localhost:8082
      KEYCLOAK_INIT_OPTIMIZE_SECRET: XALaRPl5qwTEItdwCMiPS62nVpKs7dL7
      KEYCLOAK_INIT_OPTIMIZE_ROOT_URL: http://localhost:8083
      KEYCLOAK_USERS_0_USERNAME: "demo"
      KEYCLOAK_USERS_0_PASSWORD: "demo"
      KEYCLOAK_USERS_0_FIRST_NAME: "demo"
      KEYCLOAK_USERS_0_ROLES_0: "Identity"
      KEYCLOAK_USERS_0_ROLES_1: "Optimize"
      KEYCLOAK_USERS_0_ROLES_2: "Operate"
      KEYCLOAK_USERS_0_ROLES_3: "Tasklist"
    restart: on-failure
    networks:
      - identity-network
    depends_on:
      - keycloak

  keycloak: # https://hub.docker.com/r/jboss/keycloak
    container_name: keycloak
    image: jboss/keycloak:${KEYCLOAK_VERSION:-16.1.1}
    ports:
      - "18080:8080"
    environment:
      KEYCLOAK_USER: admin
      KEYCLOAK_PASSWORD: admin
      DB_VENDOR: h2
    volumes:
      - "./.keycloak/themes/identity:/opt/jboss/keycloak/themes/identity"
    networks:
      - identity-network

  elasticsearch: # https://hub.docker.com/_/elasticsearch
    image: docker.elastic.co/elasticsearch/elasticsearch:${ELASTIC_VERSION:-7.17.0}
    container_name: elasticsearch
    ports:
      - "9200:9200"
      - "9300:9300"
    environment:
      - bootstrap.memory_lock=true
      - discovery.type=single-node
      # allow running with low disk space
      - cluster.routing.allocation.disk.threshold_enabled=false
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    restart: always
    healthcheck:
      test: [ "CMD-SHELL", "curl -f http://localhost:9200/_cat/health | grep -q green" ]
      interval: 30s
      timeout: 5s
      retries: 3
    volumes:
      - elastic:/usr/share/elasticsearch/data
    networks:
      - camunda-platform

volumes:
  zeebe:
  elastic:

networks:
  # Note there are two bridge networks: One for Camunda Platform and one for Identity.
  # Operate, Tasklist, and Optimize use both
  camunda-platform:
  identity-network:

nginx配置文件如下:


    server {
        listen       8080;
        server_name  localhost;

      
        location /graphql {
            proxy_pass   http://localhost:8082;
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header REMOTE-HOST $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }

        location /auth {
            proxy_pass   http://localhost:18080;
        }

        location /{
            root /develop/amis-editor-demo/public;
            index index.html;
        }
}

amis配置文件如下:

{
    "type": "page",
    "title": "1",
    "body": [
        {
            "type": "form",
            "title": "表单",
            "body": [
                {
                    "type": "crud",
                    "api": {
                        "method": "post",
                        "url": "/graphql",
                        "headers": {
                            "Authorization": "Bearer ${access_token}"
                        },
                        "requestAdaptor": "api.data = {\n  \"operationName\": \"GetTasks\",\n  \"variables\": {\n    \"state\": \"COMPLETED\",\n    \"pageSize\": 50\n  },\n  \"query\": \"query GetTasks($assignee: String, $assigned: Boolean, $state: TaskState, $pageSize: Int, $searchAfter: [String!], $searchBefore: [String!], $searchAfterOrEqual: [String!]) {\\n  tasks(\\n    query: {assignee: $assignee, assigned: $assigned, state: $state, pageSize: $pageSize, searchAfter: $searchAfter, searchBefore: $searchBefore, searchAfterOrEqual: $searchAfterOrEqual}\\n  ) {\\n    id\\n    name\\n    processName\\n    assignee\\n    creationTime\\n    taskState\\n    sortValues\\n    isFirst\\n    __typename\\n  }\\n}\"\n}\nreturn api;",
                        "adaptor": "debugger;\nreturn {\n  \"status\": 0,\n  \"msg\": \"\",\n  \"data\": {\n    \"items\":payload.data.tasks\n  }\n}"
                    },
                    "columns": [
                        {
                            "name": "id",
                            "label": "ID",
                            "type": "text"
                        },
                        {
                            "name": "name",
                            "label": "name",
                            "type": "text",
                            "placeholder": "-"
                        }
                    ],
                    "bulkActions": [
                    ],
                    "itemActions": [
                    ],
                    "perPageAvailable": [
                        10
                    ],
                    "messages": {
                    }
                }
            ],
            "debug": false,
            "initApi": {
                "method": "post",
                "url": "/auth/realms/camunda-platform/protocol/openid-connect/token",
                "dataType": "form",
                "data": {
                    "&": "$$",
                    "client_id": "tasklist",
                    "client_secret": "XALaRPl5qwTEItdwCMiPS62nVpKs7dL7",
                    "grant_type": "client_credentials"
                },
                "adaptor": "",
                "responseData": {
                    "&": "$$"
                }
            },
            "submitOnInit": false,
            "target": "",
            "reload": "",
            "api": {
                "method": "post",
                "url": "/graphql",
                "headers": {
                    "Authorization": "Bearer ${access_token}"
                },
                "requestAdaptor": "debugger;\ndebugger;\napi.data = {\n  \"operationName\": \"GetTasks\",\n  \"variables\": {\n    \"state\": \"COMPLETED\",\n    \"pageSize\": 50\n  },\n  \"query\": \"query GetTasks($assignee: String, $assigned: Boolean, $state: TaskState, $pageSize: Int, $searchAfter: [String!], $searchBefore: [String!], $searchAfterOrEqual: [String!]) {\\n  tasks(\\n    query: {assignee: $assignee, assigned: $assigned, state: $state, pageSize: $pageSize, searchAfter: $searchAfter, searchBefore: $searchBefore, searchAfterOrEqual: $searchAfterOrEqual}\\n  ) {\\n    id\\n    name\\n    processName\\n    assignee\\n    creationTime\\n    taskState\\n    sortValues\\n    isFirst\\n    __typename\\n  }\\n}\"\n}\nreturn api;"
            }
        }
    ]
}

核心逻辑如下:

先通过keycloak获取tasklist客户端的的access_token:

   "initApi": {
                "method": "post",
                "url": "/auth/realms/camunda-platform/protocol/openid-connect/token",
                "dataType": "form",
                "data": {
                    "&": "$$",
                    "client_id": "tasklist",
                    "client_secret": "XALaRPl5qwTEItdwCMiPS62nVpKs7dL7",
                    "grant_type": "client_credentials"
                },
                "adaptor": "",
                "responseData": {
                    "&": "$$"
                }
            }

keycloak的配置如下:

 

然后根据access_token访问graphql接口获取task信息:

      "api": {
                "method": "post",
                "url": "/graphql",
                "headers": {
                    "Authorization": "Bearer ${access_token}"
                },
                "requestAdaptor": "debugger;\ndebugger;\napi.data = {\n  \"operationName\": \"GetTasks\",\n  \"variables\": {\n    \"state\": \"COMPLETED\",\n    \"pageSize\": 50\n  },\n  \"query\": \"query GetTasks($assignee: String, $assigned: Boolean, $state: TaskState, $pageSize: Int, $searchAfter: [String!], $searchBefore: [String!], $searchAfterOrEqual: [String!]) {\\n  tasks(\\n    query: {assignee: $assignee, assigned: $assigned, state: $state, pageSize: $pageSize, searchAfter: $searchAfter, searchBefore: $searchBefore, searchAfterOrEqual: $searchAfterOrEqual}\\n  ) {\\n    id\\n    name\\n    processName\\n    assignee\\n    creationTime\\n    taskState\\n    sortValues\\n    isFirst\\n    __typename\\n  }\\n}\"\n}\nreturn api;"
            }