diff --git a/config/grafana/Nacos.json b/config/grafana/Nacos.json deleted file mode 100644 index 0fc0e2b..0000000 --- a/config/grafana/Nacos.json +++ /dev/null @@ -1,4294 +0,0 @@ -{ - "annotations": { - "list": [ - { - "builtIn": 1, - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "target": { - "limit": 100, - "matchAny": false, - "tags": [], - "type": "dashboard" - }, - "type": "dashboard" - } - ] - }, - "description": "Nacos grafana dashboard", - "editable": true, - "fiscalYearStartMonth": 0, - "gnetId": 13221, - "graphTooltip": 0, - "id": 9, - "links": [ - { - "icon": "external link", - "tags": [], - "targetBlank": true, - "title": "Monitor Guide", - "type": "link", - "url": "https://nacos.io/zh-cn/docs/monitor-guide.html" - } - ], - "liveNow": false, - "panels": [ - { - "collapsed": false, - "datasource": { - "type": "prometheus" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 0 - }, - "id": 80, - "panels": [], - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "refId": "A" - } - ], - "title": "nacos monitor", - "type": "row" - }, - { - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 3, - "w": 3, - "x": 0, - "y": 1 - }, - "id": 89, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "none", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "9.2.4", - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "count(nacos_monitor{name=\"configCount\"})", - "format": "time_series", - "intervalFactor": 1, - "refId": "A" - } - ], - "title": "UP", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 3, - "w": 3, - "x": 3, - "y": 1 - }, - "id": 90, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "none", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "9.2.4", - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "max(nacos_monitor{name='serviceCount'})", - "format": "time_series", - "intervalFactor": 1, - "refId": "A" - } - ], - "title": "service count", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 3, - "w": 3, - "x": 6, - "y": 1 - }, - "id": 93, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "none", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "9.2.4", - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "max(nacos_monitor{name='ipCount'})", - "format": "time_series", - "intervalFactor": 1, - "refId": "A" - } - ], - "title": "ip count", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 3, - "w": 3, - "x": 9, - "y": 1 - }, - "id": 92, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "none", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "9.2.4", - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "max(nacos_monitor{name='configCount', instance=~'$instance'})", - "format": "time_series", - "intervalFactor": 1, - "refId": "A" - } - ], - "title": "config count", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 3, - "w": 3, - "x": 12, - "y": 1 - }, - "id": 91, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "none", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "9.2.4", - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(nacos_monitor{name='longPolling'})", - "format": "time_series", - "intervalFactor": 1, - "refId": "A" - } - ], - "title": "long polling", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 3, - "w": 3, - "x": 15, - "y": 1 - }, - "id": 88, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "none", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "9.2.4", - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(nacos_monitor{name='getConfig', instance=~'$instance'}) by (name)", - "format": "time_series", - "intervalFactor": 1, - "refId": "A" - } - ], - "title": "config push total", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus" - }, - "gridPos": { - "h": 3, - "w": 6, - "x": 18, - "y": 1 - }, - "id": 82, - "links": [], - "options": { - "code": { - "language": "plaintext", - "showLineNumbers": false, - "showMiniMap": false - }, - "content": "
\n \n \n \n
", - "mode": "html" - }, - "pluginVersion": "9.2.4", - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "refId": "A" - } - ], - "type": "text" - }, - { - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "max": 100, - "min": 0, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "#299c46", - "value": null - }, - { - "color": "rgba(237, 129, 40, 0.89)", - "value": 50 - }, - { - "color": "#d44a3a", - "value": 80 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 4, - "w": 9, - "x": 0, - "y": 4 - }, - "id": 33, - "interval": "", - "links": [], - "maxDataPoints": 100, - "options": { - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "showThresholdLabels": false, - "showThresholdMarkers": true - }, - "pluginVersion": "9.2.4", - "repeatDirection": "h", - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "max(system_cpu_usage{instance=~'$instance'}) * 100", - "format": "time_series", - "interval": "", - "intervalFactor": 1, - "legendFormat": "", - "refId": "A" - } - ], - "title": "cpu", - "type": "gauge" - }, - { - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "max": 70, - "min": 0, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "#299c46", - "value": null - }, - { - "color": "rgba(237, 129, 40, 0.89)", - "value": 50 - }, - { - "color": "#d44a3a", - "value": 70 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 4, - "w": 9, - "x": 9, - "y": 4 - }, - "id": 32, - "links": [], - "maxDataPoints": 100, - "options": { - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "showThresholdLabels": false, - "showThresholdMarkers": true - }, - "pluginVersion": "9.2.4", - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(jvm_memory_used_bytes{area=\"heap\", instance=~'$instance'})/sum(jvm_memory_max_bytes{area=\"heap\", instance=~'$instance'}) * 100", - "format": "time_series", - "intervalFactor": 1, - "refId": "A" - } - ], - "title": "memory", - "type": "gauge" - }, - { - "dashboardFilter": "", - "datasource": { - "type": "prometheus" - }, - "gridPos": { - "h": 16, - "w": 6, - "x": 18, - "y": 4 - }, - "id": 48, - "limit": 10, - "links": [], - "nameFilter": "", - "onlyAlertsOnDashboard": false, - "options": { - "alertInstanceLabelFilter": "", - "alertName": "", - "dashboardAlerts": false, - "groupBy": [], - "groupMode": "default", - "maxItems": 20, - "sortOrder": 1, - "stateFilter": { - "error": true, - "firing": true, - "noData": false, - "normal": false, - "pending": true - }, - "viewMode": "list" - }, - "show": "current", - "sortOrder": 1, - "stateFilter": [], - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "refId": "A" - } - ], - "title": "alert list", - "type": "alertlist" - }, - { - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "max": 1500, - "min": 0, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "#299c46", - "value": null - }, - { - "color": "rgba(237, 129, 40, 0.89)", - "value": 800 - }, - { - "color": "#d44a3a", - "value": 1500 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 4, - "w": 9, - "x": 0, - "y": 8 - }, - "id": 29, - "links": [], - "maxDataPoints": 100, - "options": { - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "showThresholdLabels": false, - "showThresholdMarkers": true - }, - "pluginVersion": "9.2.4", - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "max(jvm_threads_daemon_threads{instance=~'$instance'})", - "format": "time_series", - "intervalFactor": 1, - "refId": "A" - } - ], - "title": "threads", - "type": "gauge" - }, - { - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "max": 20, - "min": 0, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "#299c46", - "value": null - }, - { - "color": "rgba(237, 129, 40, 0.89)", - "value": 5 - }, - { - "color": "#d44a3a", - "value": 10 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 4, - "w": 9, - "x": 9, - "y": 8 - }, - "id": 30, - "links": [], - "maxDataPoints": 100, - "options": { - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "showThresholdLabels": false, - "showThresholdMarkers": true - }, - "pluginVersion": "9.2.4", - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "max(system_load_average_1m{instance=~'$instance'})", - "format": "time_series", - "intervalFactor": 1, - "refId": "A" - } - ], - "title": "load", - "type": "gauge" - }, - { - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "max": 5000, - "min": 0, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "#299c46", - "value": null - }, - { - "color": "rgba(237, 129, 40, 0.89)", - "value": 3000 - }, - { - "color": "#d44a3a", - "value": 5000 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 4, - "w": 9, - "x": 0, - "y": 12 - }, - "id": 61, - "links": [], - "maxDataPoints": 100, - "options": { - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "showThresholdLabels": false, - "showThresholdMarkers": true - }, - "pluginVersion": "9.2.4", - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(rate(nacos_timer_seconds_sum{instance=~'$instance'}[1m]))/sum(rate(nacos_timer_seconds_count{instance=~'$instance'}[1m])) * 1000", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "", - "refId": "A" - } - ], - "title": "notify rt", - "type": "gauge" - }, - { - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "max": 5000, - "min": 0, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "#299c46", - "value": null - }, - { - "color": "rgba(237, 129, 40, 0.89)", - "value": 3000 - }, - { - "color": "#d44a3a", - "value": 5000 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 4, - "w": 9, - "x": 9, - "y": 12 - }, - "id": 26, - "links": [], - "maxDataPoints": 100, - "options": { - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "showThresholdLabels": false, - "showThresholdMarkers": true - }, - "pluginVersion": "9.2.4", - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(rate(http_server_requests_seconds_sum{instance=~'$instance'}[1m]))/sum(rate(http_server_requests_seconds_count{instance=~'$instance'}[1m])) * 1000", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "", - "refId": "A" - } - ], - "title": "rt", - "type": "gauge" - }, - { - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "max": 2000, - "min": 0, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "#299c46", - "value": null - }, - { - "color": "rgba(237, 129, 40, 0.89)", - "value": 1000 - }, - { - "color": "#d44a3a", - "value": 2000 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 4, - "w": 9, - "x": 0, - "y": 16 - }, - "id": 25, - "links": [], - "maxDataPoints": 100, - "options": { - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "showThresholdLabels": false, - "showThresholdMarkers": true - }, - "pluginVersion": "9.2.4", - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(rate(http_server_requests_seconds_count{instance=~'$instance'}[1m]))", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "", - "refId": "A" - } - ], - "title": "qps", - "type": "gauge" - }, - { - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "max": 5000, - "min": 0, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "#299c46", - "value": null - }, - { - "color": "rgba(237, 129, 40, 0.89)", - "value": 1000 - }, - { - "color": "#d44a3a", - "value": 5000 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 4, - "w": 9, - "x": 9, - "y": 16 - }, - "id": 70, - "links": [], - "maxDataPoints": 100, - "options": { - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "showThresholdLabels": false, - "showThresholdMarkers": true - }, - "pluginVersion": "9.2.4", - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "max(nacos_monitor{name='avgPushCost', instance=~'$instance'})", - "format": "time_series", - "intervalFactor": 1, - "refId": "A" - } - ], - "title": "avgPushCost", - "type": "gauge" - }, - { - "collapsed": false, - "datasource": { - "type": "prometheus" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 20 - }, - "id": 78, - "panels": [], - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "refId": "A" - } - ], - "title": "nacos detail", - "type": "row" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 5, - "w": 8, - "x": 0, - "y": 21 - }, - "hiddenSeries": false, - "id": 20, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(rate(http_server_requests_seconds_sum{uri=~'/v1/cs/configs|/nacos/v1/ns', instance=~'$instance'}[1m])/rate(http_server_requests_seconds_count{uri=~'/v1/cs/configs|/nacos/v1/ns/instance|/nacos/v1/ns/health', instance=~'$instance'}[1m])) by (method,uri) * 1000", - "format": "time_series", - "intervalFactor": 1, - "refId": "A" - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(rate(http_server_requests_seconds_sum{instance=~'$instance'}[1m]))/sum(rate(http_server_requests_seconds_count{instance=~'$instance'}[1m])) * 1000", - "format": "time_series", - "hide": false, - "intervalFactor": 1, - "legendFormat": "all", - "refId": "B" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "rt", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 5, - "w": 8, - "x": 8, - "y": 21 - }, - "hiddenSeries": false, - "id": 41, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": "group", - "repeatDirection": "h", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(nacos_monitor{name='longPolling', instance=~'$instance'})", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "", - "refId": "A" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "long polling", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": "", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 5, - "w": 8, - "x": 16, - "y": 21 - }, - "hiddenSeries": false, - "id": 37, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "max(system_load_average_1m{instance=~'$instance'})", - "format": "time_series", - "intervalFactor": 1, - "refId": "A" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "load 1m", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 5, - "w": 8, - "x": 0, - "y": 26 - }, - "hiddenSeries": false, - "id": 18, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "7.2.1", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(rate(http_server_requests_seconds_count{uri=~'/v1/cs/configs|/nacos/v1/ns/instance|/nacos/v1/ns/health', instance=~'$instance'}[1m])) by (method,uri)", - "format": "time_series", - "intervalFactor": 1, - "refId": "A" - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(rate(http_server_requests_seconds_count[1m]))", - "format": "time_series", - "intervalFactor": 1, - "refId": "B" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "qps", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 5, - "w": 8, - "x": 8, - "y": 26 - }, - "hiddenSeries": false, - "id": 52, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "7.2.1", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(nacos_monitor{name='leaderStatus', instance=~'$instance'})", - "format": "time_series", - "intervalFactor": 1, - "refId": "B" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "leaderStatus", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 5, - "w": 8, - "x": 16, - "y": 26 - }, - "hiddenSeries": false, - "id": 50, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "7.2.1", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(nacos_monitor{name='avgPushCost', instance=~'$instance'})", - "format": "time_series", - "intervalFactor": 1, - "refId": "A" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "avgPushCost", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 5, - "w": 8, - "x": 0, - "y": 31 - }, - "hiddenSeries": false, - "id": 53, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "7.2.1", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "max(nacos_monitor{name='maxPushCost', instance=~'$instance'})", - "format": "time_series", - "intervalFactor": 1, - "refId": "A" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "maxPushCost", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 5, - "w": 8, - "x": 8, - "y": 31 - }, - "hiddenSeries": false, - "id": 83, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "7.2.1", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(nacos_monitor{name='publish', instance=~'$instance'}) by (name)", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "publish config", - "refId": "A" - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(nacos_monitor{name='getConfig', instance=~'$instance'}) by (name)", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "get config", - "refId": "B" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "config statistics", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 5, - "w": 8, - "x": 16, - "y": 31 - }, - "hiddenSeries": false, - "id": 16, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "7.2.1", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(rate(nacos_monitor{name=~'.*HealthCheck', instance=~'$instance'}[1m])) by (name) * 60", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "", - "refId": "A" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "health check", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "collapsed": false, - "datasource": { - "type": "prometheus" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 36 - }, - "id": 74, - "panels": [], - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "refId": "A" - } - ], - "title": "nacos alert", - "type": "row" - }, - { - "alert": { - "conditions": [ - { - "evaluator": { - "params": [ - 50 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "1m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "avg" - }, - "type": "query" - } - ], - "executionErrorState": "keep_state", - "for": "1m", - "frequency": "1m", - "handler": 1, - "name": "cpu alert", - "noDataState": "ok", - "notifications": [ - { - "id": 1 - } - ] - }, - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 5, - "w": 8, - "x": 0, - "y": 37 - }, - "hiddenSeries": false, - "id": 45, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "7.2.1", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "max(system_cpu_usage) * 100", - "format": "time_series", - "intervalFactor": 1, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "fill": true, - "line": true, - "op": "gt", - "value": 50 - } - ], - "timeRegions": [], - "title": "cpu alert", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "alert": { - "conditions": [ - { - "evaluator": { - "params": [ - 15 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "1m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "avg" - }, - "type": "query" - } - ], - "executionErrorState": "keep_state", - "frequency": "60s", - "handler": 1, - "name": "load 1m alert", - "noDataState": "ok", - "notifications": [] - }, - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 5, - "w": 8, - "x": 8, - "y": 37 - }, - "hiddenSeries": false, - "id": 86, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "7.2.1", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "max(system_load_average_1m)", - "format": "time_series", - "intervalFactor": 1, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "fill": true, - "line": true, - "op": "gt", - "value": 15 - } - ], - "timeRegions": [], - "title": "load alert", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "alert": { - "conditions": [ - { - "evaluator": { - "params": [ - 60 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "avg" - }, - "type": "query" - } - ], - "executionErrorState": "keep_state", - "frequency": "60s", - "handler": 1, - "name": "memory alert", - "noDataState": "ok", - "notifications": [] - }, - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 5, - "w": 8, - "x": 16, - "y": 37 - }, - "hiddenSeries": false, - "id": 46, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "7.2.1", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(jvm_memory_used_bytes{area=\"heap\"})/sum(jvm_memory_max_bytes{area=\"heap\"}) * 100", - "format": "time_series", - "intervalFactor": 1, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "fill": true, - "line": true, - "op": "gt", - "value": 60 - } - ], - "timeRegions": [], - "title": "memory alert", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "alert": { - "conditions": [ - { - "evaluator": { - "params": [ - 500 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "1m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "avg" - }, - "type": "query" - } - ], - "executionErrorState": "keep_state", - "frequency": "60s", - "handler": 1, - "name": "threads alert", - "noDataState": "ok", - "notifications": [] - }, - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 5, - "w": 8, - "x": 0, - "y": 42 - }, - "hiddenSeries": false, - "id": 39, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "7.2.1", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "max(jvm_threads_daemon_threads)", - "format": "time_series", - "intervalFactor": 1, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "fill": true, - "line": true, - "op": "gt", - "value": 500 - } - ], - "timeRegions": [], - "title": "threads alert", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "alert": { - "conditions": [ - { - "evaluator": { - "params": [ - 5 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "1m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "avg" - }, - "type": "query" - } - ], - "executionErrorState": "keep_state", - "for": "1m", - "frequency": "1m", - "handler": 1, - "message": "too many full gc", - "name": "gc alert", - "noDataState": "ok", - "notifications": [ - { - "id": 1 - } - ] - }, - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 5, - "w": 8, - "x": 8, - "y": 42 - }, - "hiddenSeries": false, - "id": 38, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "7.2.1", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "max(rate(jvm_gc_pause_seconds_count{action=\"end of major GC\"}[5m])) * 300", - "format": "time_series", - "intervalFactor": 1, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "fill": true, - "line": true, - "op": "gt", - "value": 5 - } - ], - "timeRegions": [], - "title": "gc alert", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "alert": { - "conditions": [ - { - "evaluator": { - "params": [ - 10 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "1m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "avg" - }, - "type": "query" - } - ], - "executionErrorState": "keep_state", - "frequency": "60s", - "handler": 1, - "name": "notify task alert", - "noDataState": "ok", - "notifications": [] - }, - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 5, - "w": 8, - "x": 16, - "y": 42 - }, - "hiddenSeries": false, - "id": 49, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "7.2.1", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(nacos_monitor{name='notifyTask'})", - "format": "time_series", - "intervalFactor": 1, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "fill": true, - "line": true, - "op": "gt", - "value": 10 - } - ], - "timeRegions": [], - "title": "notify task alert", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "alert": { - "conditions": [ - { - "evaluator": { - "params": [ - 5000 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "B", - "1m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "avg" - }, - "type": "query" - } - ], - "executionErrorState": "keep_state", - "frequency": "60s", - "handler": 1, - "name": "rt alert", - "noDataState": "ok", - "notifications": [] - }, - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 5, - "w": 8, - "x": 0, - "y": 47 - }, - "hiddenSeries": false, - "id": 85, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "7.2.1", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(rate(http_server_requests_seconds_sum[1m]))/sum(rate(http_server_requests_seconds_count[1m])) * 1000", - "format": "time_series", - "hide": false, - "intervalFactor": 1, - "refId": "B" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "fill": true, - "line": true, - "op": "gt", - "value": 5000 - } - ], - "timeRegions": [], - "title": "rt alert", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "alert": { - "conditions": [ - { - "evaluator": { - "params": [ - 5000 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "1m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "avg" - }, - "type": "query" - } - ], - "executionErrorState": "keep_state", - "frequency": "60s", - "handler": 1, - "name": "long polling alert", - "noDataState": "ok", - "notifications": [] - }, - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 5, - "w": 8, - "x": 8, - "y": 47 - }, - "hiddenSeries": false, - "id": 84, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "7.2.1", - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeatDirection": "h", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "max(nacos_monitor{name='longPolling'})", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "", - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "fill": true, - "line": true, - "op": "gt", - "value": 5000 - } - ], - "timeRegions": [], - "title": "long polling alert", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": "", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "alert": { - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "1m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "avg" - }, - "type": "query" - } - ], - "executionErrorState": "keep_state", - "frequency": "60s", - "handler": 1, - "name": "config unhealth exception alert", - "noDataState": "ok", - "notifications": [] - }, - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 5, - "w": 8, - "x": 16, - "y": 47 - }, - "hiddenSeries": false, - "id": 56, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "7.2.1", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(rate(nacos_exception_total{name='unhealth'}[1m])) * 60", - "format": "time_series", - "intervalFactor": 1, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "fill": true, - "line": true, - "op": "gt", - "value": 1 - } - ], - "timeRegions": [], - "title": "config unhealth exception alert", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "alert": { - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "1m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "avg" - }, - "type": "query" - } - ], - "executionErrorState": "keep_state", - "frequency": "60s", - "handler": 1, - "name": "db exception alert", - "noDataState": "ok", - "notifications": [] - }, - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 5, - "w": 8, - "x": 0, - "y": 52 - }, - "hiddenSeries": false, - "id": 54, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "7.2.1", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(rate(nacos_exception_total{name='db'}[1m])) * 60", - "format": "time_series", - "intervalFactor": 1, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "fill": true, - "line": true, - "op": "gt", - "value": 1 - } - ], - "timeRegions": [], - "title": "db exception alert", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "alert": { - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "1m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "avg" - }, - "type": "query" - } - ], - "executionErrorState": "keep_state", - "frequency": "60s", - "handler": 1, - "name": "failedPush alert", - "noDataState": "ok", - "notifications": [] - }, - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 5, - "w": 8, - "x": 8, - "y": 52 - }, - "hiddenSeries": false, - "id": 51, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "7.2.1", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(nacos_monitor{name='failedPush'})", - "format": "time_series", - "intervalFactor": 1, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "fill": true, - "line": true, - "op": "gt", - "value": 1 - } - ], - "timeRegions": [], - "title": "failed push alert", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "alert": { - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "1m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "avg" - }, - "type": "query" - } - ], - "executionErrorState": "keep_state", - "frequency": "60s", - "handler": 1, - "name": "illegalArgument exception alert", - "noDataState": "ok", - "notifications": [] - }, - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 5, - "w": 8, - "x": 16, - "y": 52 - }, - "hiddenSeries": false, - "id": 59, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "7.2.1", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(rate(nacos_exception_total{name='illegalArgument'}[1m])) * 60", - "format": "time_series", - "intervalFactor": 1, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "fill": true, - "line": true, - "op": "gt", - "value": 1 - } - ], - "timeRegions": [], - "title": "illegalArgument exception alert", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "alert": { - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "avg" - }, - "type": "query" - } - ], - "executionErrorState": "keep_state", - "frequency": "60s", - "handler": 1, - "name": "naming disk exception alert", - "noDataState": "ok", - "notifications": [] - }, - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 5, - "w": 8, - "x": 0, - "y": 57 - }, - "hiddenSeries": false, - "id": 57, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "7.2.1", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(rate(nacos_exception_total{name='disk'}[1m])) * 60", - "format": "time_series", - "intervalFactor": 1, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "fill": true, - "line": true, - "op": "gt", - "value": 1 - } - ], - "timeRegions": [], - "title": "naming disk exception alert", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "alert": { - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "1m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "avg" - }, - "type": "query" - } - ], - "executionErrorState": "keep_state", - "frequency": "60s", - "handler": 1, - "name": "config notify exception alert", - "noDataState": "ok", - "notifications": [] - }, - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 5, - "w": 8, - "x": 8, - "y": 57 - }, - "hiddenSeries": false, - "id": 55, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "7.2.1", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(rate(nacos_exception_total{name='configNotify'}[1m])) * 60", - "format": "time_series", - "intervalFactor": 1, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "fill": true, - "line": true, - "op": "gt", - "value": 1 - } - ], - "timeRegions": [], - "title": "config notify exception alert", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "alert": { - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "1m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "avg" - }, - "type": "query" - } - ], - "executionErrorState": "keep_state", - "frequency": "60s", - "handler": 1, - "name": "naming leader send beat failed exception alert", - "noDataState": "ok", - "notifications": [] - }, - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 5, - "w": 8, - "x": 16, - "y": 57 - }, - "hiddenSeries": false, - "id": 58, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "7.2.1", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(rate(nacos_exception_total{name='leaderSendBeatFailed'}[1m])) * 60", - "format": "time_series", - "intervalFactor": 1, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "fill": true, - "line": true, - "op": "gt", - "value": 1 - } - ], - "timeRegions": [], - "title": "naming leader send beat failed exception alert", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "alert": { - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "1m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "avg" - }, - "type": "query" - } - ], - "executionErrorState": "keep_state", - "frequency": "60s", - "handler": 1, - "name": "nacos_exception alert", - "noDataState": "ok", - "notifications": [] - }, - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 5, - "w": 8, - "x": 0, - "y": 62 - }, - "hiddenSeries": false, - "id": 60, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "7.2.1", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(rate(nacos_exception_total{name='nacos'}[1m])) * 60", - "format": "time_series", - "intervalFactor": 1, - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "fill": true, - "line": true, - "op": "gt", - "value": 1 - } - ], - "timeRegions": [], - "title": "nacos exception alert", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - } - ], - "refresh": false, - "schemaVersion": 37, - "style": "dark", - "tags": [], - "templating": { - "list": [ - { - "allValue": "", - "current": { - "selected": false, - "text": "127.0.0.1:8848", - "value": "127.0.0.1:8848" - }, - "datasource": { - "type": "prometheus" - }, - "definition": "label_values(jvm_classes_loaded_classes{job=\"Nacos\"},instance)", - "hide": 0, - "includeAll": false, - "label": "instance", - "multi": false, - "name": "instance", - "options": [], - "query": { - "query": "label_values(jvm_classes_loaded_classes{job=\"Nacos\"},instance)", - "refId": "StandardVariableQuery" - }, - "refresh": 2, - "regex": "", - "skipUrlSync": false, - "sort": 0, - "tagValuesQuery": "", - "tagsQuery": "", - "type": "query", - "useTags": false - } - ] - }, - "time": { - "from": "now-5m", - "to": "now" - }, - "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ] - }, - "timezone": "", - "title": "Nacos", - "uid": "Bz_QALEiz1", - "version": 7, - "weekStart": "" -} diff --git a/config/grafana/README.md b/config/grafana/README.md deleted file mode 100644 index 2c48fb8..0000000 --- a/config/grafana/README.md +++ /dev/null @@ -1 +0,0 @@ -# 将此文件夹下所有配置文件导入到 `grafana` 内生成展示看板(此模板与项目做了定制化与官方下载的不一致, 同名看板以框架自带的为主) \ No newline at end of file diff --git a/config/grafana/SLS JVM监控大盘.json b/config/grafana/SLS JVM监控大盘.json deleted file mode 100644 index b83f9a2..0000000 --- a/config/grafana/SLS JVM监控大盘.json +++ /dev/null @@ -1,3759 +0,0 @@ -{ - "annotations": { - "list": [ - { - "builtIn": 1, - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "limit": 100, - "name": "Annotations & Alerts", - "showIn": 0, - "target": { - "limit": 100, - "matchAny": false, - "tags": [], - "type": "dashboard" - }, - "type": "dashboard" - }, - { - "datasource": { - "type": "prometheus" - }, - "enable": true, - "expr": "resets(process_uptime_seconds{application=\"$application\", instance=\"$instance\"}[1m]) > 0", - "iconColor": "rgba(255, 96, 96, 1)", - "limit": 100, - "name": "进程重启打标", - "showIn": 0, - "step": "1m", - "tagKeys": "restart-tag", - "tags": [], - "textFormat": "uptime reset", - "titleFormat": "Restart", - "type": "tags" - } - ] - }, - "description": "Dashboard for Micrometer instrumented applications (Java, Spring Boot, Micronaut)", - "editable": true, - "fiscalYearStartMonth": 0, - "gnetId": 12856, - "graphTooltip": 1, - "id": 11, - "links": [ - { - "icon": "external link", - "tags": [], - "title": "MicroMeter", - "type": "link", - "url": "http://micrometer.io/" - }, - { - "icon": "cloud", - "tags": [], - "title": "Aliyun SLS", - "type": "link", - "url": "https://www.aliyun.com/product/sls" - } - ], - "liveNow": false, - "panels": [ - { - "collapsed": false, - "datasource": { - "uid": "${DS_SPRING-DEMOT}" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 0 - }, - "id": 125, - "panels": [], - "targets": [ - { - "datasource": { - "uid": "${DS_SPRING-DEMOT}" - }, - "refId": "A" - } - ], - "title": "概览", - "type": "row" - }, - { - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "decimals": 1, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { - "h": 3, - "w": 6, - "x": 0, - "y": 1 - }, - "id": 63, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "9.2.4", - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "process_uptime_seconds{application=\"$application\", instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "", - "metric": "", - "refId": "A", - "step": 14400 - } - ], - "title": "进程启动时长", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "dateTimeAsIso" - }, - "overrides": [] - }, - "gridPos": { - "h": 3, - "w": 6, - "x": 6, - "y": 1 - }, - "id": 92, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "9.2.4", - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "process_start_time_seconds{application=\"$application\", instance=\"$instance\"}*1000", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "", - "metric": "", - "refId": "A", - "step": 14400 - } - ], - "title": "进程启动时间", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "decimals": 2, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "rgba(50, 172, 45, 0.97)", - "value": null - }, - { - "color": "rgba(237, 129, 40, 0.89)", - "value": 70 - }, - { - "color": "rgba(245, 54, 54, 0.9)", - "value": 90 - } - ] - }, - "unit": "percent" - }, - "overrides": [] - }, - "gridPos": { - "h": 3, - "w": 6, - "x": 12, - "y": 1 - }, - "id": 65, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "9.2.4", - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", area=\"heap\"})*100/sum(jvm_memory_max_bytes{application=\"$application\",instance=\"$instance\", area=\"heap\"})", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "", - "refId": "A", - "step": 14400 - } - ], - "title": "堆内存使用率", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "decimals": 2, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - }, - { - "options": { - "from": -1e+32, - "result": { - "text": "N/A" - }, - "to": 0 - }, - "type": "range" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "rgba(50, 172, 45, 0.97)", - "value": null - }, - { - "color": "rgba(237, 129, 40, 0.89)", - "value": 70 - }, - { - "color": "rgba(245, 54, 54, 0.9)", - "value": 90 - } - ] - }, - "unit": "percent" - }, - "overrides": [] - }, - "gridPos": { - "h": 3, - "w": 6, - "x": 18, - "y": 1 - }, - "id": 75, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "9.2.4", - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", area=\"nonheap\"})*100/sum(jvm_memory_max_bytes{application=\"$application\",instance=\"$instance\", area=\"nonheap\"})", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "", - "refId": "A", - "step": 14400 - } - ], - "title": "非堆内存使用率", - "type": "stat" - }, - { - "collapsed": false, - "datasource": { - "uid": "${DS_SPRING-DEMOT}" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 4 - }, - "id": 126, - "panels": [], - "targets": [ - { - "datasource": { - "uid": "${DS_SPRING-DEMOT}" - }, - "refId": "A" - } - ], - "title": "服务黄金指标", - "type": "row" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "description": "平均每秒处理的请求数", - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 6, - "x": 0, - "y": 5 - }, - "hiddenSeries": false, - "id": 111, - "legend": { - "avg": false, - "current": true, - "max": false, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(rate(http_server_requests_seconds_count{application=\"$application\", instance=\"$instance\"}[1m]))", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "HTTP", - "refId": "A" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "QPS(1分钟平均)", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "ops", - "logBase": 1, - "min": "0", - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": { - "HTTP": "#890f02", - "HTTP - 5xx": "#bf1b00" - }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 6, - "x": 6, - "y": 5 - }, - "hiddenSeries": false, - "id": 112, - "legend": { - "avg": false, - "current": true, - "max": false, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(rate(http_server_requests_seconds_count{application=\"$application\", instance=\"$instance\", status=~\"5..\"}[1m]))", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "HTTP - 5xx", - "refId": "A" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "错误数(1分钟平均)", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "ops", - "logBase": 1, - "min": "0", - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 6, - "x": 12, - "y": 5 - }, - "hiddenSeries": false, - "id": 113, - "legend": { - "avg": false, - "current": true, - "max": false, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(rate(http_server_requests_seconds_sum{application=\"$application\", instance=\"$instance\", status!~\"5..\"}[1m]))/sum(rate(http_server_requests_seconds_count{application=\"$application\", instance=\"$instance\", status!~\"5..\"}[1m]))", - "format": "time_series", - "hide": false, - "intervalFactor": 1, - "legendFormat": "HTTP - AVG", - "refId": "A" - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "max(http_server_requests_seconds_max{application=\"$application\", instance=\"$instance\", status!~\"5..\"})", - "format": "time_series", - "hide": false, - "intervalFactor": 1, - "legendFormat": "HTTP - MAX", - "refId": "B" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "请求耗时(1分钟平均)", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "s", - "logBase": 1, - "min": "0", - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "description": "饱和度指标来自于Google SRE的的黄金指标, 指服务的过载程度, 当系统过载时, 往往意味着请求需要排队处理", - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 6, - "x": 18, - "y": 5 - }, - "hiddenSeries": false, - "id": 119, - "legend": { - "alignAsTable": false, - "avg": false, - "current": true, - "max": false, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "tomcat_threads_busy_threads{application=\"$application\", instance=\"$instance\"}", - "format": "time_series", - "hide": false, - "intervalFactor": 2, - "legendFormat": "TOMCAT - BSY", - "refId": "A" - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "tomcat_threads_current_threads{application=\"$application\", instance=\"$instance\"}", - "format": "time_series", - "hide": false, - "intervalFactor": 2, - "legendFormat": "TOMCAT - CUR", - "refId": "B" - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "tomcat_threads_config_max_threads{application=\"$application\", instance=\"$instance\"}", - "format": "time_series", - "hide": false, - "intervalFactor": 2, - "legendFormat": "TOMCAT - MAX", - "refId": "C" - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "jetty_threads_busy{application=\"$application\", instance=\"$instance\"}", - "format": "time_series", - "hide": false, - "intervalFactor": 2, - "legendFormat": "JETTY - BSY", - "refId": "D" - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "jetty_threads_current{application=\"$application\", instance=\"$instance\"}", - "format": "time_series", - "hide": false, - "intervalFactor": 2, - "legendFormat": "JETTY - CUR", - "refId": "E" - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "jetty_threads_config_max{application=\"$application\", instance=\"$instance\"}", - "format": "time_series", - "hide": false, - "intervalFactor": 2, - "legendFormat": "JETTY - MAX", - "refId": "F" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "饱和度", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "min": "0", - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "collapsed": false, - "datasource": { - "uid": "${DS_SPRING-DEMOT}" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 12 - }, - "id": 127, - "panels": [], - "targets": [ - { - "datasource": { - "uid": "${DS_SPRING-DEMOT}" - }, - "refId": "A" - } - ], - "title": "JVM 内存", - "type": "row" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "editable": true, - "error": false, - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "grid": { - "leftLogBase": 1, - "rightLogBase": 1 - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 0, - "y": 13 - }, - "hiddenSeries": false, - "id": 24, - "legend": { - "avg": false, - "current": true, - "max": true, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", area=\"heap\"})", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "used", - "metric": "", - "refId": "A", - "step": 2400 - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(jvm_memory_committed_bytes{application=\"$application\", instance=\"$instance\", area=\"heap\"})", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "committed", - "refId": "B", - "step": 2400 - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(jvm_memory_max_bytes{application=\"$application\", instance=\"$instance\", area=\"heap\"})", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "max", - "refId": "C", - "step": 2400 - } - ], - "thresholds": [], - "timeRegions": [], - "title": "堆内存", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "x-axis": true, - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "y-axis": true, - "y_formats": [ - "mbytes", - "short" - ], - "yaxes": [ - { - "format": "bytes", - "logBase": 1, - "min": 0, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "editable": true, - "error": false, - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "grid": { - "leftLogBase": 1, - "rightLogBase": 1 - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 6, - "y": 13 - }, - "hiddenSeries": false, - "id": 25, - "legend": { - "avg": false, - "current": true, - "max": true, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", area=\"nonheap\"})", - "format": "time_series", - "interval": "", - "intervalFactor": 2, - "legendFormat": "used", - "metric": "", - "refId": "A", - "step": 2400 - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(jvm_memory_committed_bytes{application=\"$application\", instance=\"$instance\", area=\"nonheap\"})", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "committed", - "refId": "B", - "step": 2400 - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(jvm_memory_max_bytes{application=\"$application\", instance=\"$instance\", area=\"nonheap\"})", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "max", - "refId": "C", - "step": 2400 - } - ], - "thresholds": [], - "timeRegions": [], - "title": "非堆内存", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "x-axis": true, - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "y-axis": true, - "y_formats": [ - "mbytes", - "short" - ], - "yaxes": [ - { - "format": "bytes", - "logBase": 1, - "min": 0, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "editable": true, - "error": false, - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "grid": { - "leftLogBase": 1, - "rightLogBase": 1 - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 12, - "y": 13 - }, - "hiddenSeries": false, - "id": 26, - "legend": { - "alignAsTable": false, - "avg": false, - "current": true, - "max": true, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\"})", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "used", - "metric": "", - "refId": "A", - "step": 2400 - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(jvm_memory_committed_bytes{application=\"$application\", instance=\"$instance\"})", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "committed", - "refId": "B", - "step": 2400 - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(jvm_memory_max_bytes{application=\"$application\", instance=\"$instance\"})", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "max", - "refId": "C", - "step": 2400 - } - ], - "thresholds": [], - "timeRegions": [], - "title": "总内存", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "x-axis": true, - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "y-axis": true, - "y_formats": [ - "mbytes", - "short" - ], - "yaxes": [ - { - "format": "bytes", - "label": "", - "logBase": 1, - "min": 0, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "description": "从操作系统层面看JVM进程的内存使用, 因为JVM并不是直接按照配置的内存参数申请全部内存", - "editable": true, - "error": false, - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "grid": { - "leftLogBase": 1, - "rightLogBase": 1 - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 18, - "y": 13 - }, - "hiddenSeries": false, - "id": 86, - "legend": { - "avg": false, - "current": true, - "max": true, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "process_memory_vss_bytes{application=\"$application\", instance=\"$instance\"}", - "format": "time_series", - "hide": true, - "intervalFactor": 2, - "legendFormat": "vss", - "metric": "", - "refId": "A", - "step": 2400 - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "process_memory_rss_bytes{application=\"$application\", instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "rss", - "refId": "B" - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "process_memory_swap_bytes{application=\"$application\", instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "swap", - "refId": "C" - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "process_memory_rss_bytes{application=\"$application\", instance=\"$instance\"} + process_memory_swap_bytes{application=\"$application\", instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "total", - "refId": "D" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "JVM 进程内存", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "x-axis": true, - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "y-axis": true, - "y_formats": [ - "mbytes", - "short" - ], - "yaxes": [ - { - "format": "bytes", - "label": "", - "logBase": 1, - "min": "0", - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "collapsed": false, - "datasource": { - "type": "prometheus" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 20 - }, - "id": 128, - "panels": [], - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "refId": "A" - } - ], - "title": "JVM 负载", - "type": "row" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "editable": true, - "error": false, - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "grid": { - "leftLogBase": 1, - "rightLogBase": 1 - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 0, - "y": 21 - }, - "hiddenSeries": false, - "id": 106, - "legend": { - "avg": false, - "current": true, - "max": true, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "system_cpu_usage{application=\"$application\", instance=\"$instance\"}", - "format": "time_series", - "hide": false, - "intervalFactor": 1, - "legendFormat": "system", - "metric": "", - "refId": "A", - "step": 2400 - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "process_cpu_usage{application=\"$application\", instance=\"$instance\"}", - "format": "time_series", - "hide": false, - "intervalFactor": 1, - "legendFormat": "process", - "refId": "B" - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "avg_over_time(process_cpu_usage{application=\"$application\", instance=\"$instance\"}[1h])", - "format": "time_series", - "hide": false, - "intervalFactor": 1, - "legendFormat": "process-1h", - "refId": "C" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "CPU 使用率", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "x-axis": true, - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "y-axis": true, - "y_formats": [ - "short", - "short" - ], - "yaxes": [ - { - "decimals": 1, - "format": "percentunit", - "label": "", - "logBase": 1, - "max": "1", - "min": 0, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "editable": true, - "error": false, - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "grid": { - "leftLogBase": 1, - "rightLogBase": 1 - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 6, - "y": 21 - }, - "hiddenSeries": false, - "id": 93, - "legend": { - "avg": false, - "current": true, - "max": true, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "system_load_average_1m{application=\"$application\", instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "load1", - "metric": "", - "refId": "A", - "step": 2400 - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "system_cpu_count{application=\"$application\", instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "cpu核数", - "refId": "B" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Load", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "x-axis": true, - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "y-axis": true, - "y_formats": [ - "short", - "short" - ], - "yaxes": [ - { - "decimals": 1, - "format": "short", - "label": "", - "logBase": 1, - "min": 0, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "editable": true, - "error": false, - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "grid": { - "leftLogBase": 1, - "rightLogBase": 1 - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 12, - "y": 21 - }, - "hiddenSeries": false, - "id": 32, - "legend": { - "avg": false, - "current": true, - "max": true, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "jvm_threads_live_threads{application=\"$application\", instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "live", - "metric": "", - "refId": "A", - "step": 2400 - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "jvm_threads_daemon_threads{application=\"$application\", instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "daemon", - "metric": "", - "refId": "B", - "step": 2400 - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "jvm_threads_peak_threads{application=\"$application\", instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "peak", - "refId": "C", - "step": 2400 - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "process_threads{application=\"$application\", instance=\"$instance\"}", - "format": "time_series", - "interval": "", - "intervalFactor": 2, - "legendFormat": "process", - "refId": "D", - "step": 2400 - } - ], - "thresholds": [], - "timeRegions": [], - "title": "线程数", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "x-axis": true, - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "y-axis": true, - "y_formats": [ - "short", - "short" - ], - "yaxes": [ - { - "decimals": 0, - "format": "short", - "logBase": 1, - "min": 0, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": { - "blocked": "#bf1b00", - "new": "#fce2de", - "runnable": "#7eb26d", - "terminated": "#511749", - "timed-waiting": "#c15c17", - "waiting": "#eab839" - }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "description": "需特别关注blocked的线程数, 这意味着线程被阻塞了, 如果线程全部是blocked状态, 则系统无法处理新请求", - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 6, - "x": 18, - "y": 21 - }, - "hiddenSeries": false, - "id": 124, - "legend": { - "alignAsTable": false, - "avg": false, - "current": true, - "max": true, - "min": false, - "rightSide": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "jvm_threads_states_threads{application=\"$application\", instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{state}}", - "refId": "A" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "各状态线程数", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": { - "debug": "#1F78C1", - "error": "#BF1B00", - "info": "#508642", - "trace": "#6ED0E0", - "warn": "#EAB839" - }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "editable": true, - "error": false, - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "grid": { - "leftLogBase": 1, - "rightLogBase": 1 - }, - "gridPos": { - "h": 7, - "w": 18, - "x": 0, - "y": 28 - }, - "height": "", - "hiddenSeries": false, - "id": 91, - "legend": { - "alignAsTable": false, - "avg": false, - "current": true, - "hideEmpty": false, - "hideZero": false, - "max": true, - "min": false, - "rightSide": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": true, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [ - { - "alias": "error", - "yaxis": 1 - }, - { - "alias": "warn", - "yaxis": 1 - } - ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "increase(logback_events_total{application=\"$application\", instance=\"$instance\"}[1m])", - "format": "time_series", - "interval": "", - "intervalFactor": 2, - "legendFormat": "{{level}}", - "metric": "", - "refId": "A", - "step": 1200 - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Logback日志数", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "x-axis": true, - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "y-axis": true, - "y_formats": [ - "short", - "short" - ], - "yaxes": [ - { - "decimals": 0, - "format": "opm", - "logBase": 1, - "min": "0", - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "editable": true, - "error": false, - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "grid": { - "leftLogBase": 1, - "rightLogBase": 1 - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 18, - "y": 28 - }, - "hiddenSeries": false, - "id": 61, - "legend": { - "avg": false, - "current": true, - "max": true, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "process_files_open_files{application=\"$application\", instance=\"$instance\"}", - "format": "time_series", - "hide": false, - "intervalFactor": 2, - "legendFormat": "open", - "metric": "", - "refId": "A", - "step": 2400 - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "process_files_max_files{application=\"$application\", instance=\"$instance\"}", - "format": "time_series", - "hide": false, - "intervalFactor": 2, - "legendFormat": "max", - "metric": "", - "refId": "B", - "step": 2400 - } - ], - "thresholds": [], - "timeRegions": [], - "title": "文件描述符", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "x-axis": true, - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "y-axis": true, - "y_formats": [ - "short", - "short" - ], - "yaxes": [ - { - "decimals": 0, - "format": "short", - "logBase": 10, - "min": 0, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "collapsed": false, - "datasource": { - "type": "prometheus" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 35 - }, - "id": 129, - "panels": [], - "repeat": "persistence_counts", - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "refId": "A" - } - ], - "title": "JVM 堆内存详细", - "type": "row" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "editable": true, - "error": false, - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "grid": { - "leftLogBase": 1, - "rightLogBase": 1 - }, - "gridPos": { - "h": 7, - "w": 8, - "x": 0, - "y": 36 - }, - "hiddenSeries": false, - "id": 3, - "legend": { - "alignAsTable": false, - "avg": false, - "current": true, - "max": true, - "min": false, - "rightSide": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "maxPerRow": 3, - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": "jvm_memory_pool_heap", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", id=~\"$jvm_memory_pool_heap\"}", - "format": "time_series", - "hide": false, - "interval": "", - "intervalFactor": 2, - "legendFormat": "used", - "metric": "", - "refId": "A", - "step": 1800 - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "jvm_memory_committed_bytes{application=\"$application\", instance=\"$instance\", id=~\"$jvm_memory_pool_heap\"}", - "format": "time_series", - "hide": false, - "interval": "", - "intervalFactor": 2, - "legendFormat": "commited", - "metric": "", - "refId": "B", - "step": 1800 - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "jvm_memory_max_bytes{application=\"$application\", instance=\"$instance\", id=~\"$jvm_memory_pool_heap\"}", - "format": "time_series", - "hide": false, - "interval": "", - "intervalFactor": 2, - "legendFormat": "max", - "metric": "", - "refId": "C", - "step": 1800 - } - ], - "thresholds": [], - "timeRegions": [], - "title": "$jvm_memory_pool_heap", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "x-axis": true, - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "y-axis": true, - "y_formats": [ - "mbytes", - "short" - ], - "yaxes": [ - { - "format": "bytes", - "logBase": 1, - "min": 0, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "collapsed": false, - "datasource": { - "type": "prometheus" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 43 - }, - "id": 130, - "panels": [], - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "refId": "A" - } - ], - "title": "JVM 非堆内存详细", - "type": "row" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "editable": true, - "error": false, - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "grid": { - "leftLogBase": 1, - "rightLogBase": 1 - }, - "gridPos": { - "h": 7, - "w": 8, - "x": 0, - "y": 44 - }, - "hiddenSeries": false, - "id": 78, - "legend": { - "alignAsTable": false, - "avg": false, - "current": true, - "max": true, - "min": false, - "rightSide": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "maxPerRow": 3, - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": "jvm_memory_pool_nonheap", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", id=~\"$jvm_memory_pool_nonheap\"}", - "format": "time_series", - "hide": false, - "interval": "", - "intervalFactor": 2, - "legendFormat": "used", - "metric": "", - "refId": "A", - "step": 1800 - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "jvm_memory_committed_bytes{application=\"$application\", instance=\"$instance\", id=~\"$jvm_memory_pool_nonheap\"}", - "format": "time_series", - "hide": false, - "interval": "", - "intervalFactor": 2, - "legendFormat": "commited", - "metric": "", - "refId": "B", - "step": 1800 - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "jvm_memory_max_bytes{application=\"$application\", instance=\"$instance\", id=~\"$jvm_memory_pool_nonheap\"}", - "format": "time_series", - "hide": false, - "interval": "", - "intervalFactor": 2, - "legendFormat": "max", - "metric": "", - "refId": "C", - "step": 1800 - } - ], - "thresholds": [], - "timeRegions": [], - "title": "$jvm_memory_pool_nonheap", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "x-axis": true, - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "y-axis": true, - "y_formats": [ - "mbytes", - "short" - ], - "yaxes": [ - { - "format": "bytes", - "logBase": 1, - "min": 0, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "collapsed": false, - "datasource": { - "type": "prometheus" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 51 - }, - "id": 131, - "panels": [], - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "refId": "A" - } - ], - "title": "垃圾回收(GC)", - "type": "row" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 8, - "x": 0, - "y": 52 - }, - "hiddenSeries": false, - "id": 98, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "rate(jvm_gc_pause_seconds_count{application=\"$application\", instance=\"$instance\"}[1m])", - "format": "time_series", - "hide": false, - "intervalFactor": 1, - "legendFormat": "{{action}} ({{cause}})", - "refId": "A" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "GC 次数", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "ops", - "logBase": 1, - "min": "0", - "show": true - }, - { - "format": "short", - "label": "", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 8, - "x": 8, - "y": 52 - }, - "hiddenSeries": false, - "id": 101, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "rate(jvm_gc_pause_seconds_sum{application=\"$application\", instance=\"$instance\"}[1m])/rate(jvm_gc_pause_seconds_count{application=\"$application\", instance=\"$instance\"}[1m])", - "format": "time_series", - "hide": false, - "instant": false, - "intervalFactor": 1, - "legendFormat": "avg {{action}} ({{cause}})", - "refId": "A" - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "jvm_gc_pause_seconds_max{application=\"$application\", instance=\"$instance\"}", - "format": "time_series", - "hide": false, - "instant": false, - "intervalFactor": 1, - "legendFormat": "max {{action}} ({{cause}})", - "refId": "B" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "GC暂停时间", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "s", - "logBase": 1, - "min": "0", - "show": true - }, - { - "format": "short", - "label": "", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "description": "内存分配的大小, 以及从新生代晋升到老年代的内存大小", - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 8, - "x": 16, - "y": 52 - }, - "hiddenSeries": false, - "id": 99, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "rate(jvm_gc_memory_allocated_bytes_total{application=\"$application\", instance=\"$instance\"}[1m])", - "format": "time_series", - "interval": "", - "intervalFactor": 1, - "legendFormat": "allocated", - "refId": "A" - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "rate(jvm_gc_memory_promoted_bytes_total{application=\"$application\", instance=\"$instance\"}[1m])", - "format": "time_series", - "interval": "", - "intervalFactor": 1, - "legendFormat": "promoted", - "refId": "B" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "内存分配/晋升", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "Bps", - "logBase": 1, - "min": "0", - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "collapsed": false, - "datasource": { - "type": "prometheus" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 59 - }, - "id": 132, - "panels": [], - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "refId": "A" - } - ], - "title": "类加载", - "type": "row" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "editable": true, - "error": false, - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "grid": { - "leftLogBase": 1, - "rightLogBase": 1 - }, - "gridPos": { - "h": 7, - "w": 12, - "x": 0, - "y": 60 - }, - "hiddenSeries": false, - "id": 37, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "jvm_classes_loaded_classes{application=\"$application\", instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "loaded", - "metric": "", - "refId": "A", - "step": 1200 - } - ], - "thresholds": [], - "timeRegions": [], - "title": "已加载的类的数量", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "x-axis": true, - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "y-axis": true, - "y_formats": [ - "short", - "short" - ], - "yaxes": [ - { - "format": "short", - "logBase": 1, - "min": 0, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "description": "可能增加或减少, 在Java中使用一些脚本语言例如groovy时, 需要关注, 防止因为逻辑异常产生大量的类, 进而导致metaspace满, 而metaspace满会触发full gc, 如无法释放则会导致JVM hang住", - "editable": true, - "error": false, - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "grid": { - "leftLogBase": 1, - "rightLogBase": 1 - }, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 60 - }, - "hiddenSeries": false, - "id": 38, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "delta(jvm_classes_loaded_classes{application=\"$application\",instance=\"$instance\"}[1m])", - "format": "time_series", - "hide": false, - "interval": "", - "intervalFactor": 1, - "legendFormat": "delta-1m", - "metric": "", - "refId": "A", - "step": 1200 - } - ], - "thresholds": [], - "timeRegions": [], - "title": "加载类数量变化", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "x-axis": true, - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "y-axis": true, - "y_formats": [ - "ops", - "short" - ], - "yaxes": [ - { - "format": "short", - "label": "", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "collapsed": false, - "datasource": { - "type": "prometheus" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 67 - }, - "id": 133, - "panels": [], - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "refId": "A" - } - ], - "title": "Buffer Pools", - "type": "row" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "editable": true, - "error": false, - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "grid": { - "leftLogBase": 1, - "rightLogBase": 1 - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 0, - "y": 68 - }, - "hiddenSeries": false, - "id": 33, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "jvm_buffer_memory_used_bytes{application=\"$application\", instance=\"$instance\", id=\"direct\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "used", - "metric": "", - "refId": "A", - "step": 2400 - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "jvm_buffer_total_capacity_bytes{application=\"$application\", instance=\"$instance\", id=\"direct\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "capacity", - "metric": "", - "refId": "B", - "step": 2400 - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Direct Buffers", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "x-axis": true, - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "y-axis": true, - "y_formats": [ - "short", - "short" - ], - "yaxes": [ - { - "format": "bytes", - "logBase": 1, - "min": 0, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "editable": true, - "error": false, - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "grid": { - "leftLogBase": 1, - "rightLogBase": 1 - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 6, - "y": 68 - }, - "hiddenSeries": false, - "id": 83, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "jvm_buffer_count_buffers{application=\"$application\", instance=\"$instance\", id=\"direct\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "count", - "metric": "", - "refId": "A", - "step": 2400 - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Direct Buffers", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "x-axis": true, - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "y-axis": true, - "y_formats": [ - "short", - "short" - ], - "yaxes": [ - { - "decimals": 0, - "format": "short", - "logBase": 1, - "min": 0, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "editable": true, - "error": false, - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "grid": { - "leftLogBase": 1, - "rightLogBase": 1 - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 12, - "y": 68 - }, - "hiddenSeries": false, - "id": 85, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "jvm_buffer_memory_used_bytes{application=\"$application\", instance=\"$instance\", id=\"mapped\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "used", - "metric": "", - "refId": "A", - "step": 2400 - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "jvm_buffer_total_capacity_bytes{application=\"$application\", instance=\"$instance\", id=\"mapped\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "capacity", - "metric": "", - "refId": "B", - "step": 2400 - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Mapped Buffers", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "x-axis": true, - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "y-axis": true, - "y_formats": [ - "short", - "short" - ], - "yaxes": [ - { - "format": "bytes", - "logBase": 1, - "min": 0, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "editable": true, - "error": false, - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "grid": { - "leftLogBase": 1, - "rightLogBase": 1 - }, - "gridPos": { - "h": 7, - "w": 6, - "x": 18, - "y": 68 - }, - "hiddenSeries": false, - "id": 84, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "jvm_buffer_count_buffers{application=\"$application\", instance=\"$instance\", id=\"mapped\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "count", - "metric": "", - "refId": "A", - "step": 2400 - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Mapped Buffers", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "x-axis": true, - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "y-axis": true, - "y_formats": [ - "short", - "short" - ], - "yaxes": [ - { - "decimals": 0, - "format": "short", - "logBase": 1, - "min": 0, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - } - ], - "refresh": "5s", - "schemaVersion": 37, - "style": "dark", - "tags": [], - "templating": { - "list": [ - { - "current": { - "selected": false, - "text": "ruoyi-auth", - "value": "ruoyi-auth" - }, - "datasource": { - "type": "prometheus" - }, - "definition": "", - "hide": 0, - "includeAll": false, - "label": "Application", - "multi": false, - "name": "application", - "options": [], - "query": { - "query": "label_values(application)", - "refId": "Prometheus-application-Variable-Query" - }, - "refresh": 2, - "regex": "", - "skipUrlSync": false, - "sort": 0, - "tagValuesQuery": "", - "tagsQuery": "", - "type": "query", - "useTags": false - }, - { - "allFormat": "glob", - "current": { - "selected": false, - "text": "192.168.31.100:9210", - "value": "192.168.31.100:9210" - }, - "datasource": { - "type": "prometheus" - }, - "definition": "", - "hide": 0, - "includeAll": false, - "label": "Instance", - "multi": false, - "multiFormat": "glob", - "name": "instance", - "options": [], - "query": { - "query": "label_values(jvm_memory_used_bytes{application=\"$application\"}, instance)", - "refId": "Prometheus-instance-Variable-Query" - }, - "refresh": 2, - "regex": "", - "skipUrlSync": false, - "sort": 0, - "tagValuesQuery": "", - "tagsQuery": "", - "type": "query", - "useTags": false - }, - { - "allFormat": "glob", - "current": { - "selected": false, - "text": "All", - "value": "$__all" - }, - "datasource": { - "type": "prometheus" - }, - "definition": "", - "hide": 0, - "includeAll": true, - "label": "JVM Memory Pools Heap", - "multi": false, - "multiFormat": "glob", - "name": "jvm_memory_pool_heap", - "options": [], - "query": { - "query": "label_values(jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", area=\"heap\"},id)", - "refId": "Prometheus-jvm_memory_pool_heap-Variable-Query" - }, - "refresh": 1, - "regex": "", - "skipUrlSync": false, - "sort": 1, - "tagValuesQuery": "", - "tagsQuery": "", - "type": "query", - "useTags": false - }, - { - "allFormat": "glob", - "current": { - "selected": false, - "text": "All", - "value": "$__all" - }, - "datasource": { - "type": "prometheus" - }, - "definition": "", - "hide": 0, - "includeAll": true, - "label": "JVM Memory Pools Non-Heap", - "multi": false, - "multiFormat": "glob", - "name": "jvm_memory_pool_nonheap", - "options": [], - "query": { - "query": "label_values(jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", area=\"nonheap\"},id)", - "refId": "Prometheus-jvm_memory_pool_nonheap-Variable-Query" - }, - "refresh": 1, - "regex": "", - "skipUrlSync": false, - "sort": 2, - "tagValuesQuery": "", - "tagsQuery": "", - "type": "query", - "useTags": false - } - ] - }, - "time": { - "from": "now-24h", - "to": "now" - }, - "timepicker": { - "now": true, - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ] - }, - "timezone": "browser", - "title": "1 SLS JVM监控大盘", - "uid": "UOJjh1SMz", - "version": 1, - "weekStart": "" -} diff --git a/config/grafana/Spring Boot 2.1 Statistics.json b/config/grafana/Spring Boot 2.1 Statistics.json deleted file mode 100644 index 7d40c80..0000000 --- a/config/grafana/Spring Boot 2.1 Statistics.json +++ /dev/null @@ -1,3590 +0,0 @@ -{ - "annotations": { - "list": [ - { - "builtIn": 1, - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "target": { - "limit": 100, - "matchAny": false, - "tags": [], - "type": "dashboard" - }, - "type": "dashboard" - } - ] - }, - "description": "Dashboard for Spring Boot2.1 Statistics(based on Spring Boot2 Statistic by micrometer-prometheus).", - "editable": true, - "fiscalYearStartMonth": 0, - "gnetId": 10280, - "graphTooltip": 0, - "id": 13, - "links": [], - "liveNow": false, - "panels": [ - { - "collapsed": false, - "datasource": { - "type": "prometheus" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 0 - }, - "id": 54, - "panels": [], - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "refId": "A" - } - ], - "title": "Basic Statistics", - "type": "row" - }, - { - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "decimals": 1, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { - "h": 3, - "w": 6, - "x": 0, - "y": 1 - }, - "id": 52, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "9.2.4", - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "process_uptime_seconds{application=\"$application\", instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "", - "metric": "", - "refId": "A", - "step": 14400 - } - ], - "title": "Uptime", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "decimals": 1, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "max": 100, - "min": 0, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "rgba(50, 172, 45, 0.97)", - "value": null - }, - { - "color": "rgba(237, 129, 40, 0.89)", - "value": 70 - }, - { - "color": "rgba(245, 54, 54, 0.9)", - "value": 90 - } - ] - }, - "unit": "percent" - }, - "overrides": [] - }, - "gridPos": { - "h": 6, - "w": 5, - "x": 6, - "y": 1 - }, - "id": 58, - "links": [], - "maxDataPoints": 100, - "options": { - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "showThresholdLabels": false, - "showThresholdMarkers": true - }, - "pluginVersion": "9.2.4", - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", area=\"heap\"})*100/sum(jvm_memory_max_bytes{application=\"$application\",instance=\"$instance\", area=\"heap\"})", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "", - "refId": "A", - "step": 14400 - } - ], - "title": "Heap Used", - "type": "gauge" - }, - { - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "decimals": 1, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - }, - { - "options": { - "from": -1e+32, - "result": { - "text": "N/A" - }, - "to": 0 - }, - "type": "range" - } - ], - "max": 100, - "min": 0, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "rgba(50, 172, 45, 0.97)", - "value": null - }, - { - "color": "rgba(237, 129, 40, 0.89)", - "value": 70 - }, - { - "color": "rgba(245, 54, 54, 0.9)", - "value": 90 - } - ] - }, - "unit": "percent" - }, - "overrides": [] - }, - "gridPos": { - "h": 6, - "w": 5, - "x": 11, - "y": 1 - }, - "id": 60, - "links": [], - "maxDataPoints": 100, - "options": { - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "showThresholdLabels": false, - "showThresholdMarkers": true - }, - "pluginVersion": "9.2.4", - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "sum(jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", area=\"nonheap\"})*100/sum(jvm_memory_max_bytes{application=\"$application\",instance=\"$instance\", area=\"nonheap\"})", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "", - "refId": "A", - "step": 14400 - } - ], - "title": "Non-Heap Used", - "type": "gauge" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 6, - "w": 8, - "x": 16, - "y": 1 - }, - "hiddenSeries": false, - "id": 66, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "process_files_open_files{application=\"$application\", instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Open Files", - "refId": "A" - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "process_files_max_files{application=\"$application\", instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Max Files", - "refId": "B" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Process Open Files", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "locale", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "dateTimeAsIso" - }, - "overrides": [] - }, - "gridPos": { - "h": 3, - "w": 6, - "x": 0, - "y": 4 - }, - "id": 56, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "9.2.4", - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "process_start_time_seconds{application=\"$application\", instance=\"$instance\"}*1000", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "", - "metric": "", - "refId": "A", - "step": 14400 - } - ], - "title": "Start time", - "type": "stat" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 12, - "x": 0, - "y": 7 - }, - "hiddenSeries": false, - "id": 95, - "legend": { - "alignAsTable": true, - "avg": true, - "current": true, - "max": true, - "min": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "system_cpu_usage{instance=\"$instance\", application=\"$application\"}", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "System CPU Usage", - "refId": "A" - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "process_cpu_usage{instance=\"$instance\", application=\"$application\"}", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Process CPU Usage", - "refId": "B" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "CPU Usage", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 7 - }, - "hiddenSeries": false, - "id": 96, - "legend": { - "alignAsTable": true, - "avg": true, - "current": true, - "max": true, - "min": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "system_load_average_1m{instance=\"$instance\", application=\"$application\"}", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Load Average [1m]", - "refId": "A" - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "system_cpu_count{instance=\"$instance\", application=\"$application\"}", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "CPU Core Size", - "refId": "B" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Load Average", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "collapsed": false, - "datasource": { - "type": "prometheus" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 14 - }, - "id": 48, - "panels": [], - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "refId": "A" - } - ], - "title": "JVM Statistics - Memory", - "type": "row" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 8, - "w": 8, - "x": 0, - "y": 15 - }, - "hiddenSeries": false, - "id": 85, - "legend": { - "alignAsTable": true, - "avg": true, - "current": true, - "max": true, - "min": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": "memory_pool_heap", - "repeatDirection": "h", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "jvm_memory_used_bytes{instance=\"$instance\", application=\"$application\", id=\"$memory_pool_heap\"}", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Used", - "refId": "C" - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "jvm_memory_committed_bytes{instance=\"$instance\", application=\"$application\", id=\"$memory_pool_heap\"}", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Commited", - "refId": "A" - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "jvm_memory_max_bytes{instance=\"$instance\", application=\"$application\", id=\"$memory_pool_heap\"}", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Max", - "refId": "B" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "$memory_pool_heap (heap)", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "bytes", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 8, - "w": 8, - "x": 0, - "y": 23 - }, - "hiddenSeries": false, - "id": 88, - "legend": { - "alignAsTable": true, - "avg": true, - "current": true, - "max": true, - "min": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": "memory_pool_nonheap", - "repeatDirection": "h", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "jvm_memory_used_bytes{instance=\"$instance\", application=\"$application\", id=\"$memory_pool_nonheap\"}", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Used", - "refId": "C" - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "jvm_memory_committed_bytes{instance=\"$instance\", application=\"$application\", id=\"$memory_pool_nonheap\"}", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Commited", - "refId": "A" - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "jvm_memory_max_bytes{instance=\"$instance\", application=\"$application\", id=\"$memory_pool_nonheap\"}", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Max", - "refId": "B" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "$memory_pool_nonheap (non-heap)", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "bytes", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 8, - "w": 8, - "x": 8, - "y": 31 - }, - "hiddenSeries": false, - "id": 80, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "irate(jvm_classes_unloaded_classes_total{instance=\"$instance\", application=\"$application\"}[5m])", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Classes Unloaded", - "refId": "A" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Classes Unloaded", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "decimals": 0, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 39 - }, - "hiddenSeries": false, - "id": 50, - "legend": { - "alignAsTable": true, - "avg": true, - "current": true, - "max": true, - "min": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "jvm_classes_loaded_classes{instance=\"$instance\", application=\"$application\"}", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Classes Loaded", - "refId": "A" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Classes Loaded", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "decimals": 0, - "format": "locale", - "label": "", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 39 - }, - "hiddenSeries": false, - "id": 83, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "jvm_buffer_memory_used_bytes{instance=\"$instance\", application=\"$application\", id=\"mapped\"}", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Used Bytes", - "refId": "A" - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "jvm_buffer_total_capacity_bytes{instance=\"$instance\", application=\"$application\", id=\"mapped\"}", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Capacity Bytes", - "refId": "B" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Mapped Buffers", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 46 - }, - "hiddenSeries": false, - "id": 78, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "irate(jvm_gc_memory_allocated_bytes_total{instance=\"$instance\", application=\"$application\"}[5m])", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "allocated", - "refId": "A" - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "irate(jvm_gc_memory_promoted_bytes_total{instance=\"$instance\", application=\"$application\"}[5m])", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "promoted", - "refId": "B" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Memory Allocate/Promote", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "bytes", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 12, - "x": 0, - "y": 47 - }, - "hiddenSeries": false, - "id": 82, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "jvm_buffer_memory_used_bytes{instance=\"$instance\", application=\"$application\", id=\"direct\"}", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Used Bytes", - "refId": "A" - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "jvm_buffer_total_capacity_bytes{instance=\"$instance\", application=\"$application\", id=\"direct\"}", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Capacity Bytes", - "refId": "B" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Direct Buffers", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 54 - }, - "hiddenSeries": false, - "id": 68, - "legend": { - "alignAsTable": true, - "avg": true, - "current": true, - "max": true, - "min": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "jvm_threads_daemon_threads{instance=\"$instance\", application=\"$application\"}", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Daemon", - "refId": "A" - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "jvm_threads_live_threads{instance=\"$instance\", application=\"$application\"}", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Live", - "refId": "B" - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "jvm_threads_peak_threads{instance=\"$instance\", application=\"$application\"}", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Peak", - "refId": "C" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Threads", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "collapsed": false, - "datasource": { - "type": "prometheus" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 62 - }, - "id": 72, - "panels": [], - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "refId": "A" - } - ], - "title": "JVM Statistics - GC", - "type": "row" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 10, - "w": 12, - "x": 0, - "y": 63 - }, - "hiddenSeries": false, - "id": 74, - "legend": { - "alignAsTable": true, - "avg": true, - "current": false, - "hideEmpty": true, - "hideZero": true, - "max": true, - "min": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "irate(jvm_gc_pause_seconds_count{instance=\"$instance\", application=\"$application\"}[5m])", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "{{action}} [{{cause}}]", - "refId": "A" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "GC Count", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "locale", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 10, - "w": 12, - "x": 12, - "y": 63 - }, - "hiddenSeries": false, - "id": 76, - "legend": { - "alignAsTable": true, - "avg": true, - "current": false, - "hideEmpty": true, - "hideZero": true, - "max": true, - "min": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "irate(jvm_gc_pause_seconds_sum{instance=\"$instance\", application=\"$application\"}[5m])", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "{{action}} [{{cause}}]", - "refId": "A" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "GC Stop the World Duration", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "s", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "collapsed": false, - "datasource": { - "type": "prometheus" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 73 - }, - "id": 34, - "panels": [], - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "refId": "A" - } - ], - "title": "HikariCP Statistics", - "type": "row" - }, - { - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 4, - "w": 4, - "x": 0, - "y": 74 - }, - "id": 44, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "none", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "9.2.4", - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "hikaricp_connections{instance=\"$instance\", application=\"$application\", pool=\"$hikaricp\"}", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "", - "refId": "A" - } - ], - "title": "Connections Size", - "type": "stat" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 8, - "w": 20, - "x": 4, - "y": 74 - }, - "hiddenSeries": false, - "id": 36, - "legend": { - "alignAsTable": true, - "avg": true, - "current": true, - "hideEmpty": true, - "hideZero": false, - "max": true, - "min": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": true, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "hikaricp_connections_active{instance=\"$instance\", application=\"$application\", pool=\"$hikaricp\"}", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Active", - "refId": "B" - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "hikaricp_connections_idle{instance=\"$instance\", application=\"$application\", pool=\"$hikaricp\"}", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Idle", - "refId": "A" - }, - { - "datasource": { - "type": "prometheus" - }, - "expr": "hikaricp_connections_pending{instance=\"$instance\", application=\"$application\", pool=\"$hikaricp\"}", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Pending", - "refId": "C" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Connections", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 4, - "w": 4, - "x": 0, - "y": 78 - }, - "id": 46, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "none", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "9.2.4", - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "hikaricp_connections_timeout_total{instance=\"$instance\", application=\"$application\", pool=\"$hikaricp\"}", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "", - "refId": "A" - } - ], - "title": "Connection Timeout Count", - "type": "stat" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 6, - "w": 8, - "x": 0, - "y": 82 - }, - "hiddenSeries": false, - "id": 38, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "hikaricp_connections_creation_seconds_sum{instance=\"$instance\", application=\"$application\", pool=\"$hikaricp\"} / hikaricp_connections_creation_seconds_count{instance=\"$instance\", application=\"$application\", pool=\"$hikaricp\"}", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Creation Time", - "refId": "A" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Connection Creation Time", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "s", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 6, - "w": 8, - "x": 8, - "y": 82 - }, - "hiddenSeries": false, - "id": 42, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "hikaricp_connections_usage_seconds_sum{instance=\"$instance\", application=\"$application\", pool=\"$hikaricp\"} / hikaricp_connections_usage_seconds_count{instance=\"$instance\", application=\"$application\", pool=\"$hikaricp\"}", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Usage Time", - "refId": "A" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Connection Usage Time", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "s", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 6, - "w": 8, - "x": 16, - "y": 82 - }, - "hiddenSeries": false, - "id": 40, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "hikaricp_connections_acquire_seconds_sum{instance=\"$instance\", application=\"$application\", pool=\"$hikaricp\"} / hikaricp_connections_acquire_seconds_count{instance=\"$instance\", application=\"$application\", pool=\"$hikaricp\"}", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Acquire Time", - "refId": "A" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Connection Acquire Time", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "s", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "collapsed": false, - "datasource": { - "type": "prometheus" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 88 - }, - "id": 18, - "panels": [], - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "refId": "A" - } - ], - "title": "HTTP Statistics", - "type": "row" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 24, - "x": 0, - "y": 89 - }, - "hiddenSeries": false, - "id": 4, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "irate(http_server_requests_seconds_count{instance=\"$instance\", application=\"$application\", uri!~\".*actuator.*\"}[5m])", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "{{method}} [{{status}}] - {{uri}}", - "refId": "A" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Request Count", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "none", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 24, - "x": 0, - "y": 96 - }, - "hiddenSeries": false, - "id": 2, - "legend": { - "alignAsTable": true, - "avg": true, - "current": false, - "max": true, - "min": true, - "rightSide": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "expr": "irate(http_server_requests_seconds_sum{instance=\"$instance\", application=\"$application\", exception=\"None\", uri!~\".*actuator.*\"}[5m]) / irate(http_server_requests_seconds_count{instance=\"$instance\", application=\"$application\", exception=\"None\", uri!~\".*actuator.*\"}[5m])", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "{{method}} [{{status}}] - {{uri}}", - "refId": "A" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Response Time", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "s", - "label": "", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "collapsed": false, - "datasource": { - "type": "prometheus" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 103 - }, - "id": 22, - "panels": [], - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "refId": "A" - } - ], - "title": "Undertow Statistics", - "type": "row" - }, - { - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 4, - "w": 4, - "x": 0, - "y": 104 - }, - "id": 28, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "none", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "9.2.4", - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "editorMode": "code", - "expr": "undertow_connectors_requests_error_count{instance=\"$instance\", application=\"$application\"}", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "", - "range": true, - "refId": "A" - }, - { - "datasource": { - "type": "prometheus" - }, - "hide": false, - "refId": "B" - } - ], - "title": "Total Error Count", - "type": "stat" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "decimals": 0, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 9, - "x": 4, - "y": 104 - }, - "hiddenSeries": false, - "id": 24, - "legend": { - "alignAsTable": true, - "avg": true, - "current": true, - "max": true, - "min": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "editorMode": "code", - "expr": "undertow_sessions_active_current_sessions{instance=\"$instance\", application=\"$application\"}", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "active sessions", - "range": true, - "refId": "A" - }, - { - "datasource": { - "type": "prometheus" - }, - "hide": false, - "refId": "B" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Active Sessions", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "none", - "label": "", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 11, - "x": 13, - "y": 104 - }, - "hiddenSeries": false, - "id": 26, - "legend": { - "alignAsTable": true, - "avg": true, - "current": true, - "max": true, - "min": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "editorMode": "code", - "expr": "irate(undertow_connectors_bytes_sent_bytes{instance=\"$instance\", application=\"$application\"}[5m])", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Sent Bytes", - "range": true, - "refId": "A" - }, - { - "datasource": { - "type": "prometheus" - }, - "editorMode": "code", - "expr": "irate(undertow_connectors_bytes_received_bytes{instance=\"$instance\", application=\"$application\"}[5m])", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Recieved Bytes", - "range": true, - "refId": "B" - }, - { - "datasource": { - "type": "prometheus" - }, - "hide": false, - "refId": "C" - }, - { - "datasource": { - "type": "prometheus" - }, - "hide": false, - "refId": "D" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Sent & Recieved Bytes", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "bytes", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "datasource": { - "type": "prometheus" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 3, - "w": 4, - "x": 0, - "y": 108 - }, - "id": 32, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "none", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "9.2.4", - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "editorMode": "code", - "expr": "undertow_xwork_worker_pool_max_size{instance=\"$instance\", application=\"$application\"}", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "", - "range": true, - "refId": "A" - }, - { - "datasource": { - "type": "prometheus" - }, - "hide": false, - "refId": "B" - }, - { - "datasource": { - "type": "prometheus" - }, - "hide": false, - "refId": "C" - } - ], - "title": "Thread Config Max", - "type": "stat" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 13, - "x": 0, - "y": 111 - }, - "hiddenSeries": false, - "id": 30, - "legend": { - "alignAsTable": true, - "avg": true, - "current": true, - "max": true, - "min": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "editorMode": "code", - "expr": "undertow_xwork_worker_pool_size{instance=\"$instance\", application=\"$application\"}", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Current thread", - "range": true, - "refId": "A" - }, - { - "datasource": { - "type": "prometheus" - }, - "editorMode": "code", - "expr": "undertow_xwork_worker_thread_busy_count{instance=\"$instance\", application=\"$application\"}", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Current thread busy", - "range": true, - "refId": "B" - }, - { - "datasource": { - "type": "prometheus" - }, - "hide": false, - "refId": "C" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Threads", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "collapsed": false, - "datasource": { - "type": "prometheus" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 118 - }, - "id": 8, - "panels": [], - "targets": [ - { - "datasource": { - "type": "prometheus" - }, - "refId": "A" - } - ], - "title": "Logback Statistics", - "type": "row" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 12, - "x": 0, - "y": 119 - }, - "hiddenSeries": false, - "id": 6, - "legend": { - "alignAsTable": true, - "avg": true, - "current": true, - "max": true, - "min": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "", - "datasource": { - "type": "prometheus" - }, - "expr": "irate(logback_events_total{instance=\"$instance\", application=\"$application\", level=\"info\"}[5m])", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "info", - "rawSql": "SELECT\n $__time(time_column),\n value1\nFROM\n metric_table\nWHERE\n $__timeFilter(time_column)\n", - "refId": "A" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "INFO logs", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "none", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 119 - }, - "hiddenSeries": false, - "id": 10, - "legend": { - "alignAsTable": true, - "avg": true, - "current": true, - "max": true, - "min": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "", - "datasource": { - "type": "prometheus" - }, - "expr": "irate(logback_events_total{instance=\"$instance\", application=\"$application\", level=\"error\"}[5m])", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "error", - "rawSql": "SELECT\n $__time(time_column),\n value1\nFROM\n metric_table\nWHERE\n $__timeFilter(time_column)\n", - "refId": "A" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "ERROR logs", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "none", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 8, - "x": 0, - "y": 126 - }, - "hiddenSeries": false, - "id": 14, - "legend": { - "alignAsTable": true, - "avg": true, - "current": true, - "max": true, - "min": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "", - "datasource": { - "type": "prometheus" - }, - "expr": "irate(logback_events_total{instance=\"$instance\", application=\"$application\", level=\"warn\"}[5m])", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "warn", - "rawSql": "SELECT\n $__time(time_column),\n value1\nFROM\n metric_table\nWHERE\n $__timeFilter(time_column)\n", - "refId": "A" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "WARN logs", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "none", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 8, - "x": 8, - "y": 126 - }, - "hiddenSeries": false, - "id": 16, - "legend": { - "alignAsTable": true, - "avg": true, - "current": true, - "max": true, - "min": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "", - "datasource": { - "type": "prometheus" - }, - "expr": "irate(logback_events_total{instance=\"$instance\", application=\"$application\", level=\"debug\"}[5m])", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "debug", - "rawSql": "SELECT\n $__time(time_column),\n value1\nFROM\n metric_table\nWHERE\n $__timeFilter(time_column)\n", - "refId": "A" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "DEBUG logs", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "none", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus" - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 8, - "x": 16, - "y": 126 - }, - "hiddenSeries": false, - "id": 20, - "legend": { - "alignAsTable": true, - "avg": true, - "current": true, - "max": true, - "min": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "9.2.4", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "", - "datasource": { - "type": "prometheus" - }, - "expr": "irate(logback_events_total{instance=\"$instance\", application=\"$application\", level=\"trace\"}[5m])", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "trace", - "rawSql": "SELECT\n $__time(time_column),\n value1\nFROM\n metric_table\nWHERE\n $__timeFilter(time_column)\n", - "refId": "A" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "TRACE logs", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "none", - "logBase": 1, - "show": true - }, - { - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - } - ], - "refresh": "5s", - "schemaVersion": 37, - "style": "dark", - "tags": [], - "templating": { - "list": [ - { - "current": { - "selected": true, - "text": "ruoyi-auth", - "value": "ruoyi-auth" - }, - "datasource": { - "type": "prometheus" - }, - "definition": "label_values(application)", - "hide": 0, - "includeAll": false, - "label": "Application", - "multi": false, - "name": "application", - "options": [], - "query": { - "query": "label_values(application)", - "refId": "Prometheus-application-Variable-Query" - }, - "refresh": 1, - "regex": "", - "skipUrlSync": false, - "sort": 1, - "tagValuesQuery": "", - "tagsQuery": "", - "type": "query", - "useTags": false - }, - { - "current": { - "selected": false, - "text": "192.168.31.100:9210", - "value": "192.168.31.100:9210" - }, - "datasource": { - "type": "prometheus" - }, - "definition": "label_values(jvm_classes_loaded_classes{application=\"$application\"}, instance)", - "hide": 0, - "includeAll": false, - "label": "Instance", - "multi": false, - "name": "instance", - "options": [], - "query": { - "query": "label_values(jvm_classes_loaded_classes{application=\"$application\"}, instance)", - "refId": "Prometheus-instance-Variable-Query" - }, - "refresh": 1, - "regex": "", - "skipUrlSync": false, - "sort": 1, - "tagValuesQuery": "", - "tagsQuery": "", - "type": "query", - "useTags": false - }, - { - "current": { - "isNone": true, - "selected": false, - "text": "None", - "value": "" - }, - "datasource": { - "type": "prometheus" - }, - "definition": "", - "hide": 0, - "includeAll": false, - "label": "HikariCP-Pool", - "multi": false, - "name": "hikaricp", - "options": [], - "query": { - "query": "label_values(hikaricp_connections{instance=\"$instance\", application=\"$application\"}, pool)", - "refId": "Prometheus-hikaricp-Variable-Query" - }, - "refresh": 1, - "regex": "", - "skipUrlSync": false, - "sort": 1, - "tagValuesQuery": "", - "tagsQuery": "", - "type": "query", - "useTags": false - }, - { - "current": { - "selected": false, - "text": "All", - "value": "$__all" - }, - "datasource": { - "type": "prometheus" - }, - "definition": "", - "hide": 0, - "includeAll": true, - "label": "Memory Pool (heap)", - "multi": false, - "name": "memory_pool_heap", - "options": [], - "query": { - "query": "label_values(jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", area=\"heap\"},id)", - "refId": "Prometheus-memory_pool_heap-Variable-Query" - }, - "refresh": 1, - "regex": "", - "skipUrlSync": false, - "sort": 1, - "tagValuesQuery": "", - "tagsQuery": "", - "type": "query", - "useTags": false - }, - { - "current": { - "selected": false, - "text": "All", - "value": "$__all" - }, - "datasource": { - "type": "prometheus" - }, - "definition": "", - "hide": 0, - "includeAll": true, - "label": "Memory Pool (nonheap)", - "multi": false, - "name": "memory_pool_nonheap", - "options": [], - "query": { - "query": "label_values(jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", area=\"nonheap\"},id)", - "refId": "Prometheus-memory_pool_nonheap-Variable-Query" - }, - "refresh": 1, - "regex": "", - "skipUrlSync": false, - "sort": 1, - "tagValuesQuery": "", - "tagsQuery": "", - "type": "query", - "useTags": false - } - ] - }, - "time": { - "from": "now-1h", - "to": "now" - }, - "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ] - }, - "timezone": "", - "title": "Spring Boot 2.1 Statistics", - "uid": "spring_boot_21", - "version": 3, - "weekStart": "" -} diff --git a/dk-common/common-workflow/pom.xml b/dk-common/common-workflow/pom.xml new file mode 100644 index 0000000..446a8f9 --- /dev/null +++ b/dk-common/common-workflow/pom.xml @@ -0,0 +1,58 @@ + + + + org.dromara + dk-common + ${revision} + + 4.0.0 + + common-workflow + + + 工作流模块 + + + + + + org.dromara + common-mybatis + + + + commons-io + commons-io + 2.15.0 + + + + org.dromara + system + 2.2.2 + compile + + + + + ${project.artifactId} + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + + + repackage + + + + + + + + + diff --git a/dk-common/common-workflow/src/main/java/org/dromara/common/Exception/ServiceException.java b/dk-common/common-workflow/src/main/java/org/dromara/common/Exception/ServiceException.java new file mode 100644 index 0000000..40cbaea --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/common/Exception/ServiceException.java @@ -0,0 +1,61 @@ +/* +Copyright [2020] [https://www.stylefeng.cn] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Guns采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点: + +1.请不要删除和修改根目录下的LICENSE文件。 +2.请不要删除和修改Guns源码头部的版权声明。 +3.请保留源码和相关描述文件的项目出处,作者声明等。 +4.分发源码时候,请注明软件出处 https://gitee.com/stylefeng/guns-separation +5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/stylefeng/guns-separation +6.若您的项目无法满足以上几点,可申请商业授权,获取Guns商业授权许可,请在官网购买授权,地址为 https://www.stylefeng.cn + */ +package org.dromara.common.Exception; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.Exception.enums.abs.AbstractBaseExceptionEnum; +import org.dromara.common.response.WorkflowResultCode; + +/** + * 业务异常 + * + */ +@EqualsAndHashCode(callSuper = true) +@Data +public class ServiceException extends RuntimeException { + + private Integer code; + + private String errorMessage; + + public ServiceException(Integer code, String errorMessage) { + super(errorMessage); + this.code = code; + this.errorMessage = errorMessage; + } + + public ServiceException(AbstractBaseExceptionEnum exception) { + super(exception.getMessage()); + this.code = exception.getCode(); + this.errorMessage = exception.getMessage(); + } + + public ServiceException(WorkflowResultCode resultCode) { + super(resultCode.message()); + this.code = resultCode.code(); + this.errorMessage = resultCode.message(); + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/common/Exception/enums/abs/AbstractBaseExceptionEnum.java b/dk-common/common-workflow/src/main/java/org/dromara/common/Exception/enums/abs/AbstractBaseExceptionEnum.java new file mode 100644 index 0000000..6210412 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/common/Exception/enums/abs/AbstractBaseExceptionEnum.java @@ -0,0 +1,47 @@ +/* +Copyright [2020] [https://www.stylefeng.cn] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Guns采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点: + +1.请不要删除和修改根目录下的LICENSE文件。 +2.请不要删除和修改Guns源码头部的版权声明。 +3.请保留源码和相关描述文件的项目出处,作者声明等。 +4.分发源码时候,请注明软件出处 https://gitee.com/stylefeng/guns-separation +5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/stylefeng/guns-separation +6.若您的项目无法满足以上几点,可申请商业授权,获取Guns商业授权许可,请在官网购买授权,地址为 https://www.stylefeng.cn + */ +package org.dromara.common.Exception.enums.abs; + +/** + + * @date 2017/12/17 22:22 + */ +public interface AbstractBaseExceptionEnum { + + /** + * 获取异常的状态码 + * + * @return 状态码 + */ + Integer getCode(); + + /** + * 获取异常的提示信息 + * + * @return 提示信息 + */ + String getMessage(); + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/common/consts/ExceptionCodeConstant.java b/dk-common/common-workflow/src/main/java/org/dromara/common/consts/ExceptionCodeConstant.java new file mode 100644 index 0000000..72c3b6a --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/common/consts/ExceptionCodeConstant.java @@ -0,0 +1,27 @@ +package org.dromara.common.consts; + +public interface ExceptionCodeConstant { + // es错误码 {10} {00} {03} {001-100} + interface Elasticsearch { + int ES_INDEX_NOT_EXIST = 100003001; + } + + // 数据源 {10} {00} {04} {001-100} + interface DataSource { + int TABLE_NAME_REPEAT = 100004001; + + int COLUMN_NULL = 100004002; + + int INCREMENTAL_COLUMN_NULL = 100004003; + + // Incrementalolumn is not in column config + int INCREMENTAL_COLUMN_NOT_IN_CONFIG = 100004004; + } + + // 业务代码异常 + interface Service { + int SQL_EXCEPTION = 100008001; + int OBJECT_TARGET_NOT_EXIST = 100008051; + int VALUE_INVALID = 100010001; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/common/entity/WorkflowBaseEntity.java b/dk-common/common-workflow/src/main/java/org/dromara/common/entity/WorkflowBaseEntity.java new file mode 100644 index 0000000..f0f986a --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/common/entity/WorkflowBaseEntity.java @@ -0,0 +1,67 @@ +/* +Copyright [2020] [https://www.stylefeng.cn] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Guns采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点: + +1.请不要删除和修改根目录下的LICENSE文件。 +2.请不要删除和修改Guns源码头部的版权声明。 +3.请保留源码和相关描述文件的项目出处,作者声明等。 +4.分发源码时候,请注明软件出处 https://gitee.com/stylefeng/guns-separation +5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/stylefeng/guns-separation +6.若您的项目无法满足以上几点,可申请商业授权,获取Guns商业授权许可,请在官网购买授权,地址为 https://www.stylefeng.cn + */ +package org.dromara.common.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.TableField; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +/** + * 通用基础字段,需要此通用字段的实体可继承此类 + * + */ +@Data +public class WorkflowBaseEntity implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private Date createTime; + + /** + * 创建人 + */ + @TableField(fill = FieldFill.INSERT) + private Long createUser; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.UPDATE) + private Date updateTime; + + /** + * 更新人 + */ + @TableField(fill = FieldFill.UPDATE) + private Long updateUser; + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/common/page/WorkflowPageFactory.java b/dk-common/common-workflow/src/main/java/org/dromara/common/page/WorkflowPageFactory.java new file mode 100644 index 0000000..16a18f0 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/common/page/WorkflowPageFactory.java @@ -0,0 +1,153 @@ +/* +Copyright [2020] [https://www.stylefeng.cn] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Guns采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点: + +1.请不要删除和修改根目录下的LICENSE文件。 +2.请不要删除和修改Guns源码头部的版权声明。 +3.请保留源码和相关描述文件的项目出处,作者声明等。 +4.分发源码时候,请注明软件出处 https://gitee.com/stylefeng/guns-separation +5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/stylefeng/guns-separation +6.若您的项目无法满足以上几点,可申请商业授权,获取Guns商业授权许可,请在官网购买授权,地址为 https://www.stylefeng.cn + */ +package org.dromara.common.page; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import jakarta.servlet.http.HttpServletRequest; +import org.dromara.common.util.HttpServletUtil; + +import java.util.Collections; +import java.util.List; + + +/** + * 默认分页参数构建 + * + */ +public class WorkflowPageFactory { + + /** + * 每页大小(默认20) + */ + private static final String PAGE_SIZE_PARAM_NAME = "pageSize"; + + /** + * 第几页(从1开始) + */ + private static final String PAGE_NO_PARAM_NAME = "pageNo"; + + /** + * 默认分页,在使用时PageFactory.defaultPage会自动获取pageSize和pageNo参数 + * + * @author xuyuxiang + * @date 2020/3/30 16:42 + */ + public static Page defaultPage() { + + int pageSize = 10; + int pageNo = 1; + + HttpServletRequest request = HttpServletUtil.getRequest(); + + //每页条数 + String pageSizeString = request.getParameter(PAGE_SIZE_PARAM_NAME); + if (ObjectUtil.isNotEmpty(pageSizeString)) { + pageSize = Integer.parseInt(pageSizeString); + } + + //第几页 + String pageNoString = request.getParameter(PAGE_NO_PARAM_NAME); + if (ObjectUtil.isNotEmpty(pageNoString)) { + pageNo = Integer.parseInt(pageNoString); + } + + return new Page<>(pageNo, pageSize); + } + + public static Page customPage(Integer pageSize,Integer pageNo) { + + if(ObjectUtil.hasEmpty(pageNo,pageSize)){ + + return defaultPage(); + } + + return new Page<>(pageNo, pageSize); + } + + public static Page defaultPage(Integer pageNoParam,Integer pageSizeParam) { + + int pageSize = 10; + int pageNo = 1; + + //每页条数 moren + if (ObjectUtil.isNotEmpty(pageSizeParam)) { + pageSize = pageSizeParam; + } + + //第几页 + if (ObjectUtil.isNotEmpty(pageNoParam)) { + pageNo = pageNoParam; + } + + return new Page<>(pageNo, pageSize); + } + + + public static Page customPage(Boolean limited) { + + if(ObjectUtil.equal(limited,true)){ + + return defaultPage(); + } + + return new Page<>(0, -1); + } + + /** + * 得到分页后的数据 + * @return 分页后结果 + */ + public static List getPagedList(List data) { + int pageSize = 10; + int pageNo = 1; + + HttpServletRequest request = HttpServletUtil.getRequest(); + + //每页条数 + String pageSizeString = request.getParameter(PAGE_SIZE_PARAM_NAME); + if (ObjectUtil.isNotEmpty(pageSizeString)) { + pageSize = Integer.parseInt(pageSizeString); + } + + //第几页 + String pageNoString = request.getParameter(PAGE_NO_PARAM_NAME); + if (ObjectUtil.isNotEmpty(pageNoString)) { + pageNo = Integer.parseInt(pageNoString); + } + + int fromIndex = (pageNo - 1) * pageSize; + if (fromIndex >= data.size()) { + return Collections.emptyList(); + } + + int toIndex = pageNo * pageSize; + if (toIndex >= data.size()) { + toIndex = data.size(); + } + return data.subList(fromIndex, toIndex); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/common/page/WorkflowPageResult.java b/dk-common/common-workflow/src/main/java/org/dromara/common/page/WorkflowPageResult.java new file mode 100644 index 0000000..46ab91e --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/common/page/WorkflowPageResult.java @@ -0,0 +1,119 @@ +/* +Copyright [2020] [https://www.stylefeng.cn] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Guns采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点: + +1.请不要删除和修改根目录下的LICENSE文件。 +2.请不要删除和修改Guns源码头部的版权声明。 +3.请保留源码和相关描述文件的项目出处,作者声明等。 +4.分发源码时候,请注明软件出处 https://gitee.com/stylefeng/guns-separation +5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/stylefeng/guns-separation +6.若您的项目无法满足以上几点,可申请商业授权,获取Guns商业授权许可,请在官网购买授权,地址为 https://www.stylefeng.cn + */ +package org.dromara.common.page; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.PageUtil; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * 分页结果集 + * + * @author xuyuxiang + * @date 2020/3/30 15:44 + */ +@Data +public class WorkflowPageResult implements Serializable { + + private static final long serialVersionUID = -1L; + + /** + * 默认分页彩虹展示数量 + */ + public static final int RAINBOW_NUM = 5; + + /** + * 第几页 + */ + private Integer pageNo = 1; + + /** + * 每页条数 + */ + private Integer pageSize = 20; + + /** + * 总页数 + */ + private Integer totalPage = 0; + + /** + * 总记录数 + */ + private Integer totalRows = 0; + + /** + * 结果集 + */ + private List rows; + + /** + * 分页彩虹 + */ + private int[] rainbow; + + public WorkflowPageResult() { + } + + /** + * 将mybatis-plus的page转成自定义的PageResult,扩展了totalPage总页数,和rainBow彩虹条 + * + * @author xuyuxiang + * @date 2020/4/8 19:20 + */ + public WorkflowPageResult(Page page) { + this.setRows(page.getRecords()); + this.setTotalRows(Convert.toInt(page.getTotal())); + this.setPageNo(Convert.toInt(page.getCurrent())); + this.setPageSize(Convert.toInt(page.getSize())); + this.setTotalPage(PageUtil.totalPage(Convert.toInt(page.getTotal()), + Convert.toInt(page.getSize()))); +// this.setRainbow(PageUtil.rainbow(Convert.toInt(page.getCurrent()), +// Convert.toInt(this.getTotalPage()), RAINBOW_NUM)); + } + + /** + * 将mybatis-plus的page转成自定义的PageResult,扩展了totalPage总页数,和rainBow彩虹条 + * 可单独设置rows + * + * @author xuyuxiang + * @date 2020/4/14 20:55 + */ + public WorkflowPageResult(IPage page, List t) { + this.setRows(t); + this.setTotalRows(Convert.toInt(page.getTotal())); + this.setPageNo(Convert.toInt(page.getCurrent())); + this.setPageSize(Convert.toInt(page.getSize())); + this.setTotalPage(PageUtil.totalPage(Convert.toInt(page.getTotal()), + Convert.toInt(page.getSize()))); +// this.setRainbow(PageUtil.rainbow(Convert.toInt(page.getCurrent()), +// Convert.toInt(this.getTotalPage()), RAINBOW_NUM)); + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/common/param/WorkflowBaseParam.java b/dk-common/common-workflow/src/main/java/org/dromara/common/param/WorkflowBaseParam.java new file mode 100644 index 0000000..967a217 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/common/param/WorkflowBaseParam.java @@ -0,0 +1,355 @@ +/* +Copyright [2020] [https://www.stylefeng.cn] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Guns采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点: + +1.请不要删除和修改根目录下的LICENSE文件。 +2.请不要删除和修改Guns源码头部的版权声明。 +3.请保留源码和相关描述文件的项目出处,作者声明等。 +4.分发源码时候,请注明软件出处 https://gitee.com/stylefeng/guns-separation +5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/stylefeng/guns-separation +6.若您的项目无法满足以上几点,可申请商业授权,获取Guns商业授权许可,请在官网购买授权,地址为 https://www.stylefeng.cn + */ +package org.dromara.common.param; + +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * 通用基础参数,相关实体参数校验可继承此类 + * + */ +@Data +public class WorkflowBaseParam implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 是否禁用权限 + */ + private boolean withoutPermission = false; + + /** + * 是否进行分页 + */ + private Boolean showPageNation = true; + + /** + * 搜索值 + */ + private String searchValue; + + + /** + * 数据权限 + */ + private List dataScope; + + + /** + * 开始时间 + */ + private String startTime; + + /** + * 结束时间 + */ + private String endTime; + + /** + * 状态(字典 0正常 1停用 2删除) + */ + private Integer searchStatus; + + /** + * 参数校验分组:分页 + */ + public @interface page { + } + + /** + * 参数校验分组:列表 + */ + public @interface list { + } + + /** + * 参数校验分组:下拉 + */ + public @interface dropDown { + } + + /** + * 参数校验分组:增加 + */ + public @interface add { + } + + /** + * 参数校验分组:编辑 + */ + public @interface edit { + } + + public @interface status { + } + + /** + * 参数校验分组:更新信息 + */ + public @interface updateInfo { + } + + /** + * 参数校验分组:修改密码 + */ + public @interface updatePwd { + } + + /** + * 参数校验分组:重置密码 + */ + public @interface resetPwd { + } + + /** + * 参数校验分组:修改头像 + */ + public @interface updateAvatar { + } + + public @interface updateTask{ + } + + /** + * 参数校验分组:删除 + */ + public @interface delete { + } + + /** + * 参数校验分组:详情 + */ + public @interface detail { + } + + public @interface batch { + } + + /** + * 参数校验分组:授权角色 + */ + public @interface grantRole { + } + + /** + * 参数校验分组:授权菜单 + */ + public @interface grantMenu { + } + + /** + * 参数校验分组:授权数据 + */ + public @interface grantData { + } + + /** + * 参数校验分组:强退 + */ + public @interface force { + } + + /** + * 参数校验分组:停用 + */ + public @interface stop { + } + + /** + * 参数校验分组:启用 + */ + public @interface start { + } + + /** + * 参数校验分组:部署 + */ + public @interface deploy { + } + + /** + * 参数校验分组:挂起 + */ + public @interface suspend { + } + + /** + * 参数校验分组:激活 + */ + public @interface active { + } + + /** + * 参数校验分组:调试 + */ + public @interface debug { + } + + /** + * 参数校验分组:委托 + */ + public @interface entrust { + } + + /** + * 参数校验分组:转办 + */ + public @interface turn { + } + + /** + * 参数校验分组:追踪 + */ + public @interface trace { + } + + /** + * 参数校验分组:跳转 + */ + public @interface jump { + } + + /** + * 参数校验分组:同意 + */ + public @interface agree { + } + + /** + * 参数校验分组:退回 + */ + public @interface back { + } + + /** + * 参数校验分组:终止 + */ + public @interface end { + } + + /** + * 参数校验分组:导出 + */ + public @interface export { + } + + /** + * 参数校验分组:映射 + */ + public @interface mapping { + } + + /** + * 参数校验分组:切换 + */ + public @interface change { + } + + /** + * 参数校验分组:历史审批记录 + */ + public @interface commentHistory { + } + + /** + * 参数校验分组:修改状态 + */ + public @interface changeStatus { + } + + /** + * 参数校验分组:传阅 + */ + public @interface circulate { + } + + /** + * 参数校验分组:加签 + */ + public @interface addSign { + } + + /** + * 参数校验分组:减签 + */ + public @interface deleteSign { + } + + /** + * 参数校验分组:添加节点 + */ + public @interface addNode { + } + + /** + * 参数校验分组:节点流转 + */ + public @interface flow { + } + + + public @interface apply { + } + public @interface submit { + } + + public @interface reject { + } + public @interface cancel { + } + public @interface finish { + } + + public @interface rollback { + } + + + /** + * 参数校验分组:节点转交 + */ + public @interface forward { + } + + + public @interface valid {} + + public @interface check {} + + + public @interface todo {} + + public @interface handle {} + + public @interface cc {} + + public @interface urge {} + + public @interface install { + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/common/requestno/RequestNoContext.java b/dk-common/common-workflow/src/main/java/org/dromara/common/requestno/RequestNoContext.java new file mode 100644 index 0000000..1d467c8 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/common/requestno/RequestNoContext.java @@ -0,0 +1,58 @@ +/* +Copyright [2020] [https://www.stylefeng.cn] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Guns采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点: + +1.请不要删除和修改根目录下的LICENSE文件。 +2.请不要删除和修改Guns源码头部的版权声明。 +3.请保留源码和相关描述文件的项目出处,作者声明等。 +4.分发源码时候,请注明软件出处 https://gitee.com/stylefeng/guns-separation +5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/stylefeng/guns-separation +6.若您的项目无法满足以上几点,可申请商业授权,获取Guns商业授权许可,请在官网购买授权,地址为 https://www.stylefeng.cn + */ +package org.dromara.common.requestno; + +/** + * 临时保存当前请求号 + * + */ +public class RequestNoContext { + + private static final ThreadLocal CONTEXT_HOLDER = new ThreadLocal<>(); + + /** + * 保存请求号 + * + */ + public static void set(String requestNo) { + CONTEXT_HOLDER.set(requestNo); + } + + /** + * 获取请求号 + * + */ + public static String get() { + return CONTEXT_HOLDER.get(); + } + + /** + * 清除请求号 + * + */ + public static void clear() { + CONTEXT_HOLDER.remove(); + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/common/response/WorkflowErrorResponseData.java b/dk-common/common-workflow/src/main/java/org/dromara/common/response/WorkflowErrorResponseData.java new file mode 100644 index 0000000..d2ae4ec --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/common/response/WorkflowErrorResponseData.java @@ -0,0 +1,58 @@ +/* +Copyright [2020] [https://www.stylefeng.cn] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Guns采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点: + +1.请不要删除和修改根目录下的LICENSE文件。 +2.请不要删除和修改Guns源码头部的版权声明。 +3.请保留源码和相关描述文件的项目出处,作者声明等。 +4.分发源码时候,请注明软件出处 https://gitee.com/stylefeng/guns-separation +5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/stylefeng/guns-separation +6.若您的项目无法满足以上几点,可申请商业授权,获取Guns商业授权许可,请在官网购买授权,地址为 https://www.stylefeng.cn + */ +package org.dromara.common.response; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 失败响应结果 + * + */ +@EqualsAndHashCode(callSuper = true) +@Data +public class WorkflowErrorResponseData extends WorkflowResponseData { + + /** + * 异常的具体类名称 + */ + private String exceptionClazz; + + WorkflowErrorResponseData(String message) { + super(false, DEFAULT_ERROR_CODE, message, null); + } + + public WorkflowErrorResponseData(Integer code, String message) { + super(false, code, message, null); + } + + WorkflowErrorResponseData(Integer code, String message, Object object) { + super(false, code, message, object); + } + WorkflowErrorResponseData(){ + super(); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/common/response/WorkflowResponseData.java b/dk-common/common-workflow/src/main/java/org/dromara/common/response/WorkflowResponseData.java new file mode 100644 index 0000000..2038cdc --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/common/response/WorkflowResponseData.java @@ -0,0 +1,97 @@ +/* +Copyright [2020] [https://www.stylefeng.cn] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Guns采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点: + +1.请不要删除和修改根目录下的LICENSE文件。 +2.请不要删除和修改Guns源码头部的版权声明。 +3.请保留源码和相关描述文件的项目出处,作者声明等。 +4.分发源码时候,请注明软件出处 https://gitee.com/stylefeng/guns-separation +5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/stylefeng/guns-separation +6.若您的项目无法满足以上几点,可申请商业授权,获取Guns商业授权许可,请在官网购买授权,地址为 https://www.stylefeng.cn + */ +package org.dromara.common.response; + +import lombok.Data; + +/** + * 响应结果数据 + * + */ +@Data +public class WorkflowResponseData { + + public static final String DEFAULT_SUCCESS_MESSAGE = "请求成功"; + + public static final String DEFAULT_ERROR_MESSAGE = "网络异常"; + + public static final Integer DEFAULT_SUCCESS_CODE = 200; + + public static final Integer DEFAULT_ERROR_CODE = 500; + + /** + * 请求是否成功 + */ + private Boolean success; + + /** + * 响应状态码 + */ + private Integer code; + + /** + * 响应信息 + */ + private String message; + + /** + * 响应对象 + */ + private Object data; + + public WorkflowResponseData() { + } + + public WorkflowResponseData(Boolean success, Integer code, String message, Object data) { + this.success = success; + this.code = code; + this.message = message; + this.data = data; + } + + public static WorkflowSuccessResponseData success() { + return new WorkflowSuccessResponseData(); + } + + public static WorkflowSuccessResponseData success(Object object) { + return new WorkflowSuccessResponseData(object); + } + + public static WorkflowSuccessResponseData success(Integer code, String message, Object object) { + return new WorkflowSuccessResponseData(code, message, object); + } + + public static WorkflowErrorResponseData error(String message) { + return new WorkflowErrorResponseData(message); + } + + public static WorkflowErrorResponseData error(Integer code, String message) { + return new WorkflowErrorResponseData(code, message); + } + + public static WorkflowErrorResponseData error(Integer code, String message, Object object) { + return new WorkflowErrorResponseData(code, message, object); + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/common/response/WorkflowResult.java b/dk-common/common-workflow/src/main/java/org/dromara/common/response/WorkflowResult.java new file mode 100644 index 0000000..dcb756c --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/common/response/WorkflowResult.java @@ -0,0 +1,54 @@ +package org.dromara.common.response; + +import lombok.Data; + +/** + * API 接口返回对象 + */ +@Data +public class WorkflowResult extends WorkflowResponseData { + + public static WorkflowSuccessResponseData success(){ + WorkflowSuccessResponseData result = new WorkflowSuccessResponseData(); + result.setSuccess(true); + result.setCode(WorkflowResultCode.SUCCESS.code()); + result.setMessage(WorkflowResultCode.SUCCESS.message()); + return result; + } + + public static WorkflowSuccessResponseData success(Object data){ + WorkflowSuccessResponseData result = new WorkflowSuccessResponseData(); + result.setSuccess(true); + result.setCode(WorkflowResultCode.SUCCESS.code()); + result.setMessage(WorkflowResultCode.SUCCESS.message()); + result.setData(data); + return result; + } + + public static WorkflowSuccessResponseData success(Object data, String message){ + WorkflowSuccessResponseData result = new WorkflowSuccessResponseData(); + result.setSuccess(true); + result.setCode(WorkflowResultCode.SUCCESS.code()); + result.setMessage(message); + result.setData(data); + return result; + } + + + public static WorkflowErrorResponseData error(WorkflowResultCode resultCode){ + WorkflowErrorResponseData result = new WorkflowErrorResponseData(); + result.setSuccess(false); + result.setCode(resultCode.code()); + result.setMessage(resultCode.message()); + return result; + } + + public static WorkflowErrorResponseData error(WorkflowResultCode resultCode, Object data){ + WorkflowErrorResponseData result = new WorkflowErrorResponseData(); + result.setSuccess(false); + result.setCode(resultCode.code()); + result.setMessage(resultCode.message()); + result.setData(data); + return result; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/common/response/WorkflowResultCode.java b/dk-common/common-workflow/src/main/java/org/dromara/common/response/WorkflowResultCode.java new file mode 100644 index 0000000..ab75e90 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/common/response/WorkflowResultCode.java @@ -0,0 +1,691 @@ +package org.dromara.common.response; + +public enum WorkflowResultCode { + + /** 200~299 成功,操作被成功接收和处理 */ + SUCCESS(200,"执行成功"), + + /** 500~599 失败,服务器再处理请求过程中发生得错误 */ + FAIL(500,"糟糕,服务器竟然出岔子了,建议刷新页面再试试"), + SAVE_FAIL(501,"新增失败"), + UPDATE_FAIL(502,"修改失败"), + DELETE_FAIL(503,"删除失败"), + NOT_SUPPORT(504,"不支持该操作"), + + /** 1001~9999 业务执行错误码 */ + /** 998 Ladp服务 */ + ERROR_LADP_FAIL(998000, "认证失败!"), + ERROR_LADP_NONE_USER(998001, "无效用户!"), + ERROR_LADP_ERROR(998002, "认证异常!"), + CAS_INVALID_TICKET(9020,"CAS Ticket无效"), + + /** 角色 ****/ + ROLE_NOT_EXIST(9020,"角色不存在 "), + + ROLE_DATA_SCOPE_EMPTY(9020,"角色数据模型为空 "), + + USER_ROLE_NOT_EXIST(9020,"登录用户无角色信息,请联系管理员 "), + + ROLE_SYSTEM_FLAG(9020,"系统预设无法删除! "), + + /** + * 应用 + */ + APP_NOT_FOUND(1921,"应用不存在"), + + /** 组织机构 */ + DEPT_PARENT_NOT_EXIST(1010,"上级部门不存在"), + DEPT_CODE_REPEAT(1011,"部门代码重复"), + DEPT_NAME_REPEAT(1012,"部门名称重复"), + DEPT_NOT_EXIST(1013,"部门不存在"), + DEPT_DEL_FAIL(1014,"删除失败"), + DEPT_ERROR_FAIL(1015,"部门信息添加失败"), + DEPT_NOT_VALID(1016,"部门不合法"), + + + /** 教师 */ + TEACHER_GH_REPEAT(1030, "工号重复"), + TEACHER_NOT_EXIST(1031, "教师不存在"), + + TEACHER_CLASS_EXIST(1032, "班级已添加辅导员,无法添加,请重新选择!"), + + + /** 学生 */ + STU_XH_REPEAT(1050,"学号重复"), + STU_NOT_EXIST(1051, "学生不存在"), + + /** 白名单 */ + ALERT_WHITE_EXIST(1056,"此学生已存在于白名单中,请勿重复添加"), + ALERT_WHITE_NOT_STU(1057,"白名单用户只能为学生,请检查后提交"), + /** 文件 */ + REPORT_NOT_EXIST(1052,"分析报告不存在"), + ASSETS_PATH_NOT_EXIST(1052,"静态资源目录不存在"), + COMPOSE_FILE_ERROR(1053,"文件压缩失败"), + FILE_SUFFIX_NOT_ALLOWED(1054,"文件类型不合法"), + + FEEDBACK_SETTING_NOT_FOUND(1029,"反馈设置不存在"), + + WATERMARK_SETTING_NOT_FOUND(1029,"水印设置不存在"), + + + /** 预警分类 **/ + ALERT_TYPE_REPEAT(2023,"预警分类名称重复"), + ALERT_TYPE_DELETE(2024,"已产生对应预警事件分类数据,如需删除,请联系管理员"), + + USER_CANNOT_DELETE_ADMIN(9020, "超级管理员不能删除"), + + + USER_PERMISSION_ERROR(100105, "用户无权限,请联系管理员"), + + /** 用户组 */ + GROUP_NAME_NOT_EXIST(1060,"用户组名称不存在"), + GROUP_NAME_REPEAT(1061,"用户组名称重复"), + GROUP_OPENED_NOT_EXIST(1062,"用户组类型不存在"), + GROUP_USER_NOT_EXIST(1063,"用户组成员存在"), + GROUP_ID_NOT_EXIST(1064,"用户组ID不存在"), + + + YEAR_IS_NOT_VALID(5001,"学年不合法,请重新配置"), + SCHOOL_CALENDAR_SERVER_ERROR(5002,"节假日API服务异常"), + SCHOOL_CALENDAR_SETTING_NOT_FOUND(5003,"校历管理设置不存在"), + SCHOOL_CALENDAR_DATE_NOT_RANGE(5003,"设置的日期不在配置的时间范围内,请重新选择!"), + SCHOOL_CALENDAR_DURATION(5003,"节假日期间不允许同步预警"), + + /** + * 自定义表单 + */ + FORM_MAKING_NAME_REPEAT(1061,"表单名称重复"), + + FORM_NOT_VALID(4027,"表单数据格式不正确"), + + FORM_WIDGET_NOT_ALLOWED(1240, "不合法的表单字段"), + + + /** + * 文件 + */ + FILE_UPLOAD_FAIL(1870, "上传失败!"), + + + /** 字典 */ + DICT_TYPE_NOT_EXIST(1150, "字典不存在"), + + /** + * 用户认证 + */ + PWD_ERROR(1,"密码错误,请联系管理员"), + ACCOUNT_PWD_EMPTY(1, "账号或密码为空,请检查账号或密码"), + ACCOUNT_PWD_ERROR(2, "账号或密码错误,请检查账号或密码"), + VALID_CODE_ERROR(3, "验证码错误,请检查captcha参数"), + REQUEST_TOKEN_EMPTY(4, "请求token为空,请携带token访问本接口"), + NOT_VALID_TOKEN_TYPE(5, "token格式不正确,token请以Bearer开头,并且Bearer后边带一个空格"), + REQUEST_TOKEN_ERROR(6, "请求token错误"), + ACCOUNT_FREEZE_ERROR(7, "账号已停用,请联系管理员"), + LOGIN_EXPIRED(8, "登录已过期,请重新登录"), + NO_LOGIN_USER(9, "无登录用户"), + MODE_NOT_PERMISSION(10, "当前接口只允许在开发和测试环境调用"), + TEMP_USER_NO_PERMISSION(11, "临时用户无访问权限"), + USER_IS_NOT_ADMIN(12, "非管理员用户无法访问"), + + REFERER_ERROR(77, "REFER非法"), + PARAM_IS_INVALID(9001,"参数无效"), + PARAM_IS_BLANK(9002,"参数为空"), + PARAM_BAD_TYPE(9003,"参数类型错误"), + PARAM_MISSING(9004,"参数缺失"), + RESULT_EMPTY(9004, "查询结果为空"), + PARAM_PARSE_ERROR(9005,"参数解析异常"), + DOWNLOAD_FILE_ERROR(9006,"附件下载异常"), + ENV_NOT_ALLOWED(9001,"系统环境异常,请联系管理员"), + + FILE_UPLOAD_ERROR(1055,"文件上传失败"), + + SYSTEM_NOT_FOUND(3006, "应用不存在"), + + MODULE_NOT_FOUND(3006, "模块不存在"), + + + /** + *开放接口鉴权 + */ + AUTH_PARAM_APPKEY_NOT_FOUND(7001,"APP_KEY参数缺失"), + AUTH_PARAM_APPKEY_ERROR(7001,"APP_KEY参数错误"), + AUTH_PARAM_SIGN_NOT_FOUND(7002,"签名参数缺失"), + AUTH_PARAM_TIMESTAMP_NOT_FOUND(7003,"时间戳参数缺失"), + AUTH_PARAM_TIMESTAMP_ERROR(7004,"时间戳参数错误"), + AUTH_PARAM_SIGN_ERROR(7005,"签名校验失败"), + AUTH_PARAM_SIGN_TYPE_ERROR(7006,"签名类型不合法"), + AUTH_DATA_ACCOUNT_EMPTY(7100, "账号为空"), + + + TAG_NOT_EXIST(2001,"未找到标签"), + + TAG_FACTORY_NOT_CONFIG(2001,"标签工厂未配置"), + + TAG_FACTORY_SERVER_ERROR(9017, "标签工厂服务异常"), + TAG_FACTORY_SERVER_EMPTY(9017, "标签工厂服务返回为空"), + + TAG_FACTORY_URL_EMPTY(9018, "标签工厂地址未设置,无法配置同步预警对象,请先设置地址!"), + + TAG_FACTORY_CONFIG_ERROR(9019, "未设置标签工厂信息,请联系管理员"), + + AUTHORIZE_SETTING_ERROR(100102, "免登认证配置不合法,请检查配置"), + + /** + * 用户 + */ + USER_NOT_EXIST(9010,"用户不存在"), + USER_LOGIN_ERROR(9011,"账户不存在或密码错误"), + USER_ACCT_FORBIDDEN(9012,"账户已禁用"), + USER_HAS_EXIST(9013,"用户已存在"), + USER_ACCT_PWD_EMPTY(9014, "账号或密码为空"), + USER_AUTH_FAIL(9015, "认证失败"), + AUTH_WXWORK_NO_CODE(9016, "企业微信认证失败:code 参数为空"), + AUTH_CAS_NO_TICKET(9017, "CAS认证失败:ticket 参数为空"), + + AUTH_SC_CAS_NO_UID(9017, "CAS认证失败:uid 参数为空"), + + USER_PHONE_EXIST(9018,"手机号已存在"), + + SOURCE_NOT_EXIST(1136, "资源不存在"), + + + ALERT_STATUS_ERROR(2001,"预警状态异常"), + + ALERT_TAG_FLOW_NOT_EXIST(2001,"预警标签未配置流程"), + + ALERT_NOT_EXIST(2001,"未找到预警信息"), + ALERT_TAG_NOT_EXIST(2001,"预警事件不存在"), + ALERT_TEMPLATE_NOT_EXIST(2001,"预警模板不存在"), + ALERT_TEMPLATE_RULE_INSTALLED(2001,"预警模板已安装"), + ALERT_TEMPLATE_NAME_REPEAT(2001,"预警模板已重复"), + + + /** + * 机构管理 + */ + DELETE_HAS_SUB_DEPART(3000, "本部门存在下级部门,不允许删除"), + DELETE_HAS_USERS_IN_DEPART(3001, "部门内存在成员,不允许删除"), + CONTACT_MANAGER_NOT_EXIST(3002, "管理组不存在"), + CONTACT_MANAGER_MORE_ONE(3003, "一个用户只能存在一个管理组中"), + CONTACT_MANAGER_SUPER_ADMIN_CANNOT_SET(3004, "超级管理员不能添加到任何权限组"), + CONTACT_MANAGER_SYSTEM_DELETE(3005, "系统管理组不能删除"), + CONTACT_MANAGER_SYSTEM_UPDATE(3006, "系统管理组不能编辑"), + CONTACT_MANAGER_USER_NOT_IN(3007, "当前用户不是管理员"), + + + /** + * 开放平台 + */ + PLUGIN_CODE_REPEAT(7200,"插件已存在,请勿重复添加"), + PLUGIN_CODE_NOT_EXIST(7201,"插件不存在,请联系管理员"), + + + + INSTANCE_STAGE_ERROR(992,"流程实例状态异常"), + + INSTANCE_STAGE_FINISHED(993,"流程已结束,请勿重复操作"), + + INSTANCE_STAGE_COMPETED(994,"流程已完成,请勿重复操作"), + + HANDLER_USER_NOT_EXIST(995,"处理人不存在,请联系系统管理员"), + + DEFINITION_NOT_EXIST(996,"未找到流程配置信息"), + + DEFINITION_RUNNING_NODE_NOT_EXIST(997,"未找到正在运行的流程定义"), + + DEFINITION_NODE_NOT_EXIST(998,"未找到流程节点配置信息"), + + DEFINITION_NODE_FLOW_RULE_NOT_EXIST(998,"未找到流程节点流转规则配置"), + + NODE_TYPE_NOT_EXIST(999,"节点类型不存在"), + + NODE_START_NOT_EXIST(1000,"开始节点不存在"), + + NODE_CHECKER_TASK_NOT_EXIST(1001,"任务不存在"), + + NODE_STARTING_TRIGGER_SCENE_NOT_PERMISSION(1002,"节点不满足触发场景条件"), + + NODE_OPERATION_NOT_EXIST(1003,"节点操作类型不存在"), + + NODE_STARTING_TRIGGER_FIELD_NOT_PERMISSION(1004,"节点不满足触发字段条件"), + + NODE_STARTING_TRIGGER_DATA_NOT_PERMISSION(1005,"节点不满足触发数据条件"), + + NODE_STARTING_DATA_NOT_PERMISSION(1006,"节点数据校验不满足条件"), + + NODE_NOT_EXIST(1007,"未找到流程节点"), + + NODE_NEXT_NOT_EXIST(1008,"找不到审核节点"), + + NODE_CHECKER_NOT_PERMISSION(1009,"当前用户无审核权限"), + + NODE_CHECKER_NOT_EXIST(1010,"审核节点审核人不存在"), + + FORWARD_USER_NOT_EXIST(1011,"转交人为空"), + + FORWARD_USER_ERROR(1012,"转交人不能是当前处理人"), + + INSTANCE_NOT_EXIST(1003,"流程数据不存在"), + + NODE_TYPE_ERROR(1014,"节点类型参数异常"), + + NODE_SUGGEST_NOT_EMPTY(1015,"审核节点文本意见不能为空"), + + NODE_SIGNATURE_NOT_EMPTY(1016,"审核节点手写签名不能为空"), + + PERMISSION_SUBMIT_NO_PERMISSION(1017,"当前处理人无发起流程权限"), + + TASK_HAS_EXPIRED(1017,"待办任务已失效,请刷新页面"), + + PERMISSION_FORWARD_NO_PERMISSION(1018,"当前处理人无转交处理流程权限"), + + PERMISSION_RECALL_NOT_OPEN(1019,"系统未开启撤回功能"), + + PERMISSION_RECALL_NO_PERMISSION(1020,"当前处理人无撤回流程权限"), + + PERMISSION_RECALL_APPROVAL_NO_PERMISSION(1021,"任务节点已有人提交,发起人无法撤回"), + + PERMISSION_ROLLBACK_NOT_OPEN(1022,"系统未开启回退功能"), + + ROLLBACK_KEY_NOT_EXIST(1022,"回退节点不存在"), + + ROLLBACK_NODE_NOT_PERMISSION(1027,"回退节点不合法"), + + ROLLBACK_START_USER_NOT_EXIST(1028,"流程为匿名填报,无法回退到开始节点"), + + ROLLBACK_TASK_USER_NOT_EXIST(1029,"流程回退节点找不到负责人,请检查流程设定配置"), + + MOVING_NEXT_NODE_NOT_EXIST(1023,"找不到下一节点,流程无法流转"), + + MOVING_NEXT_NODE_CHECKER_NOT_EXIST(1024,"未找到下一个节点审核人"), + + NODE_FLOW_ERROR(1025,"提交失败,不符合流转条件"), + + INVALID_OPERATION(1026,"无效的操作类型"), + + INSTANCE_STATUS_ERROR(1028,"流程状态异常"), + + NODE_ACTIVE_NOT_EXIST(1029,"找不到激活节点"), + + SETTING_ARCHIVE_NOT_EXIST(1029,"归档设置异常,请检查流程设置"), + + ARCHIVE_USER_NOT_PERMISSION(1030,"用户无权限发起归档"), + + CC_USER_NOT_PERMISSION(1031,"用户无权限发起抄送"), + + CC_USER_NOT_EXIST(1031,"抄送用户不存在"), + + CC_TASK_NOT_EXIST(1032,"抄送任务不存在"), + + ENGINE_RESULT_EMPTY(1033,"流程引擎结果为空"), + + FLOW_RUNTIME_EXCEPTION(1034, "流程引擎发生异常,请联系管理员"), + + FLOW_STAGE_ERROR(1034, "存在未处理的预警,请检查后重新提交"), + + + NODE_CHECKER_USER_LIMIT(1035,"节点审核人数量不能超过100人"), + + NODE_CC_USER_LIMIT(1036,"节点抄送人数量不能超过100人"), + + FORM_DATA_HAS_DELETE(1037,"数据已被删除"), + + FORM_DETAIL_NOT_EXIST(1134, "表单信息不存在"), + + + TASK_NOT_EXIST(1038,"该流程已被处理或撤回"), + + TASK_PARAM_NOT_EXIST(1039,"待办参数不存在"), + + TASK_HAS_HANDLED(1040,"待办任务已处理"), + + TASK_PROCESSING_HAS_CHANGED(1040,"待办任务已在处理中状态,请勿重复更新"), + + + NODE_TRANSFER_CHECKER_NOT_CHANGE(1041,"流程负责人未改动"), + + NODE_TRANSFER_CHECKER_EMPTY(1042,"流程负责人为空"), + + USER_NOT_PERMISSION(1043,"用户无权限"), + + ROLE_NOT_PERMISSION(1043,"该角色暂无权限访问系统"), + + FLOW_INSTANCE_STARTER_NOT_FOUND(1044,"未找到流程发起人"), + + FLOW_INSTANCE_URGE_CLOSED(1045,"流程设定未开启催办"), + + FLOW_INSTANCE_URGE_LIMITED(1046,"5分钟内至多发送一次督办提醒"), + + FLOW_INSTANCE_URGE_NODE_ERROR(1046,"流程实例异常,请稍后再试"), + + FORM_PERMISSION_FAIL(1300, "用户无表单访问权限"), + FLOW_DEFINITION_NOT_EXIST(1301, "流程定义不存在"), + FLOW_DEFINITION_START_PROCESS_NOT_EXIST(1302, "流程定义开始节点不存在"), + FLOW_INSTANCE_FAIL(1303, "表单已填报,请勿重复填报"), + FLOW_INSTANCE_NOT_EXIST(1304, "流程实例不存在"), + FLOW_INSTANCE_STATUS_ERROR(1306, "流程实例状态异常"), + DATASOURCE_NOT_FOUND(1281, "找不到数据源"), + + FLOW_DRAFT_SUCCESS(1344, "草稿保存成功"), + + FLOW_URGE_SUCCESS(1344, "已提醒负责人处理"), + + FLOW_INSTANCE_PROCESS_NOT_EXIST(1305, "流程实例节点不存在"), + FLOW_INSTANCE_CC_NOT_EXIST(1306, "实例抄送不存在"), + FLOW_INSTANCE_EXIST(1305, "存在流程实例"), + + FLOW_PERMISSION_RECALL_FAIL(1320, "用户无权限撤回"), + FLOW_APPROVAL_NOT_PERMISSION(1321, "当前用户无审核权限"), + FLOW_ROLLBACK_NOT_PERMISSION(1323, "当前用户无权限退回该流程"), + FLOW_INSTANCE_NOT_SUBMIT(1322, "实例还没填报"), + FLOW_DEFINITION_NOT_APPROVER(1323, "审批节点未设置审核人"), + FLOW_DEFINITION_INSTANCE_EXIST(1325, "该流程定义存在运行实例"), + FLOW_DEFINITION_EXIST(1327, "流程定义已存在"), + FLOW_VERSION_FORM_ERROR(1326, "表单状态异常"), + FLOW_DEFINITION_PARAM_ERROR(1327, "流程参数异常"), + FLOW_USER_ROLE_NOT_PERMISSION(1328, "用户身份校验失败"), + FLOW_DEFINITION_NODE_NOT_EXIST(1329, "流程定义节点数据不存在"), + FLOW_FORM_NOT_PERMISSION(1330, "表单参数异常"), + FLOW_LINE_ELSE_CONDITION_ERROR(1331, "连接线存在多个else条件"), + FLOW_BUTTON_ROLLBACK_ERROR(1332, "未找到回退按钮"), + FLOW_DEFINITION_VERSION_NOT_EXIST(1333, "未找到流程定义"), + FLOW_INSTANCE_NOT_FINISHED(1334, "实例未结束"), + FLOW_ENDNODE_NOT_EXIST(1335, "未找到结束节点"), + FLOW_NEXT_PROCES_NOT_EXIST(1324, "提交失败,找不到下个审核节点,可联系管理员检查流程节点后重新提交。"), + FLOW_LINE_CONDITION_ERROR(1331, "提交失败,不符合流转条件,可联系管理员检查流转条件后重新提交。"), + FLOW_NEXT_NODE_CHECKER_MISSING(1336, "提交失败,找不到下个节点负责人,可联系管理员检查节点负责人后重新提交。"), + FLOW_INSTANCE_STAGE_NOT_APPROVAL(1337, "抱歉,审核任务已过期"), + FLOW_APPROVAL_PERMISSION_ERROE(1338, "抱歉,你没有审核权限"), + FLOW_DEFINITION_VERSION_STAGE_ERROR(1339, "流程版本状态异常"), + FLOW_FORM_FIELD_PERMISSION(1340, "节点未设置表单字段"), + FLOW_FORM_APPROVAL_NOT_EXIST(1341, "审核节点未设置审核人"), + FLOW_NODE_COUNT_ERROR(1342, "回退节点数量异常"), + + FLOW_INSTANCE_STAGE_FINISHED(1343, "抱歉,审核任务已结束"), + FLOW_INSTANCE_STAGE_RECALL(1344, "抱歉,审核任务已撤回"), + + CHECK_PARAM_TIME_ERROR(4000, "登记时间参数格式异常"), + + /** + * 业务异常 + */ + MODULE_NAME_REPEAT(2, "模块已存在,请检查后提交"), + FORM_NAME_REPEAT(2, "表单已存在,请检查后提交"), + MENU_NAME_REPEAT(2, "数据中心已存在,请检查后提交"), + + MENU_NAME_DEFAULT(2, "默认的数据中心只能有一个,请检查后在提交"), + MODULE_NOT_EXIST(1001,"模块不存在"), + MODULE_FIELD_NOT_EXIST(1002,"模块字段为空"), + + SCHOOL_NOT_INIT(1004,"学校基础信息未初始化,无法同步师生数据"), + + + DATASOURCE_TYPE_NOT_SUPPORTED(1003,"数据源目前不支持此类型"), + + ES_RETURN_EMPTY(2, "数据分析平台返回数据为空!"), + + + CLASS_RETURN_EMPTY(2, "班级信息为空!"), + + FACULTY_RETURN_EMPTY(2, "学院信息为空!"), + + USER_RETURN_EMPTY(2, "用户信息为空!"), + + + DEPART_TYPE_EMPTY(9020,"部门类型为空 "), + + DEPART_NOT_FOUND(9020,"用户部门不能为空 "), + + USER_MUST_INSTRUCTOR(2005,"用户角色只能为辅导员"), + + + /***********************************通讯录相关 start***************************************/ + SYNC_TYPE_EMPTY(2, "同步通讯录类型不存在!"), + SYNC_TYPE_TASK_EMPTY(2, "同步通讯录存储过程类型不存在!"), + ES_INDEX_RETURN_EMPTY(2404, "同步索引未进行配置,请进行配置!"), + SYNC_TEACHER_INDEX_NOT_EXIST(1005,"同步教师数据索引不存在"), + SYNC_STUDENT_INDEX_NOT_EXIST(1006,"同步学生数据索引不存在"), + SYNC_FACULTY_INDEX_NOT_EXIST(1007,"同步学院数据索引不存在"), + SYNC_CLASS_INDEX_NOT_EXIST(1008,"同步班级数据索引不存在"), + SYNC_TEACHER_CLASS_INDEX_NOT_EXIST(1009,"同步带班数据索引不存在"), + ES_SERVER_ERROR(1010,"网络异常/连接ES平台异常"), + + OBJECT_FIELD_NOT_VALID(1011,"数据不合法"), + + OBJECT_FIELD_FACULTY_NOT_VALID(1012,"学院数据不合法"), + OBJECT_FIELD_CLASS_NOT_VALID(1013,"班级数据不合法"), + OBJECT_FIELD_ACCOUNT_NOT_VALID(1014,"教师工号数据不合法"), + OBJECT_FIELD_PARENT_CODE_NOT_VALID(1015,"父类编码数据不合法"), + + + + /***********************************通讯录相关 end***************************************/ + + + /***********************************预警子系统 start***************************************/ + + ALERT_RULE_NOT_EXIST(100101,"预警规则不存在"), + NOTIFY_CONFIG_NOT_FOUND(100102, "提醒配置信息未找到"), + TIMER_CRON_ERROR(100103, "定时设置不合法,请检查配置"), + FORM_NOT_EXIST(100104, "自定义表单不存在,请联系管理员"), + + OPEN_TAG_NOT_EXIST(9004, "未找到合法的预警模型"), + + SYNC_RESULT_EMPTY(9004, "预警同步结果为空"), + + + + /***********************************预警子系统 end***************************************/ + + + + COMPONENT_NOT_FOUND(3005,"组件不存在"), + + /***********************************陪伴子系统 start***************************************/ + + /** 陪伴主题 **/ + ACMP_THEME_NOT_EXIST(2002,"陪伴主题不存在"), + + ACMP_THEME_DELETE(2003,"已产生对应陪伴数据,如需删除,请联系管理员"), + + ACMP_THEME_REPEAT(2004,"主题名称重复"), + + /** 陪伴选项分类 **/ + ACMP_TYPE_REPEAT(2005,"选项分类名称重复"), + + ACMP_TYPE_DELETE(2003,"分类已有陪伴选项关联,如需删除,请联系管理员"), + + ACMP_TYPE_NOT_EXIST(2002,"选项分类不存在"), + + /** 陪伴中心**/ + + ACMP_DATA_NOT_EXIST(2006,"陪伴数据不存在"), + + ACMP_DATA_NOT_SUPPORT_UPLOAD(2007,"该陪伴数据不支持上传"), + + ACMP_SETTING_DISPOSE_NOT_EXIST(2004,"未设置陪伴方式,请联系管理员"), + + ACMP_SYSTEM_NOT_EXIST(2002,"陪伴体系不存在"), + ACMP_SYSTEM_NAME_REPEAT(2005,"选项体系名称重复"), + + + ACMP_SYSTEM_CANT_DELETE(2002,"陪伴体系存在陪伴数据,无法删除"), + + + ACMP_OPTION_NOT_EXIST(2002,"陪伴选项不存在"), + + ACMP_OPTION_CANT_DELETE(2002,"陪伴选项存在陪伴数据,无法删除"), + + ACMP_OPTION_NAME_REPEAT(2005,"选项选项名称重复"), + + + ACMP_UPLOAD_FAIL(2006,"陪伴数据上传失败"), + + ACMP_ADD_FAIL(2006,"创建陪伴记录失败"), + + + ACMP_CONFIG_MISS(2007,"缺少陪伴上报配置"), + + ACMP_ADD_NOT_STUDENT(2008,"一对多陪伴未设置陪伴学生!"), + + + /***********************************陪伴子系统 end***************************************/ + + + /***********************************关注子系统 start***************************************/ + + FOLLOW_STUDENT_NOT_FOLLOWED(100301,"您未关注该学生,无法取消关注"), + + FOLLOW_EXCEL_ERROR(100302,"批量关注Excel格式不正确"), + + /***********************************关注子系统 end***************************************/ + + + /***********************************考核子系统 start***************************************/ + CHECK_USER_MUST_INSTRUCTOR(2005,"参与考核成员必须为辅导员"), + ASSESS_FOLLOW_STUDENT_NOT_FOUND(2005,"未找到关注学生陪伴考核陪伴信息"), + + ASSESS_RECOMMEND_STUDENT_NOT_FOUND(2005,"未找到关注学生陪伴考核陪伴信息"), + + /***********************************考核子系统 end***************************************/ + MESSAGE_NOT_FOUND(1046,"消息不存在"), + + + /***********************************学生预约辅导员 start***************************************/ + RESERVATION_NOT_EXIST(1046,"未找到学生预约记录"), + RESERVATION_RULE_NOT_OPEN(1046,"辅导员未开启预约"), + RESERVATION_RULE_DAY_RULE_EMPTY(1002,"未找到当天预约内容"), + RESERVATION_RULE_DAY_RULE_PERIOD_NOT_FOUND(1002,"未找到当天预约时段,请联系辅导员"), + RESERVATION_PERIOD_OVERDUE(1002,"预约时段已过期,请刷新页面"), + RESERVATION_USER_REPEATED(1002,"请勿重复预约"), + + RESERVATION_CANCEL_USER_NO_PERMISSION(1002,"非本人无权限撤回预约"), + + RESERVATION_INSTRUCTOR_NOT_EXIST(1002,"未找到辅导员信息,请联系管理员"), + + RESERVATION_STUDENT_NOT_EXIST(1002,"未找到学生,请联系管理员"), + + + RESERVATION_FINISH_COMMENT_NOT_EXIST(1046,"预约沟通结果不能为空"), + + + /***********************************学生预约辅导员 end***************************************/ + + + /***********************************我爱记学生子系统 start***************************************/ + + ASSESS_CONFIG_NOT_EXIST(2002,"考试配置不存在"), + ASSESS_CONFIG_NAME_EXIST(2002,"存在名称重复的考试,请修改考试名称"), + + ASSESS_QUESTION_CONFIG_NOT_EXIST(2002,"考试题库配置不存在,请联系管理员"), + ASSESS_QUESTION_EMPTY_ERROR(2002,"考试未设置题目,请检查考试题目配置"), + ASSESS_QUESTION_CONFIG_ERROR(2002,"题库配置错误,请检查题库是否配置了不存在的学生属性"), + ASSESS_EXAM_RECORD_NOT_FOUND(2002,"您已提交本次考试结果,请勿重复提交"), + ASSESS_TRAIN_RECORD_NOT_FOUND(2002,"很抱歉,未找到您的本次训练成绩,请联系管理员"), + + EXAM_QUESTION_OVER_LIMIT(2002,"单场考试至多500道题目"), + + ASSESS_RECORD_DELETE_ERROR(2002,"考试记录已删除,无法再次删除"), + ASSESS_RECORD_LEVEL_EXISTS(2002,"考试成绩已存在,不能再次提交答卷"), + ASSESS_CONFIG_NOT_STU(2002,"本次考试未找到符合条件的学生信息,请联系管理员"), + ASSESS_CONFIG_NOT_START(2002,"未到考试时间,无法参加考试"), + ASSESS_CONFIG_HAS_FINISHED(2002,"考试已结束"), + ASSESS_CONFIG_NOT_TIMES(2002,"您已经参加过本次考试,请勿重复考试"), + ASSESS_CONFIG_NOT_INSTRS(2002,"无考试权限:不在考试名单中,请联系管理员"), + ASSESS_RECORD_OVER_LIMIT(2002,"您目前仍有一条正在考试的记录,请先提交该考试成绩"), + ASSESS_RECORD_PERMISSION_ERROR(2002,"您没有查看此记录的权限"), + ASSESS_QUESTION_NOT_EXIST(2002,"未找到训练题目"), + + ASSESS_EXAM_HAS_RECORD(2002,"当前考试有考生正在考试,请勿操作"), + + ASSESS_RECORD_NOT_FOUND(2002,"该数据已被删除或者您没有查看该数据的权限"), + + TEACHER_NOT_FOUND(2002,"没有教师数据权限"), + + DATASOURCE_NOT_EXIST(1003,"未配置数据源,请联系管理员"), + + DATASOURCE_DEFAULT_NOT_EXIST(1003,"未配置默认数据源,请联系管理员"), + + + /***********************************我爱记学生子系统 end***************************************/ + + + /***********************************公权力监督 start***************************************/ + + PORTRAIT_TITLE_REPEAT(2006,"画像名称重复"), + + PORTRAIT_NOT_EXIST(2007,"画像不存在"), + + PORTRAIT_DELETE(2003,"已有对应的组件配置,如需删除,请联系管理员"), + + TEMPLATE_TITLE_REPEAT(2008,"模板名称重复"), + TEMPLATE_NOT_EXIST(2009,"模板不存在"), + + PORTRAIT_DASHBOARD_NOT_EXIST(2007,"数据看板不存在"), + + DATACORRECTION_SETTING_NOT_FOUND(1029,"数据纠错表单地址不存在"), + DATACOLLECTION_SETTING_NOT_FOUND(1029,"数据采集表单地址不存在"), + + PORTRAIT_EDIT_USER_NOT_PERMISSION(1029,"用户无权限编辑画像"), + PORTRAIT_DELETE_USER_NOT_PERMISSION(1029,"用户无权限删除画像"), + PORTRAIT_VIEW_USER_NOT_PERMISSION(1029,"用户无权限查看画像"), + + DASHBOARD_EDIT_USER_NOT_PERMISSION(1029,"用户无权限编辑数据看板"), + + DASHBOARD_DELETE_USER_NOT_PERMISSION(1029,"用户无权限删除数据看板"), + DASHBOARD_VIEW_USER_NOT_PERMISSION(1029,"用户无权限查看数据看板"), + + VISIT_CODE_IS_EMPTY(1029,"公开访问码为空"), + + VISIT_CODE_IS_NOT_CORRECT(1029,"访问码不正确"), + + PORTRAIT_NOT_RELEASE(1029,"画像未发布,请联系管理员"), + + /***********************************公权力监督 end***************************************/ + + //region 进度模块错误 + TASK_RUNNING(3000,"当前任务正在运行中"), + TASK_NOT_RUNNING(3001,"任务不处于运行状态"), + + TASK_NAME_NOT_NULL(3002,"任务名称不能为空"), + //endregion + + //region 画像模块相关错误码 + + ES_CLIENT_INIT_ERROR(10000,"es数据源链接失败"), + ES_CLIENT_ERROR(10001,"es连接错误"), + + + PROJECT_NOT_EXIST(1029,"科研项目未找到"), + + PROJECT_ALERT_EMPTY(2023,"科研项目数据为空"), + + OBJECT_SCHEMA_NOT_FOUND(2001,"数据接入未设置"), + + PROJECT_SQL_NOT_CONFIG(2002,"查询语句未配置"), + + + + ES_INDEX_NOT_EXIST(10001,"未找到数据盒,请检查数据盒配置"), + + //endregion + ; + + + private Integer code; + private String message; + + WorkflowResultCode(Integer code, String message){ + this.code = code; + this.message = message; + } + + public Integer code() { + return code; + } + + public String message() { + return message; + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/common/response/WorkflowSuccessResponseData.java b/dk-common/common-workflow/src/main/java/org/dromara/common/response/WorkflowSuccessResponseData.java new file mode 100644 index 0000000..af1318d --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/common/response/WorkflowSuccessResponseData.java @@ -0,0 +1,44 @@ +/* +Copyright [2020] [https://www.stylefeng.cn] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Guns采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点: + +1.请不要删除和修改根目录下的LICENSE文件。 +2.请不要删除和修改Guns源码头部的版权声明。 +3.请保留源码和相关描述文件的项目出处,作者声明等。 +4.分发源码时候,请注明软件出处 https://gitee.com/stylefeng/guns-separation +5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/stylefeng/guns-separation +6.若您的项目无法满足以上几点,可申请商业授权,获取Guns商业授权许可,请在官网购买授权,地址为 https://www.stylefeng.cn + */ +package org.dromara.common.response; + +/** + * 成功响应结果 + * + */ +public class WorkflowSuccessResponseData extends WorkflowResponseData { + + public WorkflowSuccessResponseData() { + super(true, DEFAULT_SUCCESS_CODE, DEFAULT_SUCCESS_MESSAGE, null); + } + + public WorkflowSuccessResponseData(Object object) { + super(true, DEFAULT_SUCCESS_CODE, DEFAULT_SUCCESS_MESSAGE, object); + } + + public WorkflowSuccessResponseData(Integer code, String message, Object object) { + super(true, code, message, object); + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/common/util/HttpServletUtil.java b/dk-common/common-workflow/src/main/java/org/dromara/common/util/HttpServletUtil.java new file mode 100644 index 0000000..8f9bfa8 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/common/util/HttpServletUtil.java @@ -0,0 +1,68 @@ +/* +Copyright [2020] [https://www.stylefeng.cn] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Guns采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点: + +1.请不要删除和修改根目录下的LICENSE文件。 +2.请不要删除和修改Guns源码头部的版权声明。 +3.请保留源码和相关描述文件的项目出处,作者声明等。 +4.分发源码时候,请注明软件出处 https://gitee.com/stylefeng/guns-separation +5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/stylefeng/guns-separation +6.若您的项目无法满足以上几点,可申请商业授权,获取Guns商业授权许可,请在官网购买授权,地址为 https://www.stylefeng.cn + */ +package org.dromara.common.util; + + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.dromara.common.Exception.ServiceException; +import org.dromara.common.response.WorkflowResultCode; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + + +/** + * HttpServlet工具类,获取当前request和response + * + + */ +public class HttpServletUtil { + + /** + * 获取当前请求的request对象 + * + */ + public static HttpServletRequest getRequest() { + ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + if (requestAttributes == null) { + throw new ServiceException(WorkflowResultCode.PARAM_IS_BLANK); + } else { + return requestAttributes.getRequest(); + } + } + + /** + * 获取当前请求的response对象 + * + */ + public static HttpServletResponse getResponse() { + ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + if (requestAttributes == null) { + throw new ServiceException(WorkflowResultCode.PARAM_IS_BLANK); + } else { + return requestAttributes.getResponse(); + } + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/common/util/JsonUtil.java b/dk-common/common-workflow/src/main/java/org/dromara/common/util/JsonUtil.java new file mode 100644 index 0000000..64e356b --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/common/util/JsonUtil.java @@ -0,0 +1,128 @@ +package org.dromara.common.util; + +import cn.hutool.core.util.ObjectUtil; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.lang3.StringUtils; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * 定义响应结构 + */ +public class JsonUtil { + + private static ObjectMapper MAPPER; + static{ + MAPPER=new ObjectMapper(); + } + + /** + * 将对象转换成json字符串。 + *

Title: pojoToJson

+ *

Description:

+ * @param data + * @return + */ + public static String toJson(Object data){ + String string = null; + try { + string = MAPPER.writeValueAsString(data); + if(StringUtils.isEmpty(string)){ + return null; + } + return string; + } catch (JsonProcessingException e) { + e.printStackTrace(); + return null; + } + } + + /** + * 将json结果集转化为对象 + * + * @param jsonData json数据 + * @return + */ + public static T jsonToPojo(String jsonData, Class beanType) { + try { + T t = MAPPER.readValue(jsonData, beanType); + return t; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /** + * 将json数据转换成pojo对象list + *

Title: jsonToList

+ *

Description:

+ * @param jsonData + * @param beanType + * @return + */ + public static List jsonToList(String jsonData, Class beanType) { + JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType); + try { + List list = MAPPER.readValue(jsonData, javaType); + return list; + } catch (Exception e) { + e.printStackTrace(); + } + + return null; + } + + /** + * 将Object对象里面的属性和值转化成Map对象 + * + * @param obj + * @return + * @throws IllegalAccessException + */ + public static Map objectToMap(Object obj){ + try { + Map map = new HashMap(); + Class clazz = obj.getClass(); + for (Field field : clazz.getDeclaredFields()) { + field.setAccessible(true); + String fieldName = field.getName(); + if(ObjectUtil.isNotEmpty(field.get(obj))){ + Object value = field.get(obj); + map.put(fieldName, value); + }else{ + map.put(fieldName, ""); + } + } + return map; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + public static Map jsonToMap(String json){ + try { + return MAPPER.readValue(json, new TypeReference>(){}); + } catch (JsonProcessingException e) { + e.printStackTrace(); + return null; + } + } + + public static LinkedHashMap jsonToStrMap(String json){ + try { + return MAPPER.readValue(json, new TypeReference>(){}); + } catch (JsonProcessingException e) { + e.printStackTrace(); + return null; + } + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/controller/FormDataController.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/controller/FormDataController.java new file mode 100644 index 0000000..64d351d --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/controller/FormDataController.java @@ -0,0 +1,87 @@ +package org.dromara.dataManager.controller; + + +import org.dromara.common.response.WorkflowResponseData; +import org.dromara.common.response.WorkflowResult; +import org.dromara.dataManager.param.FormDataParam; +import org.dromara.dataManager.param.UpdateDataParams; +import org.dromara.dataManager.service.FormDataService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + + +/** + * 表单数据服务API + * + */ +@RestController +@RequestMapping("/form") +public class FormDataController { + + @Autowired + private FormDataService formDataService; + + + /** + * 列表查询表单数据 + */ + @GetMapping("/data/page") + public WorkflowResponseData pageFormData(FormDataParam param) { + return WorkflowResult.success(formDataService.pageFormData(param)); + } + + + /** + * 添加表单数据 + */ + @PostMapping("/data/add") + public WorkflowResponseData addTFormData( + @RequestBody @Validated(FormDataParam.add.class) FormDataParam param) { + + return WorkflowResult.success(formDataService.addFormData(param)); + } + + + /** + * 编辑表单数据 + */ + @PostMapping("/{formId}/data/{dataId}/edit") + public WorkflowResponseData editFormData( + @PathVariable("formId")Long formId,@PathVariable("dataId")Long dataId, + @RequestBody UpdateDataParams param) { + + return WorkflowResult.success(formDataService.editFormData(param)); + } + + + /** + * 查询单个表单数据 + */ + @GetMapping("/{formId}/data/{dataId}/detail") + public WorkflowResponseData getFormDataDetail(@PathVariable("formId")Long formId, @PathVariable("dataId")Long dataId) { + + return WorkflowResult.success(formDataService.getFormDataFullInfo(formId,dataId)); + } + + + /** + * 删除表单数据 + */ + @PostMapping("/{formId}/data/{dataId}/delete") + public WorkflowResponseData deleteFormData(@PathVariable("formId")Long formId, @PathVariable("dataId")Long dataId) { + + return WorkflowResult.success(formDataService.deleteFormData(dataId)); + } + + /** + * 导出表单数据 + */ + @GetMapping("/data/export") + public void exportFormData(FormDataParam param) { + + } + +} + + diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/controller/FormDataExcelController.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/controller/FormDataExcelController.java new file mode 100644 index 0000000..f70cac0 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/controller/FormDataExcelController.java @@ -0,0 +1,96 @@ +package org.dromara.dataManager.controller; + + +import jakarta.servlet.http.HttpServletResponse; +import org.dromara.common.response.WorkflowResponseData; +import org.dromara.common.response.WorkflowResult; +import org.dromara.common.response.WorkflowResultCode; +import org.dromara.dataManager.param.DownloadDataParams; +import org.dromara.dataManager.param.ImportDataParams; +import org.dromara.dataManager.service.impt.exception.ImportDataInvalidException; +import org.dromara.dataManager.service.impt.service.ImportFromExcelService; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.json.JSONUtil; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.Map; + +/** + * @description: 表单数据导入、导入 + */ +@Slf4j +@RestController +@RequestMapping({"/manager/data","/data"}) +public class FormDataExcelController { + + @Autowired + private ImportFromExcelService importFromExcelService; + + /** + * 数据导出 + * + * @param params + * @param response + * @throws IOException + */ + @PostMapping("/export") + public void export(@RequestBody @Validated DownloadDataParams params, HttpServletResponse response) throws IOException { + // exportESDataService.exportData(params, response); + } + + /** + * 导入前预览 + * + * @param params + * @return + * @throws Exception + */ + @PostMapping("/import/preview") + public WorkflowResponseData previewExcel(@RequestParam("file") MultipartFile file, ImportDataParams params) throws Exception { + return WorkflowResult.success(importFromExcelService.previewExcel(file,params.getSheetIndex())); + } + + /** + * 数据导入 + * + * @param params + * @return + * @throws Exception + */ + @PostMapping("/import") + public WorkflowResponseData importExcelData(ImportDataParams params) { + + try { + Map realMapping = new ObjectMapper().readValue(params.getMapping(), new TypeReference>() {}); + params.setObjMapping(realMapping); + params.setValidationConfig(JSONUtil.toBean(params.getValidationConfigStr(), ImportDataParams.ValidationConfig.class)); + return WorkflowResult.success(importFromExcelService.importV2(params)); + } catch (ImportDataInvalidException e) { + return CollectionUtil.isEmpty(e.getInvalidRows()) ? WorkflowResult.error(e.getMessage()) : WorkflowResult.error(WorkflowResultCode.FAIL, e.getInvalidRows()); + } catch (Exception e) { + log.error(e.getMessage(), e); + return WorkflowResult.error("导入数据异常" + e.getMessage()); + } + } + + /** + * 下载导入数据模板 + * + * @param params + * @param + * @throws Exception + */ + @PostMapping("/import/template") + public void generateImportTemplate(@RequestBody ImportDataParams params, + HttpServletResponse response) throws Exception { + importFromExcelService.generateImportTemplate(response, params.getFormId(), params.getExportFields()); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/controller/FormDataInstanceController.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/controller/FormDataInstanceController.java new file mode 100644 index 0000000..574e9ed --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/controller/FormDataInstanceController.java @@ -0,0 +1,133 @@ +package org.dromara.dataManager.controller; + + +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.response.WorkflowResponseData; +import org.dromara.common.response.WorkflowResult; +import org.dromara.common.response.WorkflowResultCode; +import org.dromara.dataManager.param.ActiveDataParams; +import org.dromara.dataManager.param.TransferDataParams; +import org.dromara.dataManager.param.UpdateDataParams; +import org.dromara.dataManager.service.FormDataService; +import org.dromara.workflow.engine.domain.Instance; +import org.dromara.workflow.result.engine.BaseActionResult; +import org.dromara.workflow.result.engine.EngineDataResult; +import org.dromara.workflow.service.external.FlowInstanceService; +import cn.hutool.core.util.ObjectUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @desc 数据管理API + */ +@RestController +@RequestMapping({"/manager/data"}) +public class FormDataInstanceController { + @Autowired + private FlowInstanceService instanceService; + @Autowired + private FormDataService formDataService; + + /** + * 调整流程负责人 + * @param param + * @return + */ + @PostMapping("/instance/transfer") + public WorkflowResponseData transfer(@RequestBody TransferDataParams param){ + if(ObjectUtil.hasEmpty(param.getDataId(),param.getData(),param.getFormId(),param.getTransferNodeId(), + param.getCheckers())){ + return WorkflowResult.error(WorkflowResultCode.PARAM_MISSING); + } + + Instance instance = instanceService.getInstance(param.getDataId()); + + //更新流程节点调整负责人 + BaseActionResult actionRsp = instanceService.transferInstanceUser(instance,param.getTransferNodeId(),param.getCheckers()); + + if(actionRsp.getSuccess()){ + //更新表单流程数据 + EngineDataResult result = instanceService.transformInstanceDataResult(instance); + result.setUpdatorName(LoginHelper.getLoginUser().getNickname()); + param.getData().putAll(instanceService.getInstanceData(result)); + + UpdateDataParams item = new UpdateDataParams(param.getFormCode(), param.getDataId(),param.getData()); + item.setUser(LoginHelper.getLoginUser().getUserId(),LoginHelper.getLoginUser().getUsername(),LoginHelper.getLoginUser().getNickname()); + + formDataService.editFormData(item); + + return WorkflowResult.success(item.getData()); + } + + return WorkflowResult.error(actionRsp.getCode(),actionRsp.getMessage()); + } + + + /** + * 结束流程 + * @param param + * @return + */ + @PostMapping("/instance/finish") + public WorkflowResponseData finish(@RequestBody UpdateDataParams param){ + if(ObjectUtil.hasEmpty(param.getDataId(),param.getData(),param.getFormId())){ + return WorkflowResult.error(WorkflowResultCode.PARAM_MISSING); + } + Instance instance = instanceService.getInstance(param.getDataId()); + + //结束流程 + BaseActionResult actionRsp = instanceService.finishInstance(instance); + + if(actionRsp.getSuccess()){ + //更新表单流程数据 + EngineDataResult result = new EngineDataResult(instance); + result.setUpdatorName(LoginHelper.getLoginUser().getNickname()); + param.getData().putAll(instanceService.getInstanceData(result)); + + UpdateDataParams item = new UpdateDataParams(param.getFormCode(), param.getDataId(),param.getData()); + item.setUser(LoginHelper.getLoginUser().getUserId(),LoginHelper.getLoginUser().getUsername(),LoginHelper.getLoginUser().getNickname()); + formDataService.editFormData(item); + + return WorkflowResult.success(item.getData()); + } + + return WorkflowResult.error(actionRsp.getCode(),actionRsp.getMessage()); + } + + + /** + * 激活流程 + * feat_00141最新 + * @param param + * @return + */ + @PostMapping("/instance/active") + public WorkflowResponseData active(@RequestBody ActiveDataParams param){ + if(ObjectUtil.hasEmpty(param.getDataId(),param.getData(),param.getFormCode())){ + return WorkflowResult.error(WorkflowResultCode.PARAM_MISSING); + } + + Instance instance = instanceService.getInstance(param.getDataId()); + + //激活流程 + BaseActionResult actionRsp = instanceService.activeInstance(instance,param.getActiveNodeId(),param.getData()); + + if(actionRsp.getSuccess()){ + //更新表单流程数据 + EngineDataResult result = instanceService.transformInstanceDataResult(instance); + result.setUpdatorName(LoginHelper.getLoginUser().getNickname()); + param.getData().putAll(instanceService.getInstanceData(result)); + + UpdateDataParams item = new UpdateDataParams(param.getFormCode(), param.getDataId(),param.getData()); + item.setUser(LoginHelper.getLoginUser().getUserId(),LoginHelper.getLoginUser().getUsername(),LoginHelper.getLoginUser().getNickname()); + formDataService.editFormData(item); + + return WorkflowResult.success(item.getData()); + } + + return WorkflowResult.error(actionRsp.getCode(),actionRsp.getMessage()); + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/domain/FormData.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/domain/FormData.java new file mode 100644 index 0000000..7a18ab1 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/domain/FormData.java @@ -0,0 +1,97 @@ +package org.dromara.dataManager.domain; + +import com.baomidou.mybatisplus.annotation.*; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.Data; +import org.dromara.common.entity.WorkflowBaseEntity; + +import java.util.LinkedHashMap; + +/** + * 表单数据 + * + */ +@Data +@TableName(value = "t_form_data", autoResultMap = true) +public class FormData extends WorkflowBaseEntity { + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + + /** + * 表单id + */ + @TableField("form_id") + private Long formId; + + + /** + * 提交数据 + */ + @TableField(value = "form_data", typeHandler = JacksonTypeHandler.class) + private LinkedHashMap formData; + + + /** + * 流程实例id + */ + @TableField("instance_id") + private Long instanceId; + + + /** + * 流程状态 + */ + @TableField(value = "instance_stage",updateStrategy = FieldStrategy.IGNORED) + private String instanceStage; + + + /** + * 流程当前节点负责人 + */ + @TableField(value = "instance_checker",updateStrategy = FieldStrategy.IGNORED ) + private String instanceChecker; + + + /** + * 流程实例节点信息 + */ + @TableField(value = "instance_node",updateStrategy = FieldStrategy.IGNORED) + private String instanceNode; + + + /** + * 是否删除 + */ + @TableField("deleted") + private Boolean deleted; + + + + /** + * 创建人账号 + */ + @TableField("create_account") + private String createAccount; + + + + /** + * 创建人姓名 + */ + @TableField("create_name") + private String createName; + + + /** + * 最近一次更新人姓名 + */ + @TableField("update_user_name") + private String updateUserName; + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/domain/FormDataLog.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/domain/FormDataLog.java new file mode 100644 index 0000000..f2c53cc --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/domain/FormDataLog.java @@ -0,0 +1,174 @@ +package org.dromara.dataManager.domain; + +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.serializer.SerializerFeature; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Map; +import java.util.TimeZone; + +/** + * 表单数据日志 + */ +@Data +@TableName(value = "t_form_data_log",autoResultMap = true) +public class FormDataLog implements Serializable { + private static final long serialVersionUID = 7522827670631635795L; + + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + @TableField("form_id") + private Long formId; + + @TableField("form_code") + private String formCode; + + @TableField("data_id") + private Long dataId; + + @TableField("type") + private String type; + + @TableField("new_value") + private String newValue; + + @TableField("old_value") + private String oldValue; + + @TableField("create_id") + private Long createId; + + @TableField("create_account") + private String createAccount; + + @TableField("create_name") + private String createName; + + @TableField("add_time") + private Date addTime; + + @TableField("aft") + private String aft; + + @TableField("bef") + private String bef; + + @TableField("changes") + private String changes; + + @TableField("handled") + private boolean handled; + + public FormDataLog(){ + + } + + public FormDataLog(Long formId, String formCode){ + this.formId = formId; + this.formCode = formCode; + } + + public void fillData(String type,Long dataId,Map before, Map after){ + this.dataId = dataId; + this.type = type; + this.fillOldData(before); + this.fillNewData(after); + } + + public void fillOldData(Map before){ + if(MapUtil.isNotEmpty(before)){ + if(before.containsKey("createTime")){ + before.put("createTime",formatTime(before.get("createTime"))); + } + if(before.containsKey("updateTime")){ + before.put("updateTime", formatTime(before.get("updateTime"))); + } + this.bef = JSON.toJSONString(before, SerializerFeature.WriteMapNullValue); + } + } + + public void fillNewData(Map after){ + if(MapUtil.isNotEmpty(after)){ + if(after.containsKey("createTime")){ + after.put("createTime", formatTime(after.get("createTime"))); + } + if(after.containsKey("updateTime")){ + after.put("updateTime", formatTime(after.get("updateTime"))); + } + this.aft = JSON.toJSONString(after, SerializerFeature.WriteMapNullValue); + } + } + + + private String formatTime(Object timestamp) { + TimeZone timeZone = TimeZone.getTimeZone("GMT+0:00"); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); + simpleDateFormat.setTimeZone(timeZone); + + + if (timestamp instanceof Long) { + + String wrappedTime = simpleDateFormat.format(new Date((long)timestamp)); + if(StrUtil.isNotEmpty(wrappedTime)){ + + return StrUtil.replace(wrappedTime,"Z","+00:00"); + } + } + + if (timestamp instanceof Date) { + + return StrUtil.replace(simpleDateFormat.format((Date) timestamp),"Z","+00:00"); + } + + return timestamp+""; + } + + public void setUser(Long createId,String createName,String createAccount,Date createTime){ + if(ObjectUtil.hasEmpty(createId,createAccount)){ + this.createId = 0L; + this.createAccount = "system"; + this.createName = "系统"; + }else{ + this.createId = createId; + this.createName = createName; + this.createAccount = createAccount; + } + + this.addTime = createTime; + } + + + @Data + public static class UpdateWidgetResult { + + private String model; + + private String bef; + + private String aft; + + public UpdateWidgetResult(String model){ + this.model = model; + } + + public UpdateWidgetResult(String model,String bef,String aft){ + this.model = model; + this.bef = bef; + this.aft = aft; + } + + } + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/domain/FormDataLogChange.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/domain/FormDataLogChange.java new file mode 100644 index 0000000..653f86f --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/domain/FormDataLogChange.java @@ -0,0 +1,11 @@ +package org.dromara.dataManager.domain; + +import lombok.Data; + +@Data +public class FormDataLogChange extends FormDataLog { + private static final long serialVersionUID = 1040326720258635873L; + + + private String userName; +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/enums/DataAspectEnum.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/enums/DataAspectEnum.java new file mode 100644 index 0000000..67e9923 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/enums/DataAspectEnum.java @@ -0,0 +1,51 @@ +package org.dromara.dataManager.enums; + +import cn.hutool.core.util.StrUtil; +import lombok.Getter; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @Description: 数据切面枚举 + **/ +@Getter +public enum DataAspectEnum { + + SAVE("save","save","表单提交"), + + IMPORT("import","save","导入"), + + UPDATE("update","update","数据编辑"), + + UPDATE_FIELD("updateField","update","批量编辑"), + + RECOVER("recover","recover","恢复数据"), + + DELETE("delete","delete","逻辑删除"), + + SHIFT_DELETE("shift_delete","delete","物理删除"), + + CLEAR("clear","delete","清空数据"); + + + private String code; + + private String group; + + private String name; + + + DataAspectEnum(String code, String group, String name){ + this.code = code; + this.group = group; + this.name = name; + } + + public static List getGroupCode(String group){ + return Arrays.stream(values()).filter(p -> StrUtil.equals(group,p.getGroup())).map(DataAspectEnum::getCode).collect(Collectors.toList()); + } + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/enums/WidgetType.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/enums/WidgetType.java new file mode 100644 index 0000000..162eba7 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/enums/WidgetType.java @@ -0,0 +1,51 @@ +package org.dromara.dataManager.enums; + +import java.util.Arrays; +import java.util.Optional; + +public enum WidgetType { + + GENERAL("general"), + + CHECKBOX("checkbox"), + SWITCH("switch"), + EDITOR("editor"), + TEXT("text"), + LOCATION("location"), + SINGLE_MEMBER("singlemember"), + MULTIPLE_MEMBERS("multiplemembers"), + MULTIPLE_DEPARTMENTS("multiple_departments"), + SINGLE_DEPARTMENT("singledepartment"), + TABLE("table"), + IMG_UPLOAD("imgupload"), + FILE_UPLOAD("fileupload"), + DATA_LINK("datalink"), + UNIQ_KEY("uniqkey"), + FORMAT_NUMBER("format_number"), + INPUT("input"), + TEXTAREA("textarea"), + SELECT("select"), + DATE("date"), + COORDINATES("coordinates"), + PHONE("phone"), + RADIO("radio"), + MULTIPLE_SELECT("multiple_select"), + DIVIDER("divider"), + LINK_QUERY("link_query"); + + private String code; + + public String getCode() { + return code; + } + + WidgetType(String code) { + this.code = code; + } + + public static WidgetType getByCode(String code) { + Optional optional = Arrays.stream(values()).filter(type -> type.getCode().equals(code)).findFirst(); + return optional.orElse(null); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/mapper/FormDataLogChangeMapper.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/mapper/FormDataLogChangeMapper.java new file mode 100644 index 0000000..fba3ef8 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/mapper/FormDataLogChangeMapper.java @@ -0,0 +1,17 @@ +package org.dromara.dataManager.mapper; + +import org.dromara.dataManager.domain.FormDataLog; +import org.dromara.dataManager.domain.FormDataLogChange; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +public interface FormDataLogChangeMapper extends BaseMapper { + + List selectDocIds(); + + List selectLogs(@Param("docIds")List docIds); + + void updateLogs(@Param("logs")List logs); +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/mapper/FormDataLogMapper.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/mapper/FormDataLogMapper.java new file mode 100644 index 0000000..4315479 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/mapper/FormDataLogMapper.java @@ -0,0 +1,21 @@ +package org.dromara.dataManager.mapper; + +import org.dromara.dataManager.domain.FormDataLog; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +public interface FormDataLogMapper extends BaseMapper { + + List listDataLog(@Param("formId")Long formId,@Param("dataId")Long dataId); + + + boolean batchSaveDataLog(@Param("logList")List dataLogs); + + /** + * 批量删除 + * @param docIds + */ + void deleteByDataIds(@Param("dataIds") String[] docIds); +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/mapper/FormDataMapper.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/mapper/FormDataMapper.java new file mode 100644 index 0000000..8e0622d --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/mapper/FormDataMapper.java @@ -0,0 +1,18 @@ +package org.dromara.dataManager.mapper; + +import org.dromara.dataManager.result.FormDataResult; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.dromara.dataManager.domain.FormData; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Param; + + +/** + * 表单数据 Mapper 接口 + * + */ +public interface FormDataMapper extends BaseMapper { + + Page pageFormData(@Param("page") Page page,@Param("ew") QueryWrapper queryWrapper); +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/mapper/mapping/FormDataLogChangeMapper.xml b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/mapper/mapping/FormDataLogChangeMapper.xml new file mode 100644 index 0000000..dfd39b0 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/mapper/mapping/FormDataLogChangeMapper.xml @@ -0,0 +1,31 @@ + + + + + + + + + + UPDATE t_form_data_log SET aft = #{log.aft}, bef = #{log.bef}, changes = #{log.changes}, handled = #{log.handled} WHERE id = #{log.id}; + + + + diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/mapper/mapping/FormDataLogMapper.xml b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/mapper/mapping/FormDataLogMapper.xml new file mode 100644 index 0000000..5cf2324 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/mapper/mapping/FormDataLogMapper.xml @@ -0,0 +1,41 @@ + + + + + + + + INSERT INTO t_form_data_log + ( + form_id, form_code,data_id,type,aft,bef,changes,create_id,create_name,create_account,add_time + ) + VALUES + + ( + #{model.formId}, #{model.formCode}, + #{model.dataId}, #{model.type}, #{model.aft}, #{model.bef},#{model.changes}, + #{model.createId},#{model.createName},#{model.createAccount},#{model.addTime} + ) + + + + + + DELETE FROM + t_form_data_log + WHERE + data_id IN + + #{dataId} + + + + + diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/mapper/mapping/FormDataMapper.xml b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/mapper/mapping/FormDataMapper.xml new file mode 100644 index 0000000..a26ce58 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/mapper/mapping/FormDataMapper.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/param/ActiveDataParams.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/param/ActiveDataParams.java new file mode 100644 index 0000000..66104f9 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/param/ActiveDataParams.java @@ -0,0 +1,30 @@ +package org.dromara.dataManager.param; + +import lombok.Data; + +import java.util.LinkedHashMap; + +/** + * 激活实例 + */ +@Data +public class ActiveDataParams extends UpdateDataParams { + /** + * 激活的节点 id + */ + private String activeNodeId; + + + public ActiveDataParams(){} + public ActiveDataParams(String activeNodeId){ + this.activeNodeId = activeNodeId; + } + + public ActiveDataParams(String activeNodeId, String formCode, Long docId, LinkedHashMap data){ + super.setFormCode(formCode); + super.setDataId(docId); + super.setData(data); + this.activeNodeId = activeNodeId; + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/param/DataParams.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/param/DataParams.java new file mode 100644 index 0000000..37fec5e --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/param/DataParams.java @@ -0,0 +1,109 @@ +package org.dromara.dataManager.param; + +import lombok.Data; +import lombok.Getter; +import org.dromara.system.domain.SysDept; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * 数据传参 + */ +@Data +public class DataParams implements Serializable { + private static final long serialVersionUID = 8682927139425739121L; + + /** + * 表单id + */ + private Long formId; + + /** + * 表单code + */ + private String formCode; + + /** + * 权限组group id + */ + private Long permissionGroupId; + + + /** + * 操作用户信息 + */ + private Long userId; + private String userAccount; + private String userName; + private List userDepartIds; + private List userGroupIds; + private List departs; + + + /** + * 操作时间 + */ + private Date handleTime = new Date(); + + + /** + * 外链更新方式 data + */ + private AccessType accessType; + + /** + * 外链更新token + */ + private String accessToken; + + @Getter + public enum AccessType{ + form("form","表单"), + + data("data","数据"); + + private String type; + + private String name; + + AccessType(String type,String name){ + this.type = type; + this.name = name; + } + } + + public void setUser(Long userId, String userAccount, String userName, List departIds, List groupIds){ + this.userId = userId; + this.userAccount = userAccount; + this.userName = userName; + this.userDepartIds = departIds; + this.userGroupIds = groupIds; + } + public void setUser(Long userId, String userAccount, String userName, List departIds, List groupIds, List departs){ + this.userId = userId; + this.userAccount = userAccount; + this.userName = userName; + this.userDepartIds = departIds; + this.userGroupIds = groupIds; + this.departs = departs; + } + public void setUser(Long userId, String userAccount, String userName){ + this.userId = userId; + this.userAccount = userAccount; + this.userName = userName; + } + + public void setUser(DataParams dataParams){ + if(dataParams != null){ + this.userId = dataParams.getUserId(); + this.userAccount = dataParams.getUserAccount(); + this.userName = dataParams.getUserName(); + } + + } + + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/param/DownloadDataParams.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/param/DownloadDataParams.java new file mode 100644 index 0000000..a501e48 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/param/DownloadDataParams.java @@ -0,0 +1,33 @@ +package org.dromara.dataManager.param; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.dromara.common.param.WorkflowBaseParam; + +import java.util.List; + +/** + * 数据导出 + */ +@Data +public class DownloadDataParams extends DataParams { + + @NotNull(message = "表单代码不能为空", groups = WorkflowBaseParam.export.class) + private String formCode; + + @NotNull(message = "导出字段不能为空") + private List exportFields; + + private Long permissionId; + + /** + * 是否导出ID + */ + private boolean includeId = false; + + /** + * 导出文件名,如果为空则使用表单名称作为文件名 + */ + private String exportName; + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/param/FormDataModifyMessage.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/param/FormDataModifyMessage.java new file mode 100644 index 0000000..5b8d95e --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/param/FormDataModifyMessage.java @@ -0,0 +1,71 @@ +package org.dromara.dataManager.param; + +import org.dromara.dataManager.enums.DataAspectEnum; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; +import java.util.Map; + +/** + * 表单数据更新message + */ +@Data +public class FormDataModifyMessage implements Serializable { + private static final long serialVersionUID = -1603895080729468809L; + + /** + * 数据操作 + */ + private DataAspectEnum action; + + + + /** + * 表单id + */ + private Long formId; + + /** + * 表单code + */ + private String formCode; + + /** + * 操作时间 + */ + private Date handleTime; + + /** + * 操作人id + */ + private Long handleUserId; + + /** + * 操作人账号 + */ + private String handleUserAccount; + + /** + * 操作人姓名 + */ + private String handleUserName; + + + /** + * 修改前数据 + */ + private List> before = null; + + /** + * 修改后数据 + */ + private List> after; + + + /** + * 批量修改的表单字段 + */ + private String updateWidget; +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/param/FormDataParam.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/param/FormDataParam.java new file mode 100644 index 0000000..ab431a8 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/param/FormDataParam.java @@ -0,0 +1,41 @@ +package org.dromara.dataManager.param; + +import cn.hutool.json.JSONArray; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.dromara.common.param.WorkflowBaseParam; +import org.dromara.workflow.engine.enums.InstanceStage; + +import java.util.LinkedHashMap; + +/** + * 表单数据 + * + */ +@Data +public class FormDataParam extends WorkflowBaseParam { + + private static final long serialVersionUID = 1L; + + @NotNull(groups = {edit.class},message = "表单数据id不能为空") + private Long dataId; + + @NotNull(groups = {add.class},message = "表单id不能为空") + private Long formId; + + @NotNull(groups = {add.class},message = "表单数据不能为空") + private LinkedHashMap formData; + + private Long instanceId; + + private InstanceStage instanceStage; + + private JSONArray instanceChecker; + + private JSONArray instanceNode; + + private Integer deleted; + + private String app; + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/param/ImportDataParams.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/param/ImportDataParams.java new file mode 100644 index 0000000..d38288f --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/param/ImportDataParams.java @@ -0,0 +1,36 @@ +package org.dromara.dataManager.param; + +import org.dromara.dataManager.service.impt.enums.ImportMode; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.springframework.web.multipart.MultipartFile; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ImportDataParams extends DataParams { + private static final long serialVersionUID = 5013388461809737003L; + private Integer sheetIndex; + private String mapping; + private Map objMapping; + private List exportFields = new ArrayList<>(); + private ImportMode mode; + private String primaryKey; + private MultipartFile file; + private String validationConfigStr; + private ValidationConfig validationConfig; + + @Data + public static class ValidationConfig { + + private boolean required; + private boolean memberRequired; + private boolean departRequired; + private boolean optionRequired; + private boolean numberRequired; + private boolean dateRequired; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/param/TransferDataParams.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/param/TransferDataParams.java new file mode 100644 index 0000000..e11887a --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/param/TransferDataParams.java @@ -0,0 +1,38 @@ +package org.dromara.dataManager.param; + +import lombok.Data; + +import java.util.LinkedHashMap; +import java.util.List; + +/** + * 调整实例节点负责人 + */ +@Data +public class TransferDataParams extends UpdateDataParams { + /** + * 调整实例节点id + */ + private String transferNodeId; + + /** + * 调整节点负责人 + */ + private List checkers; + + public TransferDataParams(){} + public TransferDataParams(String transferNodeId){ + this.transferNodeId = transferNodeId; + } + + public TransferDataParams(String transferNodeId, List checkers, + String formCode, Long dataId, + LinkedHashMap data){ + super.setFormCode(formCode); + super.setDataId(dataId); + super.setData(data); + this.transferNodeId = transferNodeId; + this.checkers = checkers; + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/param/UpdateDataParams.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/param/UpdateDataParams.java new file mode 100644 index 0000000..0f1de32 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/param/UpdateDataParams.java @@ -0,0 +1,77 @@ +package org.dromara.dataManager.param; + +import org.dromara.workflow.engine.enums.ESDefaultFieldConst; +import lombok.Data; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * 更新表单数据 + */ +@Data +public class UpdateDataParams extends DataParams { + /** + * 数据doc id + */ + private Long dataId; + + /** + * 表单数据 + */ + private LinkedHashMap data; + + /** + * 更新之前的表单数据 + */ + private Map before; + + + public UpdateDataParams(){} + public UpdateDataParams(String formCode, Long docId, LinkedHashMap data){ + this.setFormCode(formCode); + this.dataId = docId; + this.data = data; + } + + + /** + * 转ES数据 + * @return + */ + public LinkedHashMap convertESData(){ + if(data != null){ + data.remove(ESDefaultFieldConst.OWNER); + data.remove(ESDefaultFieldConst.CREATOR); + data.remove(ESDefaultFieldConst.CREATOR_ACCOUNT); + data.remove(ESDefaultFieldConst.CREATE_TIME); + data.remove(ESDefaultFieldConst.DID); + data.remove(ESDefaultFieldConst.DELETED); + + //设置更新时间 + data.put(ESDefaultFieldConst.UPDATE_TIME, this.getHandleTime()); + data.put(ESDefaultFieldConst.UPDATOR_NAME, this.getUserName()); + } + return data; + } + + + /** + * 添加ES基础字段 + * @return + */ + public LinkedHashMap addESData(){ + if(data == null){ + data = new LinkedHashMap(); + } + data.put(ESDefaultFieldConst.OWNER, this.getUserId()); + data.put(ESDefaultFieldConst.CREATOR, this.getUserName()); + data.put(ESDefaultFieldConst.CREATOR_ACCOUNT, this.getUserAccount()); + data.put(ESDefaultFieldConst.CREATE_TIME, this.getHandleTime()); + data.put(ESDefaultFieldConst.UPDATE_TIME, this.getHandleTime()); + data.put(ESDefaultFieldConst.UPDATOR_NAME, this.getUserName()); + data.put(ESDefaultFieldConst.DID, this.getFormCode()); + data.put(ESDefaultFieldConst.DELETED, false); + return data; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/result/FormDataResult.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/result/FormDataResult.java new file mode 100644 index 0000000..3a7bc08 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/result/FormDataResult.java @@ -0,0 +1,55 @@ +package org.dromara.dataManager.result; + +import cn.hutool.json.JSONArray; +import lombok.Data; +import java.io.Serializable; +import java.util.Date; +import java.util.Map; + +/** + * 表单数据 + * + */ +@Data +public class FormDataResult implements Serializable { + + private static final long serialVersionUID = 1L; + + + private Long id; + + private Long formId; + + private Map formData; + + private Long instanceId; + + private String stage; + + private String flowStage; + + private String checkerName; + + private String nodeTitle; + + private Integer deleted; + + private Long createUser; + + private Date createTime; + + private String createName; + + private String createAccount; + + private Long updateUser; + + private Date updateTime; + + private String updateName; + + private JSONArray nodes = new JSONArray(); + + private JSONArray checkers = new JSONArray(); + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/FormDataService.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/FormDataService.java new file mode 100644 index 0000000..a20da79 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/FormDataService.java @@ -0,0 +1,87 @@ +package org.dromara.dataManager.service; + + +import java.util.List; +import java.util.Map; + +import org.dromara.common.page.WorkflowPageResult; +import org.dromara.dataManager.param.UpdateDataParams; +import org.dromara.formMaking.results.FormSourceResult; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.dataManager.domain.FormData; +import org.dromara.dataManager.param.FormDataParam; + + +/** + * 表单数据 服务类 + * + */ +public interface FormDataService extends IService { + + /** + * 分页 + * @param param + * @return + */ + WorkflowPageResult> pageFormData(FormDataParam param); + + /** + * 查询表单数据 + * @param dataId + * @return + */ + FormData getFormData(Long dataId); + + /** + * 查询数据全部字段数据 + * @param dataId + * @return + */ + Map getFormDataById(Long formId,Long dataId); + + /** + * 查询表单中指定的字段的数据 + * @param dataId + * @param includeFields + * @return + */ + Map getFormDataById(Long formId,Long dataId,String [] includeFields); + + /** + * 查询指定的data + * @param dataIds + * @return + */ + List> list(Long formId, String[] dataIds); + + + /** + * 查询表单数据的完整信息 + * @param formId + * @param dataId + * @return + */ + FormSourceResult getFormDataFullInfo(Long formId,Long dataId); + + /** + * 新增表单数据 + * @param param + * @return + */ + FormData addFormData(FormDataParam param); + + /** + * 编辑表单数据 + * @param param + * @return + */ + FormData editFormData(UpdateDataParams param); + + /** + * 删除表单数据 + * @param id + * @return + */ + boolean deleteFormData(Long id); + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impl/FormDataServiceImpl.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impl/FormDataServiceImpl.java new file mode 100644 index 0000000..7bbb059 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impl/FormDataServiceImpl.java @@ -0,0 +1,278 @@ +package org.dromara.dataManager.service.impl; + + +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.Exception.ServiceException; +import org.dromara.common.consts.ExceptionCodeConstant; +import org.dromara.common.page.WorkflowPageFactory; +import org.dromara.common.page.WorkflowPageResult; +import org.dromara.common.response.WorkflowResultCode; +import org.dromara.dataManager.param.UpdateDataParams; +import org.dromara.dataManager.result.FormDataResult; +import org.dromara.formMaking.domain.FormSource; +import org.dromara.formMaking.results.FormSourceResult; +import org.dromara.formMaking.service.FormSourceService; +import org.dromara.taskCenter.param.TaskFlowParam; +import org.dromara.taskCenter.param.TaskUpdateParam; +import org.dromara.taskCenter.service.action.impl.CreateHandler; +import org.dromara.workflow.engine.enums.InstanceStage; +import org.dromara.workflow.engine.enums.OperateType; +import org.dromara.workflow.param.model.FlowUser; +import org.dromara.workflow.result.engine.ActionNodeSubmitResult; +import org.dromara.workflow.result.engine.EngineDataResult; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + +import org.dromara.dataManager.domain.FormData; +import org.dromara.dataManager.mapper.FormDataMapper; +import org.dromara.dataManager.param.FormDataParam; +import org.dromara.dataManager.service.FormDataService; +import org.springframework.transaction.annotation.Transactional; + +/** + * 表单数据实现层 + * + */ +@Service +@Slf4j +public class FormDataServiceImpl extends ServiceImpl implements FormDataService { + + @Autowired + private CreateHandler actionService; + @Autowired + private FormSourceService formSourceService; + + + @Override + public WorkflowPageResult> pageFormData(FormDataParam param) { + if (ObjectUtil.isEmpty(param.getFormId())){ + throw new ServiceException(ExceptionCodeConstant.Service.VALUE_INVALID,"参数[formId]不能为空"); + } + + Page pageFormData = this.baseMapper.pageFormData(WorkflowPageFactory.defaultPage(),generateWrapper(param)); + List> formDataList = new ArrayList<>(); + pageFormData.getRecords().forEach(p->{ + if(p.getInstanceId() != null){ + p.getFormData().put("nodeTitle",p.getNodeTitle()); + p.getFormData().put("checkerName",p.getCheckerName()); + p.getFormData().put("flowStage",p.getStage()); + } + p.getFormData().put("createName",p.getCreateName()); + p.getFormData().put("createTime",p.getCreateTime()); + p.getFormData().put("updateName",p.getUpdateName()); + p.getFormData().put("updateTime",p.getUpdateTime()); + p.getFormData().put("instanceId",p.getInstanceId()); + p.getFormData().put("dataId",p.getId()); + formDataList.add(p.getFormData()); + }); + + return new WorkflowPageResult<>(pageFormData,formDataList); + } + + + @Override + public FormData getFormData(Long dataId) { + return this.baseMapper.selectById(dataId); + } + + @Override + public Map getFormDataById(Long formId,Long dataId) { + if (ObjectUtil.isEmpty(formId)){ + throw new ServiceException(ExceptionCodeConstant.Service.VALUE_INVALID,"参数[formId]不能为空"); + } + + if (ObjectUtil.isEmpty(dataId)){ + throw new ServiceException(ExceptionCodeConstant.Service.VALUE_INVALID,"参数[dataId]不能为空"); + } + + List formDataList = this.getFormDataByFormId(formId); + + List dataList = formDataList.stream().filter(p -> p.getId().equals(dataId)).collect(Collectors.toList()); + + if (CollUtil.isNotEmpty(dataList)){ + FormData formData = dataList.stream().findFirst().get(); + LinkedHashMap data = formData.getFormData(); + data.put("instanceId",formData.getInstanceId()); + data.put("instanceStage",formData.getInstanceStage()); + data.put("instanceChecker",formData.getInstanceChecker()); + data.put("instanceNode",formData.getInstanceNode()); + data.put("dataId",dataId); + return data; + } + + return new HashMap<>(); + } + + @Override + public Map getFormDataById(Long formId,Long dataId, String[] includeFields) { + Map formDataMap = this.getFormDataById(formId, dataId); + + Map resultMap = new HashMap<>(); + + if (ObjectUtil.isEmpty(formDataMap)){ + return resultMap; + } + + List keyList = formDataMap.keySet().stream().filter(key -> Arrays.asList(includeFields).contains(key)).collect(Collectors.toList()); + + keyList.forEach(key ->{ + resultMap.put(key,formDataMap.get(key)); + }); + + return resultMap; + } + + @Override + public List> list(Long formId, String[] dataIds) { + List> resultList = new ArrayList<>(); + + List formDataList = this.getFormDataByFormId(formId); + + if (CollUtil.isEmpty(formDataList)){ + return resultList; + } + + List resultFormData = formDataList.stream(). + filter(formData -> Arrays.asList(dataIds).contains(String.valueOf(formData.getId()))).collect(Collectors.toList()); + + resultFormData.forEach(formData -> { + LinkedHashMap data = formData.getFormData(); + data.put("instanceId",formData.getInstanceId()); + data.put("instanceStage",formData.getInstanceStage()); + data.put("instanceChecker",formData.getInstanceChecker()); + data.put("instanceNode",formData.getInstanceNode()); + data.put("dataId",formData.getId()); + resultList.add(data); + }); + + return resultList; + } + + @Override + public FormSourceResult getFormDataFullInfo(Long formId,Long dataId) { + FormSourceResult formSourceResult =formSourceService.getFormSourceById(formId); + if (ObjectUtil.isEmpty(formSourceResult)){ + + throw new ServiceException(WorkflowResultCode.FORM_NOT_EXIST); + } + formSourceResult.setFormData(this.getFormDataById(formSourceResult.getId(), dataId)); + + return formSourceResult; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public FormData addFormData(FormDataParam param) { + FormData item = new FormData(); + BeanUtils.copyProperties(param,item); + item.setFormData(param.getFormData()); + item.setDeleted(false); + item.setCreateAccount(LoginHelper.getUsername()); + item.setCreateName(LoginHelper.getLoginUser().getNickname()); + this.save(item); + + //应用表单提交 + 表单启用流程 => 触发流程引擎 + FormSource formSource = formSourceService.getFormSource(param.getFormId()); + TaskFlowParam wfParam = new TaskFlowParam( + new TaskUpdateParam(OperateType.create, formSource, item.getId(),false,item.getFormData(),item.getCreateTime()), + new FlowUser(LoginHelper.getUserId(), + LoginHelper.getLoginUser().getNickname(), + LoginHelper.getUsername(), + Arrays.asList(LoginHelper.getDeptId())) + ); + + ActionNodeSubmitResult flowRsp = actionService.action(wfParam); + if(!flowRsp.getSuccess() || flowRsp.getData() == null){ + throw new ServiceException(flowRsp.getCode(),flowRsp.getMessage()); + } + + EngineDataResult flowData = flowRsp.getData(); + Long instanceId = flowData.getInstanceId(); + item.setInstanceId(instanceId); + item.setInstanceStage(flowData.getFlowStage()); + if(InstanceStage.processing.name().equals(flowData.getFlowStage())){ + item.setInstanceNode(flowData.getNodeTitle()); + item.setInstanceChecker(flowData.getCheckerName()); + }else{ + item.setInstanceNode("结束节点"); + item.setInstanceChecker(""); + } + this.updateById(item); + + return item; + } + + @Override + public FormData editFormData(UpdateDataParams param) { + FormData item = this.queryItem(param.getDataId()); + item.setFormData(param.getData()); + if(param.getData().containsKey("instanceStage")){ + item.setInstanceStage((String) param.getData().get("instanceStage")); + } + if(param.getData().containsKey("instanceChecker")){ + item.setInstanceChecker((String) param.getData().get("instanceChecker")); + } + if(param.getData().containsKey("instanceNode")){ + item.setInstanceNode((String) param.getData().get("instanceNode")); + } + + this.baseMapper.updateById(item); + + + + return item; + } + + @Override + public boolean deleteFormData(Long id) { + + return this.baseMapper.deleteById(id) > 0; + } + + private QueryWrapper generateWrapper(FormDataParam param){ + QueryWrapper wrapper = new QueryWrapper<>(); + + if (ObjectUtil.isNotEmpty(param.getFormId())){ + wrapper.eq("tfd.form_id",param.getFormId()); + } + + if (StringUtils.isNotEmpty(param.getStartTime()) && StringUtils.isNotEmpty(param.getEndTime())){ + wrapper.ge("tfd.create_time",param.getStartTime() + " 00:00:00"); + wrapper.le("tfd.create_time",param.getEndTime() + " 23:59:59"); + } + + wrapper.orderByDesc("tfd.update_time","tfd.create_time"); + + return wrapper; + } + + private FormData queryItem(Long id) { + FormData item = this.getById(id); + if (ObjectUtil.isNull(item)) { + throw new ServiceException(4004,"未找到表单数据"); + } + return item; + } + + private List getFormDataByFormId(Long formId) { + if (ObjectUtil.isEmpty(formId)){ + throw new ServiceException(ExceptionCodeConstant.Service.VALUE_INVALID,"参数[formId]不能为空"); + } + + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(FormData::getFormId,formId); + return this.baseMapper.selectList(wrapper); + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/common/HeaderMergeStrategiesGenerator.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/common/HeaderMergeStrategiesGenerator.java new file mode 100644 index 0000000..14c50b7 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/common/HeaderMergeStrategiesGenerator.java @@ -0,0 +1,60 @@ +package org.dromara.dataManager.service.impt.common; + +import org.dromara.taskCenter.model.FormWidget; +import cn.hutool.core.collection.CollectionUtil; +import com.alibaba.excel.write.merge.OnceAbsoluteMergeStrategy; + +import java.util.*; + +public class HeaderMergeStrategiesGenerator { + + public static List generate(List formColumns, List exportFields) { + List strategyList = new ArrayList<>(); + if (formColumns == null) { + return strategyList; + } + + Map tableColumnsMap = new HashMap<>(); + List allColumns = new ArrayList<>(); + + + if (exportFields == null) { + exportFields = allColumns; + } + + List finalExportFields = exportFields; + formColumns.stream().filter(col -> finalExportFields.contains(col.getModel())).forEach(col -> { + if (CollectionUtil.isNotEmpty(col.getTableColumns())) { + + tableColumnsMap.put(col.getModel(), col); + } + allColumns.add(col.getModel()); + }); + + if (tableColumnsMap.size() <= 0) { + return strategyList; + } + + int colIndex = 0; + Set tableColumns = tableColumnsMap.keySet(); + + for (String field : exportFields) { + if (tableColumns.contains(field)) { + int colSpan = tableColumnsMap.get(field).getTableColumns().size(); + + if (colSpan == 1) { + colIndex++; + continue; + } + + strategyList.add(new OnceAbsoluteMergeStrategy(0, 0, colIndex, colIndex + colSpan - 1)); + colIndex += colSpan; + } else { + strategyList.add(new OnceAbsoluteMergeStrategy(0, 1, colIndex, colIndex)); + colIndex++; + } + } + + return strategyList; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/BaseConverter.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/BaseConverter.java new file mode 100644 index 0000000..8abcd8e --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/BaseConverter.java @@ -0,0 +1,22 @@ +package org.dromara.dataManager.service.impt.convert; + +import org.dromara.system.domain.SysDept; +import org.dromara.system.domain.SysUser; +import org.dromara.taskCenter.model.FormWidget; +import lombok.Data; + +import java.util.HashMap; +import java.util.Map; + +@Data +public abstract class BaseConverter { + private FormWidget formWidget; + + private Map accountUserMapping = new HashMap<>(); + + private Map pathDepartMapping = new HashMap<>(); + + public Object convert(String value) { + return null; + }; +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/BooleanConverter.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/BooleanConverter.java new file mode 100644 index 0000000..075edcf --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/BooleanConverter.java @@ -0,0 +1,14 @@ +package org.dromara.dataManager.service.impt.convert; + +public class BooleanConverter extends BaseConverter { + @Override + public Object convert(String value) { + if ("是".equals(value)) { + return true; + } else if ("否".equals(value)){ + return false; + } else { + return null; + } + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/CheckboxConverter.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/CheckboxConverter.java new file mode 100644 index 0000000..0cabc53 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/CheckboxConverter.java @@ -0,0 +1,11 @@ +package org.dromara.dataManager.service.impt.convert; + +public class CheckboxConverter extends BaseConverter { + @Override + public Object convert(String value) { + if (value == null) { + return null; + } + return value.split(","); + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/ConverterBuilder.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/ConverterBuilder.java new file mode 100644 index 0000000..6082e23 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/ConverterBuilder.java @@ -0,0 +1,13 @@ +package org.dromara.dataManager.service.impt.convert; + +import org.dromara.dataManager.service.impt.model.StringConverter; +import org.dromara.taskCenter.model.widget.WidgetModel; + +public class ConverterBuilder { + public static WidgetConverter getConverter(String type, WidgetModel widgetModel){ + + WidgetConverter converter = new StringConverter(widgetModel); + return converter; + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/CoordinateConverter.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/CoordinateConverter.java new file mode 100644 index 0000000..ef7bdd4 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/CoordinateConverter.java @@ -0,0 +1,20 @@ +package org.dromara.dataManager.service.impt.convert; + + +import cn.hutool.json.JSONObject; +import org.apache.commons.lang3.StringUtils; + +public class CoordinateConverter extends BaseConverter { + + @Override + public Object convert(String value) { + if (StringUtils.isNotBlank(value)) { + JSONObject coordinate = new JSONObject(); + coordinate.set("address", value); + coordinate.set("geopoint", null); + return coordinate; + } else { + return null; + } + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/DateConverter.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/DateConverter.java new file mode 100644 index 0000000..56ae669 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/DateConverter.java @@ -0,0 +1,70 @@ +package org.dromara.dataManager.service.impt.convert; + + +import com.alibaba.excel.util.DateUtils; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import java.text.ParseException; +import java.util.Date; + +@Slf4j +public class DateConverter extends BaseConverter { + + @Override + public Object convert(String value) { + if (StringUtils.isNotBlank(value)) { + try { + String format = (String) getFormWidget().getOptions().get("format"); + // 使用规定格式转换数据 + return DateUtils.parseDate(value, format); + } catch (Exception e) { + try { + // 如果转换报错,则尝试自动转换数据 + return DateUtils.parseDate(value); + } catch (Exception parseException) { + // 自动识别格式失败则尝试自动识别常用格式 + return convert2Date(value); + } + } + } else { + return null; + } + } + + private Date convert2Date(String dateString) { + + // 自动识别格式失败则尝试自动识别常用格式 + String separator = null; + + if (dateString.contains("-")) { + separator = "-"; + + } else if (dateString.contains("/")) { + separator = "/"; + + } + + if (separator != null) { + String ymd = String.format("yyyy%sMM%sdd", separator, separator); + String[] formats = new String[]{String.format("%s HH:mm:ss", ymd), String.format("%s HH:mm", ymd), String.format("%s HH", ymd), ymd}; + + Date result = null; + + for (String format: formats) { + try { + result = DateUtils.parseDate(dateString, format); + break; + } catch (ParseException parseException) { + log.error(String.format("转换为%s格式日期失败", format)); + } + } + + if (result != null) { + return result; + } + } + + return null; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/EmptyArrayValueConverter.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/EmptyArrayValueConverter.java new file mode 100644 index 0000000..ddb9040 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/EmptyArrayValueConverter.java @@ -0,0 +1,10 @@ +package org.dromara.dataManager.service.impt.convert; + +import java.util.ArrayList; + +public class EmptyArrayValueConverter extends BaseConverter { + @Override + public Object convert(String value) { + return new ArrayList<>(); + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/FormatNumberConverter.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/FormatNumberConverter.java new file mode 100644 index 0000000..036b56c --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/FormatNumberConverter.java @@ -0,0 +1,68 @@ +package org.dromara.dataManager.service.impt.convert; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.text.DecimalFormat; + +public class FormatNumberConverter extends BaseConverter { + + @Override + public Object convert(String value) { + if (value == null) { + return null; + } + + String numberWithoutSymbols = value.replaceAll(",", "").replaceAll("%", ""); + + // 将字符串转为数字 + BigDecimal number = new BigDecimal(numberWithoutSymbols); + + try { + + // 开启小数位数 + boolean isFloatChecked = (boolean) getFormWidget().getOptions().get("isFloatChecked"); + // 小数位数 + int numberDigit = getFormWidget().getOptions().get("numberDigit") == null ? 0 : (int) getFormWidget().getOptions().get("numberDigit"); + + DecimalFormat df; + + // 开启了保留小数位 + if (isFloatChecked) { + + if (numberDigit > 0 ) { + + StringBuilder digitPattern = new StringBuilder(); + + for (int index = 0; index < numberDigit; index++) { + digitPattern.append("#"); + } + + df = new DecimalFormat("#." + digitPattern); + } else { + df = new DecimalFormat("#"); + } + + // 如果是百分比字符串,再除以100 + if (value.contains("%")) { + number = number.divide(new BigDecimal(100), RoundingMode.HALF_UP); + } + + } + // 没开启保留小数位,则最多保留6位 + else { + df = new DecimalFormat("###.######"); + // 如果是百分比字符串,再除以100 + if (value.contains("%")) { + number = number.divide(new BigDecimal(100), RoundingMode.HALF_UP); + } + } + df.setRoundingMode(RoundingMode.HALF_UP); + number = new BigDecimal(df.format(number)); + + } catch (Exception e) { + number = null; + } + + return number == null ? null : number.doubleValue(); + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/GeneralConverter.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/GeneralConverter.java new file mode 100644 index 0000000..8b2da19 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/GeneralConverter.java @@ -0,0 +1,8 @@ +package org.dromara.dataManager.service.impt.convert; + +public class GeneralConverter extends BaseConverter { + @Override + public Object convert(String value) { + return value; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/InputConverter.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/InputConverter.java new file mode 100644 index 0000000..9779358 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/InputConverter.java @@ -0,0 +1,34 @@ +package org.dromara.dataManager.service.impt.convert; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +public class InputConverter extends BaseConverter { + + private static final List NUMBER_TYPES = Arrays.asList("number", "integer", "float"); + + @Override + public Object convert(String value) { + if (value == null) { + return null; + } + + Map options = getFormWidget().getOptions(); + String dataType = (String) options.get("dataType"); + + if (NUMBER_TYPES.contains(dataType)) { + try { + if ("integer".equals(dataType)) { + return Double.valueOf(value).intValue(); + } else { + return Float.valueOf(value); + } + } catch (Exception e) { + return null; + } + } + + return value; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/LocationConverter.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/LocationConverter.java new file mode 100644 index 0000000..002de24 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/LocationConverter.java @@ -0,0 +1,38 @@ +package org.dromara.dataManager.service.impt.convert; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +public class LocationConverter extends BaseConverter { + @Override + public Object convert(String value) { + if (value == null) { + return getDefaultValue(); + } + String[] location = value.split(",", -1); + Map result = new HashMap<>(); + if (location.length > 0) { + result.put("province", location[0]); + } + if (location.length > 1) { + result.put("city", location[1]); + } + if (location.length > 2) { + result.put("area", location[2]); + } + if (location.length > 3) { + result.put("address", String.join(",", Arrays.asList(location).subList(3, location.length))); + } + return result; + } + + private Map getDefaultValue() { + Map location = new HashMap<>(); + location.put("province", null); + location.put("city", null); + location.put("area", null); + location.put("address", null); + return location; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/MultipleDepartmentsConverter.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/MultipleDepartmentsConverter.java new file mode 100644 index 0000000..1f2fb11 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/MultipleDepartmentsConverter.java @@ -0,0 +1,30 @@ +package org.dromara.dataManager.service.impt.convert; + +import org.dromara.system.domain.SysDept; + +import java.util.*; + +public class MultipleDepartmentsConverter extends BaseConverter { + + @Override + public Object convert(String value) { + List> infoList = new ArrayList<>(); + + if (value == null) { + return infoList; + } + + String[] pathList = value.split(","); + Arrays.stream(pathList).forEach(path -> { + SysDept org = getPathDepartMapping().get(path); + Map info = new HashMap<>(); + info.put("key", String.valueOf(org.getDeptId())); + info.put("title", org.getDeptName()); + info.put("code", org.getDeptId()); +// info.put("path", org.getNamePath()); + infoList.add(info); + }); + + return infoList; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/MultipleMemberConverter.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/MultipleMemberConverter.java new file mode 100644 index 0000000..bf03207 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/MultipleMemberConverter.java @@ -0,0 +1,30 @@ +package org.dromara.dataManager.service.impt.convert; + + +import org.dromara.system.domain.SysUser; + +import java.util.*; + +public class MultipleMemberConverter extends BaseConverter { + + @Override + public Object convert(String value) { + List> infoList = new ArrayList<>(); + + if (value == null) { + return infoList; + } + + String[] accounts = value.split(","); + Arrays.stream(accounts).forEach(account -> { + SysUser user = getAccountUserMapping().get(account); + Map info = new HashMap<>(); + info.put("key", String.valueOf(user.getUserId())); + info.put("title", user.getNickName()); + info.put("code", user.getUserName()); + infoList.add(info); + }); + + return infoList; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/MultipleSelectConverter.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/MultipleSelectConverter.java new file mode 100644 index 0000000..d5e11a1 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/MultipleSelectConverter.java @@ -0,0 +1,11 @@ +package org.dromara.dataManager.service.impt.convert; + +public class MultipleSelectConverter extends BaseConverter { + @Override + public Object convert(String value) { + if (value == null) { + return null; + } + return value.split(","); + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/NullValueConverter.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/NullValueConverter.java new file mode 100644 index 0000000..c089547 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/NullValueConverter.java @@ -0,0 +1,8 @@ +package org.dromara.dataManager.service.impt.convert; + +public class NullValueConverter extends BaseConverter { + @Override + public Object convert(String value) { + return null; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/PhoneConverter.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/PhoneConverter.java new file mode 100644 index 0000000..d6c10d3 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/PhoneConverter.java @@ -0,0 +1,17 @@ +package org.dromara.dataManager.service.impt.convert; + +import java.util.HashMap; +import java.util.Map; + +public class PhoneConverter extends BaseConverter { + @Override + public Object convert(String value) { + if (value == null) { + return null; + } + Map result = new HashMap<>(); + result.put("phoneNumber", value); + result.put("status", 0); + return result; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/SingleDepartmentConverter.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/SingleDepartmentConverter.java new file mode 100644 index 0000000..ccbf35b --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/SingleDepartmentConverter.java @@ -0,0 +1,28 @@ +package org.dromara.dataManager.service.impt.convert; + +import org.dromara.system.domain.SysDept; + +import java.util.HashMap; +import java.util.Map; + +public class SingleDepartmentConverter extends BaseConverter { + + @Override + public Object convert(String value) { + if (value == null) { + return null; + } + + SysDept sysDepartment = getPathDepartMapping().get(value); + if (sysDepartment != null) { + Map info = new HashMap<>(); + info.put("key", String.valueOf(sysDepartment.getDeptId())); + info.put("title", sysDepartment.getDeptName()); + info.put("code", sysDepartment.getDeptId()); +// info.put("path", sysDepartment.getNamePath()); + return info; + } + + return null; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/SingleMemberConverter.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/SingleMemberConverter.java new file mode 100644 index 0000000..628e8b8 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/SingleMemberConverter.java @@ -0,0 +1,30 @@ +package org.dromara.dataManager.service.impt.convert; + + +import org.dromara.system.domain.SysUser; + +import java.util.HashMap; +import java.util.Map; + +public class SingleMemberConverter extends BaseConverter { + + public SingleMemberConverter() { + } + + @Override + public Object convert(String value) { + if (value == null) { + return null; + } + SysUser sysUser = getAccountUserMapping().get(value); + if (sysUser != null) { + Map info = new HashMap<>(); + info.put("key", String.valueOf(sysUser.getUserId())); + info.put("title", sysUser.getNickName()); + info.put("code", sysUser.getUserName()); + // info.put("type", UserDepartDataTypeEnum.USER.getCode()); + return info; + } + return null; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/WidgetConverter.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/WidgetConverter.java new file mode 100644 index 0000000..4319f49 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/WidgetConverter.java @@ -0,0 +1,69 @@ +package org.dromara.dataManager.service.impt.convert; + +import org.dromara.dataManager.param.ImportDataParams; +import org.dromara.taskCenter.model.widget.WidgetModel; +import cn.hutool.core.util.ObjectUtil; +import lombok.Data; + +/** + * 表单字段值转换 + */ +@Data +public abstract class WidgetConverter { + protected static final String BLANK_MESSAGE = "'%s'字段不能为空值"; + protected static final String IS_NOT_NUMBER = "'%s'不是数字"; + protected static final String IS_NOT_DATE = "'%s'不是日期"; + protected static final String IS_NOT_SYSTEM_ACCOUNT = "'%s'不是系统内的账号"; + protected static final String IS_NOT_SYSTEM_DEPARTMENT = "'%s'不是系统内的部门"; + protected static final String IS_NOT_VALID_OPTION = "'%s'不是合法的选项"; + protected WidgetModel widget; + private ImportDataParams.ValidationConfig validationConfig; + + public WidgetConverter() { + } + + public WidgetConverter(WidgetModel widget){ + this.widget = widget; + } + + public void validate(String value, ConvertCallBack callback){ + if (isRequiredButEmpty(value)) { + callback.fail(String.format(BLANK_MESSAGE, this.widget.getName())); + return; + } + callback.success(this.valueOf(value)); + } + + public Object valueOf(String value){ + return value; + } + + /** + * 是否必填但是数据为空 + * @param value + * @return + */ + protected boolean isRequiredButEmpty(Object value) { + if (!validationConfig.isRequired()) { + return false; + } + boolean required = this.widget.getOptions().getBool("required", false); + return required && ObjectUtil.isEmpty(value); + } + + /** + * 回调接口 + */ + public interface ConvertCallBack{ + /** + * 转换成功 + * @param convertValue + */ + void success(Object convertValue); + /** + * 转换失败 + * @param message + */ + void fail(String message); + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/WidgetConverterFactory.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/WidgetConverterFactory.java new file mode 100644 index 0000000..c0cb1ec --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/convert/WidgetConverterFactory.java @@ -0,0 +1,75 @@ +package org.dromara.dataManager.service.impt.convert; + +import org.dromara.dataManager.enums.WidgetType; +import org.springframework.boot.CommandLineRunner; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +@Component +public class WidgetConverterFactory implements CommandLineRunner { + + private static final Map converterMap = new HashMap<>(); + + public static BaseConverter getConverter(String type) { + WidgetType widgetType = WidgetType.getByCode(type); + + if (widgetType == null) { + widgetType = WidgetType.GENERAL; + } + + BaseConverter baseConverter; + + switch (widgetType) { + case SWITCH: baseConverter = new BooleanConverter();break; + case DATE: baseConverter = new DateConverter();break; + case CHECKBOX: baseConverter = new CheckboxConverter();break; + case MULTIPLE_SELECT: baseConverter = new MultipleSelectConverter();break; + case IMG_UPLOAD: + case FILE_UPLOAD: + case UNIQ_KEY: + case DATA_LINK: + baseConverter = new NullValueConverter();break; + case SINGLE_MEMBER: baseConverter = new SingleMemberConverter();break; + case SINGLE_DEPARTMENT: baseConverter = new SingleDepartmentConverter();break; + case MULTIPLE_MEMBERS: baseConverter = new MultipleMemberConverter();break; + case LOCATION: baseConverter = new LocationConverter();break; + // case INPUT: baseConverter = new InputConverter();break; + case PHONE: baseConverter = new PhoneConverter();break; + + case MULTIPLE_DEPARTMENTS: baseConverter = new MultipleDepartmentsConverter();break; + + case FORMAT_NUMBER: baseConverter = new FormatNumberConverter();break; + case COORDINATES: baseConverter = new CoordinateConverter();break; + default:baseConverter = new GeneralConverter(); + } + + return baseConverter; + + } + + @Override + public void run(String... args) throws Exception { + converterMap.put(WidgetType.GENERAL, new GeneralConverter()); + converterMap.put(WidgetType.SWITCH, new BooleanConverter()); + converterMap.put(WidgetType.DATE, new DateConverter()); + converterMap.put(WidgetType.CHECKBOX, new CheckboxConverter()); + converterMap.put(WidgetType.IMG_UPLOAD, new EmptyArrayValueConverter()); + converterMap.put(WidgetType.FILE_UPLOAD, new EmptyArrayValueConverter()); + converterMap.put(WidgetType.UNIQ_KEY, new NullValueConverter()); + converterMap.put(WidgetType.DATA_LINK, new NullValueConverter()); + converterMap.put(WidgetType.SINGLE_MEMBER, new SingleMemberConverter()); + converterMap.put(WidgetType.SINGLE_DEPARTMENT, new SingleDepartmentConverter()); + converterMap.put(WidgetType.MULTIPLE_MEMBERS, new MultipleMemberConverter()); + converterMap.put(WidgetType.LOCATION, new LocationConverter()); + converterMap.put(WidgetType.INPUT, new InputConverter()); + converterMap.put(WidgetType.PHONE, new PhoneConverter()); + + converterMap.put(WidgetType.MULTIPLE_DEPARTMENTS, new MultipleDepartmentsConverter()); + + converterMap.put(WidgetType.FORMAT_NUMBER, new FormatNumberConverter()); + converterMap.put(WidgetType.COORDINATES, new CoordinateConverter()); + converterMap.put(WidgetType.MULTIPLE_SELECT, new MultipleSelectConverter()); + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/enums/ImportMode.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/enums/ImportMode.java new file mode 100644 index 0000000..16b5e0c --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/enums/ImportMode.java @@ -0,0 +1,17 @@ +package org.dromara.dataManager.service.impt.enums; + +public enum ImportMode { + CREATE("create"), + UPDATE("update"), + CREATE_AND_UPDATE("createAndUpdate"); + + private final String mode; + + public String getMode() { + return mode; + } + + ImportMode(String mode) { + this.mode = mode; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/exception/ImportDataInvalidException.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/exception/ImportDataInvalidException.java new file mode 100644 index 0000000..ad14f17 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/exception/ImportDataInvalidException.java @@ -0,0 +1,15 @@ +package org.dromara.dataManager.service.impt.exception; + +import lombok.Data; + +import java.util.List; + +@Data +public class ImportDataInvalidException extends Exception{ + private List invalidRows; + + public ImportDataInvalidException(String message, List invalidRows) { + super(message); + this.invalidRows = invalidRows; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/exception/ImportValidationException.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/exception/ImportValidationException.java new file mode 100644 index 0000000..0b9278b --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/exception/ImportValidationException.java @@ -0,0 +1,14 @@ +package org.dromara.dataManager.service.impt.exception; + +import org.dromara.dataManager.service.impt.model.InvalidColumnResult; +import lombok.Data; + +@Data +public class ImportValidationException extends Exception{ + private InvalidColumnResult result; + + public ImportValidationException(String message, InvalidColumnResult result) { + super(message); + this.result = result; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/model/CellSpanInfo.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/model/CellSpanInfo.java new file mode 100644 index 0000000..f005986 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/model/CellSpanInfo.java @@ -0,0 +1,11 @@ +package org.dromara.dataManager.service.impt.model; + +import lombok.Data; + +@Data +public class CellSpanInfo { + private int rowIndex; + private int columnIndex; + private int colSpan; + private int rowSpan; +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/model/ColumnsNeedValidate.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/model/ColumnsNeedValidate.java new file mode 100644 index 0000000..a773206 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/model/ColumnsNeedValidate.java @@ -0,0 +1,44 @@ +package org.dromara.dataManager.service.impt.model; + +import org.dromara.dataManager.enums.WidgetType; +import org.dromara.taskCenter.model.FormWidget; +import cn.hutool.core.util.BooleanUtil; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +@Data +public class ColumnsNeedValidate { + private List requiredWidgets = new ArrayList<>(); + private List dateWidgets = new ArrayList<>(); + private List numberWidgets = new ArrayList<>(); + + private List memberWidgets = new ArrayList<>(); + private List departWidgets = new ArrayList<>(); + + private List widgets; + + public ColumnsNeedValidate(List widgets) { + this.widgets = widgets; + analyse(); + } + + private void analyse() { + + widgets.forEach(w -> { + + Object requiredObj = w.getOptions().get("required"); + if (requiredObj != null && BooleanUtil.isTrue((Boolean) requiredObj)) { + requiredWidgets.add(w); + } + if (WidgetType.DATE.getCode().equals(w.getType())) { + dateWidgets.add(w); + } + if (WidgetType.FORMAT_NUMBER.getCode().equals(w.getType())) { + numberWidgets.add(w); + } + + }); + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/model/DataAnalysisParams.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/model/DataAnalysisParams.java new file mode 100644 index 0000000..7e2f996 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/model/DataAnalysisParams.java @@ -0,0 +1,19 @@ +package org.dromara.dataManager.service.impt.model; + +import org.dromara.dataManager.param.ImportDataParams; +import org.dromara.taskCenter.model.widget.WidgetModel; +import lombok.Data; + +import java.util.List; +import java.util.Map; + +@Data +public class DataAnalysisParams { + private Long formId; + private String formCode; + private int headerNumber; + private String primaryKey; + private List formWidgets; + private Map mappings; + private ImportDataParams.ValidationConfig validationConfig; +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/model/DownloadTemplateParams.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/model/DownloadTemplateParams.java new file mode 100644 index 0000000..79bad81 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/model/DownloadTemplateParams.java @@ -0,0 +1,11 @@ +package org.dromara.dataManager.service.impt.model; + +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +@Data +public class DownloadTemplateParams { + private List exportFields = new ArrayList<>(); +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/model/ExtraMergeInfoListener.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/model/ExtraMergeInfoListener.java new file mode 100644 index 0000000..bd799e9 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/model/ExtraMergeInfoListener.java @@ -0,0 +1,40 @@ +package org.dromara.dataManager.service.impt.model; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.enums.CellExtraTypeEnum; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.metadata.CellExtra; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class ExtraMergeInfoListener extends AnalysisEventListener> { + + private final List extraMergeInfoList = new ArrayList<>(); + private int rowCount = 0; + + @Override + public void invoke(Map data, AnalysisContext analysisContext) { + rowCount += 1; + } + + @Override + public void doAfterAllAnalysed(AnalysisContext analysisContext) { + } + + @Override + public void extra(CellExtra extra, AnalysisContext context) { + if (CellExtraTypeEnum.MERGE.equals(extra.getType())) { + extraMergeInfoList.add(extra); + } + } + + public List getExtraMergeInfoList() { + return extraMergeInfoList; + } + + public int getRowCount() { + return rowCount; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/model/ImportValidatorListener.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/model/ImportValidatorListener.java new file mode 100644 index 0000000..bbe16c5 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/model/ImportValidatorListener.java @@ -0,0 +1,384 @@ +package org.dromara.dataManager.service.impt.model; + +import org.dromara.dataManager.enums.WidgetType; +import org.dromara.dataManager.service.impt.validator.ValueValidator; +import org.dromara.taskCenter.model.FormWidget; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.metadata.CellExtra; + +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +public class ImportValidatorListener extends AnalysisEventListener> { + private static final int BATCH_COUNT = 2000; + private static final List NOT_IMPORTABLE_TYPES = Arrays.asList(WidgetType.FILE_UPLOAD.getCode(), WidgetType.IMG_UPLOAD.getCode()); + + private final List extraMergeInfoList; + private final Map mapping; + private final Map widgetMap; + private final int headRows; + + private List> list = new ArrayList<>(); + private final InvalidColumnResult invalidColumnResult = new InvalidColumnResult(); + + // 子表单外的必填、日期、数字字段 + private ColumnsNeedValidate widgetsOutOfTable2Validate; + // 子表单及其内的必填、日期、数字字段 + private final Map widgetsInTable2Validate = new HashMap<>(); + // 用于标记字段的校验状态,初始都是true + Map columnValidMap = new HashMap<>(); + + // 成员字段及其值的集合 + Map> memberValueMap = new HashMap<>(); + // 部门字段及其值的集合 + Map> departValueMap = new HashMap<>(); + + public ImportValidatorListener(List extraMergeInfoList, Map mapping, Map widgetMap, int headRows) { + this.extraMergeInfoList = extraMergeInfoList; + this.mapping = mapping; + this.widgetMap = widgetMap; + this.headRows = headRows; + } + + @Override + public void invoke(Map data, AnalysisContext analysisContext) { + Map row = new HashMap<>(); + mapping.forEach((colIndex, model) -> row.put(model, data.get(colIndex))); + list.add(row); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext analysisContext) { + generateWidgetsNeedValidate(); + initValidateWidgetsStatus(); + mergeRowAndValidate(); + } + + public boolean hasInvalidData() { + return columnValidMap.containsValue(false); + } + + public InvalidColumnResult getValidationResult() { + return invalidColumnResult; + } + + private Map> getTableColumns() { + Map> tableColumns = new HashMap<>(); + + widgetMap.forEach((model, widget) -> { + if (WidgetType.TABLE.getCode().equals(widget.getType())) { + tableColumns.put(model, widget.getTableColumns().stream().map(FormWidget::getModel).collect(Collectors.toList())); + } + }); + + return tableColumns; + } + + private void mergeRowAndValidate() { + Map> tableColumns = getTableColumns(); + Set tableColumnNames = new HashSet<>(); + tableColumns.forEach((tc, columns) -> tableColumnNames.addAll(columns)); + + List> dataSave2ES = new ArrayList<>(); + + if (CollectionUtil.isNotEmpty(tableColumns)) { + // 有子表单字段,需要处理合并单元格的数据后再导入 + + AtomicInteger rowIndex = new AtomicInteger(); + while (rowIndex.get() < list.size()) { + + Map thisRow = list.get(rowIndex.get()); + Map newRow = new HashMap<>(); + + // 被合并行数,也是距离下一条数据的行数 + AtomicInteger mostMergeRows = new AtomicInteger(1); + + thisRow.forEach((field, value) -> { + // 子表单字段 + if (tableColumnNames.contains(field)) { + + // 查找这行是否有纵向合并单元格 + Optional optional = extraMergeInfoList.stream().filter(info -> info.getFirstRowIndex().equals(rowIndex.get() + headRows) && info.getLastRowIndex() - info.getFirstRowIndex() > 0).findFirst(); + // 有多条数据 + if (optional.isPresent()) { + + mostMergeRows.set(optional.get().getLastRowIndex() - optional.get().getFirstRowIndex() + 1); + + // 遍历子表单字段,并收集子表单字段的数据 + tableColumns.forEach((table, columns) -> { + List> tableData = new ArrayList<>(); + for (int index = 0; index < mostMergeRows.get(); index++) { + Map rowData = new HashMap<>(); + int finalIndex = index; + columns.forEach(colName -> { + rowData.put(colName, list.get(rowIndex.get() + finalIndex).get(colName)); + }); + + tableData.add(rowData); + } + + newRow.put(table, tableData); + }); + + } + // 只有一条数据 + else { + // 遍历子表单字段,并收集子表单字段的数据 + tableColumns.forEach((table, columns) -> { + List> tableData = new ArrayList<>(); + + Map rowData = new HashMap<>(); + columns.forEach(colName -> { + rowData.put(colName, thisRow.get(colName)); + }); + tableData.add(rowData); + + newRow.put(table, tableData); + }); + } + } + // 非子表单字段 + else { + newRow.put(field, value); + } + + }); + + // 数据索引往后移 + rowIndex.addAndGet(mostMergeRows.get()); + + dataSave2ES.add(newRow); + + // 批量保存,以免内存中存在大量临时数据 + if (dataSave2ES.size() >= BATCH_COUNT) { + validate(dataSave2ES, null); +// validateMemberDepart(); + // 清空,使其被GC + dataSave2ES.clear(); + } + // 如果所有需要校验的字段都不合法,那就终止,没必要后续数据的校验了 + if (validationFinished()) { + break; + } + } + + } else { + // 没有子表单字段,无需处理合并单元格的数据,直接导入 + dataSave2ES = list; + } + + validate(dataSave2ES, null); +// validateMemberDepart(); + + } + + private void generateWidgetsNeedValidate() { + // 归类子表单外的必填、日期、数字字段, 且已有不合法数据的字段就不再校验了 + List notTableWidgets = widgetMap.values().stream() + .filter(widget -> !WidgetType.TABLE.getCode().equals(widget.getType())) + .collect(Collectors.toList()); + widgetsOutOfTable2Validate = new ColumnsNeedValidate(notTableWidgets); + + // 归类子表单内的必填、日期、数字字段 + widgetMap.values().stream().filter(widget -> WidgetType.TABLE.getCode().equals(widget.getType())).forEach(widget -> { + // 重命名子表单内的字段 + ColumnsNeedValidate cnv = new ColumnsNeedValidate(widget.getTableColumns().stream() + .filter(tc -> !NOT_IMPORTABLE_TYPES.contains(tc.getType()) && mapping.containsValue(tc.getModel())) + .peek(tc -> tc.setName(String.format("%s.%s", widget.getName(), tc.getName()))) + .collect(Collectors.toList())); + widgetsInTable2Validate.put(widget.getModel(), cnv); + }); + + // 初始化 + widgetMap.values().forEach(widget -> { + if (WidgetType.SINGLE_MEMBER.getCode().equals(widget.getType()) || WidgetType.MULTIPLE_MEMBERS.getCode().equals(widget.getType())) { + memberValueMap.put(widget.getModel(), new HashSet<>()); + widgetsOutOfTable2Validate.getMemberWidgets().add(widget); + + } else if (WidgetType.SINGLE_DEPARTMENT.getCode().equals(widget.getType()) || WidgetType.MULTIPLE_DEPARTMENTS.getCode().equals(widget.getType())) { + departValueMap.put(widget.getModel(), new HashSet<>()); + widgetsOutOfTable2Validate.getDepartWidgets().add(widget); + + } else if (WidgetType.TABLE.getCode().equals(widget.getType())) { + widget.getTableColumns().forEach(tc -> { + if (WidgetType.SINGLE_MEMBER.getCode().equals(tc.getType()) || WidgetType.MULTIPLE_MEMBERS.getCode().equals(tc.getType())) { + memberValueMap.put(tc.getModel(), new HashSet<>()); + widgetsInTable2Validate.get(widget.getModel()).getMemberWidgets().add(tc); + + } else if (WidgetType.SINGLE_DEPARTMENT.getCode().equals(tc.getType()) || WidgetType.MULTIPLE_DEPARTMENTS.getCode().equals(tc.getType())) { + departValueMap.put(tc.getModel(), new HashSet<>()); + widgetsInTable2Validate.get(widget.getModel()).getDepartWidgets().add(tc); + + } + }); + } + }); + + } + + private void initValidateWidgetsStatus() { + + widgetsOutOfTable2Validate.getRequiredWidgets().forEach(widget -> columnValidMap.put(widget.getModel(), true)); + widgetsOutOfTable2Validate.getDateWidgets().forEach(widget -> columnValidMap.put(widget.getModel(), true)); + widgetsOutOfTable2Validate.getNumberWidgets().forEach(widget -> columnValidMap.put(widget.getModel(), true)); + + widgetsInTable2Validate.forEach((table, cnv) -> { + cnv.getRequiredWidgets().forEach(tc -> columnValidMap.put(tc.getModel(), true)); + cnv.getDateWidgets().forEach(tc -> columnValidMap.put(tc.getModel(), true)); + cnv.getNumberWidgets().forEach(tc -> columnValidMap.put(tc.getModel(), true)); + }); + + memberValueMap.keySet().forEach(member -> columnValidMap.put(member, true)); + departValueMap.keySet().forEach(depart -> columnValidMap.put(depart, true)); + + } + + private void validate(List> dataSave2ES, ColumnsNeedValidate cnv) { + + Set tableFields = widgetsInTable2Validate.keySet(); + + for (Map row: dataSave2ES) { + // 如果所有需要校验的字段都不合法,那就终止,没必要后续数据的校验了 + if (validationFinished()) { + break; + } + row.forEach((fieldName, fieldValue) -> { + + if (tableFields.contains(fieldName)) { + + if (fieldValue != null) { + + ColumnsNeedValidate tableCnv = widgetsInTable2Validate.get(fieldName); + + List> tableData = (List>) fieldValue; + + validate(tableData, tableCnv); + } + + + } else { + + ColumnsNeedValidate workingCnv = cnv == null ? widgetsOutOfTable2Validate : cnv; + + validateFieldValue(fieldName, fieldValue, workingCnv); + } + + + }); + + } + } + + private void validateFieldValue(String fieldName, Object fieldValue, ColumnsNeedValidate cnv) { + + List requiredWidgets = cnv.getRequiredWidgets().stream().filter(w -> columnValidMap.get(w.getModel())).collect(Collectors.toList()); + List dateWidgets = cnv.getDateWidgets().stream().filter(w -> columnValidMap.get(w.getModel())).collect(Collectors.toList()); + List numberWidgets = cnv.getNumberWidgets().stream().filter(w -> columnValidMap.get(w.getModel())).collect(Collectors.toList()); + + List memberWidgets = cnv.getMemberWidgets().stream().filter(w -> columnValidMap.get(w.getModel())).collect(Collectors.toList()); + List departWidgets = cnv.getDepartWidgets().stream().filter(w -> columnValidMap.get(w.getModel())).collect(Collectors.toList()); + + List requiredModels = requiredWidgets.stream().map(FormWidget::getModel).collect(Collectors.toList()); + List dateModels = dateWidgets.stream().map(FormWidget::getModel).collect(Collectors.toList()); + List numberModels = numberWidgets.stream().map(FormWidget::getModel).collect(Collectors.toList()); + + List memberModels = memberWidgets.stream().map(FormWidget::getModel).collect(Collectors.toList()); + List departModels = departWidgets.stream().map(FormWidget::getModel).collect(Collectors.toList()); + + + if (requiredModels.contains(fieldName) && ValueValidator.isEmpty(fieldValue)) { + + Optional optional = requiredWidgets.stream().filter(w -> w.getModel().equals(fieldName)).findFirst(); + String name = optional.isPresent() ? optional.get().getName() : ""; + invalidColumnResult.add(fieldName, String.format("导入「%s」字段的值存在空值数据", name)); + + columnValidMap.put(fieldName, false); + + return; + } + + if (dateModels.contains(fieldName) && !ValueValidator.isEmpty(fieldValue) && !ValueValidator.isDate(fieldValue, widgetMap.get(fieldName))) { + + Optional optional = dateWidgets.stream().filter(w -> w.getModel().equals(fieldName)).findFirst(); + String name = optional.isPresent() ? optional.get().getName() : ""; + invalidColumnResult.add(fieldName, String.format("导入「%s」字段的值存在不是日期的数据,请检查格式,错误数据:%s", name, fieldValue)); + + columnValidMap.put(fieldName, false); + + return; + + } + + if (numberModels.contains(fieldName) && !ValueValidator.isEmpty(fieldValue) && !ValueValidator.isNumber(fieldValue)) { + + Optional optional = numberWidgets.stream().filter(w -> w.getModel().equals(fieldName)).findFirst(); + String name = optional.isPresent() ? optional.get().getName() : ""; + invalidColumnResult.add(fieldName, String.format("导入「%s」字段的值存在不是数字的数据,错误数据:%s", name, fieldValue)); + + columnValidMap.put(fieldName, false); + + } + + if (memberModels.contains(fieldName) && columnValidMap.get(fieldName)) { + + if (ObjectUtil.isNotEmpty(fieldValue)) { + memberValueMap.get(fieldName).addAll(Arrays.asList(fieldValue.toString().split(","))); + } + + } + + if (departModels.contains(fieldName) && columnValidMap.get(fieldName)) { + + if (ObjectUtil.isNotEmpty(fieldValue)) { + departValueMap.get(fieldName).addAll(Arrays.asList(fieldValue.toString().split(","))); + } + } + + } + +// private void validateMemberDepart() { +// // 校验账号合法性 +// Set mAccounts = new HashSet<>(); +// memberValueMap.keySet().stream().filter(key -> columnValidMap.get(key)).forEach(member -> { +// mAccounts.addAll(memberValueMap.get(member)); +// }); +// +// Map aNameMapping = SpringUtil.getBean(ISysUserService.class).getAccountNameMapping(mAccounts); +// Set validAccounts = aNameMapping.keySet(); +// memberValueMap.keySet().stream().filter(key -> columnValidMap.get(key)).forEach(member -> { +// +// List iva = memberValueMap.get(member).stream().filter(acc -> !validAccounts.contains(acc)).collect(Collectors.toList()); +// +// if (CollectionUtil.isNotEmpty(iva)) { +// columnValidMap.put(member, false); +// invalidColumnResult.add(member, String.format("导入数据中存在非系统内用户的账号,非法账号:%s", String.join(", ", iva))); +// } +// }); +// +// // 校验部门路径合法性 +// Set dPaths = new HashSet<>(); +// departValueMap.keySet().stream().filter(key -> columnValidMap.get(key)).forEach(depart -> { +// dPaths.addAll(departValueMap.get(depart)); +// }); +// Map pDMapping = SpringUtil.getBean(DepartmentService.class).getPathDepartMapping(dPaths); +// Set validPaths = pDMapping.keySet(); +// +// departValueMap.keySet().stream().filter(key -> columnValidMap.get(key)).forEach(depart -> { +// List ivp = departValueMap.get(depart).stream().filter(dp -> !validPaths.contains(dp)).collect(Collectors.toList()); +// if (CollectionUtil.isNotEmpty(ivp)) { +// columnValidMap.put(depart, false); +// invalidColumnResult.add(depart, String.format("导入数据中存在非系统内的部门路径,非法部门路径:%s", String.join(", ", ivp))); +// } +// }); +// } + + private boolean validationFinished() { + // 如果所有需要校验的字段都不合法,那就终止,没必要后续数据的校验了 + return !columnValidMap.containsValue(true); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/model/InvalidColumnResult.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/model/InvalidColumnResult.java new file mode 100644 index 0000000..3450f14 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/model/InvalidColumnResult.java @@ -0,0 +1,27 @@ +package org.dromara.dataManager.service.impt.model; + +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +@Data +public class InvalidColumnResult { + + private List invalidColumns = new ArrayList<>(); + + public void add(String column, String message) { + invalidColumns.add(new InvalidColumn(column, message)); + } + + @Data + public static class InvalidColumn { + private String column; + private String message; + + public InvalidColumn(String column, String message) { + this.column = column; + this.message = message; + } + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/model/PreviewResult.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/model/PreviewResult.java new file mode 100644 index 0000000..12e6ad4 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/model/PreviewResult.java @@ -0,0 +1,30 @@ +package org.dromara.dataManager.service.impt.model; + +import lombok.Data; + +import java.util.List; + +@Data +public class PreviewResult { + private List headers; + private List data; + private List sheets; + private String sheetName; + private List spanInfoList; + + public PreviewResult() { + } + + public PreviewResult(List headers, List data, List sheets) { + this.headers = headers; + this.data = data; + this.sheets = sheets; + } + + public PreviewResult(List headers, List data, List sheets, String sheetName) { + this.headers = headers; + this.data = data; + this.sheets = sheets; + this.sheetName = sheetName; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/model/PreviewTableHeader.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/model/PreviewTableHeader.java new file mode 100644 index 0000000..808683b --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/model/PreviewTableHeader.java @@ -0,0 +1,18 @@ +package org.dromara.dataManager.service.impt.model; + +import cn.hutool.core.util.StrUtil; +import lombok.Data; + +import java.util.List; + +@Data +public class PreviewTableHeader { + private String title; + private List children; + private int columnIndex; + + public PreviewTableHeader(String title, int columnIndex) { + this.title = StrUtil.isBlank(title) ? "" : title; + this.columnIndex = columnIndex; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/model/StringConverter.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/model/StringConverter.java new file mode 100644 index 0000000..5d53af7 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/model/StringConverter.java @@ -0,0 +1,19 @@ +package org.dromara.dataManager.service.impt.model; + +import org.dromara.dataManager.service.impt.convert.WidgetConverter; +import org.dromara.taskCenter.model.widget.WidgetModel; + +/** + * 单行文本 + */ +public class StringConverter extends WidgetConverter { + + public StringConverter(WidgetModel widget) { + super(widget); + } + + @Override + public Object valueOf(String value) { + return value == null ? null : value.replaceAll("\n", ""); + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/service/ImportFromExcelHelper.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/service/ImportFromExcelHelper.java new file mode 100644 index 0000000..50b92bc --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/service/ImportFromExcelHelper.java @@ -0,0 +1,116 @@ +//package org.dromara.dataManager.service.impt.service; +// +//import cn.hutool.core.collection.CollUtil; +//import cn.hutool.core.collection.CollectionUtil; +//import cn.hutool.json.JSONArray; +//import cn.hutool.json.JSONObject; +//import cn.hutool.json.JSONUtil; +//import org.apache.commons.lang3.StringUtils; +//import org.elasticsearch.action.search.SearchRequest; +//import org.elasticsearch.index.query.QueryBuilders; +//import org.elasticsearch.search.builder.SearchSourceBuilder; +//import org.elasticsearch.search.sort.SortOrder; +//import org.springframework.stereotype.Component; +// +//import java.io.IOException; +//import java.util.List; +//import java.util.Map; +// +//@Component +//public class ImportFromExcelHelper { +// +// // @Autowired +// // private ElasticsearchClient elasticsearchClient; +// +// public List getNotExistIds(String index, String query, List ids) throws IOException { +// if(CollUtil.isNotEmpty(ids)){ +// return ids; +// } +// SearchRequest searchRequest = new SearchRequest(index); +// +// SearchSourceBuilder sb = SearchSourceBuilder.searchSource(); +// +// JSONObject queryObj; +// if (StringUtils.isNotBlank(query)) { +// queryObj = JSONUtil.parseObj(query); +// } else { +// queryObj = new JSONObject(); +// } +// +// if (CollectionUtil.isNotEmpty(ids)) { +// queryObj.getByPath("query.bool.must", JSONArray.class).add(JSONUtil.parseObj(QueryBuilders.idsQuery().addIds(ids.toArray(new String[0])).toString())); +// } +// +// JSONObject query4Req = new JSONObject(); +// query4Req.putOpt("bool", queryObj.getByPath("query.bool")); +// if (queryObj.get("query.filter") != null && !queryObj.getByPath("query.filter", JSONObject.class).isEmpty()) { +// query4Req.putOpt("filter", queryObj.getByPath("query.filter")); +// } +// +// sb.query(QueryBuilders.wrapperQuery(query4Req.toString())); +// sb.fetchSource(new String[]{"_id"}, new String[]{}); +// // 最大只能处理3万条数据 +// sb.size(Math.min(ids.size(), 30000)); +// +// searchRequest.source(sb); +// +// // try (final RestHighLevelClient client = elasticsearchClient.getHighClient()) { +// // +// // SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT); +// // +// // List existedIds = Arrays.stream(response.getHits().getHits()) +// // .map(SearchHit::getId) +// // .collect(Collectors.toList()); +// // +// // return ids.stream().filter(id -> !existedIds.contains(id)).collect(Collectors.toList()); +// // +// // } +// return ids; +// } +// +// public Map getPKValueMapping(String index, String query, String pk, List pkValues) throws IOException { +// +// SearchRequest searchRequest = new SearchRequest(index); +// +// SearchSourceBuilder sb = SearchSourceBuilder.searchSource(); +// sb.fetchSource(new String[]{pk}, new String[]{}); +// sb.sort("createTime", SortOrder.ASC); +// // 最多处理3万条 +// sb.size(30000); +// +// JSONObject queryObj; +// if (StringUtils.isNotBlank(query)) { +// queryObj = JSONUtil.parseObj(query); +// } else { +// queryObj = new JSONObject(); +// } +// +// if (CollectionUtil.isNotEmpty(pkValues)) { +// queryObj.getByPath("query.bool.must", JSONArray.class).add(JSONUtil.parseObj(QueryBuilders.termsQuery(pk, pkValues).toString())); +// } +// +// JSONObject query4Req = new JSONObject(); +// query4Req.putOpt("bool", queryObj.getByPath("query.bool")); +// if (queryObj.get("query.filter") != null && !queryObj.getByPath("query.filter", JSONObject.class).isEmpty()) { +// query4Req.putOpt("filter", queryObj.getByPath("query.filter")); +// } +// +// sb.query(QueryBuilders.wrapperQuery(query4Req.toString())); +// +// searchRequest.source(sb); +// // +// // try (final RestHighLevelClient client = elasticsearchClient.getHighClient()) { +// // +// // SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT); +// // +// // Map map = new HashMap<>(); +// // Arrays.stream(response.getHits().getHits()) +// // .forEach(hit -> map.put(JSONUtil.parseObj(hit.getSourceAsString()).getByPath(pk, String.class), hit.getId())); +// // +// // return map; +// // +// // } +// +// return null; +// } +//} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/service/ImportFromExcelService.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/service/ImportFromExcelService.java new file mode 100644 index 0000000..fcf6df5 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/service/ImportFromExcelService.java @@ -0,0 +1,20 @@ +package org.dromara.dataManager.service.impt.service; + +import jakarta.servlet.http.HttpServletResponse; +import org.dromara.dataManager.param.ImportDataParams; +import org.dromara.dataManager.service.impt.exception.ImportDataInvalidException; +import org.dromara.dataManager.service.impt.model.PreviewResult; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +public interface ImportFromExcelService{ + PreviewResult previewExcel(MultipartFile file,Integer sheetIndex) throws IOException; + + void generateImportTemplate(HttpServletResponse response, Long formId, List exportFields) throws IOException; + + List> importV2(ImportDataParams params) throws IOException, ImportDataInvalidException; + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/service/impl/ImportFromExcelServiceImpl.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/service/impl/ImportFromExcelServiceImpl.java new file mode 100644 index 0000000..7a18213 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/service/impl/ImportFromExcelServiceImpl.java @@ -0,0 +1,621 @@ +package org.dromara.dataManager.service.impt.service.impl; + +import cn.hutool.core.collection.CollUtil; +import jakarta.servlet.http.HttpServletResponse; +import org.dromara.common.util.JsonUtil; +import org.dromara.dataManager.enums.WidgetType; +import org.dromara.dataManager.param.ImportDataParams; +import org.dromara.dataManager.service.FormDataService; +import org.dromara.dataManager.service.impt.common.HeaderMergeStrategiesGenerator; +import org.dromara.dataManager.service.impt.enums.ImportMode; +import org.dromara.dataManager.service.impt.exception.ImportDataInvalidException; +import org.dromara.dataManager.service.impt.model.*; +import org.dromara.dataManager.service.impt.service.ImportFromExcelService; +import org.dromara.dataManager.service.impt.service.impl.excel.listener.DataAnalysisEventListener; +import org.dromara.formMaking.results.FormSourceResult; +import org.dromara.formMaking.service.FormSourceService; +import org.dromara.taskCenter.model.FormWidget; +import org.dromara.taskCenter.model.widget.WidgetModel; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.enums.CellExtraTypeEnum; +import com.alibaba.excel.metadata.CellExtra; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.excel.util.DateUtils; +import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder; +import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import java.io.IOException; +import java.net.URLEncoder; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +@Slf4j +@Service +public class ImportFromExcelServiceImpl implements ImportFromExcelService { + + @Resource + private FormSourceService sourceQueryService; + + @Resource + private FormDataService formDataService; + +// @Resource +// private ImportFromExcelHelper importFromExcelHelper; + + + @Override + public PreviewResult previewExcel(MultipartFile file, Integer sheetIndex) throws IOException { + + // FormSource form = this.sourceQueryService.getFormSourceById(formId); + + // 是否有合并表头,有的话表头有两行,没有的话表头只有一行 + /*boolean hasMergedHeaders = false; + + List formColumns = JsonUtil.jsonToList(formDetail.getColumns(), FormColumn.class); + if (formColumns != null) { + if (formColumns.stream().anyMatch(formColumn -> WidgetType.TABLE.getCode().equals(formColumn.getEleType()) && CollectionUtil.isNotEmpty(formColumn.getSubColumns()))) { + hasMergedHeaders = true; + } + }*/ + + // 获取Excel中的sheet索引 + List sheets = EasyExcel.read(file.getInputStream()) + .build() + .excelExecutor() + .sheetList() + .stream() + .map(ReadSheet::getSheetName) + .collect(Collectors.toList()); + + sheetIndex = sheetIndex == null ? 0 : sheetIndex; + + // 获取Excel中所有的数据 + ExtraMergeInfoListener mergeInfoListener = new ExtraMergeInfoListener(); + List sheetData = EasyExcel.read(file.getInputStream(), mergeInfoListener) + .extraRead(CellExtraTypeEnum.MERGE) + .sheet(sheetIndex) + .headRowNumber(0) + .doReadSync() + .stream() + .limit(30000) + .collect(Collectors.toList()); + + if (CollectionUtil.isEmpty(sheetData)) { + return new PreviewResult(new ArrayList<>(), new ArrayList<>(), sheets, sheets.get(sheetIndex)); + } + + boolean hasMergedHeaders = mergeInfoListener.getExtraMergeInfoList().stream().anyMatch(em -> em.getFirstRowIndex() == 0); + int howManyHeaders = hasMergedHeaders ? 2 : 1; + + List headers = generatePreviewTableHeaders(sheetData, mergeInfoListener.getExtraMergeInfoList(), howManyHeaders); + + List data = new ArrayList<>(); + + // 解析出数据 + if (sheetData.size() > howManyHeaders) { + data = sheetData.subList(howManyHeaders, sheetData.size()); + } + + PreviewResult previewResult = new PreviewResult(headers, data, sheets); + previewResult.setSheetName(sheets.get(sheetIndex)); + previewResult.setSpanInfoList(generateMergeInfo(mergeInfoListener.getExtraMergeInfoList(), headers, howManyHeaders)); + return previewResult; + } + + @Override + public void generateImportTemplate(HttpServletResponse response, Long formId, List exportFields) throws IOException { + FormSourceResult formInfo = sourceQueryService.getFormSourceById(formId); + List> headers = new ArrayList<>(); + + String widgetStr = JSONUtil.parseObj(formInfo.getFormJson()).getStr("list"); + + List formColumns = JsonUtil.jsonToList(widgetStr, FormWidget.class); + List exportableFields = new ArrayList<>(); + + if (formColumns != null) { + formColumns.stream() + .filter(column -> { + // 过滤掉文件、图片、流水号字段 + if (WidgetType.FILE_UPLOAD.getCode().equals(column.getType()) || WidgetType.IMG_UPLOAD.getCode().equals(column.getType()) + || WidgetType.UNIQ_KEY.getCode().equals(column.getType()) || WidgetType.TEXT.getCode().equals(column.getType()) + || WidgetType.COORDINATES.getCode().equals(column.getType())|| WidgetType.DATA_LINK.getCode().equals(column.getType()) + || WidgetType.DIVIDER.getCode().equals(column.getType())) { + return false; + } else if (CollectionUtil.isNotEmpty(column.getTableColumns())){ + List validCols = column.getTableColumns().stream() + .filter(col -> !WidgetType.FILE_UPLOAD.getCode().equals(col.getType()) + && !WidgetType.IMG_UPLOAD.getCode().equals(col.getType()) + && !WidgetType.UNIQ_KEY.getCode().equals(col.getType()) + && !WidgetType.COORDINATES.getCode().equals(col.getType()) + && exportFields.contains(col.getModel())) + .collect(Collectors.toList()); + column.setTableColumns(validCols); + return validCols.size() > 0; + } else { + return exportFields.contains(column.getModel()); + } + }) + .forEach(column -> { + if (CollectionUtil.isNotEmpty(column.getTableColumns())) { + column.getTableColumns().forEach(col -> { + List header = new ArrayList<>(); + header.add(column.getName()); + header.add(col.getName()); + headers.add(header); + }); + } else { + List header = new ArrayList<>(); + header.add(column.getName()); + headers.add(header); + + } + exportableFields.add(column.getModel()); + }); + } + + String fileName = URLEncoder.encode(String.format("%s-数据导入模版%s.xlsx", formInfo.getTitle(), DateUtils.format(new Date(), "yyyyMMddHHmmss")), "UTF-8").replaceAll("\\+", "%20"); + response.setHeader("Content-Disposition", String.format("attachment;filename=%s", fileName)); + response.setContentType("application/vnd.ms-excel"); + response.setCharacterEncoding("utf-8"); + + ExcelWriterSheetBuilder sheetBuilder = EasyExcel.write(response.getOutputStream()).sheet("sheet1"); + + HeaderMergeStrategiesGenerator.generate(formColumns, exportableFields).forEach(sheetBuilder::registerWriteHandler); + + sheetBuilder.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) + .automaticMergeHead(false) + .head(headers) + .doWrite(new ArrayList<>()); + + } + + @Override + public List> importV2(ImportDataParams params) throws IOException, ImportDataInvalidException { + MultipartFile file = params.getFile(); + Long formId = params.getFormId(); + Integer sheetIndex = params.getSheetIndex(); + Map mappings = params.getObjMapping(); + + FormSourceResult form = sourceQueryService.getFormSourceById(formId); + + // 是否有合并表头 + boolean hasMergedHeaders = hasMergedHeaders(file, sheetIndex); + + // 导入数据的表单字段 + List formWidgets = new ArrayList<>(); + + if (form.getFormJson() != null) { + Map formJson = JsonUtil.jsonToMap(form.getFormJson()); + assert formJson != null; + formWidgets = JsonUtil.jsonToList(JsonUtil.toJson(formJson.get("list")), WidgetModel.class); + } + + int headerNumber = hasMergedHeaders ? 2 : 1; + + // 导入数据量校验 + // 获取Excel中所有的数据 + ExtraMergeInfoListener countListener = new ExtraMergeInfoListener(); + EasyExcel.read(file.getInputStream(), countListener) + .sheet(sheetIndex) + .headRowNumber(headerNumber) + .doRead(); + + int rowCount = countListener.getRowCount(); + + // 有成员部门字段限制到一万条,否则最大三万条 + boolean thereAreDMC = thereAreDMColumns(formWidgets, mappings.values()); + long maxCount = thereAreDMC ? DataAnalysisEventListener.MAX_DM_DATA_COUNT : DataAnalysisEventListener.MAX_DATA_COUNT; + + if (rowCount > maxCount) { + int dataCount = headerNumber == 1 ? rowCount - headerNumber : rowCount - headerNumber + 1; + String message = thereAreDMC ? String.format("文件有%d条数据,有成员部门字段时导入数据不能超过%d条", dataCount, maxCount) : String.format("文件有%d条数据,导入数据不能超过%d条", dataCount, maxCount); + throw new ImportDataInvalidException(message, null); + } + + // String primaryKey = params.getObjMapping().containsValue(DataAnalysisEventListener.DATA_ID) ? DataAnalysisEventListener.DATA_ID : params.getPrimaryKey(); + String primaryKey = params.getPrimaryKey(); + + // 开始导入 + DataAnalysisParams dap = new DataAnalysisParams(); + dap.setFormId(form.getId()); + dap.setFormCode(form.getCode()); + dap.setHeaderNumber(headerNumber); + dap.setPrimaryKey(primaryKey); + dap.setFormWidgets(formWidgets); + dap.setMappings(mappings); + dap.setValidationConfig(params.getValidationConfig()); + + DataAnalysisEventListener listener = new DataAnalysisEventListener(dap); + + EasyExcel.read( file.getInputStream(), listener) + .extraRead(CellExtraTypeEnum.MERGE) + .headRowNumber(headerNumber) + .autoCloseStream(true) + .sheet(sheetIndex) + .doRead(); + + if (!listener.getInvalidRows().isEmpty()) { + throw new ImportDataInvalidException("导入文件中有不合法数据", listener.getInvalidRows()); + } + + List> convertedData = generateData4Save(listener.getConvertedData(), params, form.getFormJson()); + + if (convertedData.size() > 0) { + // formDataService.batchSave(formCode, LoginContextHolder.me().getSysLoginUserId(), convertedData); + } + + return convertedData; + } + + private boolean hasMergedHeaders(MultipartFile file, int sheetIndex) { + ExtraMergeInfoListener mergeInfoListener = new ExtraMergeInfoListener(); + try { + List sheetData = EasyExcel.read(file.getInputStream(), mergeInfoListener) + .extraRead(CellExtraTypeEnum.MERGE) + .sheet(sheetIndex) + .headRowNumber(0) + .doReadSync() + .stream() + .limit(1) + .collect(Collectors.toList()); + + return mergeInfoListener.getExtraMergeInfoList().stream().anyMatch(em -> em.getFirstRowIndex() == 0); + + } catch (IOException e) { + return true; + } + + } + + private boolean thereAreDMColumns(List formWidgets, Collection importFields) { + List tc = new ArrayList<>(); + formWidgets.forEach(fc -> { + if (isDMColumn(fc)) { + tc.add(fc.getModel()); + } else if (CollectionUtil.isNotEmpty(fc.getTableColumns())) { + tc.addAll(fc.getTableColumns().stream().filter(this::isDMColumn).map(WidgetModel::getModel).collect(Collectors.toList())); + } + }); + return importFields.stream().anyMatch(tc::contains); + } + + private boolean isDMColumn(WidgetModel wm) { + return wm.getType().equals(WidgetType.SINGLE_MEMBER.getCode()) || wm.getType().equals(WidgetType.SINGLE_DEPARTMENT.getCode()) + || wm.getType().equals(WidgetType.MULTIPLE_DEPARTMENTS.getCode()) || wm.getType().equals(WidgetType.MULTIPLE_MEMBERS.getCode()); + } + + /** + * 生成可保存数据 + * @param rawData + * @param params + * @return + */ + private List> generateData4Save(List> rawData, ImportDataParams params, String formJson) { + + if (ImportMode.CREATE.equals(params.getMode())) { + return generateCreateData(rawData, params.getFormId(), formJson); + } + + if (StrUtil.isNotBlank(params.getPrimaryKey())) { + + if (DataAnalysisEventListener.DATA_ID.equals(params.getPrimaryKey())) { + return generateUpsertData4IDMode(rawData, params); + } else { + return generateUpsertData4PKMode(rawData, params); + } + + } else if (params.getObjMapping().containsValue(DataAnalysisEventListener.DATA_ID)) { + return generateUpsertData4IDMode(rawData, params); + } + + return new ArrayList<>(); + } + + /** + * 根据匹配字段生成可保存数据 + * @param rawData + * @param params + * @return + */ + private List> generateUpsertData4PKMode(List> rawData, ImportDataParams params) { + // eg: singlemember_1641965976117.code, input_1641965973461 + String primaryKey = params.getPrimaryKey().contains(WidgetType.SINGLE_MEMBER.getCode()) ? String.format("%s.code", params.getPrimaryKey()) : params.getPrimaryKey(); + List pks = new ArrayList<>(); + + // 收集导入的主键 + rawData.forEach(cd -> { + + if (ObjectUtil.isNotEmpty(cd.get(primaryKey))) { + JSONObject jo = JSONUtil.parseObj(JSONUtil.toJsonStr(cd)); + pks.add(jo.getByPath(primaryKey, String.class)); + } + + }); + + try { + + // Map pkvMapping = importFromExcelHelper.getPKValueMapping(params.getFormCode(), params.toElasticsearchQuery(), params.getPrimaryKey(), pks); +// Map pkvMapping = importFromExcelHelper.getPKValueMapping(params.getFormCode(), null, +// params.getPrimaryKey(), pks); + Map pkvMapping = new HashMap<>(); + Set validPK = pkvMapping.keySet(); + + rawData = rawData.stream() + .filter(cd -> { + + JSONObject row = JSONUtil.parseObj(cd); + + // 仅更新模式仅返回有数据ID且数据ID是合法的数据 + if (ImportMode.UPDATE.equals(params.getMode())) { + return ObjectUtil.isNotEmpty(row.getByPath(primaryKey, String.class)) && validPK.contains(row.getByPath(primaryKey, String.class)); + } + // 新增和更新数据模式,返回没有匹配字段或者匹配字段是合法的数据 + else { + + String rowPK = row.getByPath(primaryKey, String.class); + // 若匹配字段是空的,这条数据是有效的 + if (StrUtil.isBlank(rowPK)) { + return true; + } else { + // 若匹配字段不是空的,则判断是否可以找到数据ID,找得到则是有效的,找不到则是无效的数据 + return StrUtil.isNotBlank(pkvMapping.get(rowPK)); + } + + } + }) + .peek(cd -> { + JSONObject row = JSONUtil.parseObj(cd); + String rowPK = row.getByPath(primaryKey, String.class); + cd.put("updateTime", new Date()); + if (StrUtil.isNotBlank(rowPK)) { + // 根据主键查找到对应的数据ID + cd.put(DataAnalysisEventListener.DATA_ID, pkvMapping.get(rowPK)); + } else { + // 为没有ID的数据创建ID + cd.put(DataAnalysisEventListener.DATA_ID, UUID.randomUUID().toString().replaceAll("-","")); + } + }) + .collect(Collectors.toList()); + + } catch (Exception e) { + e.printStackTrace(); + } + + + return rawData; + } + + /** + * 为创建模式下生成可保存的数据 + * @param rawData 原始数据 + * @return 转换后的数据 + */ + private List> generateCreateData(List> rawData, Long formId, String formJson) { + AtomicInteger count = new AtomicInteger(); + + rawData.forEach(row -> { + row.put(DataAnalysisEventListener.DATA_ID, UUID.randomUUID().toString().replaceAll("-","")); + Date date = new Date(System.currentTimeMillis() + count.getAndAdd(500)); + row.put("createTime", date); + row.put("updateTime", date); + }); + + return rawData; + } + + /** + * 根据数据ID生成可保存数据 + * @param rawData 转换前的数据 + * @param params 转换参数 + * @return 转换后的数据 + */ + private List> generateUpsertData4IDMode(List> rawData, ImportDataParams params) { + + List ids = new ArrayList<>(); + ImportMode mode = params.getMode(); + String formCode = params.getFormCode(); + // String query = params.toElasticsearchQuery(); + String query = null; + // 收集导入的ID + rawData.forEach(cd -> { + + if (ObjectUtil.isNotEmpty(cd.get(DataAnalysisEventListener.DATA_ID))) { + ids.add((String) cd.get(DataAnalysisEventListener.DATA_ID)); + } + + }); + + // 过滤掉非法ID + try { + +// List invalidIds = importFromExcelHelper.getNotExistIds(formCode, query, ids); + List invalidIds = CollUtil.newArrayList(); + rawData = rawData.stream() + .filter(cd -> { + + // 仅更新模式仅返回有数据ID且数据ID是合法的数据 + if (ImportMode.UPDATE.equals(mode)) { + return ObjectUtil.isNotEmpty(cd.get(DataAnalysisEventListener.DATA_ID)) && !invalidIds.contains((String) cd.get(DataAnalysisEventListener.DATA_ID)); + } + // 新增和更新数据模式,返回没有数据ID或者数据ID是合法的数据 + else { + return ObjectUtil.isEmpty(cd.get(DataAnalysisEventListener.DATA_ID)) || !invalidIds.contains((String) cd.get(DataAnalysisEventListener.DATA_ID)); + } + }) + .peek(cd -> { + + // 为没有ID的数据创建ID + if (ObjectUtil.isEmpty(cd.get(DataAnalysisEventListener.DATA_ID))) { + + cd.put(DataAnalysisEventListener.DATA_ID, UUID.randomUUID().toString().replaceAll("-","")); + } + cd.put("updateTime", new Date()); + + }) + .collect(Collectors.toList()); + + } catch (Exception e) { + log.error(e.getMessage(), e); + } + + return rawData; + } + + /** + * 生成预览表头 + * @param sheetData + * @param extraMergeInfoList + * @param howManyHeaders + * @return + */ + private List generatePreviewTableHeaders(List sheetData, List extraMergeInfoList, int howManyHeaders) { + List headers = new ArrayList<>(); + + // 解析出表头 + List> headerRows = sheetData.stream() + .limit(howManyHeaders) + .map(JsonUtil::toJson) + .map(JsonUtil::jsonToMap) + .collect(Collectors.toList()); + + Map firstRow = headerRows.get(0); + Map secondRow = headerRows.size() > 1 ? headerRows.get(1) : null; + + // 查看表头是否有合并单元格 + List mergedHeaderCells = extraMergeInfoList.stream() + .filter(extra -> extra.getFirstRowIndex() == 0 && extra.getLastRowIndex() == 0) + .collect(Collectors.toList()); + + List existedColumns = new ArrayList<>(); + AtomicInteger currentColumnIndex = new AtomicInteger(); + firstRow.forEach((col, value) -> { + + if (col.equals(currentColumnIndex.toString())) { + + // 判断是否是合并单元格 + Integer colIndex = Integer.parseInt(col); + Optional optional = mergedHeaderCells.stream().filter(cellExtra -> colIndex.equals(cellExtra.getFirstColumnIndex())).findFirst(); + + String strValue = ObjectUtil.isEmpty(value) ? "" : String.valueOf(value); + + if (optional.isPresent() && secondRow != null) { + // 有合并单元格 + CellExtra extra = optional.get(); + + PreviewTableHeader header = new PreviewTableHeader(strValue, new Random().nextInt() * 100); + + List children = new ArrayList<>(); + for (int cellColIndex = extra.getFirstColumnIndex(); cellColIndex <= extra.getLastColumnIndex(); cellColIndex++) { + PreviewTableHeader subHeader = new PreviewTableHeader((String) secondRow.get(String.valueOf(cellColIndex)), currentColumnIndex.get()); + children.add(subHeader); + currentColumnIndex.getAndIncrement(); + } + header.setChildren(children); + + headers.add(header); + + existedColumns.add(strValue); + + } else if (!existedColumns.contains(strValue)){ + // 没有合并单元格 + PreviewTableHeader header = new PreviewTableHeader(strValue, currentColumnIndex.get()); + if (secondRow != null && secondRow.get(col) != null && !strValue.equals(secondRow.get(col))) { + PreviewTableHeader subHeader = new PreviewTableHeader((String) secondRow.get(col), currentColumnIndex.get()); + List children = new ArrayList<>(); + children.add(subHeader); + header.setChildren(children); + } + headers.add(header); + + currentColumnIndex.getAndIncrement(); + + } + + } + + }); + + return headers; + } + + /** + * 生成合并单元格信息 + * @param extraMergeInfoList + * @param howManyHeaders + * @return + */ + private List generateMergeInfo(List extraMergeInfoList, List tableHeaders, int howManyHeaders) { + List spanInfoList = new ArrayList<>(); + + extraMergeInfoList.stream().filter(cellExtra -> cellExtra.getFirstRowIndex() >= howManyHeaders).forEach(cellExtra -> { + + int firstRowIndex = cellExtra.getFirstRowIndex(); + int firstColIndex = cellExtra.getFirstColumnIndex(); + + for (int rowIndex = cellExtra.getFirstRowIndex(); rowIndex <= cellExtra.getLastRowIndex(); rowIndex++) { + + for (int colIndex = cellExtra.getFirstColumnIndex(); colIndex <= cellExtra.getLastColumnIndex(); colIndex++) { + + if (rowIndex == firstRowIndex && colIndex == firstColIndex) { + // 第一个合并单元格 + CellSpanInfo firstMergeCell = new CellSpanInfo(); + firstMergeCell.setRowIndex(rowIndex - howManyHeaders); + firstMergeCell.setColumnIndex(getPreviewColumnIndex(tableHeaders, colIndex)); + firstMergeCell.setRowSpan(cellExtra.getLastRowIndex() - cellExtra.getFirstRowIndex() + 1); + firstMergeCell.setColSpan(cellExtra.getLastColumnIndex() - cellExtra.getFirstColumnIndex() + 1); + spanInfoList.add(firstMergeCell); + } else { + // 处理被合并的单元格(只处理了纵向被合并的单元格) + CellSpanInfo noSpanCell = new CellSpanInfo(); + noSpanCell.setRowIndex(rowIndex - howManyHeaders); + noSpanCell.setColumnIndex(getPreviewColumnIndex(tableHeaders, colIndex)); + noSpanCell.setRowSpan(0); + noSpanCell.setColSpan(0); + spanInfoList.add(noSpanCell); + } + } + } + + }); + + return spanInfoList; + } + + /** + * 计算并获得列的实际索引 + * @param tableHeaders + * @param columnIndex + * @return + */ + private int getPreviewColumnIndex(List tableHeaders, int columnIndex) { + int columnCount = 0; + int mergeCellCount = 0; + + for (PreviewTableHeader header : tableHeaders) { + + if (columnCount >= columnIndex) { + break; + } + + if (CollectionUtil.isNotEmpty(header.getChildren())) { + columnCount += header.getChildren().size(); + mergeCellCount += header.getChildren().size(); + } else { + columnCount++; + } + } + + return columnIndex - mergeCellCount + (mergeCellCount > 0 ? 1 : 0); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/service/impl/excel/ImportDemo.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/service/impl/excel/ImportDemo.java new file mode 100644 index 0000000..d586a16 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/service/impl/excel/ImportDemo.java @@ -0,0 +1,63 @@ +package org.dromara.dataManager.service.impt.service.impl.excel; + +//public class ImportDemo { +// private static final String FILE_PATH = "/Users/mofei/Downloads/导入数据改进_20220308171018.xlsx"; +// +// public static void main(String[] args) throws FileNotFoundException { +// String list = "[{\"type\":\"input\",\"icon\":\"icondanhangwenben\",\"options\":{\"width\":\"100%\",\"widgetWidth\":\"100%\",\"defaultValue\":null,\"required\":false,\"unique\":false,\"uniqueMessage\":null,\"requiredMessage\":\"\",\"dataType\":\"string\",\"dataTypeCheck\":false,\"dataTypeMessage\":\"\",\"pattern\":\"\",\"patternCheck\":false,\"patternMessage\":\"\",\"placeholder\":\"\",\"customClass\":\"\",\"disabled\":false,\"labelWidth\":100,\"isLabelWidth\":false,\"hidden\":false,\"dataBind\":true,\"showPassword\":false,\"dataRely\":{},\"defaultValueMode\":\"custom\",\"remoteDataConfig\":{\"dataSourceRefId\":null,\"dataSourceId\":null,\"mappings\":[]}},\"name\":\"姓名\",\"key\":\"1645949802163\",\"model\":\"input_1645949802163\",\"rules\":[]},{\"type\":\"date\",\"icon\":\"iconriqixuanzeqi\",\"options\":{\"defaultValue\":null,\"showDefaultValue\":null,\"readonly\":false,\"disabled\":false,\"editable\":false,\"clearable\":false,\"placeholder\":\"\",\"startPlaceholder\":\"\",\"endPlaceholder\":\"\",\"type\":\"month\",\"format\":\"yyyy-MM\",\"clearTime\":\"\",\"timestamp\":false,\"required\":false,\"requiredMessage\":\"\",\"width\":\"100%\",\"widgetWidth\":\"100%\",\"customClass\":\"\",\"labelWidth\":100,\"isLabelWidth\":false,\"hidden\":false,\"dataBind\":true,\"dataRely\":{},\"defaultValueMode\":\"custom\",\"remoteDataConfig\":{\"dataSourceRefId\":null,\"dataSourceId\":null,\"mappings\":[]}},\"name\":\"生日\",\"key\":\"1645949803610\",\"model\":\"date_1645949803610\",\"rules\":[]},{\"type\":\"format_number\",\"icon\":\"iconjishuqi\",\"options\":{\"width\":\"100%\",\"widgetWidth\":\"100%\",\"defaultValue\":null,\"showDefaultValue\":null,\"required\":true,\"placeholder\":\"\",\"disabled\":false,\"labelWidth\":100,\"requiredMessage\":\"\",\"isNumberRange\":false,\"minNumber\":null,\"showMinNumber\":null,\"maxNumber\":null,\"showMaxNumber\":null,\"numberDigit\":2,\"isMicrometerChecked\":false,\"isFloatChecked\":true,\"valueType\":\"number\",\"numberOptions\":[{\"label\":\"数值\",\"value\":\"number\",\"type\":\"number\"},{\"label\":\"百分比\",\"value\":\"percentage\",\"type\":\"percentage\"}],\"isLabelWidth\":false,\"hidden\":false,\"dataBind\":true,\"dataRely\":{},\"defaultValueMode\":\"custom\",\"remoteDataConfig\":{\"dataSourceRefId\":null,\"dataSourceId\":null,\"mappings\":[]}},\"name\":\"年龄\",\"key\":\"1645949804497\",\"model\":\"format_number_1645949804497\",\"rules\":[]},{\"type\":\"table\",\"icon\":\"iconzibiaodan\",\"options\":{\"width\":\"100%\",\"defaultValue\":[],\"customClass\":\"\",\"labelWidth\":100,\"isLabelWidth\":false,\"hidden\":false,\"dataBind\":true,\"disabled\":false,\"required\":false,\"dataRely\":{},\"defaultValueMode\":\"custom\",\"remoteDataConfig\":{\"dataSourceRefId\":null,\"dataSourceId\":null,\"mappings\":[]},\"showHideRules\":[]},\"tableColumns\":[{\"type\":\"input\",\"icon\":\"icondanhangwenben\",\"options\":{\"width\":\"180px\",\"widgetWidth\":\"standard\",\"defaultValue\":null,\"required\":false,\"unique\":false,\"uniqueMessage\":null,\"requiredMessage\":\"\",\"dataType\":\"string\",\"dataTypeCheck\":false,\"dataTypeMessage\":\"\",\"pattern\":\"\",\"patternCheck\":false,\"patternMessage\":\"\",\"placeholder\":\"\",\"customClass\":\"\",\"disabled\":false,\"labelWidth\":100,\"isLabelWidth\":false,\"hidden\":false,\"dataBind\":true,\"showPassword\":false,\"dataRely\":{},\"defaultValueMode\":\"custom\",\"remoteDataConfig\":{\"dataSourceRefId\":null,\"dataSourceId\":null,\"mappings\":[]},\"remoteFunc\":\"func_1645949816785\",\"remoteOption\":\"option_1645949816785\",\"tableColumn\":true},\"name\":\"地点\",\"novalid\":{},\"key\":\"1645949816785\",\"model\":\"input_1645949816785\",\"rules\":[]},{\"type\":\"date\",\"icon\":\"iconriqixuanzeqi\",\"options\":{\"defaultValue\":null,\"showDefaultValue\":null,\"readonly\":false,\"disabled\":false,\"editable\":false,\"clearable\":false,\"placeholder\":\"\",\"startPlaceholder\":\"\",\"endPlaceholder\":\"\",\"type\":\"date\",\"format\":\"yyyy-MM-dd\",\"clearTime\":\"\",\"timestamp\":false,\"required\":false,\"requiredMessage\":\"\",\"width\":\"180px\",\"widgetWidth\":\"standard\",\"customClass\":\"\",\"labelWidth\":100,\"isLabelWidth\":false,\"hidden\":false,\"dataBind\":true,\"dataRely\":{},\"defaultValueMode\":\"custom\",\"remoteDataConfig\":{\"dataSourceRefId\":null,\"dataSourceId\":null,\"mappings\":[]},\"remoteFunc\":\"func_1645949822756\",\"remoteOption\":\"option_1645949822756\",\"tableColumn\":true},\"name\":\"时间\",\"novalid\":{},\"key\":\"1645949822756\",\"model\":\"date_1645949822756\",\"rules\":[]},{\"type\":\"format_number\",\"icon\":\"iconjishuqi\",\"options\":{\"width\":\"180px\",\"widgetWidth\":\"standard\",\"defaultValue\":null,\"showDefaultValue\":null,\"required\":false,\"placeholder\":\"\",\"disabled\":false,\"labelWidth\":100,\"requiredMessage\":\"\",\"isNumberRange\":false,\"minNumber\":null,\"showMinNumber\":null,\"maxNumber\":null,\"showMaxNumber\":null,\"numberDigit\":0,\"isMicrometerChecked\":false,\"isFloatChecked\":false,\"valueType\":\"number\",\"numberOptions\":[{\"label\":\"数值\",\"value\":\"number\",\"type\":\"number\"},{\"label\":\"百分比\",\"value\":\"percentage\",\"type\":\"percentage\"}],\"isLabelWidth\":false,\"hidden\":false,\"dataBind\":true,\"dataRely\":{},\"defaultValueMode\":\"custom\",\"remoteDataConfig\":{\"dataSourceRefId\":null,\"dataSourceId\":null,\"mappings\":[]},\"remoteFunc\":\"func_1645949819083\",\"remoteOption\":\"option_1645949819083\",\"tableColumn\":true},\"name\":\"薪资\",\"novalid\":{},\"key\":\"1645949819083\",\"model\":\"format_number_1645949819083\",\"rules\":[]}],\"name\":\"工作经历\",\"key\":\"1645949813706\",\"model\":\"table_1645949813706\",\"rules\":[]}]\n"; +// List widgets = JSONUtil.toList(JSONUtil.parseArray(list), WidgetModel.class); +// +// Map mappings = new HashMap<>(); +// mappings.put(0,"input_1645949802163"); +// mappings.put(1,"date_1645949803610"); +// mappings.put(2,"format_number_1645949804497"); +// mappings.put(3,"input_1645949816785"); +// mappings.put(4,"date_1645949822756"); +// mappings.put(5,"format_number_1645949819083"); +// Map map = new HashMap(); +// +// File excel = new File(FILE_PATH); +// if(excel.exists()){ +// DataAnalysisEventListener listener = new DataAnalysisEventListener(null); +// EasyExcel.read( new FileInputStream(excel), listener) +// .extraRead(CellExtraTypeEnum.MERGE) +// .headRowNumber(2) +// .autoCloseStream(true) +// .sheet(0) +// .doRead(); +// +// // 打印验证成功的数据 +// List errors = new LinkedList(); +// List recordModelList = listener.getRecords(); +// recordModelList.forEach(r -> { +// if(!r.hasError()){ +// System.out.println(JSON.toJSONString(r.getData(), SerializerFeature.WriteMapNullValue)); +// }else { +// r.getErrorCells().forEach(cm -> { +// System.out.println(String.format("(%s行, %s列) ", cm.getRowIndex(), cm.getColIndex()) + cm.getValidate().getMessage()); +// }); +// errors.addAll(r.getErrorCells()); +// } +// }); +// +// /*if(errors!= null && !errors.isEmpty()) { +// File newExcel = new File("D://批注.xlsx"); +// EasyExcel.write().withTemplate(excel) +// .file(new FileOutputStream(newExcel)) +// .inMemory(true) +// .registerWriteHandler(new CommentWriteHandler(errors)) +// .autoCloseStream(true) +// .sheet() +// .doFill(null); +//// EasyExcel.write(new FileOutputStream(excel)) +//// .inMemory(Boolean.TRUE) +//// .registerWriteHandler(new CommentWriteHandler(errors)) +//// .autoCloseStream(true) +//// .sheet(0) +//// .doWrite(null); +// }*/ +// +// } +// +// } +//} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/service/impl/excel/handler/CommentWriteHandler.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/service/impl/excel/handler/CommentWriteHandler.java new file mode 100644 index 0000000..caa5fd2 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/service/impl/excel/handler/CommentWriteHandler.java @@ -0,0 +1,35 @@ +package org.dromara.dataManager.service.impt.service.impl.excel.handler; + +import org.dromara.dataManager.service.impt.service.impl.excel.model.CellModel; +import com.alibaba.excel.write.handler.RowWriteHandler; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteTableHolder; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.ss.usermodel.Row; + +import java.util.LinkedList; +import java.util.List; + +/** + * 插入批注 + */ +@Slf4j +public class CommentWriteHandler implements RowWriteHandler { + private List errors = new LinkedList(); + public CommentWriteHandler(List errors){ + this.errors = errors; + } + + @Override + public void beforeRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Integer integer, Integer integer1, Boolean aBoolean) { + } + + @Override + public void afterRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer integer, Boolean aBoolean) { + } + + @Override + public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer integer, Boolean aBoolean) { + + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/service/impl/excel/listener/DataAnalysisEventListener.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/service/impl/excel/listener/DataAnalysisEventListener.java new file mode 100644 index 0000000..fc4d1a1 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/service/impl/excel/listener/DataAnalysisEventListener.java @@ -0,0 +1,433 @@ +package org.dromara.dataManager.service.impt.service.impl.excel.listener; + + + + +import org.dromara.system.domain.SysDept; +import org.dromara.system.domain.SysUser; +import org.dromara.common.Exception.ServiceException; +import org.dromara.common.response.WorkflowResultCode; +import org.dromara.dataManager.enums.WidgetType; +import org.dromara.dataManager.param.ImportDataParams; +import org.dromara.dataManager.service.impt.convert.ConverterBuilder; +import org.dromara.dataManager.service.impt.convert.WidgetConverter; +import org.dromara.dataManager.service.impt.model.DataAnalysisParams; +import org.dromara.dataManager.service.impt.service.impl.excel.model.CellModel; +import org.dromara.dataManager.service.impt.service.impl.excel.model.RecordModel; +import org.dromara.dataManager.service.impt.service.impl.excel.model.RowModel; + +import org.dromara.taskCenter.model.widget.WidgetModel; +import cn.hutool.core.collection.CollectionUtil; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.enums.CellExtraTypeEnum; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.metadata.CellExtra; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import java.util.*; +import java.util.stream.Collectors; + +@Slf4j +@Data +public class DataAnalysisEventListener extends AnalysisEventListener> { + private static final List DATE_COLUMNS = Arrays.asList("createTime", "updateTime"); + public static final String DATA_ID = "id"; + // 没有成员部门字段时的最大导入数据量 + public static final Long MAX_DATA_COUNT = 30000L; + // 有成员部门字段时的最大导入数据量 + public static final Long MAX_DM_DATA_COUNT = 10000L; + + /** + * 表单ID + */ + private Long formId; + /** + * 表单code + */ + private String formCode; + /** + * 主键,匹配字段 + */ + private String primaryKey; + /** + * 表头行数 + */ + private int headerNumber; + /** + * 要导入的表单字段 + */ + private List importWidgets; + /** + * 表单的所有字段 + */ + private List formWidgets; + + /** + * 字段与列的映射关系 + */ + private Map mappings; + /** + * 表单字段值converter + */ + private Map converts = new HashMap(); + + /** + * excel 行信息 + */ + private List rows = new LinkedList(); + + /** + * 合并单元格信息 + */ + private List extraList = new ArrayList<>(); + + /** + * 表单记录 + */ + private LinkedList records = new LinkedList(); + + /** + * 行错误信息 + */ + private List invalidRows = new ArrayList<>(); + /** + * excel中的成员账号 + */ + private Set importMembers = new HashSet<>(); + private Map accountUserMapping = new HashMap<>(); + + + /** + * excel中的部门路径 + */ + private Set importDeparts = new HashSet<>(); + private Map pathDepartMapping = new HashMap<>(); + + public DataAnalysisEventListener(DataAnalysisParams params){ + Long formId = params.getFormId(); + String formCode = params.getFormCode(); + int headerNumber = params.getHeaderNumber(); + String primaryKey = params.getPrimaryKey(); + List formWidgets = params.getFormWidgets(); + Map mappings = params.getMappings(); + ImportDataParams.ValidationConfig validationConfig = params.getValidationConfig(); + + if(mappings == null || mappings.isEmpty() || formWidgets == null || formWidgets.isEmpty()){ + throw new ServiceException(WorkflowResultCode.FAIL); + } + + List widgets = buildImportWidgets(formWidgets, mappings); + + Map widgetMap = new HashMap<>(); + widgets.forEach(w ->{ + if(w.getType().equalsIgnoreCase(WidgetType.TABLE.getCode())){ + w.getTableColumns().forEach(sw ->{ + widgetMap.put(sw.getModel(), sw); + }); + }else { + widgetMap.put(w.getModel(), w); + } + }); + + mappings.keySet().forEach(i ->{ + + String type = widgetMap.get(mappings.get(i)) == null ? null : widgetMap.get(mappings.get(i)).getType(); + WidgetConverter converter; + + if (DATE_COLUMNS.contains(mappings.get(i))) { + + WidgetModel widget = new WidgetModel(WidgetType.DATE.getCode(), mappings.get(i), mappings.get(i)); + converter = ConverterBuilder.getConverter(WidgetType.DATE.getCode(), widget); + widgets.add(widget); + + } else if ("creatorAccount".equals(mappings.get(i)) || DATA_ID.equals(mappings.get(i))) { + + WidgetModel widget = new WidgetModel(WidgetType.GENERAL.getCode(), mappings.get(i), mappings.get(i)); + converter = ConverterBuilder.getConverter(type, widget); + widgets.add(widget); + + } else { + + converter = ConverterBuilder.getConverter(type, widgetMap.get(mappings.get(i))); + // setAccountsDepartsMapping(type, converter); + } + + converter.setValidationConfig(validationConfig); + + this.converts.put(i, converter); + }); + + this.importWidgets = widgets; + this.formWidgets = formWidgets; + this.mappings = mappings; + this.formId = formId; + this.formCode = formCode; + this.headerNumber = headerNumber; + this.primaryKey = primaryKey; + } + + @Override + public void invoke(Map data, AnalysisContext analysisContext) { + // 封装 excel 行信息,此时不做数据校验 + RowModel row = new RowModel(analysisContext.readRowHolder().getRowIndex()); + + mappings.forEach((ci, model) -> { + + row.addCell(new CellModel(converts.get(ci), row.getRowIndex(), ci, data.get(ci))); + + // 收集成员账号与部门路径 + WidgetModel widget = getWidgetByModel(model); + collectMembersAndDeparts(widget, data.get(ci)); + + }); + + this.rows.add(row); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext analysisContext) { +// +// this.accountUserMapping.putAll(SpringUtil.getBean(UserService.class).getAccountNameMapping(importMembers)); +// +// this.pathDepartMapping.putAll(SpringUtil.getBean(DepartmentService.class).getPathDepartMapping(importDeparts)); +// +// // 数据从第几行开始 +// int rowIndex = headerNumber; +// +// // 临时的 form json +// JSONObject fjObj = new JSONObject(); +// fjObj.putOpt("config", new JSONObject()); +// fjObj.putOpt("list", formWidgets); +// String fj = fjObj.toString(); +// +// // 是否有creatorAccount字段 +// boolean hasAccountField = mappings.containsValue("creatorAccount"); +// List importAccounts = new ArrayList<>(); +// +// // 是否有子表单字段 +// List tableWidgets = importWidgets.stream().filter(w -> WidgetType.TABLE.getCode().equals(w.getType())).collect(Collectors.toList()); +// +// for (int ri = 0; ri < rows.size() && rowIndex - headerNumber < rows.size(); ri ++) { +// +// int finalRowIndex = rowIndex; +// Optional optional = tableWidgets.size() > 0 ? extraList.stream().filter(extra -> extra.getFirstRowIndex() == finalRowIndex).findFirst() : Optional.empty(); +// +// RecordModel record; +// int thisRowIndex = rowIndex; +// // 有合并单元格的数据,且有子表单字段 +// if (tableWidgets.size() > 0 && optional.isPresent()) { +// +// CellExtra merge = optional.get(); +// record = new RecordModel(merge.getRowIndex()); +// for(int index = merge.getFirstRowIndex(); index <= merge.getLastRowIndex(); index ++) { +// +// int fri = rowIndex; +// Optional rmo = this.rows.stream().filter(row -> row.getRowIndex().equals(fri)).findFirst(); +// rmo.ifPresent(rowModel -> record.addRow(this.importWidgets, rowModel)); +// +// // 行数加1 +// rowIndex++; +// } +// +// if (ObjectUtil.isNotEmpty(record.getData().get(DATA_ID))) { +// // 移除子表单字段,更新模式不支持子表单字段 +// tableWidgets.forEach(tw -> record.getData().remove(tw.getModel())); +// } +// +// } +// // 没有合并单元格的数据 +// else { +// record = new RecordModel(rowIndex); +// +// int fri = rowIndex; +// Optional rmo = this.rows.stream().filter(row -> row.getRowIndex().equals(fri)).findFirst(); +// rmo.ifPresent(rowModel -> record.addRow(this.importWidgets, rowModel)); +// +// // 行数加1 +// rowIndex++; +// +// } +// +// // 记录错误信息 +// if (record.hasError()) { +// invalidRows.add(formatErrorMessage(thisRowIndex, record.getErrorCells())); +// } +// +// // 如有流水号字段则生成流水号 +// // addSerialNumberFields(record.getData(), fj); +// this.records.add(record); +// +// // 收集导入的创建人账号信息 +// if (hasAccountField && ObjectUtil.isNotEmpty(record.getData().containsKey("creatorAccount"))) { +// importAccounts.add((String) record.getData().get("creatorAccount")); +// } +// } +// +// // 添加系统字段 +// addSystemFields(hasAccountField, importAccounts); + + } + + @Override + public void extra(CellExtra extra, AnalysisContext context) { + if(extra.getType() == CellExtraTypeEnum.MERGE) { + extraList.add(extra); + } + } + + /** + * 获取处理后的数据 + * @return 处理后的数据 + */ + public List> getConvertedData() { + return this.records.stream().map(RecordModel::getData).collect(Collectors.toList()); + } + + + /** + * 添加系统字段 + * @param hasAccountField 导入字段中是否有提交人账号字段 + * @param importAccounts excel中的账号字段 + */ + private void addSystemFields(boolean hasAccountField, List importAccounts) { +// +// Map accountNameMap = getAccountNameMapping(importAccounts); +// +// this.records.forEach(item -> { +// Map row = item.getData(); +// if (hasAccountField) { +// +// if (ObjectUtil.isNotEmpty(row.get("creatorAccount"))) { +// String account = (String) row.get("creatorAccount"); +// +// SysUser user = accountNameMap.get(account); +// if (ObjectUtil.isNotNull(user)) { +// row.put("owner", user.getId()); +// row.put("creator", user.getName()); +// row.put("creatorAccount", user.getAccount()); +// } else { +// row.put("owner", LoginContextHolder.me().getSysLoginUserId()); +// row.put("creator", LoginContextHolder.me().getSysLoginUser().getName()); +// row.put("creatorAccount", LoginContextHolder.me().getSysLoginUserAccount()); +// } +// } +// +// } +// +// // 没有匹配字段说明这是一条新增的数据 +// if (primaryKey != null) { +// if (ObjectUtil.isEmpty(item.getData().get(primaryKey))) { +// row.putIfAbsent("owner", LoginContextHolder.me().getSysLoginUserId()); +// row.putIfAbsent("creator", LoginContextHolder.me().getSysLoginUser().getName()); +// row.putIfAbsent("creatorAccount", LoginContextHolder.me().getSysLoginUserAccount()); +// row.putIfAbsent("createTime", new Date()); +// } +// } else { +// row.putIfAbsent("owner", LoginContextHolder.me().getSysLoginUserId()); +// row.putIfAbsent("creator", LoginContextHolder.me().getSysLoginUser().getName()); +// row.putIfAbsent("creatorAccount", LoginContextHolder.me().getSysLoginUserAccount()); +// row.putIfAbsent("createTime", new Date()); +// } +// +// }); + + } + + private Map getAccountNameMapping(List accounts) { +// if (CollUtil.isEmpty(accounts)) { +// return new HashMap<>(); +// } +// UserService userService = SpringUtil.getBean(UserService.class); +// return userService.getAccountNameMapping(accounts); + + return new HashMap<>(); + } + + /** + * 收集excel中的成员账号与部门路径 + * @param widget 字段信息 + * @param value excel中的值 + */ + private void collectMembersAndDeparts(WidgetModel widget, String value) { + + if (StringUtils.isNotBlank(value) && widget != null) { + + if (WidgetType.SINGLE_MEMBER.getCode().equals(widget.getType()) || WidgetType.MULTIPLE_MEMBERS.getCode().equals(widget.getType())) { + importMembers.addAll(Arrays.asList(value.split(","))); + } + + if (WidgetType.SINGLE_DEPARTMENT.getCode().equals(widget.getType()) || WidgetType.MULTIPLE_DEPARTMENTS.getCode().equals(widget.getType())) { + importDeparts.addAll(Arrays.asList(value.split(","))); + } + } + } + + /** + * 格式化错误信息 + * @param rowIndex 行索引 + * @param errorCells 有错误数据的单元格 + * @return 错误信息 + */ + private String formatErrorMessage(int rowIndex, List errorCells) { + List errors = new ArrayList<>(); + errors.add(String.format("第%d行", rowIndex + 1)); + errorCells.forEach(ec -> { + errors.add(String.format("%s(%d列)", ec.getValidate().getMessage(), ec.getColIndex() + 1)); + }); + + return String.join(",", errors); + } + + /** + * 根据字段唯一标识符获取字段配置信息 + * @param model 字段唯一标识符 + * @return 字段配置信息 + */ + private WidgetModel getWidgetByModel(String model) { + + WidgetModel matched = null; + + for(WidgetModel wm: importWidgets) { + + if (WidgetType.TABLE.getCode().equals(wm.getType())) { + + Optional optional = wm.getTableColumns().stream().filter(tc -> tc.getModel().equals(model)).findFirst(); + if (optional.isPresent()) { + matched = optional.get(); + break; + } + + } else if (wm.getModel().equals(model)){ + matched = wm; + break; + } + } + return matched; + } + + private List buildImportWidgets(List formWidgets, Map mappings) { + List widgets = new ArrayList<>(); + + formWidgets.forEach(fc -> { + if (mappings.containsValue(fc.getModel())) { + widgets.add(fc); + } else if (CollectionUtil.isNotEmpty(fc.getTableColumns())) { + + List tcList = fc.getTableColumns().stream() + .filter(tc -> mappings.containsValue(tc.getModel())) + .collect(Collectors.toList()); + + if (CollectionUtil.isNotEmpty(tcList)) { + fc.setTableColumns(tcList); + widgets.add(fc); + } + } + + }); + + return widgets; + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/service/impl/excel/model/CellModel.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/service/impl/excel/model/CellModel.java new file mode 100644 index 0000000..c5ce619 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/service/impl/excel/model/CellModel.java @@ -0,0 +1,52 @@ +package org.dromara.dataManager.service.impt.service.impl.excel.model; + +import org.dromara.dataManager.service.impt.convert.WidgetConverter; +import lombok.Data; + +import java.io.Serializable; + +/** + * excel单元格model + */ +@Data +public class CellModel implements Serializable { + private static final long serialVersionUID = -1027380204378668428L; + + /** + * 表单字段值converter + */ + private WidgetConverter converter; + private Integer rowIndex; + private Integer colIndex; + private String excelValue; + private Validate validate; + + public CellModel(WidgetConverter converter, Integer rowIndex, Integer colIndex, String excelValue){ + this.converter = converter; + this.rowIndex = rowIndex; + this.colIndex = colIndex; + this.excelValue = excelValue; + } + + public void validateFail(String message){ + this.validate = new Validate(false, message); + } + + public void validateSucc(){ + this.validate = new Validate(true); + } + + @Data + static + public class Validate implements Serializable{ + private Boolean success = true; + private String message; + public Validate(Boolean success){ + this.success = success; + } + public Validate(Boolean success, String message){ + this.success = success; + this.message = message; + } + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/service/impl/excel/model/RecordModel.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/service/impl/excel/model/RecordModel.java new file mode 100644 index 0000000..a365a94 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/service/impl/excel/model/RecordModel.java @@ -0,0 +1,119 @@ +package org.dromara.dataManager.service.impt.service.impl.excel.model; + +import org.dromara.dataManager.enums.WidgetType; +import org.dromara.dataManager.service.impt.convert.WidgetConverter; +import org.dromara.taskCenter.model.widget.WidgetModel; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjectUtil; +import lombok.Data; + +import java.io.Serializable; +import java.util.*; + +/** + * 数据记录 + */ +@Data +public class RecordModel implements Serializable { + private static final long serialVersionUID = 8553281834023196024L; + + /** + * excel 合并行 + */ + private Integer rowIndex; + /** + * 表单数据 + */ + private Map data = new HashMap<>(); + + /** + * 验证错误的单元格 + */ + public List errorCells = new LinkedList(); + + public RecordModel(Integer rowIndex){ + this.rowIndex = rowIndex; + } + + public void addRow(List widgets, RowModel row){ + if(widgets != null){ + Map cellMap = row.getCells(); + widgets.forEach(w -> { + if(!w.getType().equalsIgnoreCase(WidgetType.TABLE.getCode())){ + this.putData(w.getModel(), cellMap.get(w.getModel())); + } else if (CollectionUtil.isNotEmpty(w.getTableColumns())){ + w.getTableColumns().forEach(sw -> { + this.putTableData(w.getModel(), sw.getModel(), cellMap.get(sw.getModel())); + }); + } + }); + } + } + + public boolean hasError(){ + return errorCells.size() > 0; + } + + /** + * 设置子表单数据 + * @param tableModel + * @param model + * @param cell + */ + private void putTableData(String tableModel, String model, CellModel cell){ + if (cell == null) { + return; + } + if(!data.containsKey(tableModel)){ + data.put(tableModel, new LinkedList>()); + } + List> table = (List>) data.get(tableModel); + if(cell.getRowIndex() - this.rowIndex > table.size() -1){ + table.add(new HashMap<>()); + table.get(table.size() - 1).put("_id", UUID.randomUUID().toString()); + } + + Map map = table.get(cell.getRowIndex() - this.rowIndex); + cell.getConverter().validate(cell.getExcelValue(), new WidgetConverter.ConvertCallBack() { + @Override + public void success(Object convertValue) { + // 如果是空的数据则忽略掉这个字段 + if (ObjectUtil.isNotEmpty(convertValue)) { + map.put(model, convertValue); + } + cell.validateSucc(); + } + + @Override + public void fail(String message) { + cell.validateFail(message); + errorCells.add(cell); + } + }); + } + /** + * 设置数据 + * @param model + * @param cell + */ + private void putData(String model, CellModel cell){ + if(!this.data.containsKey(model)){ + cell.getConverter().validate(cell.getExcelValue(), new WidgetConverter.ConvertCallBack() { + @Override + public void success(Object convertValue) { + // 如果是空的数据则忽略掉这个字段 + if (ObjectUtil.isNotEmpty(convertValue)) { + data.put(model, convertValue); + } + + cell.validateSucc(); + } + @Override + public void fail(String message) { + cell.validateFail(message); + errorCells.add(cell); + } + }); + } + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/service/impl/excel/model/RowMerge.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/service/impl/excel/model/RowMerge.java new file mode 100644 index 0000000..366ec75 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/service/impl/excel/model/RowMerge.java @@ -0,0 +1,30 @@ +package org.dromara.dataManager.service.impt.service.impl.excel.model; + +import lombok.Data; + +import java.io.Serializable; + +/** + * excel行合并信息 + */ +@Data +public class RowMerge implements Serializable { + private Integer rowIndex; + private Integer firstRowIndex; + private Integer lastRowIndex; + + public RowMerge(Integer rowIndex, Integer firstRowIndex, Integer lastRowIndex){ + this.rowIndex = rowIndex; + this.firstRowIndex = firstRowIndex; + this.lastRowIndex = lastRowIndex; + } + + public void update(Integer firstRowIndex, Integer lastRowIndex) { + if (firstRowIndex != null && firstRowIndex.intValue() < this.firstRowIndex.intValue()) { + this.firstRowIndex = firstRowIndex; + } + if (lastRowIndex != null && lastRowIndex.intValue() > this.lastRowIndex.intValue()) { + this.lastRowIndex = lastRowIndex; + } + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/service/impl/excel/model/RowModel.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/service/impl/excel/model/RowModel.java new file mode 100644 index 0000000..ecf3f5b --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/service/impl/excel/model/RowModel.java @@ -0,0 +1,34 @@ +package org.dromara.dataManager.service.impt.service.impl.excel.model; + +import lombok.Data; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +/** + * excel 行model + */ +@Data +public class RowModel implements Serializable { + private static final long serialVersionUID = 3100643744741570508L; + + /** + * 行号 + */ + private Integer rowIndex; + + /** + * key = 表单model + * value = CellModel + */ + private Map cells = new HashMap<>(); + + public RowModel(Integer rowIndex){ + this.rowIndex = rowIndex; + } + + public void addCell(CellModel cell){ + this.cells.put(cell.getConverter().getWidget().getModel(), cell); + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/validator/ValueValidator.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/validator/ValueValidator.java new file mode 100644 index 0000000..aea012b --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/impt/validator/ValueValidator.java @@ -0,0 +1,84 @@ +package org.dromara.dataManager.service.impt.validator; + +import org.dromara.taskCenter.model.FormWidget; +import cn.hutool.core.util.NumberUtil; +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.excel.util.DateUtils; +import lombok.extern.slf4j.Slf4j; + +import java.text.ParseException; + +@Slf4j +public class ValueValidator { + + public static boolean isEmpty(Object value) { + return ObjectUtil.isEmpty(value); + } + + public static boolean isNumber(Object value) { + if (value == null) { + return false; + } else { + String numberStr = (String) value; + numberStr = numberStr.replaceAll(",", "").replaceAll("%", ""); + return NumberUtil.isNumber(numberStr); + } + } + + public static boolean isDate(Object value, FormWidget formWidget) { + if (value != null) { + String dateObj = (String) value; + try { + String format = (String) formWidget.getOptions().get("format"); + // 使用规定格式转换数据,转换不报错就说明是日期格式数据 + DateUtils.parseDate(dateObj, format); + return true; + } catch (Exception e) { + try { + // 如果转换报错,则尝试自动转换日期格式,转换不报错就说明是日期格式数据 + DateUtils.parseDate(dateObj); + return true; + } catch (Exception parseException) { + // 自动识别格式失败则尝试自动识别常用格式,转换不报错就说明是日期格式数据 + try { + if (dateObj.contains("/") || dateObj.contains("-")) { + convert2Date(dateObj); + } else { + return false; + } + } catch (ParseException exception) { + return false; + } + return true; + } + } + } else { + return false; + } + } + private static void convert2Date(String dateString) throws ParseException { + + // 自动识别格式失败则尝试自动识别常用格式 + String separator = null; + + if (dateString.contains("-")) { + separator = "-"; + + } else if (dateString.contains("/")) { + separator = "/"; + } + + if (separator != null) { + String ymd = String.format("yyyy%sMM%sdd", separator, separator); + String[] formats = new String[]{ymd, String.format("%s HH:mm:ss", ymd), String.format("%s HH:mm", ymd), String.format("%s HH", ymd)}; + + for (String format: formats) { + DateUtils.parseDate(dateString, format); + break; + } + + } + + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/log/DataLogActionService.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/log/DataLogActionService.java new file mode 100644 index 0000000..46dc29f --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/log/DataLogActionService.java @@ -0,0 +1,20 @@ +package org.dromara.dataManager.service.log; + +import org.dromara.dataManager.domain.FormDataLog; +import org.dromara.dataManager.param.FormDataModifyMessage; + +import java.util.List; + +/** + * @Description: server + **/ +public interface DataLogActionService { + + /** + * 封装数据日志对象集合 + * @return + */ + List transformDataLogs(FormDataModifyMessage data); + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/log/FormDataLogService.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/log/FormDataLogService.java new file mode 100644 index 0000000..56c78be --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/log/FormDataLogService.java @@ -0,0 +1,37 @@ +package org.dromara.dataManager.service.log; + +import org.dromara.dataManager.domain.FormDataLog; +import org.dromara.dataManager.param.FormDataModifyMessage; +import com.baomidou.mybatisplus.extension.service.IService; +import java.util.List; + +/** + * 数据日志service + */ +public interface FormDataLogService extends IService { + + /** + * 添加数据日志 + * @param param + */ + void addDataLog(FormDataModifyMessage param); + + /** + * 查询某数据的详细数据日志 + * @param dataId + * @return + */ + List listDataLog(Long formId,Long dataId); + + /** + * 清空表单填报数据 + * @param formId + */ + void deleteByForm(Long formId); + + /** + * 批量删除 + * @param docIds + */ + void deleteByDataIds(String[] docIds); +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/log/impl/DataLogDeleteService.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/log/impl/DataLogDeleteService.java new file mode 100644 index 0000000..5cdbf3e --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/log/impl/DataLogDeleteService.java @@ -0,0 +1,53 @@ +package org.dromara.dataManager.service.log.impl; + +import org.dromara.dataManager.domain.FormDataLog; +import org.dromara.dataManager.param.FormDataModifyMessage; +import org.dromara.dataManager.service.FormDataService; +import org.dromara.dataManager.service.log.DataLogActionService; +import org.dromara.workflow.engine.enums.ESDefaultFieldConst; +import cn.hutool.core.util.ObjectUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * @Description: 删除操作 记录数据日志 + **/ +@Slf4j +@Component("deleteDataLog") +public class DataLogDeleteService implements DataLogActionService { + + @Autowired + private FormDataService formDataService; + + @Override + public List transformDataLogs(FormDataModifyMessage data) { + List formDataLogs = new ArrayList<>(); + + data.getBefore().forEach(p -> { + Map afterDataMap = formDataService.getFormDataById(data.getFormId(), (Long) p.get("dataId")); + + formDataLogs.add(transformLog(data, (Long) p.get("dataId"),afterDataMap)); + }); + + return formDataLogs; + } + + private FormDataLog transformLog(FormDataModifyMessage param, Long dataId, Map dataMap) { + if(ObjectUtil.isNotEmpty(dataId)){ + FormDataLog formDataLog = new FormDataLog(param.getFormId(),param.getFormCode()); + formDataLog.fillData(param.getAction().getCode(),dataId,null,dataMap); + dataMap.put(ESDefaultFieldConst.DELETED,false); + formDataLog.fillOldData(dataMap); + formDataLog.setUser(param.getHandleUserId(),param.getHandleUserName(),param.getHandleUserAccount(), param.getHandleTime()); + formDataLog.setChanges(null); + return formDataLog; + } + + return null; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/log/impl/DataLogSaveService.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/log/impl/DataLogSaveService.java new file mode 100644 index 0000000..7984589 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/log/impl/DataLogSaveService.java @@ -0,0 +1,42 @@ +package org.dromara.dataManager.service.log.impl; + +import org.dromara.dataManager.domain.FormDataLog; +import org.dromara.dataManager.param.FormDataModifyMessage; +import org.dromara.dataManager.service.log.DataLogActionService; +import cn.hutool.core.util.ObjectUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * @Description: 新增操作 记录数据日志 + **/ +@Slf4j +@Component("saveDataLog") +public class DataLogSaveService implements DataLogActionService { + + + @Override + public List transformDataLogs(FormDataModifyMessage data) { + + return data.getAfter().stream().map(p -> transformLog(data,(Long) p.get("dataId"),p)) + .collect(Collectors.toList()); + } + + + private FormDataLog transformLog(FormDataModifyMessage param, Long dataId,Map after + ) { + if(ObjectUtil.isNotEmpty(dataId)){ + FormDataLog formDataLog = new FormDataLog(param.getFormId(),param.getFormCode()); + formDataLog.fillData(param.getAction().getCode(),dataId,null,after); + formDataLog.setUser(param.getHandleUserId(),param.getHandleUserName(),param.getHandleUserAccount(), param.getHandleTime()); + formDataLog.setChanges(null); + return formDataLog; + } + + return null; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/log/impl/DataLogUpdateService.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/log/impl/DataLogUpdateService.java new file mode 100644 index 0000000..2f177a9 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/log/impl/DataLogUpdateService.java @@ -0,0 +1,85 @@ +package org.dromara.dataManager.service.log.impl; + +import org.dromara.common.Exception.ServiceException; +import org.dromara.common.response.WorkflowResultCode; +import org.dromara.common.util.JsonUtil; +import org.dromara.dataManager.domain.FormDataLog; +import org.dromara.dataManager.param.FormDataModifyMessage; +import org.dromara.dataManager.service.log.DataLogActionService; +import org.dromara.dataManager.service.validate.FormDataValidateService; +import org.dromara.formMaking.results.FormSourceResult; +import org.dromara.formMaking.service.FormSourceService; +import org.dromara.taskCenter.model.FormWidget; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +/** + * @Description: 单条数据修改操作 记录数据日志 + **/ +@Slf4j +@Component("updateDataLog") +public class DataLogUpdateService implements DataLogActionService { + @Autowired + private FormDataValidateService dataValidateService; + @Autowired + private FormSourceService formSourceService; + @Override + public List transformDataLogs(FormDataModifyMessage data) { + + if(ObjectUtil.hasEmpty(data.getBefore(),data.getAfter())){ + + throw new ServiceException(WorkflowResultCode.PARAM_IS_BLANK); + } + List configs = getFormWidgets(data); + if(CollUtil.isEmpty(configs)){ + + throw new ServiceException(WorkflowResultCode.FORM_DETAIL_NOT_EXIST); + } + List updateWidgets = dataValidateService.listUpdateWidgets(configs,data.getBefore().get(0), data.getAfter().get(0)); + if(CollUtil.isNotEmpty(updateWidgets)){ + + return Arrays.asList(generateLogEntity(data, data.getBefore().get(0), data.getAfter().get(0),updateWidgets)); + } + + return null; + } + + + private FormDataLog generateLogEntity(FormDataModifyMessage param,Map before, + Map after, + List updateWidgetResults + ) { + Long dataId = (Long)before.get("dataId"); + FormDataLog formDataLog = new FormDataLog(param.getFormId(),param.getFormCode()); + formDataLog.fillData(param.getAction().getCode(),dataId,before,after); + formDataLog.setUser(param.getHandleUserId(),param.getHandleUserName(),param.getHandleUserAccount(), param.getHandleTime()); + formDataLog.setChanges(JsonUtil.toJson(updateWidgetResults)); + return formDataLog; + } + + + private List getFormWidgets(FormDataModifyMessage data){ + FormSourceResult formDetail = this.formSourceService.getFormSourceById(data.getFormId()); + + Map formJson = JsonUtil.jsonToMap(formDetail.getFormJson()); + + assert formJson != null; + List columnWidgetList = JsonUtil.jsonToList(JsonUtil.toJson(formJson.get("list")), FormWidget.class); + if(CollUtil.isEmpty(columnWidgetList)){ + + log.error("###### 数据日志 update field widget not exist ######"); + return null; + } + + + return columnWidgetList; + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/log/impl/FormDataLogServiceImpl.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/log/impl/FormDataLogServiceImpl.java new file mode 100644 index 0000000..67de056 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/log/impl/FormDataLogServiceImpl.java @@ -0,0 +1,76 @@ +package org.dromara.dataManager.service.log.impl; + +import org.dromara.common.Exception.ServiceException; +import org.dromara.common.response.WorkflowResultCode; +import org.dromara.common.util.JsonUtil; +import org.dromara.dataManager.domain.FormDataLog; +import org.dromara.dataManager.mapper.FormDataLogMapper; +import org.dromara.dataManager.param.FormDataModifyMessage; +import org.dromara.dataManager.service.log.DataLogActionService; +import org.dromara.dataManager.service.log.FormDataLogService; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +@Slf4j +@Service +public class FormDataLogServiceImpl extends ServiceImpl implements FormDataLogService { + + @Autowired + private final Map dataActionService = new ConcurrentHashMap(); + + @Autowired + private FormDataLogMapper formDataLogMapper; + + @Override + public List listDataLog(Long formId,Long dataId) { + if(ObjectUtil.hasEmpty(formId,dataId)){ + + throw new ServiceException(WorkflowResultCode.PARAM_MISSING); + } + + return this.formDataLogMapper.listDataLog(formId,dataId); + } + + + @Override + public void addDataLog(FormDataModifyMessage param) { + DataLogActionService dataLogActionService = dataActionService.get(param.getAction().getCode()+"DataLog"); + if(dataLogActionService != null){ + List formDataLogList = dataLogActionService.transformDataLogs(param); + + if(CollUtil.isEmpty(formDataLogList)){ + if(log.isDebugEnabled()){ + log.error("###### data log empty {} ######", JsonUtil.toJson(param)); + } + return; + } + + this.formDataLogMapper.batchSaveDataLog(formDataLogList); + } + } + + @Override + public void deleteByForm(Long formId) { + this.formDataLogMapper.delete(new LambdaQueryWrapper().eq(FormDataLog::getFormId,formId)); + } + + /** + * 删除数据日志 + * @param dataIds + */ + @Override + public void deleteByDataIds(String... dataIds){ + if(dataIds != null && dataIds.length > 0 && dataIds[0] != null){ + this.formDataLogMapper.deleteByDataIds(dataIds); + } + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/validate/FormDataValidateService.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/validate/FormDataValidateService.java new file mode 100644 index 0000000..88e0dc6 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/validate/FormDataValidateService.java @@ -0,0 +1,67 @@ +package org.dromara.dataManager.service.validate; + +import org.dromara.dataManager.domain.FormDataLog; +import org.dromara.taskCenter.model.FormWidget; + +import java.util.List; +import java.util.Map; + +/** + * 表单数据校验/对比 + */ +public interface FormDataValidateService { + + /** + * 校验字段值是否发生变化 + * @param widgetId + * @param before + * @param after + * @return + */ + boolean checkWidgetUpdated(String widgetId,Object before, Object after); + + + /** + * 查询发生变化的表单字段的值 + */ + List listUpdateWidgets(Long formId, Map before, Map after); + + + /** + * 查询发生变化的表单字段的值 + */ + List listUpdateWidgets(List configs, Map before, Map after); + + + /** + * 查询主字段值的变化 + * @param before + * @param after + * @param model + * @return + */ + FormDataLog.UpdateWidgetResult getUpdateWidget(FormWidget model,String widgetId,Map before,Map after); + + /** + * 查询子表单子字段值的变化 + * @param before + * @param after + * @param tableId + * @return + */ + FormDataLog.UpdateWidgetResult getTableColumnUpdateWidget(List configs, + String tableId, + String subColumnId, + List> before, + List> after); + + + /** + * 查询数据变动情况【数据补偿,已废弃】 + * @param before + * @param after + * @return + */ + List listUpdatedData(Map before,Map after); + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/validate/impl/FormDataValidateServiceImpl.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/validate/impl/FormDataValidateServiceImpl.java new file mode 100644 index 0000000..b452f8f --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/service/validate/impl/FormDataValidateServiceImpl.java @@ -0,0 +1,265 @@ +package org.dromara.dataManager.service.validate.impl; + + +import org.dromara.common.Exception.ServiceException; +import org.dromara.common.response.WorkflowResultCode; +import org.dromara.common.util.JsonUtil; +import org.dromara.dataManager.domain.FormDataLog; +import org.dromara.dataManager.enums.WidgetType; +import org.dromara.dataManager.service.validate.FormDataValidateService; +import org.dromara.dataManager.widget.convert.base.BaseFormFieldConverter; +import org.dromara.dataManager.widget.convert.base.FormFieldFactory; +import org.dromara.dataManager.widget.convert.column.DefaultConverter; +import org.dromara.dataManager.widget.convert.column.TableConverter; +import org.dromara.formMaking.results.FormSourceResult; +import org.dromara.formMaking.service.FormSourceService; +import org.dromara.taskCenter.model.FormWidget; +import org.dromara.workflow.engine.enums.ESDefaultFieldConst; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.google.common.collect.Sets; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.compress.utils.Lists; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; + +@Slf4j +@Service +public class FormDataValidateServiceImpl implements FormDataValidateService { + + public static final List flowChangedFields = Arrays.asList(ESDefaultFieldConst.FLOW_STAGE); + + @Autowired + private FormSourceService formSourceService; + + @Override + public boolean checkWidgetUpdated(String widgetId,Object before, Object after){ + BaseFormFieldConverter converter = FormFieldFactory.getConverter(widgetId.contains(WidgetType.TABLE.getCode()) ? StrUtil.subBefore(widgetId,".", true) : widgetId); + if (converter != null) { + return converter.checkChange(before, after); + } + + throw new ServiceException(WorkflowResultCode.FORM_WIDGET_NOT_ALLOWED); + } + + @Override + public List listUpdateWidgets(Long formId, Map before, Map after) { + List configs = getFormWidgets(formId); + if(CollUtil.isNotEmpty(configs)){ + + return listUpdateWidgets(configs,before,after); + } + + return Lists.newArrayList(); + } + + @Override + public List listUpdateWidgets(List configs,Map before,Map after) { + List results = new ArrayList<>(); + + if(ObjectUtil.isAllNotEmpty(before,after)) { + Sets.SetView unionKeys = Sets.union(after.keySet(), before.keySet()); + LinkedHashSet sortKeys = new LinkedHashSet<>(); + configs.stream().map(FormWidget::getModel) + .filter(unionKeys::contains) + .forEach(sortKeys::add); + + if(CollUtil.isNotEmpty(unionKeys)){ + unionKeys.stream().filter(key -> !sortKeys.contains(key)).forEach(sortKeys::add); + sortKeys.forEach(key -> { + FormWidget config =configs.stream().filter(p -> StrUtil.equals(p.getModel(),key)).findAny().orElse(null); + if(config != null) { + + String tableId = key.contains(WidgetType.TABLE.getCode()) ? StrUtil.subBefore(key, ".", true) : null; + if (tableId != null) { + List> tableBeforeData = (List>)before.get(tableId); + List> tableAfterData = (List>)after.get(tableId); + + FormDataLog.UpdateWidgetResult tableUpdateResult = + getTableColumnUpdateWidget(config.getTableColumns(),tableId,null,tableBeforeData,tableAfterData); + if(tableUpdateResult != null) { + results.add(tableUpdateResult); + } + } else { + FormDataLog.UpdateWidgetResult updateResult = getUpdateWidget(config, key, before, after); + if(updateResult != null) { + results.add(getUpdateWidget(config, key, before, after)); + } + } + } + }); + } + + } + + return results; + } + + + @Override + public FormDataLog.UpdateWidgetResult getUpdateWidget(FormWidget config,String widgetId,Map before,Map after) { + if(ObjectUtil.hasEmpty(config,widgetId) || ObjectUtil.isAllEmpty(before,after)){ + return null; + } + + if (flowChangedFields.contains(widgetId)) { + FormDataLog.UpdateWidgetResult result = new FormDataLog.UpdateWidgetResult(widgetId); + + DefaultConverter converter = new DefaultConverter(); + if (converter.checkChange(before.get(widgetId), after.get(widgetId))) { + String bef = new DefaultConverter().convert(before.get(widgetId), null); + String aft = new DefaultConverter().convert(after.get(widgetId), null); + result.setBef(bef); + result.setAft(aft); + + return result; + } + } + + BaseFormFieldConverter converter = FormFieldFactory.getConverter(config.getModel()); + if(converter != null) { + FormDataLog.UpdateWidgetResult result = new FormDataLog.UpdateWidgetResult( config.getModel()); + + if(converter.checkChange(before.get(widgetId), after.get(widgetId))) { + String bData = converter.convert(before.get(widgetId), config); + String aData = converter.convert(after.get(widgetId), config); + result.setBef(bData); + result.setAft(aData); + + return result; + } + } + + return null; + } + + @Override + public FormDataLog.UpdateWidgetResult getTableColumnUpdateWidget(List config, + String tableId, + String subColumnId, + List> before, + List> after + ) { + if(ObjectUtil.hasEmpty(config,tableId) || ObjectUtil.isAllEmpty(before,after)){ + + return null; + } + TableConverter tableConverter = new TableConverter(config); + + FormDataLog.UpdateWidgetResult result = new FormDataLog.UpdateWidgetResult(tableId); + + Map>> updatedTableData = tableConverter.listUpdateData(subColumnId,before,after); + List> befData = updatedTableData.get("before"); + List> afterData = updatedTableData.get("after"); + + if(CollUtil.isEmpty(befData) && CollUtil.isEmpty(afterData)){ + + return null; + } + + if(CollUtil.isNotEmpty(befData)){ + result.setBef(JsonUtil.toJson(befData)); + } + if(CollUtil.isNotEmpty(afterData)){ + result.setAft(JsonUtil.toJson(afterData)); + } + + return result; + } + + + + private List getFormWidgets(Long formId){ + FormSourceResult formDetail = this.formSourceService.getFormSourceById(formId); + + Map formJson = JsonUtil.jsonToMap(formDetail.getFormJson()); + + assert formJson != null; + List columnWidgetList = JsonUtil.jsonToList(JsonUtil.toJson(formJson.get("list")), FormWidget.class); + if(CollUtil.isEmpty(columnWidgetList)){ + + log.error("###### 数据日志 update field widget not exist ######"); + return null; + } + + return columnWidgetList; + } + + + + + /** + * 历史数据修复专用方法(后续会废弃) + * @param before + * @param after + * @return + */ + @Override + public List listUpdatedData(Map before, Map after) { + if(ObjectUtil.isAllNotEmpty(before,after)) { + List results = new ArrayList<>(); + + after.keySet().forEach(widgetId -> { + FormDataLog.UpdateWidgetResult updateWidget = new FormDataLog.UpdateWidgetResult(widgetId); + + if(flowChangedFields.contains(widgetId)){ + DefaultConverter converter = new DefaultConverter(); + if(converter.checkChange(before.get(widgetId),after.get(widgetId))) { + String bef = new DefaultConverter().convert(before.get(widgetId), null); + String aft = new DefaultConverter().convert(after.get(widgetId), null); + updateWidget.setBef(bef); + updateWidget.setAft(aft); + + results.add(updateWidget); + } + }else{ + BaseFormFieldConverter converter = FormFieldFactory.getConverter(widgetId); + + if (converter != null) { + if(converter.checkChange(before.get(widgetId),after.get(widgetId))){ + if(!StrUtil.contains(widgetId,WidgetType.TABLE.getCode())){ + + String bData = converter.convert(before.get(widgetId), null); + + String aData = converter.convert(after.get(widgetId), null); + + updateWidget.setBef(bData); + updateWidget.setAft(aData); + }else{ + + TableConverter tableConverter = (TableConverter)converter; + tableConverter.setFormWidgets(null); + + Map>> updatedTableData = tableConverter.listUpdateData(null,( List>)before.get(widgetId),( List>)after.get(widgetId)); + List> befData = updatedTableData.get("before"); + List> afterData = updatedTableData.get("after"); + + if(CollUtil.isNotEmpty(befData)){ + updateWidget.setBef(JsonUtil.toJson(befData)); + } + if(CollUtil.isNotEmpty(afterData)){ + updateWidget.setAft(JsonUtil.toJson(afterData)); + } + } + + results.add(updateWidget); + + } + } + } + + }); + + return results; + } + + return null; + } + + public static void main(String[] args) { + System.out.println(" = " +JsonUtil.toJson(null) ); + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/base/BaseFormFieldConverter.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/base/BaseFormFieldConverter.java new file mode 100644 index 0000000..625c2d9 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/base/BaseFormFieldConverter.java @@ -0,0 +1,49 @@ +package org.dromara.dataManager.widget.convert.base; + +import cn.hutool.core.util.ObjectUtil; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.dromara.taskCenter.model.FormWidget; + +import java.util.Comparator; +import java.util.List; + +/** + * @Description: 表单数据转化器基类 + **/ +@Slf4j +@Data +public abstract class BaseFormFieldConverter { + + private FormWidget formWidget; + + + + public String convert(Object data, FormWidget formWidget){ + return ""; + }; + + public Boolean checkChange(Object oldValue,Object newValue) { + + return false; + } + + + /** + * 不相同时返回true + * @param oldSetData + * @param newSetData + * @return + */ + public static boolean comparingList(List oldSetData, List newSetData) { + + List oldData = ObjectUtil.cloneByStream(oldSetData); + List newData = ObjectUtil.cloneByStream(newSetData); + + oldData.sort(Comparator.comparing(String::hashCode)); + newData.sort(Comparator.comparing(String::hashCode)); + + return !newData.toString().equals(oldData.toString()); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/base/FormFieldFactory.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/base/FormFieldFactory.java new file mode 100644 index 0000000..fbf0ca4 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/base/FormFieldFactory.java @@ -0,0 +1,82 @@ +package org.dromara.dataManager.widget.convert.base; + +import org.dromara.dataManager.widget.convert.column.DefaultConverter; +import org.dromara.dataManager.widget.convert.enums.FormColumnType; +import org.dromara.workflow.engine.enums.ESDefaultFieldConst; +import cn.hutool.core.util.StrUtil; +import lombok.extern.slf4j.Slf4j; + +import java.util.Arrays; +import java.util.List; + +@Slf4j +public class FormFieldFactory { + + private static final String packageName = "org.dromara.dataManager.convert.column.{}"; + + + public static final List defaultFieldConst = Arrays.asList(ESDefaultFieldConst._ID,ESDefaultFieldConst.DID, + ESDefaultFieldConst.ID, + ESDefaultFieldConst.OWNER,ESDefaultFieldConst.CREATOR,ESDefaultFieldConst.CREATOR_ACCOUNT,ESDefaultFieldConst.CREATE_TIME, + ESDefaultFieldConst.UPDATE_TIME,ESDefaultFieldConst.UPDATOR_NAME,ESDefaultFieldConst.DELETED, + ESDefaultFieldConst.FLOW_INSTANCE_ID, ESDefaultFieldConst.FLOW_STAGE, + ESDefaultFieldConst.FLOW_TASK_ID, ESDefaultFieldConst.FLOW_NODE_TITLE, ESDefaultFieldConst.FLOW_CHECKER_NAME + ); + + + public static BaseFormFieldConverter create(String columnType) throws InstantiationException, + IllegalAccessException { + FormColumnType formColumnType = FormColumnType.getByType(columnType); + + if (formColumnType == null) { + return new DefaultConverter(); + } + + String columnName = columnType.substring(0, 1).toUpperCase() + columnType.substring(1)+"Converter"; + try { + Class clz = Class.forName(StrUtil.format(packageName, columnName)); + + return (BaseFormFieldConverter)clz.newInstance(); + }catch (ClassNotFoundException e){ + + return new DefaultConverter(); + } + } + + + public static BaseFormFieldConverter getConverter(String model){ + if(!model.contains("_") || defaultFieldConst.contains(model)){ + return null; + } + + String filePrefix = model.substring(0, model.lastIndexOf("_")); + + if(filePrefix.contains(".")){ + filePrefix = StrUtil.subAfter(filePrefix,".",true); + } + + FormColumnType formColumnType = FormColumnType.getByType(filePrefix); + + if (formColumnType != null) { + try{ + String columnName = filePrefix.substring(0, 1).toUpperCase() + filePrefix.substring(1)+"Converter"; + try { + Class clz = Class.forName(StrUtil.format(packageName, columnName)); + + return (BaseFormFieldConverter)clz.newInstance(); + }catch (ClassNotFoundException e){ + + return new DefaultConverter(); + } + }catch (Exception e){ + + } + } + + + return null; + } + + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/CheckboxConverter.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/CheckboxConverter.java new file mode 100644 index 0000000..857eaaa --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/CheckboxConverter.java @@ -0,0 +1,41 @@ +package org.dromara.dataManager.widget.convert.column; + +import org.dromara.dataManager.widget.convert.base.BaseFormFieldConverter; +import org.dromara.taskCenter.model.FormWidget; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.google.common.base.Joiner; +import java.util.List; + +public class CheckboxConverter extends BaseFormFieldConverter { + + @Override + public String convert(Object value, FormWidget widget) { + if (ObjectUtil.isEmpty(value)) { + return ""; + } + + List checkBoxValue = (List)value; + if(CollUtil.isNotEmpty(checkBoxValue)){ + + return Joiner.on("、").skipNulls().join(checkBoxValue); + } + + return ""; + } + + + @Override + public Boolean checkChange(Object oldValue,Object newValue) { + if(ObjectUtil.isEmpty(oldValue)){ + return ObjectUtil.isNotEmpty(newValue); + } + + if (!ObjectUtil.equal(oldValue,newValue) ) { + return true; + } + + return comparingList((List)oldValue,(List)newValue); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/CoordinatesConverter.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/CoordinatesConverter.java new file mode 100644 index 0000000..d3c18aa --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/CoordinatesConverter.java @@ -0,0 +1,96 @@ +package org.dromara.dataManager.widget.convert.column; + + +import org.dromara.dataManager.widget.convert.base.BaseFormFieldConverter; +import org.dromara.taskCenter.model.FormWidget; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONObject; + +import java.util.Map; + +public class CoordinatesConverter extends BaseFormFieldConverter { + + @Override + public String convert(Object value, FormWidget widget) { + if (ObjectUtil.isEmpty(value)) { + return ""; + } + + + if(value instanceof JSONObject) { + JSONObject data = (JSONObject)value; + + if(ObjectUtil.isNotNull(data.get("address"))){ + return (String) data.get("address"); + } + } + + if(value instanceof Map) { + Map data = (Map)value; + + if(ObjectUtil.isNotNull(data.get("address"))){ + + return (String) data.get("address"); + } + } + + return ""; + } + + @Override + public Boolean checkChange(Object oldValue,Object newValue) { + if(ObjectUtil.isAllEmpty(oldValue,newValue)){ + return false; + } + if (ObjectUtil.isEmpty(oldValue) && ObjectUtil.isNotEmpty(newValue)) { + return true; + } + if (ObjectUtil.isNotEmpty(oldValue) && ObjectUtil.isEmpty(newValue)) { + return true; + } + + if(oldValue instanceof JSONObject){ + JSONObject bef = (JSONObject)oldValue; + JSONObject aft = (JSONObject)newValue; + + JSONObject befGeoPoint = (JSONObject)bef.get("geopoint"); + JSONObject aftGeoPoint = (JSONObject)aft.get("geopoint"); + + if(!ObjectUtil.equal(befGeoPoint,aftGeoPoint) || !ObjectUtil.equal(bef.get("address"),aft.get("address"))){ + + return true; + } + + if(befGeoPoint != null && aftGeoPoint != null){ + return !(ObjectUtil.equal(bef.get("address"),aft.get("address")) + && ObjectUtil.equal(befGeoPoint.get("lon"),aftGeoPoint.get("lon")) + && ObjectUtil.equal(befGeoPoint.get("lat"),aftGeoPoint.get("lat"))); + } + } + + + if(oldValue instanceof Map){ + Map bef = (Map)oldValue; + Map aft = (Map)newValue; + + Map befGeoPoint = (Map)bef.get("geopoint"); + Map aftGeoPoint = (Map)aft.get("geopoint"); + + if(!ObjectUtil.equal(befGeoPoint,aftGeoPoint) || !ObjectUtil.equal(bef.get("address"),aft.get("address"))){ + + return true; + } + + if(befGeoPoint != null && aftGeoPoint != null){ + return ObjectUtil.equal(bef.get("address"),aft.get("address")) + && ObjectUtil.equal(befGeoPoint.get("lon"),aftGeoPoint.get("lon")) + && ObjectUtil.equal(befGeoPoint.get("lat"),aftGeoPoint.get("lat")); + } + + } + + return false; + + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/DatalinkConverter.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/DatalinkConverter.java new file mode 100644 index 0000000..1640d88 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/DatalinkConverter.java @@ -0,0 +1,35 @@ +package org.dromara.dataManager.widget.convert.column; + +import org.dromara.dataManager.widget.convert.base.BaseFormFieldConverter; +import org.dromara.taskCenter.model.FormWidget; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import java.util.HashMap; + +public class DatalinkConverter extends BaseFormFieldConverter { + + @Override + public String convert(Object value, FormWidget widget) { + if (ObjectUtil.isEmpty(value)) { + return ""; + } + + return value.toString(); + } + + @Override + public Boolean checkChange(Object oldValue,Object newValue) { + if(ObjectUtil.isAllEmpty(oldValue,newValue)){ + + return false; + } + + if(oldValue == null && ObjectUtil.isNotEmpty(newValue)){ + HashMap dataMap = (HashMap) newValue; + return StrUtil.isNotEmpty((String)dataMap.get("id")); + } + + return !ObjectUtil.equal(oldValue,newValue); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/DateConverter.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/DateConverter.java new file mode 100644 index 0000000..d1653f3 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/DateConverter.java @@ -0,0 +1,150 @@ +package org.dromara.dataManager.widget.convert.column; + +import org.dromara.dataManager.widget.convert.base.BaseFormFieldConverter; +import org.dromara.taskCenter.model.FormWidget; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import lombok.extern.slf4j.Slf4j; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; + +@Slf4j +public class DateConverter extends BaseFormFieldConverter { + + @Override + public String convert(Object value, FormWidget widget) { + if (ObjectUtil.isEmpty(value) || StrUtil.equals("null",value.toString())) { + return ""; + } + + String formatOption = "yyyy-MM-dd HH:mm:ss"; + if(widget != null){ + formatOption = (String) widget.getOptions().get("format"); + } + SimpleDateFormat defaultFormat = new SimpleDateFormat(formatOption); + + try { + String dateTime = value.toString(); + + if(StrUtil.equals("0",dateTime) || dateTime.length() == 10){ + return dateTime; + } + + return convertTime2GMT08(dateTime,defaultFormat); + } catch (Exception e) { + e.printStackTrace(); + } + + return ""; + } + + public Date converts(Object value, FormWidget widget){ + if (ObjectUtil.isEmpty(value)) { + return null; + } + String dateTime = (String)value; + dateTime = dateTime.replace("Z", " UTC"); + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS Z"); + + try { + return format.parse(dateTime); + } catch (Exception e) { + e.printStackTrace(); + } + + return null; + } + + + @Override + public Boolean checkChange(Object oldValue,Object newValue) { + if (!ObjectUtil.equal(oldValue,newValue) ) { + return true; + } + + try{ + String oldTimeValue = this.convert(oldValue,null); + String newTimeValue = this.convert(newValue,null); + + return !StrUtil.equals(oldTimeValue,newTimeValue); + + }catch (Exception e){ + e.printStackTrace(); + return false; + } + } + + /** + * @description: 将带有0时区的字符串时间(2021-09-22T03:00:00.000Z),转换为东八区默认时间(yyyy-MM-dd HH:mm:ss) + */ + public static String convertTime2GMT08(String time,SimpleDateFormat sdf) throws ParseException { + + //时间格式自己定义 + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:sszzz"); + TimeZone tz; + + // 设置时区为"GMT+08:00"(需要输出时间的时区 ) + tz = TimeZone.getTimeZone("GMT+08:00"); + + time = time.replace("+00:00","Z"); + + String msStr = StrUtil.subBetween(time,".","Z"); + if(StrUtil.isNotEmpty(msStr)){ + time = time.replace(StrUtil.format(".{}Z",msStr), ""); + } + + // 后面的+0000为国际时间,其它时区请自行更换 (如GMT+08:00 为+0800) + Date date = df.parse(time.replace("T"," ") + "+0000"); + + // 获取默认的DateFormat,用于格式化Date + if(sdf == null){ + sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + } + + // 设置时区为tz + sdf.setTimeZone(tz); + // 获取格式化后的字符串 + return sdf.format(date); + } + + public static String convertStr(Object date) { + String formatOption = "yyyy-MM-dd"; + SimpleDateFormat defaultFormat = new SimpleDateFormat(formatOption); + + if(date instanceof String){ + String dateTime = (String)date; + dateTime = dateTime.replace("Z", " UTC"); + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS Z"); + try { + Date time = format.parse(dateTime); + + return defaultFormat.format(time); + } catch (Exception e) { + e.printStackTrace(); + } + } + if(date instanceof Date){ + Date dateTime = (Date)date; + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); + try { + return format.format(dateTime); + } catch (Exception e) { + } + } + + return null; + } + + public static void main(String[] args) { + try{ + // "2022-02-13T16:00:00.000+00:00" + + System.out.println(" = " + convertTime2GMT08("2022-02-13T16:00:00.123+00:00",null)); + }catch (Exception e){ + e.printStackTrace(); + } + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/DefaultConverter.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/DefaultConverter.java new file mode 100644 index 0000000..04217aa --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/DefaultConverter.java @@ -0,0 +1,27 @@ +package org.dromara.dataManager.widget.convert.column; + +import org.dromara.dataManager.widget.convert.base.BaseFormFieldConverter; +import org.dromara.taskCenter.model.FormWidget; +import cn.hutool.core.util.ObjectUtil; + +public class DefaultConverter extends BaseFormFieldConverter { + + @Override + public String convert(Object value, FormWidget widget) { + if (ObjectUtil.isEmpty(value)) { + return ""; + } + + return value.toString(); + } + + @Override + public Boolean checkChange(Object oldValue,Object newValue) { + if(ObjectUtil.isEmpty(oldValue)){ + return ObjectUtil.isNotEmpty(newValue); + } + + return !ObjectUtil.equal(oldValue,newValue); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/EditorConverter.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/EditorConverter.java new file mode 100644 index 0000000..23e725d --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/EditorConverter.java @@ -0,0 +1,40 @@ +package org.dromara.dataManager.widget.convert.column; + +import org.dromara.dataManager.widget.convert.base.BaseFormFieldConverter; +import org.dromara.taskCenter.model.FormWidget; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HtmlUtil; + +public class EditorConverter extends BaseFormFieldConverter { + + @Override + public String convert(Object value, FormWidget widget) { + if (ObjectUtil.isEmpty(value)) { + return ""; + } + + return value.toString(); + } + + @Override + public Boolean checkChange(Object oldValue,Object newValue) { + if(ObjectUtil.isEmpty(oldValue)){ + return ObjectUtil.isNotEmpty(newValue); + } + + return !StrUtil.equals(oldValue+"",newValue+"") && + !StrUtil.equals(HtmlUtil.unwrapHtmlTag(oldValue+"","\n","\t","p"),HtmlUtil.unwrapHtmlTag(newValue+"","\n","\t","p")); + } + + + + + public static void main(String[] args) { + String str = "\t

语言哟之登记卡那刺客技术大牛从事地产

\n"; + + System.out.println(" = " + HtmlUtil.unwrapHtmlTag(str+"","\n","\t","p")); + System.out.println(" = " + HtmlUtil.removeHtmlTag(str+"","\n","\t","p")); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/FileuploadConverter.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/FileuploadConverter.java new file mode 100644 index 0000000..034e346 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/FileuploadConverter.java @@ -0,0 +1,73 @@ +package org.dromara.dataManager.widget.convert.column; + +import org.dromara.dataManager.widget.convert.base.BaseFormFieldConverter; +import org.dromara.taskCenter.model.FormWidget; +import org.dromara.workflow.engine.enums.ESDefaultFieldConst; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.google.common.base.Joiner; +import lombok.extern.slf4j.Slf4j; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +@Slf4j +public class FileuploadConverter extends BaseFormFieldConverter { + + @Override + public String convert(Object value, FormWidget widget) { + + if (ObjectUtil.isEmpty(value)) { + return ""; + } + + JSONArray jsonArray = JSONUtil.parseArray(value); + List imgResult = new ArrayList(); + + jsonArray.forEach(imgItem ->{ + JSONObject item = (JSONObject)imgItem; + imgResult.add((String) item.get("name")); + }); + + return Joiner.on("、").skipNulls().join(imgResult); + } + + + @Override + public Boolean checkChange(Object oldValue,Object newValue) { + if(ObjectUtil.isEmpty(oldValue)){ + List imgData = getFileId(newValue); + return CollUtil.isNotEmpty(imgData); + } + + return comparingList(getFileId(oldValue),getFileId(newValue)); + } + + private List getFileId(Object oldValue) { + List fileIdList = new ArrayList<>(); + + if(oldValue instanceof JSONArray){ + JSONArray data = (JSONArray) oldValue; + if(CollUtil.isNotEmpty(data)){ + for(int i =0;i> data = (ArrayList>) oldValue; + if(CollUtil.isNotEmpty(data)){ + data.forEach(imgItem ->{ + fileIdList.add((String) imgItem.get(ESDefaultFieldConst.ID)); + }); + } + } + + return fileIdList; + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/Format_numberConverter.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/Format_numberConverter.java new file mode 100644 index 0000000..555e2b0 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/Format_numberConverter.java @@ -0,0 +1,29 @@ +package org.dromara.dataManager.widget.convert.column; + +import org.dromara.dataManager.widget.convert.base.BaseFormFieldConverter; +import org.dromara.dataManager.widget.handler.FormatNumberHandler; +import org.dromara.taskCenter.model.FormWidget; +import cn.hutool.core.util.NumberUtil; +import cn.hutool.core.util.ObjectUtil; + +public class Format_numberConverter extends BaseFormFieldConverter { + + private final static FormatNumberHandler handler = new FormatNumberHandler(); + + @Override + public String convert(Object numberParam, FormWidget widget) { + Object res = handler.handle(numberParam, widget.getOptions()).toString(); + return res == null ? "" : res.toString(); + } + + @Override + public Boolean checkChange(Object oldValue,Object newValue) { + if(ObjectUtil.isEmpty(oldValue)){ + return ObjectUtil.isNotEmpty(newValue); + } + + return !(NumberUtil.isNumber(oldValue.toString()) ? Double.valueOf(oldValue.toString()) : "" ) + .equals(newValue != null ? Double.valueOf(newValue.toString()) : ""); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/ImguploadConverter.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/ImguploadConverter.java new file mode 100644 index 0000000..54f264e --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/ImguploadConverter.java @@ -0,0 +1,69 @@ +package org.dromara.dataManager.widget.convert.column; + +import org.dromara.dataManager.widget.convert.base.BaseFormFieldConverter; +import org.dromara.taskCenter.model.FormWidget; +import org.dromara.workflow.engine.enums.ESDefaultFieldConst; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.google.common.base.Joiner; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class ImguploadConverter extends BaseFormFieldConverter { + + @Override + public String convert(Object value, FormWidget widget) { + + if (ObjectUtil.isEmpty(value)) { + return ""; + } + + JSONArray jsonArray = JSONUtil.parseArray(value); + List imgResult = new ArrayList(); + + jsonArray.forEach(imgItem ->{ + JSONObject item = (JSONObject)imgItem; + imgResult.add((String) item.get("name")); + }); + + return Joiner.on("、").skipNulls().join(imgResult); + } + + + @Override + public Boolean checkChange(Object oldValue,Object newValue) { + if(ObjectUtil.isEmpty(oldValue)){ + List imgData = getImgList(newValue); + return CollUtil.isNotEmpty(imgData); + } + + return comparingList(getImgList(oldValue),getImgList(newValue)); + } + + private List getImgList(Object oldValue) { + List imgIds = new ArrayList<>(); + + if(oldValue instanceof JSONArray){ + JSONArray data = (JSONArray) oldValue; + if(CollUtil.isNotEmpty(data)){ + for(int i =0;i> data = (ArrayList>) oldValue; + if(CollUtil.isNotEmpty(data)){ + data.forEach(imgItem ->{ + imgIds.add((String) imgItem.get(ESDefaultFieldConst.ID)); + }); + } + } + return imgIds; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/LocationConverter.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/LocationConverter.java new file mode 100644 index 0000000..dcd993b --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/LocationConverter.java @@ -0,0 +1,93 @@ +package org.dromara.dataManager.widget.convert.column; + +import org.dromara.dataManager.widget.convert.base.BaseFormFieldConverter; +import org.dromara.taskCenter.model.FormWidget; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONObject; + +import java.util.HashMap; +import java.util.Map; + +public class LocationConverter extends BaseFormFieldConverter { + + + @Override + public String convert(Object value, FormWidget widget) { + + if (ObjectUtil.isEmpty(value)) { + return ""; + } + + StringBuilder sb = new StringBuilder(); + + if(value instanceof JSONObject){ + JSONObject locationData = (JSONObject) value; + + if(locationData.get("province") != null){ + Object province = locationData.get("province"); + if(province instanceof String){ + sb.append((String)province); + } + } + if(locationData.get("city") != null){ + Object city = locationData.get("city"); + if(city instanceof String){ + sb.append(" "+city); + } + } + if(locationData.get("area") != null){ + Object area = locationData.get("area"); + if(area instanceof String){ + sb.append(" "+area); + } + } + if(locationData.get("address") != null){ + Object address = locationData.get("address"); + if(address instanceof String){ + sb.append(" "+address); + } + } + + } + + if(value instanceof HashMap){ + Map locationData = (Map) value; + + if(locationData.get("province") != null){ + Object province = locationData.get("province"); + if(province instanceof String){ + sb.append((String)province); + } + } + if(locationData.get("city") != null){ + Object city = locationData.get("city"); + if(city instanceof String){ + sb.append(" "+city); + } + } + if(locationData.get("area") != null){ + Object area = locationData.get("area"); + if(area instanceof String){ + sb.append(" "+area); + } + } + if(locationData.get("address") != null){ + Object address = locationData.get("address"); + if(address instanceof String){ + sb.append(" "+address); + } + } + } + + return sb.toString(); + } + + + @Override + public Boolean checkChange(Object oldValue,Object newValue) { + + return !StrUtil.equals(convert(oldValue,null),convert(newValue,null)); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/Multiple_departmentsConverter.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/Multiple_departmentsConverter.java new file mode 100644 index 0000000..fc23dd3 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/Multiple_departmentsConverter.java @@ -0,0 +1,93 @@ +package org.dromara.dataManager.widget.convert.column; + +import org.dromara.dataManager.widget.convert.base.BaseFormFieldConverter; +import org.dromara.taskCenter.model.FormWidget; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONObject; +import com.google.common.base.Joiner; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class Multiple_departmentsConverter extends BaseFormFieldConverter { + + @Override + public String convert(Object value, FormWidget widget) { + if (ObjectUtil.isEmpty(value)) { + return ""; + } + + + List departmentTitleSet = new ArrayList<>(); + + if(value instanceof JSONArray){ + ((JSONArray) value).forEach(p -> { + departmentTitleSet.add(((JSONObject)p).get("title")+""); + }); + }else{ + List> multipleMembers = (List>) value; + + if (CollUtil.isNotEmpty(multipleMembers)) { + multipleMembers.forEach(p -> { + departmentTitleSet.add(p.get("title")); + }); + } + } + + if(CollUtil.isNotEmpty(departmentTitleSet)){ + + return Joiner.on(",").skipNulls().join(departmentTitleSet); + } + + return ""; + } + + @Override + public Boolean checkChange(Object oldValue,Object newValue) { + if(ObjectUtil.isEmpty(oldValue)){ + + List keyIds = getKeyList(newValue); + return CollUtil.isNotEmpty(keyIds); + } + + if (!ObjectUtil.equal(oldValue,newValue) ) { + + return true; + } + + return comparingList(getKeyList(oldValue),getKeyList(newValue)); + } + + + private List getKeyList(Object value) { + List keySet = new ArrayList<>(); + if(ObjectUtil.isEmpty(value)){ + return keySet; + } + + if(value instanceof JSONArray){ + JSONArray multipleMembers = (JSONArray) value; + + if (CollUtil.isNotEmpty(multipleMembers)) { + for(int i=0;i> multipleMembers = (ArrayList>) value; + if (CollUtil.isNotEmpty(multipleMembers)) { + for(int i=0;i multipleList = (List)value; + if(CollUtil.isNotEmpty(multipleList)){ + + return Joiner.on("、").skipNulls().join(multipleList); + } + + return ""; + } + + + @Override + public Boolean checkChange(Object oldValue,Object newValue) { + if(ObjectUtil.isEmpty(oldValue)){ + return ObjectUtil.isNotEmpty(newValue); + } + + if (!ObjectUtil.equal(oldValue,newValue) ) { + return true; + } + + return comparingList((List)oldValue,(List)newValue); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/MultiplemembersConverter.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/MultiplemembersConverter.java new file mode 100644 index 0000000..b11a1f9 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/MultiplemembersConverter.java @@ -0,0 +1,94 @@ +package org.dromara.dataManager.widget.convert.column; + +import org.dromara.dataManager.widget.convert.base.BaseFormFieldConverter; +import org.dromara.taskCenter.model.FormWidget; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONObject; +import com.google.common.base.Joiner; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class MultiplemembersConverter extends BaseFormFieldConverter { + + @Override + public String convert(Object value, FormWidget widget) { + if (ObjectUtil.isEmpty(value)) { + return ""; + } + + List memberTitleSet = new ArrayList<>(); + + if(value instanceof JSONArray){ + ((JSONArray) value).forEach(p -> { + memberTitleSet.add(((JSONObject)p).get("title")+""); + }); + }else{ + List> multipleMembers = (List>) value; + + if (CollUtil.isNotEmpty(multipleMembers)) { + multipleMembers.forEach(p -> { + memberTitleSet.add(p.get("title")); + }); + } + } + + + if(CollUtil.isNotEmpty(memberTitleSet)){ + + return Joiner.on(",").skipNulls().join(memberTitleSet); + } + + return ""; + + } + + + @Override + public Boolean checkChange(Object oldValue,Object newValue) { + if(ObjectUtil.isEmpty(oldValue)){ + + List keyIds = getKeyList(newValue); + return CollUtil.isNotEmpty(keyIds); + } + + if (!ObjectUtil.equal(oldValue,newValue) ) { + + return true; + } + + return comparingList(getKeyList(oldValue),getKeyList(newValue)); + } + + + private List getKeyList(Object value) { + List keySet = new ArrayList<>(); + if(ObjectUtil.isEmpty(value)){ + return keySet; + } + + if(value instanceof JSONArray){ + JSONArray multipleMembers = (JSONArray) value; + + if (CollUtil.isNotEmpty(multipleMembers)) { + for(int i=0;i> multipleMembers = (ArrayList>) value; + if (CollUtil.isNotEmpty(multipleMembers)) { + for(int i=0;i phoneData = (Map) value; + + return ObjectUtil.isNotNull(phoneData.get("phoneNumber")) ? phoneData.get("phoneNumber").toString() : ""; + } + + return ""; + } + + @Override + public Boolean checkChange(Object oldValue,Object newValue) { + if(oldValue == null && ObjectUtil.isNotEmpty(newValue)) { + + if (newValue instanceof JSONObject) { + JSONObject phoneData = (JSONObject) newValue; + return ObjectUtil.isNotNull(phoneData.get("phoneNumber")); + } + + if (newValue instanceof LinkedHashMap) { + HashMap phoneData = (HashMap) newValue; + return ObjectUtil.isNotNull(phoneData.get("phoneNumber")); + } + + } + + String oldPhoneNumber = ""; + String newPhoneNumber = ""; + + if(oldValue instanceof JSONObject){ + JSONObject oldValueData = (JSONObject) oldValue; + if (ObjectUtil.isNotNull(oldValueData) && ObjectUtil.isNotNull(oldValueData.get("phoneNumber"))) { + oldPhoneNumber = (String) oldValueData.get("phoneNumber"); + } + + JSONObject newValueData = (JSONObject) newValue; + if (ObjectUtil.isNotNull(newValueData) && ObjectUtil.isNotNull(newValueData.get("phoneNumber"))) { + newPhoneNumber = (String)newValueData.get("phoneNumber"); + } + } + + + if(oldValue instanceof LinkedHashMap){ + LinkedHashMap oldValueData = (LinkedHashMap) oldValue; + if (ObjectUtil.isNotNull(oldValueData) && ObjectUtil.isNotNull(oldValueData.get("phoneNumber"))) { + oldPhoneNumber = (String) oldValueData.get("phoneNumber"); + } + + LinkedHashMap newValueData = (LinkedHashMap) newValue; + if (ObjectUtil.isNotNull(newValueData) && ObjectUtil.isNotNull(newValueData.get("phoneNumber"))) { + newPhoneNumber = (String)newValueData.get("phoneNumber"); + } + } + + return !StrUtil.equals(oldPhoneNumber,newPhoneNumber); + } + + public static void main(String[] args) { + System.out.println(" = " + new JSONNull().toString()); + } + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/SingledepartmentConverter.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/SingledepartmentConverter.java new file mode 100644 index 0000000..d5f12f4 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/SingledepartmentConverter.java @@ -0,0 +1,82 @@ +package org.dromara.dataManager.widget.convert.column; + +import org.dromara.dataManager.widget.convert.base.BaseFormFieldConverter; +import org.dromara.taskCenter.model.FormWidget; +import org.dromara.workflow.engine.enums.ESDefaultFieldConst; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONObject; + +import java.util.HashMap; +import java.util.LinkedHashMap; + +public class SingledepartmentConverter extends BaseFormFieldConverter { + + @Override + public String convert(Object value, FormWidget widget) { + if (ObjectUtil.isEmpty(value)) { + return ""; + } + if(value instanceof JSONObject){ + + return((JSONObject) value).get("title")+""; + } + + HashMap memberMap = (HashMap) value; + + return memberMap.get("title"); + + } + + + @Override + public Boolean checkChange(Object oldValue,Object newValue) { + if (!ObjectUtil.equal(oldValue,newValue) ) { + + return true; + } + + String oldKey = ""; + String newKey = ""; + + if(oldValue instanceof LinkedHashMap){ + LinkedHashMap oldValueData = (LinkedHashMap) oldValue; + if (ObjectUtil.isNotEmpty(oldValueData)) { + oldKey = (String) oldValueData.get(ESDefaultFieldConst.ID); + } + + LinkedHashMap newValueData = (LinkedHashMap) newValue; + if (ObjectUtil.isNotEmpty(newValueData)) { + newKey = (String) newValueData.get(ESDefaultFieldConst.ID); + } + } + + if(oldValue instanceof HashMap){ + HashMap oldValueData = (HashMap) oldValue; + if (ObjectUtil.isNotEmpty(oldValueData)) { + oldKey = (String) oldValueData.get(ESDefaultFieldConst.ID); + } + + HashMap newValueData = (HashMap) newValue; + if (ObjectUtil.isNotEmpty(newValueData)) { + newKey = (String) newValueData.get(ESDefaultFieldConst.ID); + } + } + + if(oldValue instanceof JSONObject){ + JSONObject oldValueData = (JSONObject) oldValue; + if (ObjectUtil.isNotEmpty(oldValueData)) { + oldKey = (String) oldValueData.get(ESDefaultFieldConst.ID); + } + + JSONObject newValueData = (JSONObject) newValue; + if (ObjectUtil.isNotEmpty(newValueData)) { + newKey = (String) newValueData.get(ESDefaultFieldConst.ID); + } + } + + + return !StrUtil.equals(newKey,oldKey); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/SinglememberConverter.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/SinglememberConverter.java new file mode 100644 index 0000000..ce5d2e4 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/SinglememberConverter.java @@ -0,0 +1,85 @@ +package org.dromara.dataManager.widget.convert.column; + +import org.dromara.dataManager.widget.convert.base.BaseFormFieldConverter; +import org.dromara.taskCenter.model.FormWidget; +import org.dromara.workflow.engine.enums.ESDefaultFieldConst; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONObject; +import java.util.HashMap; +import java.util.LinkedHashMap; + +public class SinglememberConverter extends BaseFormFieldConverter { + +// private final UserService userService; +// +// public SinglememberConverter() { +// userService = SpringUtil.getBean(UserService.class); +// } + + @Override + public String convert(Object value, FormWidget widget) { + if (ObjectUtil.isEmpty(value)) { + return ""; + } + if(value instanceof JSONObject){ + + return((JSONObject) value).get("title")+""; + } + + HashMap memberMap = (HashMap) value; + + return memberMap.get("title"); + + } + + @Override + public Boolean checkChange(Object oldValue, Object newValue) { + if (!ObjectUtil.equal(oldValue,newValue)){ + + return true; + } + + String oldKey = ""; + String newKey = ""; + if(oldValue instanceof LinkedHashMap){ + LinkedHashMap oldValueData = (LinkedHashMap) oldValue; + if (ObjectUtil.isNotEmpty(oldValueData)) { + oldKey = (String) oldValueData.get(ESDefaultFieldConst.ID); + } + + LinkedHashMap newValueData = (LinkedHashMap) newValue; + if (ObjectUtil.isNotEmpty(newValueData)) { + newKey = (String) newValueData.get(ESDefaultFieldConst.ID); + } + } + + if(oldValue instanceof HashMap){ + HashMap oldValueData = (HashMap) oldValue; + if (ObjectUtil.isNotEmpty(oldValueData)) { + oldKey = (String) oldValueData.get(ESDefaultFieldConst.ID); + } + + HashMap newValueData = (HashMap) newValue; + if (ObjectUtil.isNotEmpty(newValueData)) { + newKey = (String) newValueData.get(ESDefaultFieldConst.ID); + } + } + + if(oldValue instanceof JSONObject){ + JSONObject oldValueData = (JSONObject) oldValue; + if (ObjectUtil.isNotEmpty(oldValueData)) { + oldKey = (String) oldValueData.get(ESDefaultFieldConst.ID); + } + + JSONObject newValueData = (JSONObject) newValue; + if (ObjectUtil.isNotEmpty(newValueData)) { + newKey = (String) newValueData.get(ESDefaultFieldConst.ID); + } + } + + + return !StrUtil.equals(newKey, oldKey); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/TableConverter.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/TableConverter.java new file mode 100644 index 0000000..97fa79e --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/column/TableConverter.java @@ -0,0 +1,252 @@ +package org.dromara.dataManager.widget.convert.column; + +import org.dromara.dataManager.widget.convert.base.BaseFormFieldConverter; +import org.dromara.dataManager.widget.convert.base.FormFieldFactory; +import org.dromara.taskCenter.model.FormWidget; +import org.dromara.workflow.engine.enums.ESDefaultFieldConst; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONObject; +import com.google.common.collect.Sets; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +import java.util.*; +import java.util.stream.Collectors; + +@Slf4j +@Data +public class TableConverter extends BaseFormFieldConverter { + + private List formWidgets; + + public TableConverter(List formWidgets){ + this.formWidgets = formWidgets; + } + + /** + * + * 子表单支持的字段类型: + * 基础字段(8个):单行文本、多行文本、数字、日期时间、单选框组、复选框组(字符串数组)、下拉单选框、下拉复选框(字符串数组) + * 高级字段(4个):附件(对象)、图片(对象)、地址(对象)、定位(对象) + * 成员部门字段(4个):成员单选(对象)、成员多选(对象数组)、部门单选(对象)、部门多选(对象数组) + * @return + */ + public Boolean checkChange(Object oldValue,Object newValue) { + + boolean hasChange = false; + + if(oldValue instanceof ArrayList){ + //1、判断行数是否发生变化 + List> befData = (List>)oldValue; + List> aftData = (List>)newValue; + + + if(CollUtil.isEmpty(befData) && CollUtil.isEmpty(aftData)){ + return false; + } + if(befData.size() != aftData.size()){ + return false; + } + + + for(Map data : aftData){ + //2、判断每一行是否一致 + String rowDataId = (String) data.get(ESDefaultFieldConst._ID); + if(StrUtil.isEmpty(rowDataId)){ + continue; + } + boolean hasRow = befData.stream().anyMatch(p -> StrUtil.equals((String)p.get(ESDefaultFieldConst._ID), rowDataId)); + if(!hasRow){ + hasChange = true; + break; + } + } + + if(!hasChange){ + //3、判断每一列的数据是否一致 + for(int i=0;i aft = aftData.get(i); + String rowId = (String) aft.get(ESDefaultFieldConst._ID); + + Map bef = befData.get(i); + if(StrUtil.isNotEmpty(rowId)){ + bef = befData.stream().filter(p -> StrUtil.equals((String)p.get(ESDefaultFieldConst._ID),rowId)).findAny().get(); + } + + if(!hasChange){ + for(String rowModel : aft.keySet()){ + BaseFormFieldConverter converter = FormFieldFactory.getConverter(rowModel); + if(converter != null){ + if(converter.checkChange(bef.get(rowModel),aft.get(rowModel))){ + hasChange = true; + break; + } + } + } + } + + } + } + } + + if(oldValue instanceof JSONArray){ + //1、判断行数是否发生变化 + JSONArray befData = (JSONArray)oldValue; + JSONArray aftData = (JSONArray)newValue; + + + if(CollUtil.isEmpty(befData) && CollUtil.isEmpty(aftData)){ + return false; + } + if(befData.size() != aftData.size()){ + return true; + } + + + for(int i=0;i { + JSONObject item = (JSONObject)p; + return StrUtil.equals((String)item.get(ESDefaultFieldConst._ID), rowDataId); + }); + if(!hasRow){ + hasChange = true; + break; + } + } + + if(!hasChange){ + //3、判断每一列的数据是否一致 + for(int i=0;i { + JSONObject item = (JSONObject) p; + return StrUtil.equals((String)item.get(ESDefaultFieldConst._ID),rowId); + }).findAny().get(); + } + + if(!hasChange){ + for(String rowModel : data.keySet()){ + BaseFormFieldConverter converter = FormFieldFactory.getConverter(rowModel); + if(converter != null){ + if(converter.checkChange(bef.get(rowModel),data.get(rowModel))){ + hasChange = true; + break; + } + } + } + } + + } + } + } + + + return hasChange; + } + + + /** + * 查询子表单行列数据变化 + * @param subColumnId 为空则对比全部子字段 + * @param before 改动之前的所有行数据 + * @param after 改动之后的所有行数据 + * @return + */ + public Map>> listUpdateData(String subColumnId, + List> before, + List> after + ) { + Map>> result = new HashMap<>(); + + Set befLineIds = new HashSet<>(); + if(CollUtil.isNotEmpty(before)){ + befLineIds = before.stream().filter(p -> ObjectUtil.isNotEmpty(p.get(ESDefaultFieldConst._ID))).map(p -> p.get(ESDefaultFieldConst._ID).toString()).collect(Collectors.toSet()); + } + Set aftLineIds = new HashSet<>(); + if(CollUtil.isNotEmpty(after)){ + aftLineIds = after.stream().filter(p -> ObjectUtil.isNotEmpty(p.get(ESDefaultFieldConst._ID))).map(p -> p.get(ESDefaultFieldConst._ID).toString()).collect(Collectors.toSet()); + } + + Sets.SetView addedLines = Sets.difference(aftLineIds, befLineIds); + Sets.SetView deletedLines = Sets.difference(befLineIds, aftLineIds); + Sets.SetView totalLines = Sets.union(befLineIds,aftLineIds); + + List> befResult = new ArrayList<>(); + List> aftResult = new ArrayList<>(); + + Set tableColumns = subColumnId == null ?this.formWidgets.stream().map(FormWidget::getModel).collect(Collectors.toSet()) : new HashSet<>(Arrays.asList(subColumnId)); + + for(String lineId : totalLines){ + if(addedLines.contains(lineId)){ + aftResult.add(new HashMap(){{put(ESDefaultFieldConst._ID,lineId);}}); + }else if(deletedLines.contains(lineId)){ + befResult.add(new HashMap(){{put(ESDefaultFieldConst._ID,lineId);}}); + }else{ + //判断行列数据是否修改 + Map befLine = before.stream().filter(p -> ObjectUtil.equal(p.get(ESDefaultFieldConst._ID),lineId)).findAny().get(); + Map aftLine = after.stream().filter(p -> ObjectUtil.equal(p.get(ESDefaultFieldConst._ID),lineId)).findAny().get(); + Map befUpdatedLine = new HashMap<>(); + Map aftUpdatedLine = new HashMap<>(); + for(String column : tableColumns){ + BaseFormFieldConverter converter = FormFieldFactory.getConverter(column); + if(converter != null && converter.checkChange(befLine.get(column),aftLine.get(column))){ + FormWidget columnConfig = this.formWidgets.stream().filter(p -> StrUtil.equals(p.getModel(),column)).findFirst().orElse(null); + if(columnConfig != null){ + befUpdatedLine.put(column,converter.convert(befLine.get(column),columnConfig)); + aftUpdatedLine.put(column,converter.convert(aftLine.get(column),columnConfig)); + } + } + } + + if(MapUtil.isNotEmpty(befUpdatedLine)){ + befUpdatedLine.put(ESDefaultFieldConst._ID,lineId); + befResult.add(befUpdatedLine); + } + if(MapUtil.isNotEmpty(aftUpdatedLine)){ + aftUpdatedLine.put(ESDefaultFieldConst._ID,lineId); + aftResult.add(aftUpdatedLine); + } + } + } + + result.put("before",befResult); + result.put("after",aftResult); + return result; + } + + + + + public static void main(String[] args) { + Set sets = Sets.newHashSet(1, 2, 3, 4, 5, 6); + Set sets2 = Sets.newHashSet(3, 4, 5, 6, 7, 8, 9); + // 交集 + System.out.println("交集为:"); + Sets.SetView intersection = Sets.intersection(sets, sets2); + for (Integer temp : intersection) { + System.out.println(temp); + } + // 差集 + System.out.println("差集为:"); + Sets.SetView diff = Sets.difference(sets, sets2); + for (Integer temp : diff) { + System.out.println(temp); + } + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/enums/FormColumnType.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/enums/FormColumnType.java new file mode 100644 index 0000000..3f18003 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/enums/FormColumnType.java @@ -0,0 +1,65 @@ +package org.dromara.dataManager.widget.convert.enums; + +import lombok.Getter; + +import java.util.Arrays; +import java.util.Optional; + +@Getter +public enum FormColumnType { + + /** + * 基础字段 + */ + INPUT("input"), + TEXTAREA("textarea"), + RADIO("radio"), + CHECKBOX("checkbox"), + TIME("time"), + DATE("date"), + SELECT("select"), + MULTIPLE_SELECT("multiple_select"), + FORMAT_NUMBER("format_number"), + DIVIDER("divider"), + + /** + * 高级字段 + */ + FILE_UPLOAD("fileupload"), + IMG_UPLOAD("imgupload"), + EDITOR("editor"), + TABLE("table"), + LOCATION("location"), + UNIQ_KEY("uniqkey"), + COORDINATES("coordinates"), + DATA_LINK("datalink"), + LINK_QUERY("link_query"), + PHONE("phone"), + + /** + * 成员部门字段 + */ + SINGLE_MEMBER("singlemember"), + MULTIPLE_MEMBERS("multiplemembers"), + SINGLE_DEPARTMENT("singledepartment"), + MULTIPLE_DEPARTMENTS("multiple_departments"); + + private String code; + + public String getCode() { + return code; + } + + FormColumnType(String code) { + this.code = code; + } + + public static FormColumnType getByType(String type) { + Optional optional = + Arrays.stream(values()).filter(item -> item.getCode().equals(type)).findFirst(); + return optional.orElse(null); + } + + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/model/FormDataChangedConvert.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/model/FormDataChangedConvert.java new file mode 100644 index 0000000..45aeea0 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/model/FormDataChangedConvert.java @@ -0,0 +1,26 @@ +package org.dromara.dataManager.widget.convert.model; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * @Description: 表单数据(格式化之后) + **/ +@Data +@EqualsAndHashCode(callSuper = true) +public class FormDataChangedConvert extends FormDataConvert{ + + /** + * 变化后的值 + */ + private String newValue; + + + public FormDataChangedConvert(String model, String name, String value,String newValue){ + this.setModel(model); + this.setName(name); + this.setValue(value); + this.setNewValue(newValue); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/model/FormDataConvert.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/model/FormDataConvert.java new file mode 100644 index 0000000..0d2da7b --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/model/FormDataConvert.java @@ -0,0 +1,35 @@ +package org.dromara.dataManager.widget.convert.model; + +import lombok.Data; + +/** + * @Description: 表单数据(格式化之后) + **/ +@Data +public class FormDataConvert { + + /** + * 字段id + */ + private String model; + + /** + * 字段名称 + */ + private String name; + + /** + * 格式化的值 + */ + private String value; + + public FormDataConvert(){ + } + + public FormDataConvert(String model,String name,String value){ + this.model = model; + this.name = name; + this.value = value; + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/service/FormDataConvertService.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/service/FormDataConvertService.java new file mode 100644 index 0000000..f64c66f --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/convert/service/FormDataConvertService.java @@ -0,0 +1,108 @@ +package org.dromara.dataManager.widget.convert.service; + +import org.dromara.common.util.JsonUtil; +import org.dromara.dataManager.widget.convert.base.BaseFormFieldConverter; +import org.dromara.dataManager.widget.convert.base.FormFieldFactory; +import org.dromara.dataManager.service.FormDataService; +import org.dromara.dataManager.widget.convert.model.FormDataConvert; +import org.dromara.formMaking.results.FormSourceResult; +import org.dromara.formMaking.service.FormSourceService; +import org.dromara.taskCenter.model.FormWidget; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * @Description: 表单数据转化服务 + **/ +@Slf4j +@Service +public class FormDataConvertService { + + @Autowired + private FormDataService formDataService; + @Autowired + private FormSourceService formSourceService; + /** + * 表单数据转化 + * @param formId 表单id + * @param formData 表单数据 + * @param widgetModels 要转化的字段id + * @return + */ + public List convert(Long formId, Map formData, List widgetModels){ + if(ObjectUtil.hasEmpty(formId,formData)){ + + return null; + } + + FormSourceResult formDetail = formSourceService.getFormSourceById(formId); + + return convert(formDetail,formData,widgetModels); + } + + + public List convert(Long formId, String formCode, Long dataId, List widgetModels){ + if(ObjectUtil.hasEmpty(formId,formCode,dataId)){ + + return null; + } + + Map formData = formDataService.getFormDataById(formId,dataId); + FormSourceResult formDetail = formSourceService.getFormSourceById(formId); + + return convert(formDetail,formData,widgetModels); + } + + + + public List convert(FormSourceResult formDetail, Map formData, List widgetModels){ + if(ObjectUtil.hasEmpty(formDetail,formData)){ + + return null; + } + + List result = new ArrayList<>(); + + Map formJson = JsonUtil.jsonToMap(formDetail.getFormJson()); + + List columnList = JsonUtil.jsonToList(JsonUtil.toJson(formJson.get("list")), FormWidget.class); + + // 字段与控件类型的映射关系 + if (CollUtil.isNotEmpty(columnList)) { + + if(CollUtil.isNotEmpty(widgetModels)){ + columnList = columnList.stream().filter(p -> widgetModels.contains(p.getModel())).collect(Collectors.toList()); + } + + if(CollUtil.isNotEmpty(columnList)){ + columnList.forEach(p -> { + try { + FormDataConvert convertedData = new FormDataConvert(p.getModel(), p.getName(), convertColumn(p.getType(), formData.get(p.getModel()),p)); + result.add(convertedData); + }catch (Exception e){ + log.error("###### data convert model {} exception {} ######",p.getModel(),e.getMessage()); + } + }); + } + } + + return result; + } + + + private String convertColumn(String type,Object data,FormWidget widget)throws InstantiationException,IllegalAccessException { + BaseFormFieldConverter baseFormFieldConverter = FormFieldFactory.create(type); + + return baseFormFieldConverter.convert(data,widget); + } + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/handler/FormatNumberHandler.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/handler/FormatNumberHandler.java new file mode 100644 index 0000000..1270e04 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/handler/FormatNumberHandler.java @@ -0,0 +1,70 @@ +package org.dromara.dataManager.widget.handler; + +import org.dromara.dataManager.widget.handler.base.WidgetHandler; + +import java.text.DecimalFormat; +import java.util.Map; + +public class FormatNumberHandler implements WidgetHandler { + + @Override + public Object handle(Object value, Map options) { + if (value == null) { + return ""; + } + + String valueType = (String) options.get("valueType"); + // 开启显示千分符 + boolean isMicrometerChecked = (boolean) options.get("isMicrometerChecked"); + // 开启小数位数 + boolean isFloatChecked = (boolean) options.get("isFloatChecked"); + // 小数位数 + int numberDigit = options.get("numberDigit") == null ? 0 : (int) options.get("numberDigit"); + + if ("number".equals(valueType)) { + return fmtMicrometer(value.toString(), isFloatChecked, numberDigit, isMicrometerChecked); + } else if ("percentage".equals(valueType)) { + double doubleNumber = Double.parseDouble(value.toString()); + String strNumber = fmtMicrometer(Double.valueOf(doubleNumber * 100).toString(), isFloatChecked, numberDigit, false); + return strNumber + "%"; + } + + return ""; + } + + private String fmtMicrometer(String text, boolean isFloatChecked, int numberDigit, boolean isMicrometerChecked) { + + if (!isFloatChecked && !isMicrometerChecked) { + DecimalFormat df = new DecimalFormat("###.######"); + return df.format(Double.parseDouble(text)); + } + + StringBuilder digitPattern = new StringBuilder(); + if (isFloatChecked) { + for (int index = 0; index < numberDigit; index++) { + digitPattern.append("0"); + } + if (numberDigit > 0) { + digitPattern.insert(0, "."); + } + } + + if (numberDigit <= 0) { + digitPattern.append(".######"); + } + + DecimalFormat df = new DecimalFormat("##0" + digitPattern.toString()); + + if (isMicrometerChecked) { + df = new DecimalFormat("###,##0" + digitPattern.toString()); + } + + double number = 0.0; + try { + number = Double.parseDouble(text); + } catch (Exception e) { + number = 0.0; + } + return df.format(number); + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/handler/base/WidgetHandler.java b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/handler/base/WidgetHandler.java new file mode 100644 index 0000000..08e02a1 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/dataManager/widget/handler/base/WidgetHandler.java @@ -0,0 +1,7 @@ +package org.dromara.dataManager.widget.handler.base; + +import java.util.Map; + +public interface WidgetHandler { + Object handle(Object value, Map options); +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/formMaking/controller/FormSourceController.java b/dk-common/common-workflow/src/main/java/org/dromara/formMaking/controller/FormSourceController.java new file mode 100644 index 0000000..2618ff7 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/formMaking/controller/FormSourceController.java @@ -0,0 +1,117 @@ +package org.dromara.formMaking.controller; + + +import org.dromara.common.param.WorkflowBaseParam; +import org.dromara.common.response.WorkflowResponseData; +import org.dromara.common.response.WorkflowResult; +import org.dromara.common.response.WorkflowSuccessResponseData; +import org.dromara.formMaking.domain.FormSource; +import org.dromara.formMaking.param.FormSourceParam; +import org.dromara.formMaking.service.FormSourceService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +/** + * 自定义表单基础信息API + */ +@RestController +@RequestMapping("/form") +@Slf4j +public class FormSourceController { + + @Autowired + private FormSourceService formSourceService; + + /** + * 分页查询表单基础信息 + * @return + */ + @GetMapping("/page") + public WorkflowResponseData pageFormSource(@RequestParam(value = "formName",required = false) String formName){ + return new WorkflowSuccessResponseData(formSourceService.pageFormSource(formName)); + } + + /** + * 查询表单基础信息 + * @return + */ + @GetMapping("/list") + public WorkflowResponseData listFormSource(Long appId){ + return new WorkflowSuccessResponseData(formSourceService.listFormSource(appId)); + } + + /** + * 根据表单id获取配置信息 + * @return + */ + @GetMapping("/{code}/info") + public WorkflowResponseData getFormSourceByCode(@PathVariable("code") String code){ + return new WorkflowSuccessResponseData(formSourceService.getFormSourceByCode(code)); + } + + /** + * 根据表单id获取配置信息 + * @return + */ + @GetMapping("/{formId}/detail") + public WorkflowResponseData getFromDetail(@PathVariable("formId") Long formId){ + return new WorkflowSuccessResponseData(formSourceService.getFormSourceById(formId)); + } + + /** + * 新增表单基础信息 + * @return + */ + @PostMapping("/add") + public WorkflowResponseData addFormSource(@RequestBody @Validated(WorkflowBaseParam.add.class) FormSourceParam param){ + + return WorkflowResult.success(formSourceService.addFormSource(0L,param.getFormName(),param.getFormCode(), param.getFormJson())); + } + + /** + * 重命名表单 + * @return + */ + @PostMapping("/rename") + public WorkflowResponseData renameForm(@RequestBody @Validated(WorkflowBaseParam.updateInfo.class) FormSourceParam param){ + + return WorkflowResult.success(formSourceService.renameForm(param.getFormId(),param.getFormName())); + } + + + /** + * 编辑自定义表单 + * @return + */ + @PostMapping("/edit") + public WorkflowResponseData editFormSource(@RequestBody @Validated(WorkflowBaseParam.edit.class) FormSourceParam formSourceParam){ + FormSource formSource = formSourceService.editFormSource(formSourceParam); + + return WorkflowResult.success(formSource); + } + + + /** + * 删除表单 + * @return + */ + @PostMapping("/{formId}/delete") + public WorkflowResponseData deleteFormSource(@PathVariable("formId") Long formId){ + formSourceService.deleteFormSource(formId); + + return WorkflowResult.success(); + } + + /** + * 绑定部门id + * @return + */ + @PostMapping("/bind/depart") + public WorkflowResponseData bindDepart(@RequestBody FormSourceParam formSourceParam){ + + return formSourceService.bindDepart(formSourceParam)? WorkflowResult.success("绑定成功"): WorkflowResult.error("绑定失败!"); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/formMaking/domain/FormDetail.java b/dk-common/common-workflow/src/main/java/org/dromara/formMaking/domain/FormDetail.java new file mode 100644 index 0000000..8eecab4 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/formMaking/domain/FormDetail.java @@ -0,0 +1,43 @@ +package org.dromara.formMaking.domain; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.entity.WorkflowBaseEntity; + +/** + * 表单配置表 + */ +@Data +@TableName("t_form_detail") +@EqualsAndHashCode(callSuper = true) +public class FormDetail extends WorkflowBaseEntity { + + /** + * 主键id + */ + @TableId("id") + private Long id; + + /** + * 表单ID + */ + @TableField("form_id") + private Long formId; + + /** + * 表单JSON + */ + @TableField("form_json") + private String formJson; + + + /** + * 表单版本号 + */ + @TableField("version") + private Integer version; + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/formMaking/domain/FormSource.java b/dk-common/common-workflow/src/main/java/org/dromara/formMaking/domain/FormSource.java new file mode 100644 index 0000000..4f7d553 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/formMaking/domain/FormSource.java @@ -0,0 +1,79 @@ +package org.dromara.formMaking.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.entity.WorkflowBaseEntity; + +import java.util.List; + +/** + * 表单基础信息表 + */ +@Data +@TableName("t_form_source") +@EqualsAndHashCode(callSuper = true) +public class FormSource extends WorkflowBaseEntity { + + /** + * 主键id + */ + @TableId(value = "id",type = IdType.AUTO) + private Long id; + + /** + * 表单/分组/仪表板/数据表code + */ + @TableField("code") + private String code; + /** + * 标题 + */ + @TableField("title") + private String title; + /** + * 是否为流程表单 + */ + @TableField("has_flow") + private boolean hasFlow; + /** + * 图标 + */ + @TableField("icon") + private String icon; + /** + * 图标颜色 + */ + @TableField("color") + private String color; + /** + * 当前层级排序 + */ + @TableField("sort") + private Integer sort; + + /** + * 当前版本号 + */ + @TableField("version") + private Integer version; + + + /** + * 部门id集合 + */ + @TableField(value = "depart_ids",typeHandler = JacksonTypeHandler.class) + private List departIds; + + /** + * 创建人 + */ + @TableField("create_name") + private String createName; + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/formMaking/mapper/FormDetailMapper.java b/dk-common/common-workflow/src/main/java/org/dromara/formMaking/mapper/FormDetailMapper.java new file mode 100644 index 0000000..af66b81 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/formMaking/mapper/FormDetailMapper.java @@ -0,0 +1,7 @@ +package org.dromara.formMaking.mapper; + +import org.dromara.formMaking.domain.FormDetail; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +public interface FormDetailMapper extends BaseMapper { +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/formMaking/mapper/FormSourceMapper.java b/dk-common/common-workflow/src/main/java/org/dromara/formMaking/mapper/FormSourceMapper.java new file mode 100644 index 0000000..26fc48f --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/formMaking/mapper/FormSourceMapper.java @@ -0,0 +1,21 @@ +package org.dromara.formMaking.mapper; + +import org.dromara.formMaking.domain.FormSource; +import org.dromara.formMaking.results.FormSourceResult; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Param; + +public interface FormSourceMapper extends BaseMapper { + + Integer getVersion(@Param("formId") Long formId); + + Page pageFormSource(@Param("page") Page page, @Param("ew") QueryWrapper queryWrapper); + + FormSourceResult getFormSource(@Param("formId")Long formId); + + FormSourceResult getFormSourceByCode(@Param("formCode")String formCode); + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/formMaking/mapper/mapping/FormDetailMapper.xml b/dk-common/common-workflow/src/main/java/org/dromara/formMaking/mapper/mapping/FormDetailMapper.xml new file mode 100644 index 0000000..15a9875 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/formMaking/mapper/mapping/FormDetailMapper.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/dk-common/common-workflow/src/main/java/org/dromara/formMaking/mapper/mapping/FormSourceMapper.xml b/dk-common/common-workflow/src/main/java/org/dromara/formMaking/mapper/mapping/FormSourceMapper.xml new file mode 100644 index 0000000..c827d10 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/formMaking/mapper/mapping/FormSourceMapper.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + diff --git a/dk-common/common-workflow/src/main/java/org/dromara/formMaking/param/FormSourceParam.java b/dk-common/common-workflow/src/main/java/org/dromara/formMaking/param/FormSourceParam.java new file mode 100644 index 0000000..5d6da5d --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/formMaking/param/FormSourceParam.java @@ -0,0 +1,42 @@ +package org.dromara.formMaking.param; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.param.WorkflowBaseParam; + +import java.util.List; + + +@Data +@EqualsAndHashCode(callSuper = true) +public class FormSourceParam extends WorkflowBaseParam { + + /** + * 表单id + */ + @NotNull(message = "表单id不能为空", groups = {updateInfo.class,edit.class}) + private Long formId; + + private String formCode; + + /** + * 表单名称 + */ + @NotNull(message = "表单名称不能为空", groups = {updateInfo.class}) + private String formName; + + private String formType; + + /** + * 表单配置 + */ + @NotNull(message = "表单配置不能为空", groups = {edit.class}) + private String formJson; + + /** + * 部门id集合 + */ + private List departIds; + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/formMaking/results/FormSourceResult.java b/dk-common/common-workflow/src/main/java/org/dromara/formMaking/results/FormSourceResult.java new file mode 100644 index 0000000..f544d0c --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/formMaking/results/FormSourceResult.java @@ -0,0 +1,37 @@ +package org.dromara.formMaking.results; + +import org.dromara.formMaking.domain.FormSource; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.Map; + +/** + * @Description: server + **/ +@Data +@EqualsAndHashCode(callSuper = true) +public class FormSourceResult extends FormSource { + + /** + * 当前表单主版本号 + */ + private Integer curVersion; + + + /** + * 历史表单版本号 + */ + private String historyVersion; + + /** + * 表单配置 + */ + private String formJson; + + /** + * 表单数据 + */ + private Map formData; + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/formMaking/service/FormSourceService.java b/dk-common/common-workflow/src/main/java/org/dromara/formMaking/service/FormSourceService.java new file mode 100644 index 0000000..f817bf7 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/formMaking/service/FormSourceService.java @@ -0,0 +1,46 @@ +package org.dromara.formMaking.service; + +import org.dromara.common.page.WorkflowPageResult; +import org.dromara.formMaking.domain.FormDetail; +import org.dromara.formMaking.domain.FormSource; +import org.dromara.formMaking.param.FormSourceParam; +import org.dromara.formMaking.results.FormSourceResult; +import com.baomidou.mybatisplus.extension.service.IService; + +import java.util.List; + +public interface FormSourceService extends IService { + + WorkflowPageResult pageFormSource(String formName); + + List listFormSource(Long appId); + + List listFormSourceByApp(List appIds); + + FormSourceResult getFormSourceByCode(String code); + + boolean checkFormExist(Long appId,Long formId); + + FormSource getFormSource(Long formId); + + FormSourceResult getFormSourceById(Long formId); + + FormSource addFormSource(Long appId,String formName,String formCode,String formJson); + + FormSource addFormSource(Long appId,String formName); + + FormSource renameForm(Long formId,String formName); + + FormSource editFormSource(FormSourceParam formSourceParam); + + boolean deleteFormSource(Long formId); + + FormDetail saveOrUpdateFormDetail(Long id, String formJson); + + FormDetail getFormDetail(Long formId,Integer version); + + boolean deleteFormDetail(Long formId); + + boolean bindDepart(FormSourceParam formSourceParam); + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/formMaking/service/impl/FormSourceServiceImpl.java b/dk-common/common-workflow/src/main/java/org/dromara/formMaking/service/impl/FormSourceServiceImpl.java new file mode 100644 index 0000000..5179389 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/formMaking/service/impl/FormSourceServiceImpl.java @@ -0,0 +1,289 @@ +package org.dromara.formMaking.service.impl; + + +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.Exception.ServiceException; +import org.dromara.common.entity.WorkflowBaseEntity; +import org.dromara.common.page.WorkflowPageFactory; +import org.dromara.common.page.WorkflowPageResult; +import org.dromara.common.response.WorkflowResultCode; +import org.dromara.formMaking.domain.FormDetail; +import org.dromara.formMaking.domain.FormSource; +import org.dromara.formMaking.mapper.FormDetailMapper; +import org.dromara.formMaking.mapper.FormSourceMapper; +import org.dromara.formMaking.param.FormSourceParam; +import org.dromara.formMaking.results.FormSourceResult; +import org.dromara.formMaking.service.FormSourceService; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.UUID; + +/** + * 表单基础信息接口 + */ +@Service +public class FormSourceServiceImpl extends ServiceImpl implements FormSourceService { + + + @Autowired + FormDetailMapper formDetailMapper; + + /** + * 分页查询表单基础信息 + * @param formName + * @return + */ + @Override + public WorkflowPageResult pageFormSource(String formName) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + if (StringUtils.isNotEmpty(formName)){ + queryWrapper.like("source.title",formName); + } + return new WorkflowPageResult<>(this.baseMapper.pageFormSource(WorkflowPageFactory.defaultPage(),queryWrapper)); + } + + @Override + public List listFormSource(Long appId) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.orderByDesc(FormSource::getCreateTime).orderByDesc(WorkflowBaseEntity::getUpdateTime); + return this.list(queryWrapper); + } + + @Override + public List listFormSourceByApp(List apps) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.orderByDesc(FormSource::getCreateTime).orderByDesc(WorkflowBaseEntity::getUpdateTime); + return this.list(queryWrapper); + } + + @Override + public FormSourceResult getFormSourceByCode(String code) { + + return this.baseMapper.getFormSourceByCode(code); + } + + @Override + public boolean checkFormExist(Long appId, Long formId) { + if(ObjectUtil.isAllEmpty(appId,formId)){ + + throw new ServiceException(WorkflowResultCode.PARAM_MISSING); + } + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + + if(formId != null){ + queryWrapper.eq(FormSource::getId,formId); + } + + return this.count(queryWrapper) > 0; + } + + @Override + public FormSource getFormSource(Long formId) { + return this.getById(formId); + } + + @Override + public FormSourceResult getFormSourceById(Long formId) { + return this.baseMapper.getFormSource(formId); + } + + + /** + * 获取表单配置 + * @param formId + * @return + */ + @Override + public FormDetail getFormDetail(Long formId,Integer version) { + if (ObjectUtil.isEmpty(formId)){ + throw new ServiceException(WorkflowResultCode.PARAM_IS_BLANK); + } + FormSource formSource = getFormSource(formId); + if(formSource == null){ + throw new ServiceException(WorkflowResultCode.FORM_NOT_EXIST); + } + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(FormDetail::getFormId,formId); + if(version != null){ + queryWrapper.eq(FormDetail::getVersion,version); + }else{ + queryWrapper.eq(FormDetail::getVersion,formSource.getVersion()); + } + return this.formDetailMapper.selectOne(queryWrapper); + } + + @Override + public FormSource addFormSource(Long appId, String formName,String formCode,String formJson) { + FormSource formSource = new FormSource(); + if(StrUtil.isNotEmpty(formCode)){ + formSource.setCode(formCode); + }else{ + formSource.setCode(UUID.randomUUID().toString().replaceAll("-","")); + } + formSource.setHasFlow(true); + formSource.setVersion(1); + formSource.setTitle(StrUtil.isNotEmpty(formName) ? formName : "未命名表单"); + formSource.setCreateName(LoginHelper.getLoginUser().getNickname()); + + this.save(formSource); + + if(StrUtil.isNotEmpty(formJson)){ + this.saveOrUpdateFormDetail(formSource.getId(),formJson); + } + + return formSource; + } + + /** + * 新增表单信息 + * @return + */ + @Override + @Transactional(rollbackFor = Exception.class) + public FormSource addFormSource(Long appId,String formName) { + FormSource formSource = new FormSource(); + formSource.setCode(UUID.randomUUID().toString().replaceAll("-","")); + formSource.setHasFlow(true); + formSource.setVersion(1); + formSource.setTitle(StrUtil.isNotEmpty(formName) ? formName : "未命名表单"); + formSource.setCreateName(LoginHelper.getLoginUser().getNickname()); + + this.save(formSource); + + return formSource; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public FormSource renameForm(Long formId,String formName) { + if (ObjectUtil.hasEmpty(formId,formName)){ + throw new ServiceException(WorkflowResultCode.PARAM_IS_BLANK); + } + FormSource form = this.getById(formId); + if(form == null){ + + throw new ServiceException(WorkflowResultCode.FORM_NOT_EXIST); + } + form.setTitle(formName.trim()); + this.updateById(form); + + return form; + } + + + /** + * 修改表单配置 + * @param + * @param + */ + @Override + @Transactional(rollbackFor = Exception.class) + public FormSource editFormSource(FormSourceParam param) { + FormSource form = this.getById(param.getFormId()); + if(form == null){ + + throw new ServiceException(WorkflowResultCode.FORM_NOT_EXIST); + } + + FormDetail formDetail = saveOrUpdateFormDetail(param.getFormId(), param.getFormJson()); + if(formDetail != null){ + form.setVersion(formDetail.getVersion()); + this.baseMapper.updateById(form); + } + + return this.baseMapper.getFormSource(form.getId()); + } + + /** + *删除表单 + * @param formId + */ + @Override + public boolean deleteFormSource(Long formId) { + if (ObjectUtil.isEmpty(formId)){ + throw new ServiceException(WorkflowResultCode.PARAM_IS_BLANK); + } + if (this.remove(new LambdaQueryWrapper().eq(FormSource::getId,formId))){ + return deleteFormDetail(formId); + } + return false; + } + + @Override + public FormDetail saveOrUpdateFormDetail(Long formId, String formJson) { + if(ObjectUtil.hasEmpty(formId,formJson)){ + throw new ServiceException(WorkflowResultCode.PARAM_MISSING); + } + + Integer version = this.baseMapper.getVersion(formId); + FormDetail formDetail = new FormDetail(); + formDetail.setFormId(formId); + formDetail.setFormJson(formJson); + formDetail.setVersion(version + 1); + this.formDetailMapper.insert(formDetail); + + return formDetail; + } + + + /** + * 删除表单配置 + * @param formId + * @return + */ + @Override + public boolean deleteFormDetail(Long formId) { + if (ObjectUtil.isEmpty(formId)){ + throw new ServiceException(WorkflowResultCode.PARAM_IS_BLANK); + } + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(FormDetail::getFormId,formId); + return this.formDetailMapper.delete(queryWrapper) > 0; + } + + /** + * 表单绑定部门 + * @param formSourceParam + * @return + */ + @Override + public boolean bindDepart(FormSourceParam formSourceParam) { + if (ObjectUtil.isEmpty(formSourceParam.getFormId()) || ObjectUtil.isEmpty(formSourceParam.getDepartIds())) { + throw new RuntimeException("请求参数为空!"); + } + + LambdaUpdateWrapper wrapper = new LambdaUpdateWrapper<>(); + wrapper.set(FormSource::getDepartIds,formSourceParam.getDepartIds()); + wrapper.eq(FormSource::getId,formSourceParam.getFormId()); + + return this.update(wrapper); + } + + /** + * 校验参数,检查是否存在相同的名称 + * + */ + private void checkParam(FormSource formSource) { + Long id = formSource.getId(); + String formName = formSource.getTitle(); + + LambdaQueryWrapper queryWrapperByName = new LambdaQueryWrapper<>(); + queryWrapperByName.eq(FormSource::getTitle, formName) + .ne(FormSource::getId, id); + long countByName = this.count(queryWrapperByName); + + if (countByName >= 1) { + throw new ServiceException(WorkflowResultCode.FORM_MAKING_NAME_REPEAT); + } + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/api/TaskController.java b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/api/TaskController.java new file mode 100644 index 0000000..b3986e3 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/api/TaskController.java @@ -0,0 +1,209 @@ +package org.dromara.taskCenter.api; + + +import org.dromara.common.Exception.ServiceException; +import org.dromara.common.param.WorkflowBaseParam; +import org.dromara.common.response.WorkflowResponseData; +import org.dromara.common.response.WorkflowResult; +import org.dromara.common.response.WorkflowResultCode; +import org.dromara.taskCenter.param.TaskQueryParam; +import org.dromara.taskCenter.param.TaskUpdateParam; +import org.dromara.taskCenter.service.action.TaskActionStrategyContext; +import org.dromara.taskCenter.service.query.TaskQueryStrategyContext; +import org.dromara.workflow.engine.exception.WorkflowException; +import org.dromara.workflow.service.external.FlowTaskService; +import cn.hutool.core.collection.CollUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +public class TaskController { + + @Autowired + private TaskQueryStrategyContext taskQueryStrategyContext; + @Autowired + private TaskActionStrategyContext taskActionStrategyContext; + @Autowired + private FlowTaskService taskService; + + /** + * 查询待办列表 + * @param data + * @return + */ + @GetMapping({"/workplace/workflow/query","/app/{appId}/workflow/query"}) + public WorkflowResponseData queryTaskList(@Validated(WorkflowBaseParam.page.class) TaskQueryParam data){ + + return WorkflowResult.success(taskQueryStrategyContext.pageTask(data)); + } + + /** + * 查询待办任务详情 + * @param data + * @return + */ + @PostMapping({"/workflow/info","/app/{appId}/workflow/info"}) + public WorkflowResponseData queryTaskInfo(@RequestBody @Validated(WorkflowBaseParam.detail.class) TaskQueryParam data) { + try { + + return WorkflowResult.success(taskQueryStrategyContext.queryTask(data)); + } catch (Exception e) { + e.printStackTrace(); + if (e instanceof ServiceException) { + return WorkflowResult.error(((ServiceException) e).getCode(), e.getMessage()); + } + if (e instanceof WorkflowException) { + return WorkflowResult.error(((WorkflowException) e).getCode(), e.getMessage()); + } + return WorkflowResult.error(500, e.getMessage()); + } + } + + /** + * 查询待办节点转交成员 + */ + @PostMapping("/app/{appId}/form/{formCode}/workflow/forward") + public WorkflowResponseData queryForwardUser(@RequestBody @Validated(WorkflowBaseParam.forward.class) TaskUpdateParam data){ + try{ + + return WorkflowResult.success(taskQueryStrategyContext.forwardUser(data.getTaskId(),data.getForm().getFormData())); + }catch (Exception e){ + if(e instanceof ServiceException){ + return WorkflowResult.error(((ServiceException) e).getCode(),e.getMessage()); + } + if(e instanceof WorkflowException){ + return WorkflowResult.error(((WorkflowException) e).getCode(),e.getMessage()); + } + return WorkflowResult.error(500,e.getMessage()); + } + } + + /** + * 查询待办、抄送任务数量 + */ + @PostMapping({"/workplace/workflow/count","/app/{appId}/workflow/count"}) + public WorkflowResponseData count( + @PathVariable(value = "appId",required = false)Long appId){ + + return WorkflowResult.success(taskQueryStrategyContext.count()); + } + + + /** + * 待办任务流转(urge、submit、recall、draft、print、rollback、forward、finish) + * @param data + * @return + */ + @PostMapping("/app/{appId}/form/{formCode}/workflow/update") + public WorkflowResponseData handleTask(@RequestBody @Validated(WorkflowBaseParam.edit.class) TaskUpdateParam data){ + try { + + return taskActionStrategyContext.execute(data); + }catch (Exception e){ + e.printStackTrace(); + if(e instanceof ServiceException){ + return WorkflowResult.error(((ServiceException) e).getCode(),e.getMessage()); + } + if(e instanceof WorkflowException){ + return WorkflowResult.error(((WorkflowException) e).getCode(),e.getMessage()); + } + return WorkflowResult.error(500,e.getMessage()); + } + } + + /** + * 更新待办任务处置状态为正在处理 + * @return + */ + @PostMapping("/app/{appId}/form/{formCode}/task/{taskId}/processing") + public WorkflowResponseData updateTaskProcessing(@PathVariable("taskId")Long taskId){ + try { + + return taskActionStrategyContext.updateTaskProcessing(taskId); + }catch (Exception e){ + e.printStackTrace(); + if(e instanceof ServiceException){ + return WorkflowResult.error(((ServiceException) e).getCode(),e.getMessage()); + } + if(e instanceof WorkflowException){ + return WorkflowResult.error(((WorkflowException) e).getCode(),e.getMessage()); + } + return WorkflowResult.error(500,e.getMessage()); + } + } + + /** + * 更新待办任务处置状态为正在处理 + * @return + */ + @PostMapping("/app/{appId}/task/batch/processing") + public WorkflowResponseData batchUpdateTaskProcessing(@RequestBody TaskUpdateParam data){ + try { + if(CollUtil.isEmpty(data.getTaskIds())){ + return WorkflowResult.error(WorkflowResultCode.NODE_CHECKER_TASK_NOT_EXIST); + } + return taskActionStrategyContext.batchUpdateTaskProcessing(data.getTaskIds()); + }catch (Exception e){ + e.printStackTrace(); + if(e instanceof ServiceException){ + return WorkflowResult.error(((ServiceException) e).getCode(),e.getMessage()); + } + if(e instanceof WorkflowException){ + return WorkflowResult.error(((WorkflowException) e).getCode(),e.getMessage()); + } + return WorkflowResult.error(500,e.getMessage()); + } + } + + /** + * 批量处理待办任务(batchSubmit) + * @param data + * @return + */ + @PostMapping("/app/{appId}/workflow/batch/update") + public WorkflowResponseData handleTask(@RequestBody @Validated(WorkflowBaseParam.edit.class) List data){ + try { + + return taskActionStrategyContext.batchHandleTask(data); + }catch (Exception e){ + e.printStackTrace(); + if(e instanceof ServiceException){ + return WorkflowResult.error(((ServiceException) e).getCode(),e.getMessage()); + } + if(e instanceof WorkflowException){ + return WorkflowResult.error(((WorkflowException) e).getCode(),e.getMessage()); + } + return WorkflowResult.error(500,e.getMessage()); + } + } + + /** + * 更新状态 + * @param data + * @return + */ + @PostMapping("/app/{appId}/form/{formCode}/workflow/read") + public WorkflowResponseData readTask(@RequestBody @Validated(WorkflowBaseParam.cc.class) TaskUpdateParam data){ + try { + taskService.updateCcStatus(data.getTaskId()); + + return WorkflowResult.success(); + }catch (ServiceException e){ + + return WorkflowResult.error(e.getCode(),e.getMessage()); + } + } + + + /** + * 查询待办任务数量 + */ + @GetMapping({"/workplace/workflow/count/todo"}) + public WorkflowResponseData countTodo(){ + return WorkflowResult.success(taskQueryStrategyContext.countTodo()); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/mapper/TaskMapper.java b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/mapper/TaskMapper.java new file mode 100644 index 0000000..4df5b13 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/mapper/TaskMapper.java @@ -0,0 +1,33 @@ +package org.dromara.taskCenter.mapper; + +import org.dromara.taskCenter.param.TaskQueryParam; +import org.dromara.taskCenter.result.TaskInstanceResult; +import org.dromara.taskCenter.result.TaskPageResult; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Param; + +/** + * @Description: server + **/ +public interface TaskMapper { + + Page listMyUndoTask(@Param("page")Page page, @Param("param") TaskQueryParam param, @Param( "userId")Long userId); + + Page listMyStartTask(@Param("page")Page page, @Param("param") TaskQueryParam param,@Param( "userId")Long userId); + + Page listMyStartTaskV2(@Param("page")Page page, @Param("param") TaskQueryParam param,@Param( "userId")Long userId); + + Page listMyHandleTask(@Param("page")Page page, @Param("param") TaskQueryParam param,@Param( "userId")Long userId); + + Page listMyCcTask(@Param("page")Page page, @Param("param") TaskQueryParam param,@Param( "userId")Long userId); + + Integer getMyUndoTaskCount(@Param("userId")Long userId); + + Integer getMyCcTaskCount(@Param("userId")Long userId); + + TaskInstanceResult queryInstanceByTodo(@Param("taskId")Long taskId); + + TaskInstanceResult queryInstanceByTodoIgnoreStatus(@Param("taskId")Long taskId); + + TaskInstanceResult queryInstanceByCc(@Param("ccId")Long ccId); +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/mapper/mapping/TaskMapper.xml b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/mapper/mapping/TaskMapper.xml new file mode 100644 index 0000000..58679f2 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/mapper/mapping/TaskMapper.xml @@ -0,0 +1,300 @@ + + + + + + select t.id as 'taskId',t.node_key as 'nodeKey',t.node_name as 'nodeName', t.user_id as 'userId',t.user_name as 'userName',t.status + , t.create_time as 'createTime',t.priority,t.processing,t.drafting + , s.id as formId + , s.color as 'formColor',s.icon as 'formIcon',s.title as 'formName', t.update_time as 'updateTime', p.id as 'instanceId',p.data_id as 'dataId',p.stage + , p.create_user as 'applyId',p.node_keys as 'nextNodes', p.create_name as 'applyName',q.form_json as 'formJson',p.definition_id as 'definitionId',fd.form_data as originFormData + from t_workflow_instance_task t + inner join t_workflow_instance p on t.instance_id = p.id + inner join t_form_data fd on fd.id = p.data_id + inner join t_form_source s on t.form_id = s.id + left join t_form_detail q on q.form_id = t.form_id and s.version = q.version + + + + + and json_extract( fd.form_data, "$.tagId" ) = CAST(#{param.tagId} AS CHAR) + + + and json_extract( fd.form_data, "$.tagGroupName" ) like concat('%',#{param.tagGroupName},'%') + + + and json_extract( fd.form_data, "$.projectLevel" ) = CAST(#{param.projectLevel} AS CHAR) + + + and json_extract( fd.form_data, "$.tagLevel" ) = #{param.tagLevel} + + + and json_extract( fd.form_data, "$.tagGroupName" ) = #{param.tagGroupName} + + + + and json_extract( fd.form_data, "$.projectNum" ) like concat('%',#{param.projectNum},'%') + + + and json_extract( fd.form_data, "$.projectName" ) like concat('%',#{param.projectName},'%') + + + and json_extract( fd.form_data, "$.projectUserName" ) like concat('%',#{param.projectUserName},'%') + + + and json_extract( fd.form_data, "$.projectOrgId" ) = CAST(#{param.projectOrgId} AS CHAR) + + + and json_extract( fd.form_data, "$.projectLevels" ) = CAST(#{param.projectLevel} AS CHAR) + + + and json_extract( fd.form_data, "$.projectType" ) = CAST( #{param.projectType} AS CHAR) + + + and json_extract( fd.form_data, "$.projectStage" ) = CAST(#{param.projectStage} AS CHAR) + + + and json_extract( fd.form_data, "$.houseType" ) = CAST(#{param.houseType} AS CHAR) + + + and json_extract( fd.form_data, "$.houseStatus" ) = CAST(#{param.houseStatus} AS CHAR) + + + and json_extract( fd.form_data, "$.houseName" ) like concat('%',#{param.houseName},'%') + + + and json_extract( fd.form_data, "$.duration" ) = #{param.duration} + + + and json_extract( fd.form_data, "$.alertId" ) like concat('%',#{param.alertId},'%') + + + and json_extract( fd.form_data, "$.projectUserName" ) like concat('%',#{param.projectUserName},'%') + + + and json_extract( fd.form_data, "$.projectNum" ) like concat('%',#{param.projectNum},'%') + + + + + + and TO_DAYS(NOW()) = TO_DAYS(t.create_time) + + + and date_sub(curdate(),INTERVAL WEEKDAY(curdate()) + 1 DAY) date(t.create_time) + and date_sub(curdate(),INTERVAL WEEKDAY(curdate()) - 5 DAY) = ]]> date(t.create_time) + + + and concat(date_format(LAST_DAY(now()),'%Y-%m-'),'01') date(t.create_time) + and LAST_DAY(now()) = ]]> date(t.create_time) + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/model/FormWidget.java b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/model/FormWidget.java new file mode 100644 index 0000000..ae2920f --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/model/FormWidget.java @@ -0,0 +1,50 @@ +package org.dromara.taskCenter.model; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.Data; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class FormWidget { + private String type; + private String icon; + private String name; + private String model; + private String key; + private Map options; + private List tableColumns; + private List rules; + private Object novalid; + private List columns; + private List list; + private LinkedHashMap _dataStatus; + /** + * 以下是栅栏布局字段特有 + */ + private int span; + private int xs; + private int sm; + private int md; + private int lg; + private int xl; + + /*标签页专属*/ + private String tab; + + // will be deleted later + private String parent; + // will be deleted later + private boolean visible; + + public FormWidget() { + } + + public FormWidget(String type, String name) { + this.type = type; + this.name = name; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/model/SimpleFormFieldModel.java b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/model/SimpleFormFieldModel.java new file mode 100644 index 0000000..1acdf27 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/model/SimpleFormFieldModel.java @@ -0,0 +1,68 @@ +package org.dromara.taskCenter.model; + +import org.dromara.taskCenter.model.options.SimpleFieldOptionModel; +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * 简单表单字段模型 + */ +@Data +public class SimpleFormFieldModel implements Serializable { + /** + * 字段唯一标识 + */ + private String model; + + /** + * 字段名称 + */ + private String name; + + /** + * 字段类型 + */ + private String type; + + /** + * 嵌套字段信息 + */ + @JsonInclude(JsonInclude.Include.NON_NULL) + private List children; + + /** + * 字段权限 + */ + private SimpleFieldOptionModel options; + + /** + * 子表单字段权限, @JsonInclude 用于非子表单json输出的时候过滤掉 + */ + @JsonInclude(JsonInclude.Include.NON_NULL) + private List tableColumns; + + public SimpleFormFieldModel(String model){ + this.model = model; + this.options = new SimpleFieldOptionModel(); + } + public SimpleFormFieldModel(String model, String name){ + this.model = model; + this.name = name; + this.options = new SimpleFieldOptionModel(); + } + public SimpleFormFieldModel(String model, String name,String type){ + this.model = model; + this.name = name; + this.type = type; + this.options = new SimpleFieldOptionModel(); + } + + public SimpleFormFieldModel(String model, Boolean hidden, Boolean disabled){ + this.model = model; + this.options = new SimpleFieldOptionModel(hidden,disabled); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/model/SimpleFormModel.java b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/model/SimpleFormModel.java new file mode 100644 index 0000000..f26eeaf --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/model/SimpleFormModel.java @@ -0,0 +1,313 @@ +package org.dromara.taskCenter.model; + + +import org.dromara.formMaking.domain.FormDetail; +import org.dromara.taskCenter.model.options.SimpleFieldOptionModel; +import org.dromara.workflow.engine.enums.ESDefaultFieldConst; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.alibaba.fastjson.JSON; +import lombok.Data; + +import java.io.Serializable; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 简单表单模型 + */ +@Data +public class SimpleFormModel implements Serializable { + public static final String LIST = "list"; + + /** + * 字段唯一标识 + */ + public static final String FIELD_MODEL = "model"; + + /** + * 字段类型 + */ + public static final String FIELD_TYPE = "type"; + public static final String FIELD_TYPE_TABLE = "table"; + + /** + * 子表单子字段 + */ + public static final String FIELD_TABLE_COLUMNS = "tableColumns"; + + /** + * 字段options + */ + public static final String FIELD_OPTIONS = "options"; + public static final String FIELD_OPTIONS_HIDDEN = "hidden"; + public static final String FIELD_OPTIONS_DISABLED = "disabled"; + public static final String FIELD_OPTIONS_TABLE_OPERATE = "tableOperate"; + + public static final String FIELD_TYPE_SYSTEM = "system"; + + + private static final List systemFieldConst = Arrays.asList(ESDefaultFieldConst.CREATOR, + ESDefaultFieldConst.CREATE_TIME, ESDefaultFieldConst.UPDATE_TIME, ESDefaultFieldConst.UPDATOR_NAME, + ESDefaultFieldConst.FLOW_NODE_TITLE, ESDefaultFieldConst.FLOW_CHECKER_NAME + ); + + private JSONArray list; + private JSONObject config; + + public List getSimpleFormFieldModels() { + if (list != null) { + return JSONUtil.toList(list, SimpleFormFieldModel.class); + } + return null; + } + + /** + * 递归处理表单字段的权限 + * + * @param perms + */ + public void recurResetFieldsPermission(List perms) { + Map map = perms.stream().filter(p -> ObjectUtil.isNotEmpty(p.getModel())).collect(Collectors.toMap(SimpleFormFieldModel::getModel, SimpleFormFieldModel -> SimpleFormFieldModel)); + updateWidgetPermission(this.list,map); + } + + private void updateWidgetPermission(JSONArray widgets, Map map) { + if(widgets == null || widgets.isEmpty()){ + return; + } + widgets.forEach(p -> { + JSONObject item = (JSONObject) p; + SimpleFormFieldModel curField = map.getOrDefault(item.getStr(FIELD_MODEL), null); + if (item.getByPath("options.hidden") != null) { + item.putByPath("options.hidden", curField != null ? curField.getOptions().isHidden() : true); + } + if (item.getByPath("options.disabled") != null) { + item.putByPath("options.disabled", curField != null ? curField.getOptions().isDisabled() : true); + } + if (item.containsKey("columns")) { + updateWidgetPermission(item.getJSONArray("columns"),map); + } + if (item.containsKey("list")) { + updateWidgetPermission(item.getJSONArray("list"),map); + } + if (item.containsKey("tableColumns")) { + updateWidgetPermission(item.getJSONArray("tableColumns"),map); + } + }); + } + + /** + * 重置字段权限,该方法会改变 表单 formJson 中的字段权限 + * 重置逻辑: + * 1)如果表单中的字段 存在于 perms 中 则用 perms 中的字段权限替换,否则统一设置为不可编辑、不可查看 + * 2)子表单字段同上 + * + * @param perms + */ + public void resetFieldsPermission(List perms) { + this.setFieldsPermission(list, perms); + + // this.addSystemFieldPermission(list, perms); + return; + } + + + /** + * 添加系统字段权限,添加的字段会追加到 表单formJson.list 属性后 + * + * @param hasFlow + */ + public void addDefaultFields(boolean hasFlow) { + if (list == null) { + list = new JSONArray(); + } + List defaults = new LinkedList<>(); + defaults.add(new SimpleFormFieldModel("creator", "提交人", "input")); + defaults.add(new SimpleFormFieldModel("createTime", "提交时间", "date")); + defaults.add(new SimpleFormFieldModel("updateTime", "更新时间", "date")); + if (hasFlow) { + defaults.add(new SimpleFormFieldModel("flowStage", "流程状态", "input")); + defaults.add(new SimpleFormFieldModel("nodeTitle", "当前节点", "input")); + defaults.add(new SimpleFormFieldModel("checkerName", "节点负责人", "input")); + } + + list.addAll(defaults); + return; + } + + /** + * 生成字段权限模型,该方法不会改变表单formJson + * + * @param hidden + * @param disabled + * @return + */ + public List cloneSimpleFormFieldModels(boolean hidden, boolean disabled) { + if (list != null && !list.isEmpty()) { + List result = JSONUtil.toList(list, SimpleFormFieldModel.class); + result.forEach(f -> { + f.getOptions().setFieldPermission(hidden, disabled); + if (f.getTableColumns() != null && !f.getTableColumns().isEmpty()) { + f.getTableColumns().forEach(s -> { + s.getOptions().setFieldPermission(hidden, disabled); + }); + } + + // 如果子表单是可以编辑的,默认给子表单的操作权限也设置为可以编辑 + if (FIELD_TYPE_TABLE.equalsIgnoreCase(f.getType())) { + if (f.getOptions().getTableOperate() == null) { + f.getOptions().setTableOperate(new SimpleFieldOptionModel.TableOperate()); + } + + f.getOptions().getTableOperate().reset(!disabled, !disabled, !disabled, !disabled); + } + }); + return result; + } + return null; + } + + /** + * 生成字段权限模型,该方法不会改变表单formJson + * 生成逻辑: + * 1)如果表单中的字段 存在于 perms 中 则用 perms 中的字段权限替换,否则统一设置为不可编辑、不可查看 + * 2)子表单字段同上 + * + * @param perms + * @return + */ + public List cloneSimpleFormFieldModels(List perms) { + if (list != null && !list.isEmpty()) { + // 重新生成一个 list + JSONArray cloneList = JSONUtil.parseArray(list.toString()); + + // 按给定的字段权限充值 + this.setFieldsPermission(cloneList, perms); + + // 反序列化 + return JSONUtil.toList(cloneList, SimpleFormFieldModel.class); + } + return null; + } + + /** + * 批量设置表单字段权限 + * + * @param fields + * @param perms + */ + private void setFieldsPermission(JSONArray fields, List perms) { + // newFields 转 map, key = model, vlaue= object + if (fields != null && !fields.isEmpty()) { + Map map = new HashMap<>(); + if (perms != null && !perms.isEmpty()) { + map = perms.stream().filter(p -> ObjectUtil.isNotEmpty(p.getModel())).collect(Collectors.toMap(SimpleFormFieldModel::getModel, + SimpleFormFieldModel -> SimpleFormFieldModel)); + } + for (Object c : fields) { + JSONObject f = (JSONObject) c; + this.setFieldItemPermission(f, map.get(f.getStr(FIELD_MODEL))); + } + } + return; + } + + /** + * 添加系统默认字段 + * + * @param fields + * @param perms + */ + private void addSystemFieldPermission(JSONArray fields, List perms) { + List systemFields = perms.stream().filter(p -> systemFieldConst.contains(p.getModel())).collect(Collectors.toList()); + if (CollUtil.isNotEmpty(systemFields)) { + systemFields.forEach(field -> { + JSONObject item = new JSONObject(); + item.set(FIELD_MODEL, field.getModel()); + item.set(FIELD_TYPE, FIELD_TYPE_SYSTEM); + + JSONObject options = new JSONObject(); + options.set(FIELD_OPTIONS_HIDDEN, field.getOptions().isHidden()); + options.set(FIELD_OPTIONS_DISABLED, field.getOptions().isDisabled()); + item.set(FIELD_OPTIONS, options); + + fields.add(item); + }); + + } + } + + + /** + * 设置单独字段权限 + * + * @param field 表单字段 + * @param perm 字段权限 + */ + private void setFieldItemPermission(JSONObject field, SimpleFormFieldModel perm) { + JSONObject options = field.getJSONObject(FIELD_OPTIONS); + if (options != null) { + Map data = new HashMap<>(); + if (perm != null) { + data.put(FIELD_OPTIONS_HIDDEN, perm.getOptions().isHidden()); + data.put(FIELD_OPTIONS_DISABLED, perm.getOptions().isDisabled()); + } else { + data.put(FIELD_OPTIONS_HIDDEN, true); + data.put(FIELD_OPTIONS_DISABLED, true); + } + options.putAll(data); + + // 子表单 + if (FIELD_TYPE_TABLE.equalsIgnoreCase(field.getStr(FIELD_TYPE))) { + this.setTableFieldItemPermission(field, perm); + } + } + return; + } + + /** + * 设置子表单字段权限 + * + * @param field + * @param perm + */ + private void setTableFieldItemPermission(JSONObject field, SimpleFormFieldModel perm) { + // 设置子表单操作权限 + JSONObject options = field.getJSONObject(FIELD_OPTIONS); + + // 如果没有子表单权限字段,则默认子表单操作权限均不可用 + // 如果有子表单权限字段,如果有操作权限配置则填充,如果没有则默认均可操作(兼容老表单) + if (perm == null) { + options.set(FIELD_OPTIONS_TABLE_OPERATE, new SimpleFieldOptionModel.TableOperate(false, false, false, false)); + } else { + if (perm.getOptions().getTableOperate() != null) { + + options.set(FIELD_OPTIONS_TABLE_OPERATE, new SimpleFieldOptionModel.TableOperate(perm.getOptions().getTableOperate().getCreatable(), + perm.getOptions().getTableOperate().getInsertable(), + perm.getOptions().getTableOperate().getEditable(), + perm.getOptions().getTableOperate().getDeletable())); + } else { + options.set(FIELD_OPTIONS_TABLE_OPERATE, new SimpleFieldOptionModel.TableOperate(true, true, true, true)); + } + } + + // 设置子表单字段权限 + this.setFieldsPermission(field.getJSONArray(FIELD_TABLE_COLUMNS), perm == null ? null : perm.getTableColumns()); + return; + } + + + public static SimpleFormModel getSimpleFormModel(FormDetail formDetail) { + SimpleFormModel simpleFormModel; + if (formDetail != null) { + simpleFormModel = JSON.parseObject(formDetail.getFormJson(), SimpleFormModel.class); + } else { + simpleFormModel = new SimpleFormModel(); + } + return ObjectUtil.cloneByStream(simpleFormModel); + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/model/options/SimpleFieldOptionModel.java b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/model/options/SimpleFieldOptionModel.java new file mode 100644 index 0000000..b949d72 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/model/options/SimpleFieldOptionModel.java @@ -0,0 +1,88 @@ +package org.dromara.taskCenter.model.options; + +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONUtil; +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * 表单字段options 属性 + */ +@Data +public class SimpleFieldOptionModel implements Serializable { + private boolean hidden = true; + private boolean disabled = true; + @JsonInclude(JsonInclude.Include.NON_NULL) + private TableOperate tableOperate; + private JSONArray rules; + + public SimpleFieldOptionModel(){ + super(); + } + public SimpleFieldOptionModel(boolean hidden, boolean disabled){ + this.hidden = hidden; + this.disabled = disabled; + } + + /** + * 重置字段权限 + * @param hidden + * @param disabled + */ + public void setFieldPermission(boolean hidden, boolean disabled){ + this.hidden = hidden; + this.disabled = disabled; + } + + public void setTableOperate(boolean creatable, boolean insertable, boolean editable, boolean deletable){ + if(this.tableOperate == null){ + this.tableOperate = new TableOperate(); + } + this.tableOperate.setCreatable(creatable); + this.tableOperate.setInsertable(insertable); + this.tableOperate.setEditable(editable); + this.tableOperate.setDeletable(deletable); + } + + /** + * 获取rules + * @param clazz + * @param + * @return + */ + public List getRules(Class clazz){ + return JSONUtil.toList(rules, clazz); + } + + /** + * 子表单操作权限 + */ + @Data + public static class TableOperate implements Serializable{ + private static final long serialVersionUID = 1692531713968837525L; + private Boolean creatable = false; + private Boolean insertable = false; + private Boolean editable = false; + private Boolean deletable = false; + + public TableOperate(){ + super(); + } + public TableOperate(boolean creatable, boolean insertable, boolean editable, boolean deletable){ + this.creatable = creatable; + this.insertable = insertable; + this.editable = editable; + this.deletable = deletable; + } + + public void reset(boolean creatable, boolean insertable, boolean editable, boolean deletable){ + this.creatable = creatable; + this.insertable = insertable; + this.editable = editable; + this.deletable = deletable; + } + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/model/widget/WidgetModel.java b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/model/widget/WidgetModel.java new file mode 100644 index 0000000..a1b43ac --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/model/widget/WidgetModel.java @@ -0,0 +1,34 @@ +package org.dromara.taskCenter.model.widget; + +import cn.hutool.json.JSONObject; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * 用于表单字段json映射对象(字段可以根据需要后续自行补充),具备基础校验功能 + * + * chenc + */ +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class WidgetModel implements Serializable { + private static final long serialVersionUID = 1826530099495858744L; + + protected String type; + protected String name; + protected String model; + protected JSONObject options = new JSONObject(); + private List tableColumns; + + public WidgetModel() { + } + + public WidgetModel(String type, String name, String model) { + this.type = type; + this.name = name; + this.model = model; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/param/OpenApiTodoParam.java b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/param/OpenApiTodoParam.java new file mode 100644 index 0000000..c655064 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/param/OpenApiTodoParam.java @@ -0,0 +1,11 @@ +package org.dromara.taskCenter.param; + +import lombok.Data; + +@Data +public class OpenApiTodoParam { + + private String userId; + private String account; + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/param/OpenTaskQueryParam.java b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/param/OpenTaskQueryParam.java new file mode 100644 index 0000000..36c4b54 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/param/OpenTaskQueryParam.java @@ -0,0 +1,62 @@ +package org.dromara.taskCenter.param; + +import org.dromara.taskCenter.result.TaskPageResult; +import lombok.Data; +import java.util.Date; +import java.util.List; + +/** + * @author + */ +@Data +public class OpenTaskQueryParam { + /** + * 应用ID + */ + private Long appId; + + /** + * 待办ID + */ + private Long taskId; + + /** + * 流程实例ID + */ + private Long instanceId; + + /** + * 申请人 + */ + private String applyName; + + /** + * 申请人ID + */ + private String applyId; + + /** + * 申请时间 + */ + private Date createTime; + + /** + * 表单名称 + */ + private String formName; + + /** + * 流程流程状态 + */ + private String stage; + + /** + * 表单数据 + */ + private List formData; + + /** + * url + */ + private String url; +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/param/TaskBatchUpdateParam.java b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/param/TaskBatchUpdateParam.java new file mode 100644 index 0000000..7bb2324 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/param/TaskBatchUpdateParam.java @@ -0,0 +1,17 @@ +package org.dromara.taskCenter.param; + +import org.dromara.workflow.engine.enums.OperateType; +import lombok.Data; + +@Data +public class TaskBatchUpdateParam { + + private OperateType action; + + private Long taskId; + + private String dataId; + + private TaskUpdateParam.FormInfo form; + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/param/TaskFlowParam.java b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/param/TaskFlowParam.java new file mode 100644 index 0000000..a872f44 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/param/TaskFlowParam.java @@ -0,0 +1,157 @@ +package org.dromara.taskCenter.param; + +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.api.model.LoginUser; +import org.dromara.workflow.engine.enums.OperateType; +import org.dromara.workflow.param.engine.EngineRequest; +import org.dromara.workflow.param.model.FlowUser; +import cn.hutool.core.date.DateUtil; +import lombok.Data; + +import java.io.Serializable; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.Map; + +@Data +public class TaskFlowParam implements Serializable { + private static final long serialVersionUID = 1L; + + private static final String pattern = "yyyyMMddHHmmss"; + + /** + * 待办操作 + */ + private OperateType action; + + + /** + * 待办id + */ + private Long taskId; + + /** + * 实例id + */ + private Long instanceId; + + /** + * 数据id + */ + private Long dataId; + + /** + * 表单数据 + */ + private EngineRequest.FormData form; + + /** + * 处理人 + */ + private FlowUser handlerUser; + + /** + * 转交人 + */ + private Long forwardUser; + + /** + * 业务发起时间 + */ + private String requestTime; + + /** + * 是否批量操作 + */ + private Boolean isBatch; + + + public void setUser(Long userId,String userName,String account){ + this.handlerUser = new FlowUser(userId,userName,account); + } + + + /***************************流程定义****************************/ + + /** + * 参数校验分组:创建 + */ + public @interface create {} + + /** + * 参数校验分组:更新 + */ + public @interface update {} + + /** + * 参数校验分组:激活 + */ + public @interface active {} + + + /** + * 参数校验分组:删除 + */ + public @interface delete {} + + /** + * 参数校验分组:详情 + */ + public @interface detail {} + + + public TaskFlowParam(TaskUpdateParam param,FlowUser handlerUser){ + this.setAction(param.getAction()); + this.setDataId(param.getDataId()); + if(param.getTaskId() != null){ + this.setTaskId(param.getTaskId()); + } + + EngineRequest.FormData formInfo = new EngineRequest.FormData(); + formInfo.setFormId(param.getForm().getFormId()); + formInfo.setFormCode(param.getForm().getFormCode()); + formInfo.setFormName(param.getForm().getFormName()); + formInfo.setData(param.getForm().getFormData()); + formInfo.setComment(param.getForm().getComment()); + formInfo.setSignature(param.getForm().getSignature()); + formInfo.setChangedWidgets(new HashSet<>()); + this.setForm(formInfo); + + if(OperateType.forward.equals(param.getAction())){ + this.setForwardUser(param.getForwardUser()); + } + + this.requestTime = DateUtil.format(param.getRequestTime(),pattern); + this.isBatch = false; + + this.handlerUser = handlerUser; + } + + + public TaskFlowParam(TaskUpdateParam param, Map formData){ + this.setAction(param.getAction()); + this.setDataId(param.getDataId()); + this.setTaskId(param.getTaskId()); + + EngineRequest.FormData formInfo = new EngineRequest.FormData(); + formInfo.setFormId(param.getForm().getFormId()); + formInfo.setFormCode(param.getForm().getFormCode()); + formInfo.setFormName(param.getForm().getFormName()); + if(formData != null){ + formInfo.setData(new LinkedHashMap(formData)); + } + formInfo.setComment(param.getForm().getComment()); + formInfo.setSignature(param.getForm().getSignature()); + formInfo.setChangedWidgets(new HashSet<>()); + this.setForm(formInfo); + + LoginUser loginUser = LoginHelper.getLoginUser(); + this.setUser(loginUser.getUserId(),loginUser.getNickname(),loginUser.getUsername()); + + this.requestTime = DateUtil.format(param.getRequestTime(),pattern); + + this.isBatch = true; + } + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/param/TaskQueryParam.java b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/param/TaskQueryParam.java new file mode 100644 index 0000000..d03d203 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/param/TaskQueryParam.java @@ -0,0 +1,115 @@ +package org.dromara.taskCenter.param; + +import lombok.Data; + +import java.util.LinkedHashMap; + +@Data +public class TaskQueryParam{ + + /** + * 是否进行分页 + */ + private Boolean showPageNation = true; + + + private String app; + + private Long formId; + + private String formName; + + private String time; + + private TaskType type; + + /** + * 未处理 preprocessing 正在处理 processing 草稿 draft + */ + private String status; + + private Long taskId; + + private String applyName; + + private String sortType; + + private String order; + + private Boolean batch = false; + + private LinkedHashMap formData; + + /** + * 预警模型id + */ + private Long tagId; + + private String tagName; + + private String tagGroupName; + + private String tagLevel; + + private String duration; + + + /** + * 预警编号 + */ + private String alertId; + + + /** + * 项目负责人 + */ + private String projectUserName; + + /** + * 项目编号 + */ + private String projectNum; + + /** + * 项目名称 + */ + private String projectName; + + /** + * 项目所在部门id + */ + private Long projectOrgId; + + /** + * 项目类型 + */ + private Integer projectType; + + /** + * 项目级别 + */ + private Integer projectLevel; + + /** + * 项目阶段 + */ + private Integer projectStage; + + /** + * 房屋名称 + */ + private String houseName; + + /** + * 房屋状态 + */ + private Integer houseStatus; + + /** + * 房屋类型 + */ + private Integer houseType; + + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/param/TaskType.java b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/param/TaskType.java new file mode 100644 index 0000000..64fd4c9 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/param/TaskType.java @@ -0,0 +1,9 @@ +package org.dromara.taskCenter.param; + +/** + * @Description: 待办类型枚举 + **/ +public enum TaskType { + + todo,start,handle,cc, +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/param/TaskUpdateParam.java b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/param/TaskUpdateParam.java new file mode 100644 index 0000000..8a41ecc --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/param/TaskUpdateParam.java @@ -0,0 +1,89 @@ +package org.dromara.taskCenter.param; + +import org.dromara.formMaking.domain.FormSource; +import org.dromara.workflow.engine.enums.OperateType; +import lombok.Data; + +import java.util.Date; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Set; + +@Data +public class TaskUpdateParam{ + + private OperateType action; + + private Long taskId; + + private List taskIds; + + private Long dataId; + + private Long forwardUser; + + private Boolean print; + + private FormInfo form; + + private Date requestTime = new Date(); + + @Data + public static class FormInfo{ + + /** + * 表单id + */ + private Long formId; + + /** + * 表单code + */ + private String formCode; + + /** + * 表单名称 + */ + private String formName; + + /** + * 表单数据 + */ + private LinkedHashMap formData; + + /** + * 文本意见 + */ + private String comment; + + /** + * 手写签名 + */ + private String signature; + + /** + * 表单变动字段 + */ + private Set updatedWidget; + } + + + public TaskUpdateParam(){} + + public TaskUpdateParam(OperateType action, FormSource form, Long dataId, Boolean print, + LinkedHashMap formData, + Date handleTime){ + this.action = action; + this.dataId = dataId; + + FormInfo formInfo = new FormInfo(); + formInfo.setFormId(form.getId()); + formInfo.setFormCode(form.getCode()); + formInfo.setFormName(form.getTitle()); + formInfo.setFormData(formData); + this.form = formInfo; + this.requestTime = handleTime; + this.print = print; + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/result/OpenApiTodoResult.java b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/result/OpenApiTodoResult.java new file mode 100644 index 0000000..3ea7418 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/result/OpenApiTodoResult.java @@ -0,0 +1,20 @@ +package org.dromara.taskCenter.result; + +import lombok.Data; + +/** + * @Description: 待办任务批量处理结果 + **/ +@Data +public class OpenApiTodoResult { + + private Integer todoCount; + + private String account; + + + public OpenApiTodoResult(Integer todoCount, String account) { + this.todoCount = todoCount; + this.account = account; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/result/TaskBatchActionResult.java b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/result/TaskBatchActionResult.java new file mode 100644 index 0000000..282bbe2 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/result/TaskBatchActionResult.java @@ -0,0 +1,23 @@ +package org.dromara.taskCenter.result; + +import org.dromara.workflow.result.engine.BaseActionResult; +import lombok.Data; + +import java.util.List; + +/** + * @Description: 待办任务批量处理结果 + **/ +@Data +public class TaskBatchActionResult { + + private Integer total; + + private List data; + + + public TaskBatchActionResult(Integer total, List data) { + this.total = total; + this.data = data; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/result/TaskInfoResult.java b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/result/TaskInfoResult.java new file mode 100644 index 0000000..27f040b --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/result/TaskInfoResult.java @@ -0,0 +1,114 @@ +package org.dromara.taskCenter.result; + +import org.dromara.formMaking.domain.FormSource; +import org.dromara.formMaking.results.FormSourceResult; +import org.dromara.formMaking.service.FormSourceService; +import org.dromara.workflow.engine.domain.Instance; +import org.dromara.workflow.engine.enums.NodeType; +import org.dromara.workflow.engine.model.setting.Node; +import cn.hutool.extra.spring.SpringUtil; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; + +import java.util.Map; + +@Slf4j +@Data +public class TaskInfoResult { + + /** + * 待办信息 + */ + private TaskInstanceResult task; + + /** + * 表单 + */ + private FormInfo form; + + /** + * 数据 + */ + private Map data; + + /** + * 节点配置 + */ + private Node node; + + /** + * 是否查看流程日志 + */ + private Boolean logVisible; + + + public TaskInfoResult(TaskInstanceResult task, FormSourceResult formDetail) { + FormSource source = SpringUtil.getBean(FormSourceService.class).getById(formDetail.getId()); + + FormInfo formInfo = new FormInfo(); + BeanUtils.copyProperties(source,formInfo); + formInfo.setFormId(source.getId()); + formInfo.setFormCode(source.getCode()); + formInfo.setFormJson(formDetail.getFormJson()); + formInfo.setFormName(source.getTitle()); + formInfo.setFormCode(source.getCode()); + formInfo.setHasFlow(true); + formInfo.setDefinitionId(task.getDefinitionId()); + this.form = formInfo; + + this.task = task; + } + + public TaskInfoResult(Instance instance, FormSourceResult formDetail) { + FormSource source = SpringUtil.getBean(FormSourceService.class).getById(formDetail.getId()); + + FormInfo formInfo = new FormInfo(); + BeanUtils.copyProperties(source,formInfo); + formInfo.setFormId(source.getId()); + formInfo.setFormCode(source.getCode()); + formInfo.setFormJson(formDetail.getFormJson()); + formInfo.setFormName(source.getTitle()); + formInfo.setFormCode(source.getCode()); + formInfo.setHasFlow(true); + formInfo.setDefinitionId(instance.getDefinitionId()); + this.form = formInfo; + + TaskInstanceResult taskInstanceResult = new TaskInstanceResult(); + taskInstanceResult.setInstanceId(instance.getId()); + taskInstanceResult.setFormId(instance.getFormId()); + taskInstanceResult.setDataId(instance.getDataId()); + taskInstanceResult.setStage(instance.getStage().name()); + taskInstanceResult.setDefinitionId(instance.getDefinitionId()); + taskInstanceResult.setNodeKey(NodeType.start.name()); + taskInstanceResult.setNodeName("开始节点"); + taskInstanceResult.setHandleUserId(instance.getCreateUser()); + taskInstanceResult.setHandleUserName(instance.getCreateName()); + taskInstanceResult.setStatus(1); + taskInstanceResult.setCreateUser(instance.getCreateUser()); + taskInstanceResult.setCreateName(instance.getCreateName()); + taskInstanceResult.setCreateAccount(instance.getCreateAccount()); + taskInstanceResult.setCreateTime(instance.getCreateTime()); + this.task = taskInstanceResult; + } + + + + + @Data + public class FormInfo{ + + private Long formId; + + private String formCode; + + private String formName; + + private Boolean hasFlow; + + private Long definitionId; + + private String formJson; + + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/result/TaskInstanceResult.java b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/result/TaskInstanceResult.java new file mode 100644 index 0000000..4282884 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/result/TaskInstanceResult.java @@ -0,0 +1,45 @@ +package org.dromara.taskCenter.result; + +import lombok.Data; + +import java.util.Date; + +/** + * @Description: 待办任务 + **/ +@Data +public class TaskInstanceResult { + + private Long taskId; + + private Long instanceId; + + private String app; + + private Long formId; + + private Long dataId; + + private String stage; + + private Long definitionId; + + private String nodeKey; + + private String nodeName; + + private Long handleUserId; + + private String handleUserName; + + private Integer status; + + private Long createUser; + + private String createName; + + private String createAccount; + + private Date createTime; + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/result/TaskPageResult.java b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/result/TaskPageResult.java new file mode 100644 index 0000000..156264b --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/result/TaskPageResult.java @@ -0,0 +1,100 @@ +package org.dromara.taskCenter.result; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; +import java.util.List; + +/** + * @Description: 待办中心VO + **/ +@Data +public class TaskPageResult { + + private Long appId; + + private Long taskId; + + private Long userId; + + private String userName; + + private String dataId; + + private Long instanceId; + + private Long definitionId; + + private String nodeKey; + + private String nodeName; + + private String stage; + + private String applyId; + + private String applyName; + + private Date applyTime; + + private Long handlerId; + + private String handlerName; + + private Integer status; + + private Boolean processing; + + private Boolean drafting; + + private String draftData; + + private Long formId; + + private String formColor; + + private String formIcon; + + private String formName; + + private String formJson; + + private String formCode; + + private Date createTime; + + private Date updateTime; + + private Boolean priority; + + private String originFormData; + + private List formData; + + /** + * 实例下面节点信息 + * nodeId,name,checkerInfo(id,name,account) + */ + private String nextNodes; + + /** + * 是否允许批量审核 + */ + private Boolean batchSubmit; + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class FormDataConvert { + + private String model; + + private String name; + + private String value; + + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/action/TaskActionService.java b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/action/TaskActionService.java new file mode 100644 index 0000000..ba81272 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/action/TaskActionService.java @@ -0,0 +1,12 @@ +package org.dromara.taskCenter.service.action; + +import org.dromara.taskCenter.param.TaskFlowParam; +import org.dromara.workflow.result.engine.ActionNodeSubmitResult; +import org.springframework.stereotype.Component; + +@Component +public interface TaskActionService{ + + ActionNodeSubmitResult action(TaskFlowParam data); + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/action/TaskActionStrategyContext.java b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/action/TaskActionStrategyContext.java new file mode 100644 index 0000000..3dc302d --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/action/TaskActionStrategyContext.java @@ -0,0 +1,148 @@ +package org.dromara.taskCenter.service.action; + + +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.api.model.LoginUser; +import org.dromara.common.Exception.ServiceException; +import org.dromara.common.response.WorkflowResponseData; +import org.dromara.common.response.WorkflowResult; +import org.dromara.common.response.WorkflowResultCode; +import org.dromara.dataManager.domain.FormData; +import org.dromara.dataManager.service.FormDataService; +import org.dromara.taskCenter.param.TaskFlowParam; +import org.dromara.taskCenter.param.TaskUpdateParam; +import org.dromara.taskCenter.result.TaskBatchActionResult; +import org.dromara.workflow.engine.enums.OperateType; +import org.dromara.workflow.engine.exception.WorkflowCode; +import org.dromara.workflow.param.model.FlowUser; +import org.dromara.workflow.result.engine.ActionNodeSubmitResult; +import org.dromara.workflow.result.engine.BaseActionResult; +import org.dromara.workflow.result.engine.EngineDataResult; +import org.dromara.workflow.service.internal.InstanceTaskService; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +@Slf4j +@Component +public class TaskActionStrategyContext { + + @Autowired + private final Map taskHandlerServiceMap = new ConcurrentHashMap(); + + @Autowired + private FormDataService formDataService; + @Autowired + private InstanceTaskService instanceTaskService; + + + public WorkflowResponseData execute(TaskUpdateParam data){ + + if(!OperateType.create.equals(data.getAction()) && ObjectUtil.hasEmpty(data.getTaskId(),data.getAction(),data.getForm(),data.getDataId())){ + return WorkflowResult.error(WorkflowResultCode.PARAM_MISSING); + } + + LoginUser loginUser = LoginHelper.getLoginUser(); + if(OperateType.draft.equals(data.getAction())){ + ActionNodeSubmitResult engineResult = taskHandlerServiceMap.get(data.getAction().getCode()+"Handler").action(new TaskFlowParam(data,new FlowUser(loginUser.getUserId(),loginUser.getNickname(),loginUser.getUsername(),Arrays.asList(loginUser.getDeptId())))); + + return engineResult.getSuccess() ? WorkflowResult.success(engineResult.getData(), WorkflowResultCode.FLOW_DRAFT_SUCCESS.message()) : WorkflowResult.error(engineResult.getCode(),engineResult.getMessage()); + } + if(OperateType.urge.equals(data.getAction())){ + ActionNodeSubmitResult engineResult = taskHandlerServiceMap.get(data.getAction().getCode()+"Handler").action(new TaskFlowParam(data,new FlowUser(loginUser.getUserId(),loginUser.getNickname(),loginUser.getUsername(),Arrays.asList(loginUser.getDeptId())))); + + return engineResult.getSuccess() ? WorkflowResult.success(engineResult.getData(), WorkflowResultCode.FLOW_URGE_SUCCESS.message()) : WorkflowResult.error(engineResult.getCode(),engineResult.getMessage()); + } + + try { + //流程引擎节点流转 + ActionNodeSubmitResult engineResult = taskHandlerServiceMap.get(data.getAction().getCode()+"Handler").action(new TaskFlowParam(data,new FlowUser(loginUser.getUserId(),loginUser.getNickname(),loginUser.getUsername(),Arrays.asList(loginUser.getDeptId())))); + + //更新表单数据 + if(engineResult.getSuccess()){ + updateFormData(data, engineResult.getData()); + } + + return engineResult.getSuccess() ? + WorkflowResult.success(engineResult.getData(),engineResult.getData().getAction().getName()+"成功") : + WorkflowResult.error(engineResult.getCode(),engineResult.getMessage()); + }catch (Exception e){ + log.error("###### task info data source not found {} ######",Arrays.toString(e.getStackTrace())); + return WorkflowResult.error(WorkflowResultCode.DATASOURCE_NOT_FOUND); + } + + } + + public WorkflowResponseData updateTaskProcessing(Long taskId){ + + return WorkflowResult.success(instanceTaskService.updateTaskProcessing(taskId)); + } + + public WorkflowResponseData batchUpdateTaskProcessing(List taskIds){ + + instanceTaskService.batchUpdateTaskProcessing(taskIds); + return WorkflowResult.success(); + } + + + public WorkflowResponseData batchHandleTask(List data){ + if(CollUtil.isEmpty(data)){ + + throw new ServiceException(WorkflowResultCode.PARAM_IS_BLANK); + } + + List engineData = new ArrayList<>(); + for(TaskUpdateParam param : data){ + Map formData = this.formDataService.getFormDataById(param.getForm().getFormId(),param.getDataId()); + //流程引擎节点流转 + if(formData != null){ + formData.putAll(param.getForm().getFormData()); + + ActionNodeSubmitResult engineResult = taskHandlerServiceMap.get(param.getAction().getCode()+"Handler").action(new TaskFlowParam(param, formData)); + + if(engineResult == null){ + log.error("###### workflow action exception result {} ######", JSONUtil.toJsonStr(param)); + engineData.add(BaseActionResult.error(WorkflowCode.ENGINE_RESULT_EMPTY)); + //todo elasticsearchAccessor.update(param.getForm().getFormCode(), param.getDataId(),befFormData); + continue; + } + + //更新表单数据 + if(engineResult.getSuccess()){ + updateFormData(param, engineResult.getData()); + } + + engineData.add(engineResult); + } + } + + return WorkflowResult.success(new TaskBatchActionResult(data.size(),engineData)); + } + + + private void updateFormData(TaskUpdateParam data, EngineDataResult engineResult) { + if(ObjectUtil.hasEmpty(engineResult.getInstanceId(),engineResult.getFormInfo().getFormId(),engineResult.getDataId())){ + + throw new ServiceException(WorkflowResultCode.PARAM_MISSING); + } + FormData formData = formDataService.getById(data.getDataId()); + formData.setInstanceNode(engineResult.getNodeTitle()); + formData.setInstanceStage(engineResult.getFlowStage()); + formData.setInstanceChecker(engineResult.getCheckerName()); + if(data.getForm().getFormData() != null){ + LinkedHashMap afterFormData = formData.getFormData(); + afterFormData.putAll(data.getForm().getFormData()); + formData.setFormData(afterFormData); + } + + formDataService.updateById(formData); + } + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/action/impl/CancelHandler.java b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/action/impl/CancelHandler.java new file mode 100644 index 0000000..bb20100 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/action/impl/CancelHandler.java @@ -0,0 +1,208 @@ +package org.dromara.taskCenter.service.action.impl; + + +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.taskCenter.param.TaskFlowParam; +import org.dromara.taskCenter.service.action.TaskActionService; +import org.dromara.workflow.engine.domain.Instance; +import org.dromara.workflow.engine.domain.InstanceTask; +import org.dromara.workflow.engine.domain.base.EdgeInfo; +import org.dromara.workflow.engine.enums.InstanceStage; +import org.dromara.workflow.engine.enums.NodeType; +import org.dromara.workflow.engine.enums.OperateType; +import org.dromara.workflow.engine.enums.TaskStatus; +import org.dromara.workflow.engine.exception.WorkflowCode; +import org.dromara.workflow.engine.exception.WorkflowException; +import org.dromara.workflow.engine.factory.FlowSyncManager; +import org.dromara.workflow.engine.model.setting.Model; +import org.dromara.workflow.engine.model.setting.Node; +import org.dromara.workflow.param.engine.EngineRequest; +import org.dromara.workflow.param.instance.InstanceLogParam; +import org.dromara.workflow.param.model.FlowUser; +import org.dromara.workflow.remind.flow.FlowRemindHelper; +import org.dromara.workflow.result.engine.ActionNodeSubmitResult; +import org.dromara.workflow.result.engine.EngineDataResult; +import org.dromara.workflow.service.external.FlowModelService; +import org.dromara.workflow.service.internal.InstanceLogService; +import org.dromara.workflow.service.internal.InstanceService; +import org.dromara.workflow.service.internal.InstanceTaskService; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.*; + +@Component("cancelHandler") +public class CancelHandler implements TaskActionService { + + @Autowired + private InstanceService instanceService; + @Autowired + private InstanceTaskService instanceTaskService; + @Autowired + private FlowModelService flowModelService; + @Autowired + private InstanceLogService logService; + @Autowired + private FlowRemindHelper flowRemindHelper; + + + @Override + public ActionNodeSubmitResult action(TaskFlowParam data) { + Instance instance = instanceService.getById(data.getTaskId()); + if (instance == null) { + + throw new WorkflowException(WorkflowCode.INSTANCE_NOT_EXIST); + } + + EngineRequest erp = new EngineRequest(); + erp.setTasks(flowRemindHelper.getTasks(instance.getId(), null, TaskStatus.unhandled)); + + Model model = flowModelService.getDefinitionModel(instance.getDefinitionId()); + + FlowUser handleUser = new FlowUser(LoginHelper.getUserId(),LoginHelper.getLoginUser().getNickname(), LoginHelper.getLoginUser().getUsername()); + + validate(model, instance, handleUser); + + executeAction(model, instance, handleUser); + + addLog(model, instance, handleUser); + + ActionNodeSubmitResult res = transformActionResult(data,instance,handleUser); + + BeanUtils.copyProperties(data,erp); + erp.setDefinitionId(instance.getDefinitionId()); + erp.setModel(model); + erp.setHandlerUser(new FlowUser(LoginHelper.getUserId(),LoginHelper.getLoginUser().getNickname(), LoginHelper.getLoginUser().getUsername())); + EngineRequest.InstanceData instanceData = new EngineRequest.InstanceData(instance); + erp.setInstance(instanceData); + FlowSyncManager.me().executeFlowInfo(erp); + + return res; + } + + /** + * 1、处理人是实例发起人(已校验) 2、流程属性允许撤回流程 3、当前审核节点的上一节点是发起节点且所有审核人审核状态都是未审核 + */ + private void validate(Model model, Instance instance, FlowUser handleUser) { + + // 当前处理人必须是实例发起人人 + if (!instance.getCreateUser().equals(handleUser.getId())) { + + throw new WorkflowException(WorkflowCode.PERMISSION_RECALL_NO_PERMISSION); + } + + // 流程状态必须是进行中 + if (!InstanceStage.processing.equals(instance.getStage())) { + + throw new WorkflowException(WorkflowCode.INSTANCE_STAGE_ERROR); + } + + // 流程当前节点必须是开始节点 + if (instance.getNodeKeys().stream().anyMatch(p -> StrUtil.equals(p.getTarget(), NodeType.start.name()))) { + + throw new WorkflowException(WorkflowCode.INSTANCE_STAGE_ERROR); + } + + // 流程属性允许撤回流程 + if (!model.getConfig().getCancel()) { + + throw new WorkflowException(WorkflowCode.PERMISSION_CANCEL_NOT_OPEN); + } + +// // 当前所有任务节点的待办任务 状态都是未处理 +// if (taskService.checkNodeHandledTask(instance.getId(), +// instance.getNodeKeys().stream().map(EdgeInfo::getTarget).collect(Collectors.toList()))) { +// +// throw new WorkflowException(WorkflowCode.PERMISSION_RECALL_APPROVAL_NO_PERMISSION); +// } + + } + + private void addLog(Model model, Instance instance, FlowUser flowUser) { + Node startNode = model.getNodeList().stream().filter(p -> StrUtil.equals(NodeType.start.name(), p.getId())) + .findFirst().get(); + + InstanceLogParam instanceLog = new InstanceLogParam(OperateType.cancel, instance, startNode, false, + instance.getUpdateTime()); + instanceLog.setIsBatch(false); + instanceLog.addUser(flowUser.getId(), flowUser.getName(), flowUser.getAccount()); + instanceLog.addContent(null,null); + logService.create(instanceLog); + } + + private ActionNodeSubmitResult executeAction(Model model, Instance instance, FlowUser handleUser) { + + instance.setStage(InstanceStage.finished); + // instance.setRoutes(Lists.emptyList()); + Node startNode = model.getNodeList().stream().filter(p -> StrUtil.equals(NodeType.start.name(), p.getId())) + .findFirst().get(); + + instance.setNodeKeys(Arrays.asList(new EdgeInfo(instance.getNodeKeys().get(0).getTarget(), + NodeType.start.name(), startNode.getName(), Arrays.asList(handleUser)))); + instance.setUpdateUser(handleUser.getId()); + instance.setUpdateTime(new Date()); + + this.instanceService.updateById(instance); + + List instanceTasks = this.instanceTaskService + .list(new LambdaQueryWrapper().eq(InstanceTask::getInstanceId, instance.getId())); + + if (CollUtil.isNotEmpty(instanceTasks)) { + instanceTasks.forEach(t -> { + t.setStatus(TaskStatus.outDated.getCode()); + }); + this.instanceTaskService.updateBatchById(instanceTasks, 500); + } + + InstanceTask nodeTask = new InstanceTask(); + nodeTask.setNodeKey(NodeType.start.name()); + nodeTask.setNodeName("开始节点"); + nodeTask.setInstanceId(instance.getId()); + nodeTask.setFormId(instance.getFormId()); + nodeTask.setUserId(instance.getCreateUser()); + nodeTask.setUserName(instance.getCreateName()); + nodeTask.setUserAccount(instance.getCreateAccount()); + nodeTask.setStatus(TaskStatus.unhandled.getCode()); + nodeTask.setCreateUser(instance.getCreateUser()); + nodeTask.setCreateTime(new Date()); + nodeTask.setUpdateTime(new Date()); + this.instanceTaskService.save(nodeTask); + // 更新待办任务 + this.instanceTaskService.deleteInstanceUnHandledTask(instance.getId()); + return null; + } + + private ActionNodeSubmitResult transformActionResult(TaskFlowParam data, Instance instance, FlowUser handleUser) { + EngineDataResult result = new EngineDataResult(); + result.setAction(OperateType.cancel); + result.setDataId(instance.getDataId()); + result.setFormInfo(data.getForm()); + result.setInstanceId(instance.getId()); + result.setFlowStage(instance.getStage().name()); + + if (instance.getStage().equals(InstanceStage.finished)) { + result.setNodeTitle(instance.getNodeKeys().get(0).getTargetName()); + Map> nodeInfo = new HashMap<>(); + nodeInfo.put("start", Arrays.asList(new EngineDataResult.NodeHandler(result.getNodeTitle(), + instance.getCreateUser(), instance.getCreateName(), instance.getCreateAccount()))); + result.setNodeInfo(nodeInfo); + result.setCheckerName(null); + } + + result.setCreateId(instance.getCreateUser()); + result.setCreator(instance.getCreateName()); + result.setCreatorAccount(instance.getCreateAccount()); + result.setCreateTime(instance.getCreateTime()); + + result.setUpdatorId(handleUser.getId()); + result.setUpdatorName(handleUser.getName()); + result.setUpdatorAccount(handleUser.getAccount()); + result.setUpdateTime(instance.getUpdateTime()); + + return ActionNodeSubmitResult.success(result); + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/action/impl/CreateHandler.java b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/action/impl/CreateHandler.java new file mode 100644 index 0000000..d2866f0 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/action/impl/CreateHandler.java @@ -0,0 +1,37 @@ +package org.dromara.taskCenter.service.action.impl; + + +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.taskCenter.param.TaskFlowParam; +import org.dromara.taskCenter.service.action.TaskActionService; +import org.dromara.workflow.param.engine.EngineRequest; +import org.dromara.workflow.param.model.FlowUser; +import org.dromara.workflow.result.engine.ActionNodeSubmitResult; +import org.dromara.workflow.service.external.FlowInstanceService; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component("createHandler") +public class CreateHandler implements TaskActionService { + + @Autowired + private FlowInstanceService instanceService; + + @Override + public ActionNodeSubmitResult action(TaskFlowParam data) { + EngineRequest erp = new EngineRequest(); + BeanUtils.copyProperties(data,erp); + + if(data.getHandlerUser() == null){ +// if(LoginContextHolder.me().getSysLoginUser().isAnonymous()){ +// erp.setHandlerUser(new FlowUser(-1L,"匿名用户","anonymous")); +// }else{ +// erp.setHandlerUser(new FlowUser(LoginHelper.getUserId(),LoginHelper.getLoginUser().getNickname(), LoginHelper.getLoginUser().getUsername())); +// } + erp.setHandlerUser(new FlowUser(LoginHelper.getUserId(),LoginHelper.getLoginUser().getNickname(), LoginHelper.getLoginUser().getUsername())); + } + + return instanceService.action(erp); + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/action/impl/DraftHandler.java b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/action/impl/DraftHandler.java new file mode 100644 index 0000000..b6c5de7 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/action/impl/DraftHandler.java @@ -0,0 +1,43 @@ +package org.dromara.taskCenter.service.action.impl; + + +import org.dromara.common.Exception.ServiceException; +import org.dromara.common.response.WorkflowResultCode; +import org.dromara.taskCenter.param.TaskFlowParam; +import org.dromara.taskCenter.service.action.TaskActionService; +import org.dromara.workflow.engine.domain.Instance; +import org.dromara.workflow.engine.domain.InstanceTask; +import org.dromara.workflow.engine.enums.TaskStatus; +import org.dromara.workflow.result.engine.ActionNodeSubmitResult; +import org.dromara.workflow.service.external.FlowTaskService; +import org.dromara.workflow.service.internal.InstanceService; +import org.dromara.workflow.service.internal.InstanceTaskService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component("draftHandler") +public class DraftHandler implements TaskActionService { + + @Autowired + private FlowTaskService flowTaskService; + @Autowired + private InstanceService instanceService; + @Autowired + private InstanceTaskService instanceTaskService; + + @Override + public ActionNodeSubmitResult action(TaskFlowParam data) { + InstanceTask instanceTask = instanceTaskService.getById(data.getTaskId()); + if(instanceTask == null){ + throw new ServiceException(WorkflowResultCode.NODE_CHECKER_TASK_NOT_EXIST); + } + if(instanceTask.getStatus().equals(TaskStatus.handled.getCode())){ + + throw new ServiceException(WorkflowResultCode.TASK_HAS_HANDLED); + } + Instance instance = instanceService.getById(instanceTask.getInstanceId()); + flowTaskService.saveTaskDraft(instance,instanceTask,data.getForm().getData()); + + return ActionNodeSubmitResult.success(null); + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/action/impl/FinishHandler.java b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/action/impl/FinishHandler.java new file mode 100644 index 0000000..ce34bbd --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/action/impl/FinishHandler.java @@ -0,0 +1,26 @@ +package org.dromara.taskCenter.service.action.impl; + +import org.dromara.taskCenter.param.TaskFlowParam; +import org.dromara.taskCenter.service.action.TaskActionService; +import org.dromara.workflow.param.engine.EngineRequest; +import org.dromara.workflow.result.engine.ActionNodeSubmitResult; +import org.dromara.workflow.service.external.FlowInstanceService; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component("finishHandler") +public class FinishHandler implements TaskActionService { + + @Autowired + private FlowInstanceService instanceService; + + @Override + public ActionNodeSubmitResult action(TaskFlowParam data) { + EngineRequest erp = new EngineRequest(); + BeanUtils.copyProperties(data,erp); + + return instanceService.action(erp); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/action/impl/ForwardHandler.java b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/action/impl/ForwardHandler.java new file mode 100644 index 0000000..8d7030e --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/action/impl/ForwardHandler.java @@ -0,0 +1,45 @@ +package org.dromara.taskCenter.service.action.impl; + + +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.service.ISysUserService; +import org.dromara.taskCenter.param.TaskFlowParam; +import org.dromara.taskCenter.service.action.TaskActionService; +import org.dromara.workflow.engine.exception.WorkflowCode; +import org.dromara.workflow.param.engine.EngineRequest; +import org.dromara.workflow.param.model.FlowUser; +import org.dromara.workflow.result.engine.ActionNodeSubmitResult; +import org.dromara.workflow.service.external.FlowInstanceService; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component("forwardHandler") +public class ForwardHandler implements TaskActionService { + + @Autowired + private ISysUserService userService; + @Autowired + private FlowInstanceService instanceService; + + @Override + public ActionNodeSubmitResult action(TaskFlowParam data) { + if(data.getForwardUser() == null){ + + return ActionNodeSubmitResult.error(WorkflowCode.PARAM_MISSING); + } + SysUserVo userInfo = userService.selectUserById(data.getForwardUser()); + if(userInfo == null){ + + return ActionNodeSubmitResult.error(WorkflowCode.FORWARD_USER_NOT_EXIST); + } + + FlowUser forwardUser = new FlowUser(userInfo.getUserId(),userInfo.getNickName(),userInfo.getUserName()); + EngineRequest erp = new EngineRequest(); + BeanUtils.copyProperties(data,erp); + erp.setForwardUser(forwardUser); + + return instanceService.action(erp); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/action/impl/RecallHandler.java b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/action/impl/RecallHandler.java new file mode 100644 index 0000000..0f7078b --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/action/impl/RecallHandler.java @@ -0,0 +1,212 @@ +package org.dromara.taskCenter.service.action.impl; + + +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.api.model.LoginUser; +import org.dromara.taskCenter.param.TaskFlowParam; +import org.dromara.taskCenter.service.action.TaskActionService; +import org.dromara.workflow.engine.domain.Instance; +import org.dromara.workflow.engine.domain.InstanceTask; +import org.dromara.workflow.engine.domain.base.EdgeInfo; +import org.dromara.workflow.engine.enums.InstanceStage; +import org.dromara.workflow.engine.enums.NodeType; +import org.dromara.workflow.engine.enums.OperateType; +import org.dromara.workflow.engine.enums.TaskStatus; +import org.dromara.workflow.engine.exception.WorkflowCode; +import org.dromara.workflow.engine.exception.WorkflowException; +import org.dromara.workflow.engine.factory.FlowSyncManager; +import org.dromara.workflow.engine.model.setting.Model; +import org.dromara.workflow.engine.model.setting.Node; +import org.dromara.workflow.param.engine.EngineRequest; +import org.dromara.workflow.param.instance.InstanceLogParam; +import org.dromara.workflow.param.model.FlowUser; +import org.dromara.workflow.remind.flow.FlowRemindHelper; +import org.dromara.workflow.result.engine.ActionNodeSubmitResult; +import org.dromara.workflow.result.engine.EngineDataResult; +import org.dromara.workflow.service.external.FlowModelService; +import org.dromara.workflow.service.external.FlowTaskService; +import org.dromara.workflow.service.internal.InstanceLogService; +import org.dromara.workflow.service.internal.InstanceService; +import org.dromara.workflow.service.internal.InstanceTaskService; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.*; +import java.util.stream.Collectors; + +@Component("recallHandler") +public class RecallHandler implements TaskActionService { + + + @Autowired + private InstanceService instanceService; + @Autowired + private InstanceTaskService instanceTaskService; + @Autowired + private FlowModelService flowModelService; + @Autowired + private FlowTaskService taskService; + @Autowired + private InstanceLogService logService; + @Autowired + private FlowRemindHelper flowRemindHelper; + + @Override + public ActionNodeSubmitResult action(TaskFlowParam data) { + Instance instance = instanceService.getById(data.getTaskId()); + if(instance == null){ + + throw new WorkflowException(WorkflowCode.INSTANCE_NOT_EXIST); + } + + EngineRequest erp = new EngineRequest(); + erp.setTasks(flowRemindHelper.getTasks(instance.getId(), null, TaskStatus.unhandled)); + + Model model = flowModelService.getDefinitionModel(instance.getDefinitionId()); + + LoginUser loginUser = LoginHelper.getLoginUser(); + FlowUser handleUser = new FlowUser(loginUser.getUserId(),loginUser.getNickname(),loginUser.getUsername()); + + validate(model,instance,handleUser); + + executeAction(model,instance,handleUser); + + addLog(model,instance,handleUser); + + ActionNodeSubmitResult res = transformActionResult(data,instance,handleUser); + + BeanUtils.copyProperties(data,erp); + erp.setDefinitionId(instance.getDefinitionId()); + erp.setModel(model); + erp.setHandlerUser(new FlowUser(loginUser.getUserId(),loginUser.getNickname(),loginUser.getUsername())); + EngineRequest.InstanceData instanceData = new EngineRequest.InstanceData(instance); + erp.setInstance(instanceData); + FlowSyncManager.me().executeFlowInfo(erp); + + return res; + } + + /** + * 1、处理人是实例发起人(已校验) + * 2、流程属性允许撤回流程 + * 3、当前审核节点的上一节点是发起节点且所有审核人审核状态都是未审核 + */ + private void validate(Model model, Instance instance,FlowUser handleUser) { + + //当前处理人必须是实例发起人人 + if(!instance.getCreateUser().equals(handleUser.getId())){ + + throw new WorkflowException(WorkflowCode.PERMISSION_RECALL_NO_PERMISSION); + } + + //流程状态必须是进行中 + if(!InstanceStage.processing.equals(instance.getStage())){ + + throw new WorkflowException(WorkflowCode.INSTANCE_STAGE_ERROR); + } + + //流程当前节点必须是开始节点 + if(instance.getNodeKeys().stream().anyMatch(p -> StrUtil.equals(p.getTarget(), NodeType.start.name()))){ + + throw new WorkflowException(WorkflowCode.INSTANCE_STAGE_ERROR); + } + + //流程属性允许撤回流程 + if (!model.getConfig().getRecall()) { + + throw new WorkflowException(WorkflowCode.PERMISSION_RECALL_NOT_OPEN); + } + + //当前所有任务节点的待办任务 状态都是未处理 + if (taskService.checkNodeHandledTask(instance.getId(), instance.getNodeKeys().stream().map(EdgeInfo::getTarget).collect(Collectors.toList()))) { + + throw new WorkflowException(WorkflowCode.PERMISSION_RECALL_APPROVAL_NO_PERMISSION); + } + + } + + + private void addLog(Model model,Instance instance,FlowUser flowUser){ + Node startNode = model.getNodeList().stream().filter(p -> StrUtil.equals(NodeType.start.name(),p.getId())).findFirst().get(); + + InstanceLogParam instanceLog = new InstanceLogParam(OperateType.recall, instance,startNode, false,instance.getUpdateTime()); + instanceLog.setIsBatch(false); + instanceLog.addUser(flowUser.getId(), flowUser.getName(), flowUser.getAccount()); + instanceLog.addContent(null,null); + instanceLog.setNextNodes(Arrays.asList(NodeType.start.name())); + logService.create(instanceLog); + } + + + private ActionNodeSubmitResult executeAction(Model model,Instance instance,FlowUser handleUser){ + + instance.setStage(InstanceStage.processing); + // instance.setRoutes(Lists.emptyList()); + Node startNode = model.getNodeList().stream().filter(p -> StrUtil.equals(NodeType.start.name(),p.getId())).findFirst().get(); + + instance.setNodeKeys(Arrays.asList(new EdgeInfo(instance.getNodeKeys().get(0).getTarget(), NodeType.start.name(),startNode.getName(),Arrays.asList(handleUser)))); + instance.setUpdateUser(handleUser.getId()); + instance.setUpdateTime(new Date()); + + this.instanceService.updateById(instance); + + List instanceTasks = this.instanceTaskService.list(new LambdaQueryWrapper().eq(InstanceTask::getInstanceId, instance.getId())); + + if(CollUtil.isNotEmpty(instanceTasks)){ + instanceTasks.forEach(t -> { + t.setStatus(TaskStatus.outDated.getCode()); + }); + this.instanceTaskService.updateBatchById(instanceTasks,500); + } + + InstanceTask nodeTask = new InstanceTask(); + nodeTask.setNodeKey(NodeType.start.name()); + nodeTask.setNodeName("开始节点"); + nodeTask.setInstanceId(instance.getId()); + nodeTask.setFormId(instance.getFormId()); + nodeTask.setUserId(instance.getCreateUser()); + nodeTask.setUserName(instance.getCreateName()); + nodeTask.setUserAccount(instance.getCreateAccount()); + nodeTask.setStatus(TaskStatus.unhandled.getCode()); + nodeTask.setCreateUser(instance.getCreateUser()); + nodeTask.setCreateTime(new Date()); + nodeTask.setUpdateTime(new Date()); + this.instanceTaskService.save(nodeTask); + + return null; + } + + + private ActionNodeSubmitResult transformActionResult(TaskFlowParam data,Instance instance,FlowUser handleUser){ + EngineDataResult result = new EngineDataResult(); + result.setAction(OperateType.recall); + result.setDataId(instance.getDataId()); + result.setFormInfo(data.getForm()); + result.setInstanceId(instance.getId()); + result.setFlowStage(instance.getStage().name()); + + if(instance.getStage().equals(InstanceStage.processing)){ + result.setNodeTitle(instance.getNodeKeys().get(0).getTargetName()); + Map> nodeInfo = new HashMap<>(); + nodeInfo.put("start",Arrays.asList(new EngineDataResult.NodeHandler(result.getNodeTitle(),instance.getCreateUser(),instance.getCreateName(),instance.getCreateAccount()))); + result.setNodeInfo(nodeInfo); + result.setCheckerName(null); + } + + result.setCreateId(instance.getCreateUser()); + result.setCreator(instance.getCreateName()); + result.setCreatorAccount(instance.getCreateAccount()); + result.setCreateTime(instance.getCreateTime()); + + result.setUpdatorId(handleUser.getId()); + result.setUpdatorName(handleUser.getName()); + result.setUpdatorAccount(handleUser.getAccount()); + result.setUpdateTime(instance.getUpdateTime()); + + return ActionNodeSubmitResult.success(result); + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/action/impl/RollbackHandler.java b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/action/impl/RollbackHandler.java new file mode 100644 index 0000000..2c2a7af --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/action/impl/RollbackHandler.java @@ -0,0 +1,27 @@ +package org.dromara.taskCenter.service.action.impl; + +import org.dromara.taskCenter.param.TaskFlowParam; +import org.dromara.taskCenter.service.action.TaskActionService; +import org.dromara.workflow.param.engine.EngineRequest; +import org.dromara.workflow.result.engine.ActionNodeSubmitResult; +import org.dromara.workflow.service.external.FlowInstanceService; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component("rollbackHandler") +public class RollbackHandler implements TaskActionService { + + @Autowired + private FlowInstanceService instanceService; + + @Override + public ActionNodeSubmitResult action(TaskFlowParam data) { + + EngineRequest erp = new EngineRequest(); + BeanUtils.copyProperties(data,erp); + + return instanceService.action(erp); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/action/impl/SubmitHandler.java b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/action/impl/SubmitHandler.java new file mode 100644 index 0000000..f5aabd0 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/action/impl/SubmitHandler.java @@ -0,0 +1,35 @@ +package org.dromara.taskCenter.service.action.impl; + + +import cn.hutool.core.collection.CollUtil; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.api.model.LoginUser; +import org.dromara.taskCenter.param.TaskFlowParam; +import org.dromara.taskCenter.service.action.TaskActionService; +import org.dromara.workflow.param.engine.EngineRequest; +import org.dromara.workflow.param.model.FlowUser; +import org.dromara.workflow.result.engine.ActionNodeSubmitResult; +import org.dromara.workflow.service.external.FlowInstanceService; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component("submitHandler") +public class SubmitHandler implements TaskActionService { + + @Autowired + private FlowInstanceService instanceService; + + + @Override + public ActionNodeSubmitResult action(TaskFlowParam data) { + + EngineRequest erp = new EngineRequest(); + BeanUtils.copyProperties(data,erp); + LoginUser loginUser = LoginHelper.getLoginUser(); + erp.setHandlerUser(new FlowUser(loginUser.getUserId(),loginUser.getNickname(),loginUser.getUsername(), CollUtil.newArrayList())); + + return instanceService.action(erp); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/action/impl/UrgeHandler.java b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/action/impl/UrgeHandler.java new file mode 100644 index 0000000..08cc886 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/action/impl/UrgeHandler.java @@ -0,0 +1,28 @@ +package org.dromara.taskCenter.service.action.impl; + +import org.dromara.taskCenter.param.TaskFlowParam; +import org.dromara.taskCenter.service.action.TaskActionService; +import org.dromara.workflow.result.engine.ActionNodeSubmitResult; +import org.dromara.workflow.result.engine.BaseActionResult; +import org.dromara.workflow.service.external.FlowInstanceService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component("urgeHandler") +public class UrgeHandler implements TaskActionService { + + @Autowired + private FlowInstanceService instanceService; + + @Override + public ActionNodeSubmitResult action(TaskFlowParam data) { + + BaseActionResult rsp = instanceService.urgeInstance(data.getTaskId()); + if(rsp.getSuccess()){ + return ActionNodeSubmitResult.success(); + } + + return ActionNodeSubmitResult.error(rsp.getCode(),rsp.getMessage()); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/query/TaskQueryService.java b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/query/TaskQueryService.java new file mode 100644 index 0000000..f9c93c5 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/query/TaskQueryService.java @@ -0,0 +1,15 @@ +package org.dromara.taskCenter.service.query; + + +import org.dromara.common.page.WorkflowPageResult; +import org.dromara.taskCenter.param.TaskQueryParam; +import org.dromara.taskCenter.result.TaskInfoResult; +import org.dromara.taskCenter.result.TaskPageResult; + +public interface TaskQueryService { + + WorkflowPageResult pageTask(TaskQueryParam param); + + TaskInfoResult getTask(TaskQueryParam param); + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/query/TaskQueryStrategyContext.java b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/query/TaskQueryStrategyContext.java new file mode 100644 index 0000000..249c549 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/query/TaskQueryStrategyContext.java @@ -0,0 +1,382 @@ +package org.dromara.taskCenter.service.query; + +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.Exception.ServiceException; +import org.dromara.common.page.WorkflowPageResult; +import org.dromara.common.response.WorkflowResultCode; +import org.dromara.dataManager.service.FormDataService; +import org.dromara.dataManager.widget.convert.enums.FormColumnType; +import org.dromara.dataManager.widget.convert.model.FormDataConvert; +import org.dromara.dataManager.widget.convert.service.FormDataConvertService; +import org.dromara.taskCenter.mapper.TaskMapper; +import org.dromara.taskCenter.model.SimpleFormFieldModel; +import org.dromara.taskCenter.model.SimpleFormModel; +import org.dromara.taskCenter.param.TaskQueryParam; +import org.dromara.taskCenter.result.TaskInfoResult; +import org.dromara.taskCenter.result.TaskInstanceResult; +import org.dromara.taskCenter.result.TaskPageResult; +import org.dromara.workflow.engine.enums.ESDefaultFieldConst; +import org.dromara.workflow.engine.enums.HandleUserType; +import org.dromara.workflow.engine.enums.OperateType; +import org.dromara.workflow.engine.model.setting.Field; +import org.dromara.workflow.engine.model.setting.Node; +import org.dromara.workflow.param.model.FlowUser; +import org.dromara.workflow.service.external.FlowModelService; +import org.dromara.workflow.service.internal.InstanceTaskService; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.spring.SpringUtil; +import com.alibaba.fastjson.JSON; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +@Slf4j +@Component +public class TaskQueryStrategyContext { + + //不参与待办显示的字段 6个:编辑器、分割线 子表单、关联查询、编辑器、关联数据 + private static final List unlessFields = Arrays.asList(FormColumnType.TABLE.getCode(), FormColumnType.LINK_QUERY.getCode(), + FormColumnType.DATA_LINK.getCode(),FormColumnType.EDITOR.getCode(),FormColumnType.DIVIDER.getCode(),FormColumnType.COORDINATES.getCode()); + + @Autowired + private final Map taskQueryStrategyMap = new ConcurrentHashMap(); + @Autowired + private FlowModelService modelService; + @Autowired + private InstanceTaskService instanceTaskService; + @Autowired + private TaskMapper taskMapper; + @Autowired + private FormDataService formDataService; + @Autowired + private FlowModelService flowModelService; + @Autowired + private FormDataConvertService formDataConvertService; + + /** + * 分页查询待办任务 + * @param param + * @return + */ + public WorkflowPageResult pageTask(TaskQueryParam param){ + + return taskQueryStrategyMap.get(param.getType().name()).pageTask(param); + } + + /** + * 查询待办任务详情 + * @param param + * @return + */ + public TaskInfoResult queryTask(TaskQueryParam param){ + + return taskQueryStrategyMap.get(param.getType().name()).getTask(param); + } + + + public List forwardUser(Long taskId, LinkedHashMap formData) { + + TaskInstanceResult taskInfo = taskMapper.queryInstanceByTodo(taskId); + if(taskInfo == null){ + throw new ServiceException(WorkflowResultCode.TASK_NOT_EXIST); + } + + Node nodeInfo = modelService.getDefinitionNode(taskInfo.getDefinitionId(),taskInfo.getNodeKey()); + + List flowUser = instanceTaskService.parseNodeUser(HandleUserType.TaskForwardUser, + taskInfo.getCreateUser(), + nodeInfo, formData); + + return flowUser.stream().filter(user -> !LoginHelper.getUserId().equals(user.getId())).collect(Collectors.toList()); + } + + + /** + * 待办节点字段 + * @param taskResults + * @return + */ + public void transformFormColumn(TaskQueryParam param,List taskResults){ + if(CollUtil.isEmpty(taskResults)){ + + return; + } + + Multimap multimap = ArrayListMultimap.create(); + for (TaskPageResult entry : taskResults) { + multimap.put(entry.getFormId(), entry.getDataId()); + } + Map>> formDataMap = new HashMap<>(); + multimap.keySet().forEach(formId -> { + + Collection dataIds = multimap.get(formId); + try { + List> formDatas = this.formDataService.list(formId, dataIds.toArray(new String[dataIds.size()])); + formDataMap.put(formId,formDatas); + }catch (Exception e){ + log.info("###### task query form index not exist {} ######",formId); + } + }); + + + Map formJsonMap = new HashMap<>(); + for (TaskPageResult entry : taskResults) { + formJsonMap.put(entry.getFormId(), entry.getFormJson()); + } + + Map> formFieldMap = new HashMap<>(); + + for(Long formId : formJsonMap.keySet()){ + String formJson = formJsonMap.get(formId); + List fields = JSON.parseObject(formJson, SimpleFormModel.class).getSimpleFormFieldModels(); + if(CollUtil.isNotEmpty(fields)){ + formFieldMap.put(formId,fields); + } + } + + taskResults.parallelStream().forEach(p -> { + List formDataList = new ArrayList<>(); + + + try { + List fields = formFieldMap.get(p.getFormCode()); + if (CollUtil.isNotEmpty(fields)) { + + List allFieldList = flowModelService.getNodeViewFields(p.getDefinitionId(), p.getNodeKey()); + + List viewNodeFields = allFieldList.stream().filter( s -> !unlessFields.contains(s.getType())).map(Field::getId).collect(Collectors.toList()); + + if(CollUtil.isNotEmpty(fields)){ + List viewFormFields = fields.stream().filter(s -> viewNodeFields.contains(s.getModel())).collect(Collectors.toList()); + + //待办至多显示3条冗余字段 + if(CollUtil.isNotEmpty(viewFormFields)){ + List fieldList = viewFormFields.subList(0,Math.min(viewFormFields.size(),3)); + if(CollUtil.isNotEmpty(fieldList)){ + + List fieldIds = fieldList.stream().map(SimpleFormFieldModel::getModel).collect(Collectors.toList()); + + List dataConverts = new ArrayList<>(); + Optional> taskFormDataOpt = + formDataMap.get(p.getFormCode()).stream().filter(data -> StrUtil.equals((String)data.get(ESDefaultFieldConst.ID),p.getDataId())).findFirst(); + if(taskFormDataOpt.isPresent()){ + //查询表单实例字段 + dataConverts = formDataConvertService.convert( + p.getFormId(), + taskFormDataOpt.get(), + fieldIds); + } + + for (SimpleFormFieldModel column : fieldList) { + TaskPageResult.FormDataConvert columnData = new TaskPageResult.FormDataConvert(); + columnData.setName(column.getName()); + columnData.setModel(column.getModel()); + + if (CollUtil.isNotEmpty(dataConverts)) { + Optional columnDataOptional = dataConverts.stream().filter(s -> StrUtil.equals(s.getModel(), column.getModel())).findFirst(); + + if (columnDataOptional.isPresent()) { + FormDataConvert formDataConvert = columnDataOptional.get(); + columnData.setValue(formDataConvert.getValue()); + }else{ + columnData.setValue(""); + } + } + + formDataList.add(columnData); + } + + } + } + } + } + + } catch (Exception e) { + log.error("###### task query dirty data exist:{} ######", e.getMessage()); + } + + p.setFormData(formDataList); + + if(param.getBatch()) { + Node taskNode = modelService.getDefinitionNode(p.getDefinitionId(),p.getNodeKey()); + if(taskNode != null){ + p.setBatchSubmit(taskNode.getOperation().stream().anyMatch(opr -> StrUtil.equals(OperateType.batchSubmit.name(),opr.getType()))); + } + }else{ + p.setBatchSubmit(false); + } + + }); + + } + + + /** + * 查询待办、抄送任务数量 + * @param + * @return + */ + public Map count() { + Map result = new HashMap<>(); + Integer ccTaskCount = SpringUtil.getBean(TaskMapper.class).getMyCcTaskCount(LoginHelper.getUserId()); + Integer todoTaskCount = SpringUtil.getBean(TaskMapper.class).getMyUndoTaskCount(LoginHelper.getUserId()); + result.put("todo",todoTaskCount); + result.put("cc",ccTaskCount); + + return result; + } + + public Map allCount(Long appId) { + Map result = new HashMap<>(); + Integer ccTaskCount = SpringUtil.getBean(TaskMapper.class).getMyCcTaskCount(LoginHelper.getUserId()); + Integer todoTaskCount = SpringUtil.getBean(TaskMapper.class).getMyUndoTaskCount(LoginHelper.getUserId()); + Integer handlerTaskCount = 0; + result.put("todo",todoTaskCount); + result.put("cc",ccTaskCount); + result.put("handler",handlerTaskCount); + + return result; + } + + /** + * 查询待办数量 + * @param + * @return + */ + public Integer countTodo() { + return SpringUtil.getBean(TaskMapper.class).getMyUndoTaskCount(LoginHelper.getUserId()); + } + + public Integer countTodoByUserId(Long userId){ + return taskMapper.getMyUndoTaskCount( userId); + } + + /** + * 查询待办任务填报数据 + * @param formCode + * @param dataId + * @param fields + * @return + */ + public Map queryTaskData(Long formId,String formCode,Long dataId,List fields){ + + List systemFields = Arrays.asList(ESDefaultFieldConst._ID,ESDefaultFieldConst.DID,ESDefaultFieldConst.ID, + ESDefaultFieldConst.OWNER,ESDefaultFieldConst.CREATOR,ESDefaultFieldConst.CREATOR_ACCOUNT,ESDefaultFieldConst.CREATE_TIME, + ESDefaultFieldConst.UPDATE_TIME,ESDefaultFieldConst.UPDATOR_NAME,ESDefaultFieldConst.DELETED, + ESDefaultFieldConst.FLOW_INSTANCE_ID, ESDefaultFieldConst.FLOW_STAGE, + ESDefaultFieldConst.FLOW_TASK_ID, ESDefaultFieldConst.FLOW_NODE_TITLE, ESDefaultFieldConst.FLOW_CHECKER_NAME + ); + + if(CollUtil.isNotEmpty(fields)){ + List viewFields = fields.stream().filter(Field::getView).map(Field::getId).collect(Collectors.toList()); + viewFields.addAll(systemFields); + if(CollUtil.isNotEmpty(viewFields)){ + String[] fieldsArrary = new String[viewFields.size()]; + viewFields.toArray(fieldsArrary); + return SpringUtil.getBean(FormDataService.class).getFormDataById(formId,dataId,fieldsArrary); + } + } + + return SpringUtil.getBean(FormDataService.class).getFormDataById(formId,dataId); + } + + + + /** + * 将嵌套的流程字段拍平转成标准的表单字段权限 + * + * @param fields + * @return + */ + public List flatWorkflowNodeFields(List fields) { + if (CollUtil.isEmpty(fields)) { + return Collections.emptyList(); + } + List totalFields = new ArrayList<>(); + recurseNodeFields(totalFields, fields); + + return totalFields.stream().map(f -> { + SimpleFormFieldModel sfm = new SimpleFormFieldModel(f.getId()); + sfm.setType(f.getType()); + sfm.getOptions().setFieldPermission(!f.getView(), !f.getEdit()); + return sfm; + }).collect(Collectors.toList()); + } + + private void recurseNodeFields(List totalFields, List fields) { + if (CollUtil.isEmpty(fields)) { + return; + } + fields.forEach(p -> { + totalFields.add(p); + if (CollUtil.isNotEmpty(p.getChildren())) { + recurseNodeFields(totalFields, p.getChildren()); + } + }); + } + + + + /** + * 将流程字段权限转标准的表单字段权限 + * + * @param fields + * @return + */ + public List convertFlowFieldPermission(List fields) { + if (fields != null && !fields.isEmpty()) { + List result = new LinkedList<>(); + fields.forEach(f -> { + SimpleFormFieldModel sfm = new SimpleFormFieldModel(f.getId()); + sfm.setType(f.getType()); + sfm.getOptions().setFieldPermission(!f.getView(), !f.getEdit()); + result.add(sfm); + }); + return result; + } + + return null; + } + + /** + * 查看已处理的待办任务详情-字段权限全部不可编辑 + * @param fields + * @return + */ + public static List convertOverdueFlowFieldPermission(List fields) { + if (fields != null && !fields.isEmpty()) { + List result = new LinkedList<>(); + fields.forEach(f -> { + SimpleFormFieldModel sfm = new SimpleFormFieldModel(f.getId()); + sfm.setType(f.getType()); + sfm.getOptions().setFieldPermission(!f.getView(), true); + + if (StrUtil.equals(f.getType(), "table")) { + List tableColumns = fields.stream().filter(p -> StrUtil.equals(p.getParentId(), f.getId())).collect(Collectors.toList()); + if (CollUtil.isNotEmpty(tableColumns)) { + List tableChildColumns = convertOverdueFlowFieldPermission(tableColumns); + sfm.setTableColumns(tableChildColumns); + } + + // 如果老的流程子表单字段没有定义过操作权限,默认为全不可编辑,否则用流程定义中的子表单操作权限 + if(f.getTableOperate() != null){ + sfm.getOptions().setTableOperate(f.getTableOperate().getCreatable(), f.getTableOperate().getInsertable(), f.getTableOperate().getEditable(), f.getTableOperate().getDeletable()); + }else { + sfm.getOptions().setTableOperate(true, true, true, true); + } + } + result.add(sfm); + }); + return result; + } + + return null; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/query/impl/CcService.java b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/query/impl/CcService.java new file mode 100644 index 0000000..42597f3 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/query/impl/CcService.java @@ -0,0 +1,123 @@ +package org.dromara.taskCenter.service.query.impl; + + +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.Exception.ServiceException; +import org.dromara.common.page.WorkflowPageFactory; +import org.dromara.common.page.WorkflowPageResult; +import org.dromara.common.response.WorkflowResultCode; +import org.dromara.dataManager.service.FormDataService; +import org.dromara.formMaking.results.FormSourceResult; +import org.dromara.formMaking.service.FormSourceService; +import org.dromara.taskCenter.mapper.TaskMapper; +import org.dromara.taskCenter.model.SimpleFormFieldModel; +import org.dromara.taskCenter.model.SimpleFormModel; +import org.dromara.taskCenter.param.TaskQueryParam; +import org.dromara.taskCenter.result.TaskInfoResult; +import org.dromara.taskCenter.result.TaskInstanceResult; +import org.dromara.taskCenter.result.TaskPageResult; +import org.dromara.taskCenter.service.query.TaskQueryService; +import org.dromara.taskCenter.service.query.TaskQueryStrategyContext; +import org.dromara.workflow.engine.model.setting.Model; +import org.dromara.workflow.engine.model.setting.Node; +import org.dromara.workflow.engine.model.setting.Operate; +import org.dromara.workflow.service.external.FlowModelService; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.*; + +@Component("cc") +public class CcService extends TaskQueryStrategyContext implements TaskQueryService { + + @Autowired + private FormSourceService formSourceService; + @Autowired + private TaskMapper taskMapper; + @Autowired + private FlowModelService flowModelService; + @Autowired + private FormDataService formDataService; + + @Override + public WorkflowPageResult pageTask(TaskQueryParam param) { + Page taskList = taskMapper.listMyCcTask(WorkflowPageFactory.customPage(param.getShowPageNation()),param, LoginHelper.getUserId()); + // super.transformFormColumn(param,taskList.getRecords()); + + return new WorkflowPageResult<>(taskList); + } + + @Override + public TaskInfoResult getTask(TaskQueryParam param) { + TaskInstanceResult task = taskMapper.queryInstanceByCc(param.getTaskId()); + + if(task == null){ + + throw new ServiceException(WorkflowResultCode.TASK_NOT_EXIST); + } + + FormSourceResult formDetail = formSourceService.getFormSourceById(task.getFormId()); + + if(formDetail == null){ + + throw new ServiceException(WorkflowResultCode.FORM_NOT_EXIST); + } + + TaskInfoResult result = new TaskInfoResult(task,formDetail); + + Model model = flowModelService.getDefinitionModel(task.getDefinitionId()); + + Optional optional = model.getNodeList().stream().filter(p -> StrUtil.equals(task.getNodeKey(),p.getId())).findFirst(); + if(optional.isPresent()) { + Node node = optional.get(); + + // 待办任务表单数据 + Map taskData = formDataService.getFormDataById(task.getFormId(),task.getDataId()); + if(taskData == null){ + throw new ServiceException(WorkflowResultCode.FORM_NOT_EXIST); + } + + result.setData(taskData); + + SimpleFormModel simpleFormModel = JSONUtil.toBean(formDetail.getFormJson(), SimpleFormModel.class);; + + // 重置表单字段权限 + if (simpleFormModel.getList() != null && !simpleFormModel.getList().isEmpty()) { + List flowFields = convertFlowFieldPermission(node.getField()); + + simpleFormModel.resetFieldsPermission(flowFields); + } + + // 表单formJson 信息 + result.getForm().setFormJson(JSONUtil.toJsonStr(simpleFormModel)); + + //判断当前抄送任务所在节点是抄送节点还是审核节点 + node.setOperation(new ArrayList<>()); + if(StrUtil.startWith(node.getId(),"task")){ + //审核节点开启了提交并打印按钮 + Optional printOpt = node.getOperation().stream().filter(p -> StrUtil.equals("submitByPrint", p.getType())).findFirst(); + if (printOpt.isPresent()) { + node.setOperation(Arrays.asList(Operate.printOperate())); + } + }else if(StrUtil.startWith(node.getId(),"cc")){ + //抄送节点开启了查看时允许打印 + if(node.getPrint() != null && node.getPrint() == true ){ + node.setOperation(Arrays.asList(Operate.printOperate())); + } + } + + node.setSuggest(null); + result.setNode(node); + } + + result.setLogVisible(model.getConfig().getWorkflowLog()); + + return result; + } + + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/query/impl/HandleService.java b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/query/impl/HandleService.java new file mode 100644 index 0000000..476df20 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/query/impl/HandleService.java @@ -0,0 +1,135 @@ +package org.dromara.taskCenter.service.query.impl; + + +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.Exception.ServiceException; +import org.dromara.common.page.WorkflowPageFactory; +import org.dromara.common.page.WorkflowPageResult; +import org.dromara.common.response.WorkflowResultCode; +import org.dromara.dataManager.service.FormDataService; +import org.dromara.formMaking.results.FormSourceResult; +import org.dromara.formMaking.service.FormSourceService; +import org.dromara.taskCenter.mapper.TaskMapper; +import org.dromara.taskCenter.model.SimpleFormFieldModel; +import org.dromara.taskCenter.model.SimpleFormModel; +import org.dromara.taskCenter.param.TaskQueryParam; +import org.dromara.taskCenter.result.TaskInfoResult; +import org.dromara.taskCenter.result.TaskInstanceResult; +import org.dromara.taskCenter.result.TaskPageResult; +import org.dromara.taskCenter.service.query.TaskQueryService; +import org.dromara.taskCenter.service.query.TaskQueryStrategyContext; +import org.dromara.workflow.engine.domain.InstanceTask; +import org.dromara.workflow.engine.enums.TaskStatus; +import org.dromara.workflow.engine.model.setting.Model; +import org.dromara.workflow.engine.model.setting.Node; +import org.dromara.workflow.engine.model.setting.Operate; +import org.dromara.workflow.service.external.FlowModelService; +import org.dromara.workflow.service.internal.InstanceTaskService; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +@Component("handle") +public class HandleService extends TaskQueryStrategyContext implements TaskQueryService { + @Autowired + private FormSourceService formSourceService; + @Autowired + private TaskMapper taskMapper; + @Autowired + private InstanceTaskService instanceTaskService; + @Autowired + private FlowModelService flowModelService; + @Autowired + private FormDataService formDataService; + + + @Override + public WorkflowPageResult pageTask(TaskQueryParam param) { + Page taskList = taskMapper.listMyHandleTask(WorkflowPageFactory.customPage(param.getShowPageNation()), param, LoginHelper.getUserId()); + // super.transformFormColumn(param,taskList.getRecords()); + + return new WorkflowPageResult<>(taskList); + } + + + @Override + public TaskInfoResult getTask(TaskQueryParam param) { + TaskInstanceResult task = taskMapper.queryInstanceByTodo(param.getTaskId()); + + if(task == null){ + + throw new ServiceException(WorkflowResultCode.TASK_NOT_EXIST); + } + + FormSourceResult formDetail = formSourceService.getFormSourceById(task.getFormId()); + + if(formDetail == null){ + + throw new ServiceException(WorkflowResultCode.FORM_NOT_EXIST); + } + + //校验当前登录用户是否处理过待办任务 + List handledTasks = instanceTaskService.listInstanceNodeUserTask(task.getInstanceId(),task.getNodeKey(),LoginHelper.getUserId(), TaskStatus.handled); + if(CollUtil.isEmpty(handledTasks)){ + + throw new ServiceException(WorkflowResultCode.USER_NOT_PERMISSION); + } + + TaskInfoResult result = new TaskInfoResult(task,formDetail); + + Model model = flowModelService.getDefinitionModel(task.getDefinitionId()); + + Optional nodeOptional = model.getNodeList().stream().filter(p -> StrUtil.equals(task.getNodeKey(),p.getId())).findFirst(); + if(!nodeOptional.isPresent()){ + + throw new ServiceException(WorkflowResultCode.FLOW_DEFINITION_NODE_NOT_EXIST); + } + + Node taskNode = nodeOptional.get(); + + // 待办任务表单数据 + Map taskData = formDataService.getFormDataById(task.getFormId(),task.getDataId()); + + if(taskData == null){ + throw new ServiceException(WorkflowResultCode.DATASOURCE_NOT_EXIST); + } + + result.setData(taskData); + + SimpleFormModel simpleFormModel = JSONUtil.toBean(formDetail.getFormJson(), SimpleFormModel.class);; + + // 重置表单字段权限 + if (simpleFormModel.getList() != null && !simpleFormModel.getList().isEmpty()) { + List flowFields = convertFlowFieldPermission(taskNode.getField()); + + simpleFormModel.resetFieldsPermission(flowFields); + } + + // 表单formJson 信息 + result.getForm().setFormJson(JSONUtil.toJsonStr(simpleFormModel)); + + taskNode.setSuggest(null); + List operateList = new ArrayList<>(); + + //是否允许打印 + Optional printOpt = taskNode.getOperation().stream().filter(p -> StrUtil.equals("submitByPrint", p.getType())).findFirst(); + printOpt.ifPresent(operate -> operateList.add(Operate.printOperate())); + + taskNode.setOperation(operateList); + + result.setNode(taskNode); + + result.setLogVisible(model.getConfig().getWorkflowLog()); + + return result; + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/query/impl/StartService.java b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/query/impl/StartService.java new file mode 100644 index 0000000..9d5fc67 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/query/impl/StartService.java @@ -0,0 +1,201 @@ +package org.dromara.taskCenter.service.query.impl; + + +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.Exception.ServiceException; +import org.dromara.common.page.WorkflowPageFactory; +import org.dromara.common.page.WorkflowPageResult; +import org.dromara.common.response.WorkflowResultCode; +import org.dromara.dataManager.service.FormDataService; +import org.dromara.formMaking.results.FormSourceResult; +import org.dromara.formMaking.service.FormSourceService; +import org.dromara.taskCenter.mapper.TaskMapper; +import org.dromara.taskCenter.model.SimpleFormFieldModel; +import org.dromara.taskCenter.model.SimpleFormModel; +import org.dromara.taskCenter.param.TaskQueryParam; +import org.dromara.taskCenter.result.TaskInfoResult; +import org.dromara.taskCenter.result.TaskPageResult; +import org.dromara.taskCenter.service.query.TaskQueryService; +import org.dromara.taskCenter.service.query.TaskQueryStrategyContext; +import org.dromara.workflow.engine.domain.Instance; +import org.dromara.workflow.engine.domain.InstanceTask; +import org.dromara.workflow.engine.enums.InstanceStage; +import org.dromara.workflow.engine.enums.NodeType; +import org.dromara.workflow.engine.enums.OperateType; +import org.dromara.workflow.engine.model.setting.Model; +import org.dromara.workflow.engine.model.setting.Node; +import org.dromara.workflow.engine.model.setting.Operate; +import org.dromara.workflow.service.external.FlowInstanceService; +import org.dromara.workflow.service.external.FlowModelService; +import org.dromara.workflow.service.external.FlowTaskService; +import org.dromara.workflow.service.internal.InstanceService; +import org.dromara.workflow.service.internal.InstanceTaskService; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.spring.SpringUtil; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.google.common.collect.Sets; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.*; +import java.util.stream.Collectors; +import org.dromara.workflow.engine.domain.base.EdgeInfo; +@Component("start") +public class StartService extends TaskQueryStrategyContext implements TaskQueryService { + + @Autowired + private FormSourceService formDetailService; + @Autowired + private FlowModelService flowModelService; + @Autowired + private FlowInstanceService flowInstanceService; + @Autowired + private InstanceTaskService instanceTaskService; + @Autowired + private TaskMapper taskMapper; + + @Override + public WorkflowPageResult pageTask(TaskQueryParam param) { + Page taskList = taskMapper.listMyStartTaskV2(WorkflowPageFactory.customPage(param.getShowPageNation()), param, LoginHelper.getUserId()); + super.transformFormColumn(param,taskList.getRecords()); + + return new WorkflowPageResult<>(taskList); + } + + + @Override + public TaskInfoResult getTask(TaskQueryParam param) { + + Instance instance = flowInstanceService.getInstance(param.getTaskId()); + if(instance == null){ + //兼容已经发出的任务链接 + InstanceTask instanceTask = instanceTaskService.getById(param.getTaskId()); + if(instanceTask != null && instanceTask.getUserId().equals(LoginHelper.getUserId())){ + instance = flowInstanceService.getInstance(instanceTask.getInstanceId()); + }else{ + throw new ServiceException(WorkflowResultCode.TASK_NOT_EXIST); + } + } + + FormSourceResult formDetail = formDetailService.getFormSourceById(instance.getFormId()); + + if(formDetail == null){ + + throw new ServiceException(WorkflowResultCode.FORM_NOT_EXIST); + } + + // 废弃:校验当前登录用户是否是这条待办任务实例发起人 + // 新版:只要经办过就能看 + if(!amIInThisFlow(instance.getId(), instance.getCreateUser())){ + throw new ServiceException(WorkflowResultCode.USER_NOT_PERMISSION); + } + + TaskInfoResult result = new TaskInfoResult(instance,formDetail); + + Model model = flowModelService.getDefinitionModel(instance.getDefinitionId()); + Node startNode = model.getNodeList().stream().filter(p -> StrUtil.equals(p.getId(),NodeType.start.name())).findFirst().get(); + + // 待办任务表单数据 + Map taskData = SpringUtil.getBean(FormDataService.class).getFormDataById(instance.getFormId(),result.getTask().getDataId()); + + if(taskData == null){ + throw new ServiceException(WorkflowResultCode.DATASOURCE_NOT_FOUND); + } + + result.setData(taskData); + + SimpleFormModel simpleFormModel = JSONUtil.toBean(formDetail.getFormJson(), SimpleFormModel.class);; + + // 重置表单字段权限 + if (simpleFormModel.getList() != null && !simpleFormModel.getList().isEmpty()) { + List flowFields = convertFlowFieldPermission(startNode.getField()); + + simpleFormModel.resetFieldsPermission(flowFields); + } + + // 表单formJson 信息 + result.getForm().setFormJson(JSONUtil.toJsonStr(simpleFormModel)); + + List operateList = new ArrayList<>(); + + //流程属性开启催办 + 流程处于进行中 + 流程激活节点在开始节点 + if(ObjectUtil.equal(true,model.getConfig().getUrge()) && + InstanceStage.processing.equals(instance.getStage()) && + instance.getNodeKeys().stream().noneMatch(p -> StrUtil.equals(p.getTarget(),NodeType.start.name()))){ + operateList.add(new Operate(OperateType.urge.name(),OperateType.urge.getName(), false)); + } + + //是否允许撤回 + if(checkUserRecall(instance.getId(),startNode) && model.getConfig().getRecall() && !InstanceStage.completed.equals(instance.getStage()) + && instance.getNodeKeys().stream().noneMatch(p -> StrUtil.equals(p.getTarget(),NodeType.start.name()))){ + operateList.add(new Operate(OperateType.recall.name(),OperateType.recall.getName(), false)); + } + + // 是否允许取消 + if (checkUserCancel(instance.getId(), startNode) && model.getConfig().getCancel() + && !InstanceStage.completed.equals(instance.getStage()) + && !InstanceStage.finished.equals(instance.getStage()) && instance.getNodeKeys().stream() + .noneMatch(p -> StrUtil.equals(p.getTarget(), NodeType.start.name()))) { + operateList.add(new Operate(OperateType.cancel.name(), OperateType.cancel.getName(), true)); + } + + //是否允许打印 + Optional printOpt = startNode.getOperation().stream().filter(p -> StrUtil.equals("submitByPrint", p.getType())).findFirst(); + printOpt.ifPresent(operate -> operateList.add(Operate.printOperate())); + + startNode.setOperation(operateList); + + result.setNode(startNode); + + result.setLogVisible(model.getConfig().getWorkflowLog()); + + return result; + } + + private boolean checkUserRecall(Long instanceId,Node startNode) { + Instance instance = SpringUtil.getBean(InstanceService.class).getById(instanceId); + //判断是否可以撤回 -> 实例当前节点没有处理人 + Set currentKeys = instance.getNodeKeys().stream().map(EdgeInfo::getTarget).collect(Collectors.toSet()); + + Set nextNodeKeys = + startNode.getNext().stream().map(Node.EdgeCondition::getEdge).map(EdgeInfo::getTarget).collect(Collectors.toSet()); + + //当前节点存在,但开始节点不存在 + Sets.SetView differNodes = Sets.difference(currentKeys, nextNodeKeys); + if(CollUtil.isEmpty(differNodes) && CollUtil.isNotEmpty(currentKeys)){ + //当前节点所有负责人都没有审批过 + if(!SpringUtil.getBean(FlowTaskService.class).checkNodeHandledTask(instance.getId(),new ArrayList<>(currentKeys))){ + + return true; + } + } + + return false; + } + + private boolean checkUserCancel(Long instanceId, Node startNode) { + Instance instance = SpringUtil.getBean(InstanceService.class).getById(instanceId); + // 判断是否可以撤回 -> 实例当前节点没有处理人 + Set currentKeys = instance.getNodeKeys().stream().map(EdgeInfo::getTarget).collect(Collectors.toSet()); + if (CollUtil.isNotEmpty(currentKeys)) { + return true; + } + return false; + } + private boolean amIInThisFlow(Long instanceId, Long instanceCreator) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(InstanceTask::getInstanceId,instanceId); + wrapper.orderByDesc(InstanceTask::getCreateTime); + List tasks = instanceTaskService.list(wrapper); + List handlers = new ArrayList<>(); + if (tasks != null) { + handlers = tasks.stream().map(t -> t.getUserId()).distinct().collect(Collectors.toList()); + } + handlers.add(instanceCreator); + return handlers.contains(LoginHelper.getUserId()); + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/query/impl/TodoService.java b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/query/impl/TodoService.java new file mode 100644 index 0000000..dfce755 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/taskCenter/service/query/impl/TodoService.java @@ -0,0 +1,148 @@ +package org.dromara.taskCenter.service.query.impl; + +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.Exception.ServiceException; +import org.dromara.common.page.WorkflowPageFactory; +import org.dromara.common.page.WorkflowPageResult; +import org.dromara.common.response.WorkflowResultCode; +import org.dromara.dataManager.service.FormDataService; +import org.dromara.formMaking.results.FormSourceResult; +import org.dromara.formMaking.service.FormSourceService; +import org.dromara.taskCenter.mapper.TaskMapper; +import org.dromara.taskCenter.model.SimpleFormFieldModel; +import org.dromara.taskCenter.model.SimpleFormModel; +import org.dromara.taskCenter.param.TaskQueryParam; +import org.dromara.taskCenter.result.TaskInfoResult; +import org.dromara.taskCenter.result.TaskInstanceResult; +import org.dromara.taskCenter.result.TaskPageResult; +import org.dromara.taskCenter.service.query.TaskQueryService; +import org.dromara.taskCenter.service.query.TaskQueryStrategyContext; +import org.dromara.workflow.engine.enums.NodeType; +import org.dromara.workflow.engine.enums.OperateType; +import org.dromara.workflow.engine.enums.TaskStatus; +import org.dromara.workflow.engine.model.setting.Model; +import org.dromara.workflow.engine.model.setting.Node; +import org.dromara.workflow.service.external.FlowModelService; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +@Slf4j +@Component("todo") +public class TodoService extends TaskQueryStrategyContext implements TaskQueryService { + @Autowired + private FormSourceService formSourceService; + @Autowired + private TaskMapper taskMapper; + @Autowired + private FlowModelService flowModelService; + @Autowired + private FormDataService formDataService; + + @Override + public WorkflowPageResult pageTask(TaskQueryParam param) { + Page taskList = taskMapper.listMyUndoTask(WorkflowPageFactory.customPage(param.getShowPageNation()), param, + LoginHelper.getUserId()); + // super.transformFormColumn(param,taskList.getRecords()); + + return new WorkflowPageResult<>(taskList); + } + + + @Override + public TaskInfoResult getTask(TaskQueryParam param) { + TaskInstanceResult task = taskMapper.queryInstanceByTodo(param.getTaskId()); + + if(task == null){ + + throw new ServiceException(WorkflowResultCode.TASK_NOT_EXIST); + } + + //校验当前登录用户是否有权限查看当前待办任务 + if(! LoginHelper.getUserId().equals(task.getHandleUserId())){ + + throw new ServiceException(WorkflowResultCode.USER_NOT_PERMISSION); + } + FormSourceResult formDetail = formSourceService.getFormSourceById(task.getFormId()); + if(formDetail == null){ + + throw new ServiceException(WorkflowResultCode.FORM_NOT_EXIST); + } + + TaskInfoResult result = new TaskInfoResult(task,formDetail); + + Model model = flowModelService.getDefinitionModel(task.getDefinitionId()); + Optional optional = model.getNodeList().stream().filter(p -> StrUtil.equals(task.getNodeKey(),p.getId())).findFirst(); + if (optional.isPresent()) { + + Node node = optional.get(); + + // 待办任务表单数据 + Map taskData = formDataService.getFormDataById(task.getFormId(),task.getDataId()); + if(taskData == null){ + throw new ServiceException(WorkflowResultCode.FORM_DATA_HAS_DELETE); + } + + result.setData(taskData); + + SimpleFormModel simpleFormModel = JSONUtil.toBean(formDetail.getFormJson(), SimpleFormModel.class);; + + // 重置表单字段权限 + if (simpleFormModel.getList() != null && !simpleFormModel.getList().isEmpty()) { + if(TaskStatus.unhandled.getCode().equals(task.getStatus())) { + List nodeFlatFields = flatWorkflowNodeFields(node.getField()); + simpleFormModel.recurResetFieldsPermission(nodeFlatFields); + }else{ + List flowFields = convertOverdueFlowFieldPermission(node.getField()); + simpleFormModel.resetFieldsPermission(flowFields); + } + } + + // 表单formJson 信息 + result.getForm().setFormJson(JSONUtil.toJsonStr(simpleFormModel)); + + if(TaskStatus.unhandled.getCode().equals(task.getStatus())) { + //替换提交按钮类型(approved(已废弃) -> submit) + if (node.getOperation().stream().anyMatch(p -> StrUtil.equals(OperateType.submit.getCode(), p.getType()))) { + node.setOperation(node.getOperation().stream().filter(p -> !StrUtil.equals("approved", p.getType())).collect(Collectors.toList())); + } + + //兼容历史按钮类型 + node.getOperation().forEach(opr -> { + if(StrUtil.equals("approved",opr.getType())){ + opr.setType(OperateType.submit.name()); + } + if(StrUtil.equals("print",opr.getType())){ + opr.setType(OperateType.submitByPrint.name()); + } + }); + + //流程实例如果是匿名提交 && 回退节点为开始节点:不显示回退节点 + if(task.getCreateUser() == -1L && StrUtil.equals(NodeType.start.name(),node.getRollbackKey())){ + node.setOperation(node.getOperation().stream().filter(p -> !StrUtil.equals(OperateType.rollback.getCode(),p.getType())).collect(Collectors.toList())); + } + }else{ + node.setOperation(new ArrayList<>()); + } + + result.setNode(node); + } + + result.setLogVisible(model.getConfig().getWorkflowLog()); + + return result; + } + + + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/api/DefinitionController.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/api/DefinitionController.java new file mode 100644 index 0000000..562abb5 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/api/DefinitionController.java @@ -0,0 +1,126 @@ +package org.dromara.workflow.api; + + +import org.dromara.common.response.WorkflowResponseData; +import org.dromara.common.response.WorkflowResult; +import org.dromara.workflow.param.model.DefinitionParam; +import org.dromara.workflow.service.external.FlowModelService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +/** + * @Description: 表单工作流 + **/ +@RestController +@RequestMapping("/manager/form/{sourceId}/workflow") +public class DefinitionController { + + @Autowired + private FlowModelService flowModelService; + + /** + * 查询表单流程定义 + * + * @param sourceId + * @return + */ + @GetMapping("/info") + public WorkflowResponseData getFormModel( + @PathVariable(value = "sourceId") Long sourceId + ) { + + return WorkflowResult.success(this.flowModelService.getByForm(sourceId)); + } + + /** + * 查询单个流程定义 + * + * @param sourceId + * @return + */ + @GetMapping("/info/{id}") + public WorkflowResponseData getOne( + @PathVariable(value = "sourceId") Long sourceId , + @PathVariable(value = "id") Long id + ) { + + return WorkflowResult.success(this.flowModelService.getByVersion(id)); + } + + /** + * 创建流程定义 + * + * @param app + * @param sourceId + * @return + */ + @PutMapping("/info") + public WorkflowResponseData create( + @PathVariable(value = "app") String app, + @PathVariable(value = "sourceId") Long sourceId, + @RequestBody DefinitionParam param + ) { + + return WorkflowResult.success(this.flowModelService.create(param)); + } + + + /** + * 更新流程定义 + * + * @param app + * @param sourceId + * @return + */ + @PostMapping("/info") + public WorkflowResponseData update( + @PathVariable(value = "app") Long app, + @PathVariable(value = "sourceId") Long sourceId, + @RequestBody DefinitionParam param + ) { + + return WorkflowResult.success(this.flowModelService.update(param)); + } + + /** + * 删除流程定义 + * + * @param app + * @param sourceId + * @return + */ + @DeleteMapping("/info") + public WorkflowResponseData delete( + @PathVariable(value = "app") String app, + @PathVariable(value = "sourceId") Long sourceId, + @RequestBody DefinitionParam param + ) { + + return WorkflowResult.success(this.flowModelService.delete(param)); + } + + /** + * 激活流程定义 + * + * @param sourceId + * @return + */ + @PostMapping("/active") + public WorkflowResponseData active( + @PathVariable(value = "sourceId") Long sourceId, + @RequestBody DefinitionParam param + ) { + + return WorkflowResult.success(this.flowModelService.active(param)); + } + + @GetMapping("/nodeTitles") + public WorkflowResponseData listNodeTitles( + @PathVariable(value = "sourceId") Long sourceId + ) { + + return WorkflowResult.success(flowModelService.listNodeTitles(sourceId)); + } + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/api/InstanceController.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/api/InstanceController.java new file mode 100644 index 0000000..8008c89 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/api/InstanceController.java @@ -0,0 +1,142 @@ +package org.dromara.workflow.api; + + +import org.dromara.common.response.WorkflowResponseData; +import org.dromara.common.response.WorkflowResult; +import org.dromara.workflow.engine.enums.OperateType; +import org.dromara.workflow.engine.exception.WorkflowException; +import org.dromara.workflow.service.external.FlowInstanceService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Arrays; + +@Slf4j +@RequestMapping("/workflow/instance") +@RestController +public class InstanceController { + + @Autowired + private FlowInstanceService instanceService; + + /** + * 查询流程实例已经处理的节点信息 + * @param instanceId + * @return + */ + @GetMapping("/{instanceId}/node/handled") + public WorkflowResponseData listInstanceHandledNodes(@PathVariable("instanceId")Long instanceId){ + try{ + + return WorkflowResult.success(instanceService.listInstanceHandledNodes(instanceId)); + }catch (WorkflowException e){ + + log.error("###### workflow 查询实例已处理的节点信息异常:{} ######",Arrays.toString(e.getStackTrace())); + return WorkflowResult.error(e.getCode(),e.getMessage()); + } + } + + /** + * 查询流程实例正在激活的节点信息 + * @param instanceId + * @return + */ + @GetMapping("/{instanceId}/node/active") + public WorkflowResponseData listInstanceActiveNodes(@PathVariable("instanceId")Long instanceId){ + try{ + + return WorkflowResult.success(instanceService.listInstanceActiveNodes(instanceId)); + }catch (WorkflowException e){ + + log.error("###### workflow 查询实例已处理的节点信息异常:{} ######",Arrays.toString(e.getStackTrace())); + return WorkflowResult.error(e.getCode(),e.getMessage()); + } + } + + /** + * 查询实例节点的审核人信息(优先查询实例节点调整负责人,没有的话查询实例当前节点流转负责人) + * @param instanceId + * @return + */ + @GetMapping("/{instanceId}/node/{nodeId}/checker") + public WorkflowResponseData listInstanceNodeCheckers(@PathVariable("instanceId")Long instanceId, + @PathVariable("nodeId")String nodeId){ + try{ + + return WorkflowResult.success(instanceService.listInstanceNodeChecker(instanceId,nodeId)); + }catch (WorkflowException e){ + + log.error("###### workflow 查询实例节点的审核人信息异常:{} ######",Arrays.toString(e.getStackTrace())); + return WorkflowResult.error(e.getCode(),e.getMessage()); + } + } + + + /** + * 实例流程图 + */ + @GetMapping("/chart/{instanceId}") + public WorkflowResponseData chart(@PathVariable("instanceId")Long instanceId){ + try{ + + return WorkflowResult.success(instanceService.getChartV2(instanceId)); + }catch (WorkflowException e){ + e.printStackTrace(); + return WorkflowResult.error(e.getCode(),e.getMessage()); + } + } + + + /** + * 实例流程动态 + */ + @GetMapping(value = "/log/{instanceId}") + public WorkflowResponseData log(@PathVariable("instanceId")Long instanceId){ + try{ + + return WorkflowResult.success(instanceService.listLog(instanceId)); + }catch (WorkflowException e){ + e.printStackTrace(); + return WorkflowResult.error(e.getCode(),e.getMessage()); + } + } + + /** + * 实例的流程日志 + */ + @GetMapping(value = "/instancelog/{instanceId}/{type}") + public WorkflowResponseData logOfInstance(@PathVariable("instanceId")Long instanceId, @PathVariable("type")String type){ + try{ + OperateType action = OperateType.valueOf(type); + + return WorkflowResult.success(instanceService.listLogByInstance(instanceId,action)); + } + catch (WorkflowException e){ + e.printStackTrace(); + return WorkflowResult.error(e.getCode(),e.getMessage()); + } + } + + /** + * 实例流程动态(待办任务) + */ + @GetMapping(value = "/tasklog/{taskId}/{type}") + public WorkflowResponseData logOfTask(@PathVariable("taskId")Long taskId, @PathVariable("type")String type){ + try{ + OperateType action = OperateType.valueOf(type); + return WorkflowResult.success(instanceService.listLogByTask(taskId,action)); + } + catch (WorkflowException e){ + e.printStackTrace(); + return WorkflowResult.error(e.getCode(),e.getMessage()); + } + } + + +} + + diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/callback/FlowCallback.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/callback/FlowCallback.java new file mode 100644 index 0000000..47b35e0 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/callback/FlowCallback.java @@ -0,0 +1,11 @@ +package org.dromara.workflow.engine.callback; + +import org.dromara.workflow.param.engine.EngineRequest; +import org.dromara.workflow.result.engine.ActionAutoSubmitResult; +import org.dromara.workflow.result.engine.EngineActionResult; + +public interface FlowCallback { + + ActionAutoSubmitResult callback(EngineRequest request, EngineActionResult result); + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/domain/Definition.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/domain/Definition.java new file mode 100644 index 0000000..9f523d2 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/domain/Definition.java @@ -0,0 +1,30 @@ +package org.dromara.workflow.engine.domain; + +import org.dromara.workflow.engine.domain.base.FlowBase; +import org.dromara.workflow.engine.enums.DefinitionStage; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * @Description: server + **/ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_workflow_definition") +public class Definition extends FlowBase { + + @TableId(type = IdType.AUTO) + private Long id; + + private Long formId; + + private String snapshots; + + private Integer version; + + //流程定义类型(running:启用中 history:历史流程 desgin: 设计中 ) + private DefinitionStage stage; +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/domain/Instance.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/domain/Instance.java new file mode 100644 index 0000000..dfc6c72 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/domain/Instance.java @@ -0,0 +1,88 @@ +package org.dromara.workflow.engine.domain; + +import org.dromara.workflow.engine.domain.adapter.EdgeInfoTypeHandler; +import org.dromara.workflow.engine.domain.base.EdgeInfo; +import org.dromara.workflow.engine.enums.InstanceStage; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * @Description: 流程实例信息表 + **/ +@Data +@TableName(value = "t_workflow_instance",autoResultMap = true) +public class Instance implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(type = IdType.AUTO) + private Long id; + + /** + * 表单id + */ + private Long formId; + + /** + * 当前节点 + */ + @TableField(typeHandler = EdgeInfoTypeHandler.class, value = "node_keys") + private List nodeKeys; + + /** + * 数据id + */ + private Long dataId; + + /** + * 流程阶段 + */ + private InstanceStage stage; + + /** + * 流程定义id + */ + private Long definitionId; + + /** + * 是否删除(0:未删除 1:已删除) + */ + private Boolean deleted; + + /** + * 创建人 + */ + private Long createUser; + + /** + * 创建人姓名 + */ + private String createName; + + /** + * 创建人账号 + */ + private String createAccount; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.UPDATE) + private Date updateTime; + + /** + * 更新人 + */ + @TableField(fill = FieldFill.UPDATE) + private Long updateUser; + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/domain/InstanceCc.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/domain/InstanceCc.java new file mode 100644 index 0000000..036210a --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/domain/InstanceCc.java @@ -0,0 +1,43 @@ +package org.dromara.workflow.engine.domain; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; + +import java.util.Date; + +/** + * @Description: 流程实例节点抄送记录表 + **/ +@Data +@TableName("t_workflow_instance_cc") +public class InstanceCc { + + @TableId(type = IdType.AUTO) + private Long id; + + private Long formId; + + private Long instanceId; + + private String nodeKey; + + private String nodeName; + + private Integer status; + + private Long userId; + + // private String userName; + + private Long createUser; + + private String createName; + + private String createAccount; + + private Date createTime; + + @TableField(fill = FieldFill.UPDATE) + private Date updateTime; + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/domain/InstanceLog.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/domain/InstanceLog.java new file mode 100644 index 0000000..fdf82e2 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/domain/InstanceLog.java @@ -0,0 +1,85 @@ +package org.dromara.workflow.engine.domain; + +import org.dromara.workflow.remind.flow.model.FlowInstanceMessage; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.Data; +import lombok.Getter; + +import java.util.Date; +import java.util.List; + +@Data +@TableName(value = "t_workflow_instance_log",autoResultMap = true) +public class InstanceLog { + + @TableId(type = IdType.AUTO) + private Long id; + + private Long formId; + + private Long instanceId; + + private String nodeKey; + + private String nodeName; + + private String opType; + + private String opName; + + private Boolean isBatch; + + private Boolean autoCommit; + + private Date createTime; + + private Long handlerId; + + private String handlerAccount; + + private String handlerName; + + // CHARGER:流程负责人 SYSTEM:系统管理员 ROBOT:系统机器人 + private HandlerType handlerType; + + /** + * 当前操作后续流转的节点 + */ + @TableField(value = "next_nodes",typeHandler = JacksonTypeHandler.class) + private List nextNodes; + + private String comment; + + private String signature; + + + + @Getter + public enum HandlerType{ + CHARGER("流程负责人"), + + SYSTEM("系统管理员"), + + ROBOT("系统机器人"); + + private String name; + + HandlerType(String name){ + this.name = name; + } + } + + public void addHandlerType(FlowInstanceMessage.ManageInfo manageInfo){ + if(manageInfo == null || manageInfo.getUserId() == null){ + this.handlerType = HandlerType.CHARGER; + }else if(manageInfo.getUserId() == -1){ + this.handlerType = HandlerType.ROBOT; + }else{ + this.handlerType = HandlerType.SYSTEM; + } + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/domain/InstanceTask.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/domain/InstanceTask.java new file mode 100644 index 0000000..b645fde --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/domain/InstanceTask.java @@ -0,0 +1,80 @@ +package org.dromara.workflow.engine.domain; + +import com.baomidou.mybatisplus.annotation.*; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; + +/** + * @Description: 流程实例节点参与者数据表 + **/ +@Data +@TableName("t_workflow_instance_task") +public class InstanceTask { + + @TableId(type = IdType.AUTO) + private Long id; + + private Long formId; + + private Long instanceId; + + private String nodeKey; + + private String nodeName; + /** + * 节点是否正在处理中 + */ + private Boolean nodeActive; + + /** + * 是否正在处理中 + */ + private Boolean processing; + + /** + * 是否处于草稿状态 + */ + private Boolean drafting; + + + /** + * 节点审核人id + */ + private Long userId; + + /** + * 节点审核人姓名 + */ + private String userName; + + /** + * 节点审核人账号 + */ + private String userAccount; + + + /** + * 任务状态 -1:已过时 0:未处理 1:已处理 + */ + private Integer status; + + /** + * 是否高优先级 + */ + private Boolean priority; + + private Long createUser; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + @TableField(fill = FieldFill.UPDATE) + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/domain/adapter/EdgeInfoTypeHandler.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/domain/adapter/EdgeInfoTypeHandler.java new file mode 100644 index 0000000..b8a5c4a --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/domain/adapter/EdgeInfoTypeHandler.java @@ -0,0 +1,54 @@ +package org.dromara.workflow.engine.domain.adapter; + + +import org.dromara.common.util.JsonUtil; +import org.dromara.workflow.engine.domain.base.EdgeInfo; +import cn.hutool.json.JSONUtil; +import org.apache.commons.lang3.StringUtils; +import org.apache.ibatis.type.JdbcType; +import org.apache.ibatis.type.MappedJdbcTypes; +import org.apache.ibatis.type.MappedTypes; +import org.apache.ibatis.type.TypeHandler; + +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +@MappedJdbcTypes(JdbcType.VARCHAR) // 数据库类型 +@MappedTypes({List.class}) // java数据类型 +public class EdgeInfoTypeHandler implements TypeHandler> { + + @Override + public void setParameter(PreparedStatement preparedStatement, int i, List edgeInfos, JdbcType jdbcType) throws SQLException { + preparedStatement.setString(i, JSONUtil.toJsonStr(edgeInfos)); + } + + @Override + public List getResult(ResultSet resultSet, String s) throws SQLException { + if (StringUtils.isBlank(resultSet.getString(s))) { + return new ArrayList<>(); + } + return JsonUtil.jsonToList(resultSet.getString(s), EdgeInfo.class); + } + + @Override + public List getResult(ResultSet resultSet, int i) throws SQLException { + if (StringUtils.isBlank(resultSet.getString(i))) { + return new ArrayList<>(); + } + return JsonUtil.jsonToList(resultSet.getString(i), EdgeInfo.class); + } + + @Override + public List getResult(CallableStatement callableStatement, int i) throws SQLException { + String value = callableStatement.getString(i); + + if (StringUtils.isBlank(value)) { + return new ArrayList<>(); + } + return JsonUtil.jsonToList(value, EdgeInfo.class); + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/domain/adapter/NodeInfoTypeHandler.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/domain/adapter/NodeInfoTypeHandler.java new file mode 100644 index 0000000..a5153a4 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/domain/adapter/NodeInfoTypeHandler.java @@ -0,0 +1,52 @@ +package org.dromara.workflow.engine.domain.adapter; + +import org.dromara.common.util.JsonUtil; +import org.dromara.workflow.engine.domain.base.NodeInfo; +import org.apache.commons.lang3.StringUtils; +import org.apache.ibatis.type.JdbcType; +import org.apache.ibatis.type.MappedJdbcTypes; +import org.apache.ibatis.type.MappedTypes; +import org.apache.ibatis.type.TypeHandler; + +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +@MappedJdbcTypes(JdbcType.VARCHAR) // 数据库类型 +@MappedTypes({List.class}) // java数据类型 +public class NodeInfoTypeHandler implements TypeHandler> { + + @Override + public void setParameter(PreparedStatement preparedStatement, int i, List NodeInfos, JdbcType jdbcType) throws SQLException { + preparedStatement.setString(i, JsonUtil.toJson(NodeInfos)); + } + + @Override + public List getResult(ResultSet resultSet, String s) throws SQLException { + if (StringUtils.isBlank(resultSet.getString(s))) { + return new ArrayList<>(); + } + return JsonUtil.jsonToList(resultSet.getString(s), NodeInfo.class); + } + + @Override + public List getResult(ResultSet resultSet, int i) throws SQLException { + if (StringUtils.isBlank(resultSet.getString(i))) { + return new ArrayList<>(); + } + return JsonUtil.jsonToList(resultSet.getString(i), NodeInfo.class); + } + + @Override + public List getResult(CallableStatement callableStatement, int i) throws SQLException { + String value = callableStatement.getString(i); + + if (StringUtils.isBlank(value)) { + return new ArrayList<>(); + } + return JsonUtil.jsonToList(value, NodeInfo.class); + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/domain/base/EdgeInfo.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/domain/base/EdgeInfo.java new file mode 100644 index 0000000..adf8a45 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/domain/base/EdgeInfo.java @@ -0,0 +1,38 @@ +package org.dromara.workflow.engine.domain.base; + +import org.dromara.workflow.param.model.FlowUser; +import lombok.Data; + +import java.util.List; + +/** + * @Description: server + **/ +@Data +public class EdgeInfo { + + private String source; + + private String target; + + private String targetName; + + private List users; + + public EdgeInfo(){} + + + public EdgeInfo(String source,String target,String targetName){ + this.source = source; + this.target = target; + this.targetName = targetName; + } + + public EdgeInfo(String source,String target,String targetName,List users){ + this.source = source; + this.target = target; + this.targetName = targetName; + this.users = users; + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/domain/base/FlowBase.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/domain/base/FlowBase.java new file mode 100644 index 0000000..96b0fa2 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/domain/base/FlowBase.java @@ -0,0 +1,51 @@ +package org.dromara.workflow.engine.domain.base; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.TableField; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +/** + * @Description: 流程定义相关基类 + **/ +@Data +public class FlowBase implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private Date createTime; + + /** + * 创建人 + */ + @TableField(fill = FieldFill.INSERT) + private Long createUser; + + /** + * 创建人姓名 + */ + private String createName; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.UPDATE) + private Date updateTime; + + /** + * 更新人 + */ + @TableField(fill = FieldFill.UPDATE) + private Long updateUser; + + + + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/domain/base/NodeInfo.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/domain/base/NodeInfo.java new file mode 100644 index 0000000..f59ee3f --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/domain/base/NodeInfo.java @@ -0,0 +1,14 @@ +package org.dromara.workflow.engine.domain.base; + +import lombok.Data; + +/** + * @Description: server + **/ +@Data +public class NodeInfo extends EdgeInfo{ + + + private Boolean rollback; + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/CcStatus.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/CcStatus.java new file mode 100644 index 0000000..7424b23 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/CcStatus.java @@ -0,0 +1,26 @@ +package org.dromara.workflow.engine.enums; + +import lombok.Getter; + +/** + * @Description: 抄送状态(0:未读 1:已读 2:已失效) + **/ +@Getter +public enum CcStatus { + + unread(0,"未读"), + + read(1,"已读"), + + failure(2,"已失效"); + + private Integer code; + + private String desc; + + CcStatus(Integer code, String desc) { + this.code = code; + this.desc = desc; + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/DataRuleEnum.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/DataRuleEnum.java new file mode 100644 index 0000000..94908c9 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/DataRuleEnum.java @@ -0,0 +1,23 @@ +package org.dromara.workflow.engine.enums; + +import lombok.Getter; + +/** + * @Description: 节点校验条件 + **/ +@Getter +public enum DataRuleEnum { + + allDataCommit(0,"所有数据均可提交"), + dataValidated(1,"满足条件的数据才可提交"); + + private Integer code; + + private String desc; + + DataRuleEnum(Integer code, String desc) { + this.code = code; + this.desc = desc; + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/DefinitionStage.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/DefinitionStage.java new file mode 100644 index 0000000..b761d70 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/DefinitionStage.java @@ -0,0 +1,24 @@ +package org.dromara.workflow.engine.enums; + +/** + * @Description: 流程设计状态 + **/ +public enum DefinitionStage { + + running("启动中"), + + history("历史流程"), + + design("设计中"); + + private String desc; + + DefinitionStage(String desc) { + this.desc = desc; + } + + public String getDesc() { + return desc; + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/ESDefaultFieldConst.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/ESDefaultFieldConst.java new file mode 100644 index 0000000..a77e0cd --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/ESDefaultFieldConst.java @@ -0,0 +1,32 @@ +package org.dromara.workflow.engine.enums; + +/** + * ES系统字段常量 + */ +public class ESDefaultFieldConst { + public static final String _ID = "_id"; + public static final String OWNER = "owner"; + public static final String CREATOR = "creator"; + public static final String CREATOR_ACCOUNT = "creatorAccount"; + public static final String CREATE_TIME = "createTime"; + public static final String UPDATE_TIME = "updateTime"; + public static final String UPDATOR_NAME = "updateName"; + public static final String DID = "_did"; + public static final String DELETED = "_deleted"; + + /** + * 流程相关 + */ + public static final String FLOW_INSTANCE_ID = "instanceId"; + + public static final String FLOW_TASK_ID = "taskId"; + + public static final String FLOW_STAGE = "instanceStage"; + public static final String FLOW_NODE_TITLE = "instanceNode"; + public static final String FLOW_CHECKER_NAME = "instanceChecker"; + + /** + * 非ES字段 + */ + public static final String ID = "id"; +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/FlowTaskType.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/FlowTaskType.java new file mode 100644 index 0000000..6e17f69 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/FlowTaskType.java @@ -0,0 +1,11 @@ +package org.dromara.workflow.engine.enums; + + +/** + * @desc 任务类型(审核、抄送) + */ +public enum FlowTaskType { + + submit,cc; + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/HandleUserType.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/HandleUserType.java new file mode 100644 index 0000000..192caa0 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/HandleUserType.java @@ -0,0 +1,25 @@ +package org.dromara.workflow.engine.enums; + +import lombok.Getter; + +/** + * @Description: 用户类型(开始节点发起人(子流程) 任务节点审核人 任务节点抄送人 任务节点转交人 抄送节点抄送人) + **/ +@Getter +public enum HandleUserType { + + TaskChecker("任务节点处理人"), + + TaskForwardUser("任务节点转交人"), + + TaskCcUser("任务节点抄送人"), + + CcUser("抄送节点抄送人"); + + private String desc; + + HandleUserType(String desc) { + this.desc = desc; + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/InstanceStage.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/InstanceStage.java new file mode 100644 index 0000000..062018c --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/InstanceStage.java @@ -0,0 +1,26 @@ +package org.dromara.workflow.engine.enums; + +/** + * @Description: 实例状态枚举 + **/ +public enum InstanceStage { + + starting("创建中"), + + processing("运行中"), + + completed("流转完成"), + + finished("手动结束"); + + private String desc; + + InstanceStage(String desc) { + this.desc = desc; + } + + public String getDesc() { + return desc; + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/LogStatus.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/LogStatus.java new file mode 100644 index 0000000..381738a --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/LogStatus.java @@ -0,0 +1,26 @@ +package org.dromara.workflow.engine.enums; + +import lombok.Getter; + +/** + * @Description: 节点状态(0:已激活 1:已提交 2:已失效) + **/ +@Getter +public enum LogStatus { + + active(0,"已激活"), + + arrived(1,"已流转"), + + failure(2,"已失效"); + + private Integer code; + + private String desc; + + LogStatus(Integer code, String desc) { + this.code = code; + this.desc = desc; + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/NodeStage.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/NodeStage.java new file mode 100644 index 0000000..e2ec85f --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/NodeStage.java @@ -0,0 +1,10 @@ +package org.dromara.workflow.engine.enums; + +/** + * @Description: 节点状态(激活、处理过、未处理) + **/ +public enum NodeStage { + + active,flowed,unFlowed; + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/NodeType.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/NodeType.java new file mode 100644 index 0000000..5e2cc67 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/NodeType.java @@ -0,0 +1,34 @@ +package org.dromara.workflow.engine.enums; + +import org.dromara.workflow.engine.model.setting.Node; +import cn.hutool.core.util.StrUtil; + +/** + * @Description: 节点类型(预置、开始、任务、抄送、结束) + **/ +public enum NodeType { + + preset,start,task,cc,end; + + + public static NodeType getNodeType(OperateType action, Node node){ + if(OperateType.create.equals(action)){ + return NodeType.preset; + } + + if(OperateType.recall.equals(action) || StrUtil.equals(NodeType.start.name(),node.getId())){ + return NodeType.start; + } + + if (OperateType.cancel.equals(action) || StrUtil.equals(NodeType.start.name(), node.getId())) { + return NodeType.start; + } + + if(OperateType.submit.equals(action)){ + return NodeType.task; + } + + return action.getNodes()[0]; + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/OperateType.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/OperateType.java new file mode 100644 index 0000000..58bd794 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/OperateType.java @@ -0,0 +1,59 @@ +package org.dromara.workflow.engine.enums; + +import lombok.Getter; + +@Getter +public enum OperateType { + + create("create","创建", NodeType.preset), + + + submit("submit","提交",NodeType.start,NodeType.task), + + submitByPrint("submitByPrint","提交并打印",NodeType.start,NodeType.task,NodeType.cc), + + batchSubmit("batchSubmit","批量提交",NodeType.task), + + recall("recall","撤回",NodeType.task), + + rollback("rollback","回退",NodeType.task), + + draft("draft","暂存",NodeType.task), + + forward("forward","转交",NodeType.task), + + active("active","激活",NodeType.end), + + finish("finish","关闭",NodeType.task), + transfer("transfer","转交",NodeType.task), + + urge("urge","催办",NodeType.start), + + cancel("cancel", "撤回并取消", NodeType.task); + + + private String code; + + private String name; + + private NodeType[] nodes; + + + OperateType(String code,String name,NodeType ...nodes){ + this.code = code; + this.name = name; + this.nodes = nodes; + } + + + public static OperateType getOperate(String operation) { + for (OperateType item : OperateType.values()) { + if (item.name().equals(operation)) { + return item; + } + } + return null; + } + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/TaskStatus.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/TaskStatus.java new file mode 100644 index 0000000..2af8d7d --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/TaskStatus.java @@ -0,0 +1,27 @@ +package org.dromara.workflow.engine.enums; + +import lombok.Getter; + +/** + * @Description: 处理状态(0:未处理 1:已处理 -1:已过时) + **/ +@Getter +public enum TaskStatus { + + unhandled(0,"未处理"), + + handled(1,"已处理"), + + + outDated(-1,"已过时"); + + private Integer code; + + private String desc; + + TaskStatus(Integer code, String desc) { + this.code = code; + this.desc = desc; + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/TriggerScene.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/TriggerScene.java new file mode 100644 index 0000000..22983be --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/TriggerScene.java @@ -0,0 +1,24 @@ +package org.dromara.workflow.engine.enums; + +import lombok.Getter; + + +@Getter +public enum TriggerScene { + + saveOrUpdate(0,"新增或更新字段"), + + save(1,"仅新增"), + + update(2,"仅更新"); + + private Integer code; + + private String desc; + + TriggerScene(Integer code, String desc) { + this.code = code; + this.desc = desc; + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/json/node.json b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/json/node.json new file mode 100644 index 0000000..bcdf25b --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/json/node.json @@ -0,0 +1,61 @@ +{ + "name": "流程B", + "nodeList": [ + { + "id": "nodeA", + "name": "流程B-节点A", + "type": "task", + "left": "18px", + "top": "223px", + "ico": "el-icon-user-solid", + "state": "success" + }, + { + "id": "nodeB", + "type": "task", + "name": "流程B-节点B", + "left": "351px", + "top": "96px", + "ico": "el-icon-goods", + "state": "error" + }, + { + "id": "nodeC", + "name": "流程B-节点C", + "type": "task", + "left": "354px", + "top": "351px", + "ico": "el-icon-present", + "state": "warning" + }, + { + "id": "nodeD", + "name": "流程B-节点D", + "type": "task", + "left": "723px", + "top": "215px", + "ico": "el-icon-present", + "state": "running" + } + ], + "lineList": [ + { + "from": "nodeA", + "to": "nodeB", + "label": "条件A" + }, + { + "from": "nodeA", + "to": "nodeC", + "label": "条件B" + }, + { + "from": "nodeB", + "to": "nodeD" + }, + { + "from": "nodeC", + "to": "nodeD" + } + ] +} \ No newline at end of file diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/nodeMoving/AutoCommitEnum.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/nodeMoving/AutoCommitEnum.java new file mode 100644 index 0000000..cb537e5 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/nodeMoving/AutoCommitEnum.java @@ -0,0 +1,24 @@ +package org.dromara.workflow.engine.enums.nodeMoving; + +import lombok.Getter; + +/** + * @Description: 自动提交规则 + **/ +@Getter +public enum AutoCommitEnum { + + none(0,"不启用"), + lastChecker(1,"负责人与上一节点处理人相同"), + handlered(2,"负责人处理过该流程"); + + private Integer code; + + private String desc; + + AutoCommitEnum(Integer code, String desc) { + this.code = code; + this.desc = desc; + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/nodeMoving/DynamicType.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/nodeMoving/DynamicType.java new file mode 100644 index 0000000..f6c7ce5 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/nodeMoving/DynamicType.java @@ -0,0 +1,56 @@ +package org.dromara.workflow.engine.enums.nodeMoving; + +import cn.hutool.core.util.StrUtil; +import lombok.Getter; + +/** + * @Description: server + **/ +@Getter +public enum DynamicType { + + singlemember(5,"singlemember"), + + multiplemembers(5,"multiplemembers"), + + singledepatment(5,"singledepatment"), + + multipledepartment(5,"multipledepartment"), + + starter(5,"instance_starter"); + + + private Integer code; + + private String name; + + DynamicType(Integer code, String name){ + this.code = code; + this.name = name; + } + + + public static DynamicType getColumnType(String key){ + if(StrUtil.isNotEmpty(key)){ + if(key.startsWith("singlemember")){ + return DynamicType.singlemember; + } + if(key.startsWith("multiplemembers")){ + return DynamicType.multiplemembers; + } + if(key.startsWith("singledepartment")){ + return DynamicType.singledepatment; + } + if(key.startsWith("multiple_departments")){ + return DynamicType.multipledepartment; + } + if(key.startsWith("instance_starter")){ + return DynamicType.starter; + } + } + + return null; + } + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/nodeMoving/NodeFlowRuleEnum.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/nodeMoving/NodeFlowRuleEnum.java new file mode 100644 index 0000000..4c967ab --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/nodeMoving/NodeFlowRuleEnum.java @@ -0,0 +1,29 @@ +package org.dromara.workflow.engine.enums.nodeMoving; + +import lombok.Getter; + +/** + * @Description: 节点流转规则 + **/ +@Getter +public enum NodeFlowRuleEnum { + + anyOnApproved(0,"任意负责人提交后进入下一节点"), + + allApproved(1,"全部负责人提交后进入下一节点"), + + voteForPercent(2,"按审核人比例通过后进入下一节点"), + + voteForFixCount(3,"按固定人数提交后进入下一节点"); + + + private Integer code; + + private String desc; + + NodeFlowRuleEnum(Integer code, String desc) { + this.code = code; + this.desc = desc; + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/permission/ApprovalOperationEnum.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/permission/ApprovalOperationEnum.java new file mode 100644 index 0000000..b6a42b1 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/enums/permission/ApprovalOperationEnum.java @@ -0,0 +1,49 @@ +package org.dromara.workflow.engine.enums.permission; + +/** + * @Description: 审核节点操作按钮枚举 + **/ +public enum ApprovalOperationEnum { + + suggest(0,"文本意见"), + signature(1,"手写签名"), + + approval(10,"提交"), + print(11,"提交并打印"), + + rollback(15, "回退"), + forward(16, "转交"), + + batchUpdate(17, "批量提交"), + + finished(20,"结束流程"); + + private Integer code; + private String title; + + ApprovalOperationEnum(Integer code, String title){ + this.code = code; + this.title = title; + } + + public Integer code(){ + return this.code; + } + public String title(){ + return this.title; + } + + + public static ApprovalOperationEnum getApprovalOperation(String type) { + for (ApprovalOperationEnum item : values()) { + if (item.name().equals(type)) { + return item; + } + } + return null; + } + + + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/exception/WorkflowCode.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/exception/WorkflowCode.java new file mode 100644 index 0000000..6171e41 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/exception/WorkflowCode.java @@ -0,0 +1,168 @@ +package org.dromara.workflow.engine.exception; + +/** + * @Description: 流程异常代码 + **/ +public enum WorkflowCode { + SUCCESS(200,"流转成功"), + + PARAM_IS_INVALID(9001,"参数无效"), + PARAM_IS_BLANK(9002,"参数为空"), + PARAM_BAD_TYPE(9003,"参数类型错误"), + PARAM_MISSING(9004,"参数缺失"), + RESULT_EMPTY(9004, "查询结果为空"), + PARAM_PARSE_ERROR(9005,"参数解析异常"), + ILLEGAL_ARGUMENT(1000,"参数异常"), + SERVER_ERROR(9006,"流程服务器异常"), + + + INSTANCE_STAGE_ERROR(992,"流程实例状态异常"), + + INSTANCE_STAGE_FINISHED(993,"流程已结束,请勿重复操作"), + + INSTANCE_STAGE_COMPETED(994,"流程已完成,请勿重复操作"), + + HANDLER_USER_NOT_EXIST(995,"处理人不存在,请联系系统管理员"), + + DEFINITION_NOT_EXIST(996,"未找到流程配置信息"), + + DEFINITION_RUNNING_NODE_NOT_EXIST(997,"未找到正在运行的流程定义"), + + DEFINITION_NODE_NOT_EXIST(998,"未找到流程节点配置信息"), + + DEFINITION_NODE_FLOW_RULE_NOT_EXIST(998,"未找到流程节点流转规则配置"), + + NODE_TYPE_NOT_EXIST(999,"节点类型不存在"), + + NODE_START_NOT_EXIST(1000,"开始节点不存在"), + + NODE_CHECKER_TASK_NOT_EXIST(1001,"任务不存在"), + + NODE_STARTING_TRIGGER_SCENE_NOT_PERMISSION(1002,"节点不满足触发场景条件"), + + NODE_OPERATION_NOT_EXIST(1003,"节点操作类型不存在"), + + NODE_STARTING_TRIGGER_FIELD_NOT_PERMISSION(1004,"节点不满足触发字段条件"), + + NODE_STARTING_TRIGGER_DATA_NOT_PERMISSION(1005,"节点不满足触发数据条件"), + + NODE_STARTING_DATA_NOT_PERMISSION(1006,"节点数据校验不满足条件"), + + NODE_NOT_EXIST(1007,"未找到流程节点"), + + NODE_NEXT_NOT_EXIST(1008,"找不到审核节点"), + + NODE_CHECKER_NOT_PERMISSION(1009,"当前用户无审核权限"), + + NODE_CHECKER_NOT_EXIST(1010,"审核节点审核人不存在"), + + FORWARD_USER_NOT_EXIST(1011,"转交人为空"), + + FORWARD_USER_ERROR(1012,"转交人不能是当前处理人"), + + INSTANCE_NOT_EXIST(1003,"流程数据不存在"), + + NODE_TYPE_ERROR(1014,"节点类型参数异常"), + + NODE_SUGGEST_NOT_EMPTY(1015,"审核节点文本意见不能为空"), + + NODE_SIGNATURE_NOT_EMPTY(1016,"审核节点手写签名不能为空"), + + PERMISSION_SUBMIT_NO_PERMISSION(1017,"当前处理人无发起流程权限"), + + TASK_HAS_EXPIRED(1017,"待办任务已失效,请刷新页面"), + + PERMISSION_FORWARD_NO_PERMISSION(1018,"当前处理人无转交处理流程权限"), + + PERMISSION_RECALL_NOT_OPEN(1019,"系统未开启撤回功能"), + + PERMISSION_RECALL_NO_PERMISSION(1020,"当前处理人无撤回流程权限"), + + PERMISSION_RECALL_APPROVAL_NO_PERMISSION(1021,"任务节点已有人提交,发起人无法撤回"), + + PERMISSION_ROLLBACK_NOT_OPEN(1022,"系统未开启回退功能"), + + ROLLBACK_KEY_NOT_EXIST(1022,"回退节点不存在"), + + ROLLBACK_NODE_NOT_PERMISSION(1027,"回退节点不合法"), + + ROLLBACK_START_USER_NOT_EXIST(1028,"流程为匿名填报,无法回退到开始节点"), + + ROLLBACK_TASK_USER_NOT_EXIST(1029,"流程回退节点找不到负责人,请检查流程设定配置"), + + MOVING_NEXT_NODE_NOT_EXIST(1023,"找不到下一节点,流程无法流转"), + + MOVING_NEXT_NODE_CHECKER_NOT_EXIST(1024,"未找到下一个节点审核人"), + + NODE_FLOW_ERROR(1025,"提交失败,不符合流转条件"), + + INVALID_OPERATION(1026,"无效的操作类型"), + + INSTANCE_STATUS_ERROR(1028,"流程状态异常"), + + NODE_ACTIVE_NOT_EXIST(1029,"找不到激活节点"), + + SETTING_ARCHIVE_NOT_EXIST(1029,"归档设置异常,请检查流程设置"), + + ARCHIVE_USER_NOT_PERMISSION(1030,"用户无权限发起归档"), + + CC_USER_NOT_PERMISSION(1031,"用户无权限发起抄送"), + + CC_USER_NOT_EXIST(1031,"抄送用户不存在"), + + CC_TASK_NOT_EXIST(1032,"抄送任务不存在"), + + ENGINE_RESULT_EMPTY(1033,"流程引擎结果为空"), + + FLOW_RUNTIME_EXCEPTION(1034, "流程引擎发生异常,请联系管理员"), + + NODE_CHECKER_USER_LIMIT(1035,"节点审核人数量不能超过100人"), + + NODE_CC_USER_LIMIT(1036,"节点抄送人数量不能超过100人"), + + FORM_DATA_HAS_DELETE(1037,"数据已被删除"), + + TASK_NOT_EXIST(1038,"该流程已被处理或撤回"), + + TASK_PARAM_NOT_EXIST(1039,"待办参数不存在"), + + TASK_HAS_HANDLED(1040,"待办任务已处理,请勿重复操作"), + + NODE_TRANSFER_CHECKER_NOT_CHANGE(1041,"流程负责人未改动"), + + NODE_TRANSFER_CHECKER_EMPTY(1042,"流程负责人为空"), + + USER_NOT_PERMISSION(1043,"用户无权限"), + + FLOW_INSTANCE_STARTER_NOT_FOUND(1044,"未找到流程发起人"), + + FLOW_INSTANCE_URGE_CLOSED(1045,"流程设定未开启催办"), + + FLOW_INSTANCE_URGE_LIMITED(1046,"频率限制内没有可以发送的成员"), + + FLOW_INSTANCE_URGE_NODE_ERROR(1046,"流程实例异常,请稍后再试"), + + NODE_TRANSFER_START_CHECKER_LIMITED(1047, "开始节点负责人只能一个"), + + PERMISSION_CANCEL_NOT_OPEN(1048, "系统未开启撤回并取消功能"); + + + + + private Integer code; + private String message; + + WorkflowCode(Integer code, String message){ + this.code = code; + this.message = message; + } + + public Integer code() { + return code; + } + + public String message() { + return message; + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/exception/WorkflowException.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/exception/WorkflowException.java new file mode 100644 index 0000000..5304a69 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/exception/WorkflowException.java @@ -0,0 +1,29 @@ +package org.dromara.workflow.engine.exception; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * @desc 流程引擎异常 + */ +@EqualsAndHashCode(callSuper = true) +@Data +public class WorkflowException extends RuntimeException { + + private Integer code; + + private String errorMessage; + + + public WorkflowException(WorkflowCode resultCode){ + super(resultCode.message()); + this.code = resultCode.code(); + this.errorMessage = resultCode.message(); + } + + public WorkflowException(Integer code,String errorMessage){ + super(errorMessage); + this.code = code; + this.errorMessage =errorMessage; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/factory/BaseLink.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/factory/BaseLink.java new file mode 100644 index 0000000..163696b --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/factory/BaseLink.java @@ -0,0 +1,42 @@ +package org.dromara.workflow.engine.factory; + +import lombok.Data; + +/** + * @Description: 责任链基类 + **/ +@Data +public abstract class BaseLink{ + + private String name; + + private BaseLink next; + + public BaseLink(){ + + } + + public BaseLink(String name){ + this.name = name; + } + + public String name(){ + return name; + } + + public BaseLink next(){ + return next; + } + + /** + * 设置下一个责任链 + * @param next + */ + public BaseLink appendNextLink(BaseLink next) { + this.next = next; + + return this; + } + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/factory/FlowEngine.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/factory/FlowEngine.java new file mode 100644 index 0000000..8c1bf3c --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/factory/FlowEngine.java @@ -0,0 +1,223 @@ +package org.dromara.workflow.engine.factory; + +import org.dromara.workflow.engine.callback.FlowCallback; +import org.dromara.workflow.engine.domain.InstanceTask; +import org.dromara.workflow.engine.enums.HandleUserType; +import org.dromara.workflow.engine.enums.InstanceStage; +import org.dromara.workflow.engine.enums.NodeType; +import org.dromara.workflow.engine.enums.OperateType; +import org.dromara.workflow.engine.enums.nodeMoving.AutoCommitEnum; +import org.dromara.workflow.engine.exception.WorkflowCode; +import org.dromara.workflow.engine.exception.WorkflowException; +import org.dromara.workflow.param.engine.EngineRequest; +import org.dromara.workflow.param.model.FlowUser; +import org.dromara.workflow.result.engine.ActionAutoSubmitResult; +import org.dromara.workflow.result.engine.ActionNodeSubmitResult; +import org.dromara.workflow.result.engine.EngineActionResult; +import org.dromara.workflow.service.internal.InstanceLogService; +import org.dromara.workflow.service.internal.InstanceTaskService; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.transaction.support.TransactionSynchronizationAdapter; +import org.springframework.transaction.support.TransactionSynchronizationManager; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import org.dromara.workflow.engine.model.setting.Node; +@Slf4j +@Component +public class FlowEngine implements FlowCallback { + + @Autowired + private FlowExecutor action; + @Autowired + private InstanceTaskService taskService; + @Autowired + private InstanceLogService instanceLogService; + + public FlowEngine(){} + + public ActionNodeSubmitResult action(EngineRequest request){ + try { + //执行流程引擎 + return action.handle(request,this); + } catch (Exception e) { + e.printStackTrace(); + + if(e instanceof WorkflowException){ + return ActionNodeSubmitResult.error(((WorkflowException) e).getCode(),((WorkflowException) e).getErrorMessage()); + } + + return ActionNodeSubmitResult.error(WorkflowCode.FLOW_RUNTIME_EXCEPTION); + } + } + + + @Override + public ActionAutoSubmitResult callback(EngineRequest request, EngineActionResult result) { + log.info("###### workflow 节点{}回调开始 ######",request.getCurrent().getId()); + + log.info("###### workflow 是否自动流转:{} ######",result.getIsAuto()); + + log.info("###### workflow 是否推送提醒:{} ######",result.getIsSend()); + + if(CollUtil.isNotEmpty(result.getNextNodes())){ + log.info("###### workflow 下面的节点:{} ######",result.getNextNodes().stream().map(Node::getId).collect(Collectors.toList())); + } + + if(result.getIsSend()){ + sendFlowMessage(request); + } + + //预置节点流转 + if(StrUtil.equals(NodeType.preset.name(),request.getCurrent().getId())){ + return handleStartAction(request); + } + + //自动提交节点流转 + List next = result.getAutoSubmitNodes(); + if(CollUtil.isNotEmpty(next)){ + log.info("###### workflow 自动流转的节点:{} ######",next.stream().map(Node::getId).collect(Collectors.toList())); + + List results = new ArrayList<>(); + AutoCommitEnum autoSubmitRule = request.getModel().getConfig().getAutoCommit(); + if(CollUtil.isNotEmpty(next)){ + for(Node node : next){ + + EngineRequest erp = new EngineRequest(); + BeanUtils.copyProperties(request, erp); + BeanUtils.copyProperties(request.getInstance(), erp.getInstance()); + + log.info("###### workflow 自动提交的节点:{} ######",node.getId()); + erp.setAction(OperateType.submit); + erp.setAutoSubmit(true); + erp.setCurrent(node); + erp.clearFormComment(); + erp.setLastNotAutoSubmitNodeTaskId(request.getTaskId()); + erp.setLastNotAutoSubmitNode(request.getCurrent()); + + List nodeUser = this.taskService.parseNodeUser(HandleUserType.TaskChecker,erp.getInstance().getCreateUser(),node,erp.getForm().getData()); + if(CollUtil.isNotEmpty(nodeUser)){ + for(FlowUser user : nodeUser){ + + if(!NodeType.start.equals(erp.getNodeType()) && validUserSubmitAccess(autoSubmitRule,erp.getInstance().getId(),user,erp.getHandlerUser())){ + InstanceTask instanceTask = taskService.getUserNodeUnHandleTask(erp.getInstance().getId(),node.getId(),user.getId()); + if(instanceTask != null){ + erp.setHandlerUser(user); + erp.setTaskId(instanceTask.getId()); + erp.setInstanceTask(instanceTask); + results.add(action.handle(erp,this)); + } + } + + } + } + } + + if(results.stream().anyMatch(p -> !p.getSuccess())){ + + Optional failedResult = results.stream().filter(p -> !p.getSuccess()).findFirst(); + if(failedResult.isPresent()){ + + return ActionAutoSubmitResult.error(failedResult.get().getCode(),failedResult.get().getMessage()); + } + } + + if (results != null && results.size() > 0) { + request.getInstance().setStage(InstanceStage.valueOf(results.get(results.size() - 1).getData().getFlowStage())); + } + + return ActionAutoSubmitResult.success(results.stream().map(ActionNodeSubmitResult::getData).collect(Collectors.toList())); + } + } + + return ActionAutoSubmitResult.success(); + } + + /** + * 预置节点自动提交业务实现 + * @param request + * @return + */ + private ActionAutoSubmitResult handleStartAction(EngineRequest request) { + request.setAction(OperateType.submit); + request.setAutoSubmit(false); + request.setCurrent(request.getInstance().getNextNodes().get(NodeType.start).get(0)); + request.clearFormComment(); + InstanceTask instanceTask = taskService.getUserNodeUnHandleTask(request.getInstance().getId(), + request.getCurrent().getId(), request.getHandlerUser().getId()); + if(instanceTask == null){ + + throw new WorkflowException(WorkflowCode.NODE_CHECKER_TASK_NOT_EXIST); + } + request.setTaskId(instanceTask.getId()); + request.setInstanceTask(instanceTask); + + ActionNodeSubmitResult submitResult = this.action(request); + + if(submitResult.getSuccess()){ + return ActionAutoSubmitResult.success(Arrays.asList(submitResult.getData())); + } + + return ActionAutoSubmitResult.error(submitResult.getCode(),submitResult.getMessage()); + } + + + /** + * 流程设置自动提交规则 + * 负责人处理过该流程 -> 查询历史提交日志判断接下来要负责的用户是否有权限自动提交 + * 上一节点与当前负责人相同 -> 查询当前处理人和接下来要负责的用户是否相同 + */ + private boolean validUserSubmitAccess(AutoCommitEnum autoSubmitRule,Long instanceId,FlowUser submitUser, + FlowUser currentUser){ + + // 上一节点与当前负责人相同 + if(AutoCommitEnum.lastChecker.equals(autoSubmitRule)){ + return submitUser.getId().equals(currentUser.getId()); + } + + //负责人处理过该流程 + if(AutoCommitEnum.handlered.equals(autoSubmitRule)){ + + return instanceLogService.checkUserSubmit(instanceId,Arrays.asList(submitUser.getId())); + } + + return false; + } + + + + /** + * 发送流程消息 + * @param engineRequestParam + */ + public static void sendFlowMessage(EngineRequest engineRequestParam) { + try { + // 这段代码的作用是保证流程消息推送在前面的引擎业务提交完之后再执行 + boolean synchronizationActive = TransactionSynchronizationManager.isSynchronizationActive(); + if (synchronizationActive) { + TransactionSynchronizationManager.registerSynchronization( + new TransactionSynchronizationAdapter() { + @Override + public void afterCommit() { + FlowSyncManager.me().executeFlowInfo(engineRequestParam); + } + } + ); + } else { + FlowSyncManager.me().executeFlowInfo(engineRequestParam); + } + } catch (Exception e) { + e.printStackTrace(); + log.error(">>> 发送流程异常,具体信息为:{}", e.getMessage()); + } + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/factory/FlowExecutor.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/factory/FlowExecutor.java new file mode 100644 index 0000000..6dc5fb8 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/factory/FlowExecutor.java @@ -0,0 +1,121 @@ +package org.dromara.workflow.engine.factory; + +import org.dromara.workflow.engine.callback.FlowCallback; +import org.dromara.workflow.engine.enums.NodeType; +import org.dromara.workflow.engine.exception.WorkflowCode; +import org.dromara.workflow.engine.exception.WorkflowException; +import org.dromara.workflow.engine.model.node.BaseNode; +import org.dromara.workflow.engine.model.setting.Node; +import org.dromara.workflow.engine.operation.BaseAction; +import org.dromara.workflow.param.engine.EngineRequest; +import org.dromara.workflow.param.instance.InstanceLogParam; +import org.dromara.workflow.result.engine.ActionAutoSubmitResult; +import org.dromara.workflow.result.engine.ActionNodeSubmitResult; +import org.dromara.workflow.result.engine.EngineActionResult; +import org.dromara.workflow.result.engine.EngineDataResult; +import org.dromara.workflow.service.internal.DecisionService; +import org.dromara.workflow.service.internal.InstanceLogService; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import lombok.EqualsAndHashCode; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +@Slf4j +@EqualsAndHashCode(callSuper = true) +@Component +public class FlowExecutor extends BaseLink{ + + @Autowired + private DecisionService decisionService; + @Autowired + private InstanceLogService logService; + @Autowired + private final Map nodeMap = new ConcurrentHashMap(); + @Autowired + private final Map actionMap = new ConcurrentHashMap(); + + public FlowExecutor(){} + + public ActionNodeSubmitResult handle(EngineRequest request, FlowCallback callback) { + + log.info("###### workflow start working ######"); + + //初始化流程实例 + decisionService.initInstance(request); + + //配置流程定义 + decisionService.initModel(request); + + //配置实例当前节点 + decisionService.initCurrent(request); + + //查询流程实例数据 + request.setNodeType(NodeType.getNodeType(request.getAction(),request.getCurrent())); + + log.info("###### workflow current node {} ######",request.getCurrent().getId()); + + //校验节点属性 + BaseNode node = nodeMap.get(request.getNodeType().name()+"Node"); + if(node == null){ + + throw new WorkflowException(WorkflowCode.NODE_OPERATION_NOT_EXIST); + } + + node.setAction(actionMap.get(request.getAction()+"Action")); + + //设置节点动向 + node.setNext(request); + + //校验节点数据 + node.validate(request); + + //流转节点数据 + EngineActionResult actionRsp = node.action(request); + + //流程日志 + addLog(request); + + //节点流转完成回调 + ActionAutoSubmitResult result = callback.callback(request,actionRsp); + + if(result.getSuccess()){ + return ActionNodeSubmitResult.success(EngineDataResult.wrapResult(request)); + } + + return ActionNodeSubmitResult.error(result.getCode(),result.getMessage()); + } + + /** + * 添加流程日志 + * @param request + */ + private void addLog(EngineRequest request) { + InstanceLogParam instanceLog = new InstanceLogParam(request.getAction(), request.getInstance(), + request.getCurrent(), request.getAutoSubmit(), + DateUtil.parse(request.getRequestTime(),DatePattern.PURE_DATETIME_PATTERN)); + + instanceLog.setIsBatch(request.getIsBatch()); + instanceLog.addUser(request.getHandlerUser().getId(), request.getHandlerUser().getName(), request.getHandlerUser().getAccount()); + instanceLog.addContent(request.getForm().getComment(),request.getForm().getSignature()); + List nextNodeIds = new ArrayList<>(); + request.getInstance().getNextNodes().keySet().forEach(type -> { + if(CollUtil.isNotEmpty(request.getInstance().getNextNodes().get(type))){ + nextNodeIds.addAll(request.getInstance().getNextNodes().get(type).stream().map(Node::getId).collect(Collectors.toList())); + } + }); + instanceLog.setNextNodes(nextNodeIds.stream().distinct().collect(Collectors.toList())); + + logService.create(instanceLog); + } + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/factory/FlowSyncManager.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/factory/FlowSyncManager.java new file mode 100644 index 0000000..6be1f8d --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/factory/FlowSyncManager.java @@ -0,0 +1,64 @@ +package org.dromara.workflow.engine.factory; + + +import org.dromara.common.requestno.RequestNoContext; +import org.dromara.workflow.param.engine.EngineRequest; +import org.dromara.workflow.remind.flow.FlowInstanceProducer; +import cn.hutool.extra.spring.SpringUtil; +import cn.hutool.log.Log; +import org.springframework.scheduling.concurrent.ScheduledExecutorFactoryBean; + +import java.util.TimerTask; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +public class FlowSyncManager { + + private static final Log log = Log.get(); + + /** + * 异步操作记录日志的线程池 + */ + private static final ScheduledThreadPoolExecutor EXECUTOR = new ScheduledThreadPoolExecutor(10, new ScheduledExecutorFactoryBean()); + + private FlowSyncManager() { + } + + private static final FlowSyncManager LOG_MANAGER = new FlowSyncManager(); + + public static FlowSyncManager me() { + return LOG_MANAGER; + } + + + public void executeFlowInfo(EngineRequest param) { + TimerTask timerTask = executeTask(param); + execute(timerTask); + } + + public void execute(TimerTask task) { + + //日志记录操作延时 + int operateDelayTime = 300; + EXECUTOR.schedule(task, operateDelayTime, TimeUnit.MILLISECONDS); + } + + + public static TimerTask executeTask(EngineRequest param) { + + return new TimerTask() { + @Override + public void run() { + try { + + SpringUtil.getBean(FlowInstanceProducer.class).send(param); + + } catch (Exception e) { + log.error(e); + log.error(">>> 创建流程日志异常,请求号为:{},具体信息为:{}", RequestNoContext.get(), e.getMessage()); + } + } + }; + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/listener/TaskHandledListener.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/listener/TaskHandledListener.java new file mode 100644 index 0000000..a7dc352 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/listener/TaskHandledListener.java @@ -0,0 +1,22 @@ +package org.dromara.workflow.engine.listener; + +import org.dromara.workflow.engine.domain.InstanceTask; +import org.dromara.workflow.engine.enums.OperateType; +import org.dromara.workflow.param.engine.EngineRequest; + +import java.util.List; + +/** + * flow task handled listener interface + */ +public interface TaskHandledListener { + /** + * 待办任务操作(提交、退回、转交、终止等)完成后调用该方法,建议实现类采用异步/线程的方式执行业务逻辑 + * @param operate + * @param formId + * @param instance + * @param taskId + * @param tasks + */ + void onTaskHandledEvent(OperateType operate, Long formId, EngineRequest.InstanceData instance, Long taskId, List tasks); +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/node/BaseNode.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/node/BaseNode.java new file mode 100644 index 0000000..63e82b0 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/node/BaseNode.java @@ -0,0 +1,152 @@ +package org.dromara.workflow.engine.model.node; + + +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.service.ISysUserService; +import org.dromara.workflow.engine.enums.HandleUserType; +import org.dromara.workflow.engine.enums.NodeType; +import org.dromara.workflow.engine.enums.OperateType; +import org.dromara.workflow.engine.exception.WorkflowCode; +import org.dromara.workflow.engine.exception.WorkflowException; +import org.dromara.workflow.engine.model.setting.Node; +import org.dromara.workflow.engine.operation.BaseAction; +import org.dromara.workflow.param.engine.EngineRequest; +import org.dromara.workflow.param.model.FlowUser; +import org.dromara.workflow.result.engine.EngineActionResult; +import org.dromara.workflow.service.internal.DecisionService; +import org.dromara.workflow.service.internal.InstanceTaskService; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import lombok.Getter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +@Component +public abstract class BaseNode { + @Autowired + private DecisionService decisionService; + @Autowired + private ISysUserService userService; + @Autowired + private InstanceTaskService instanceTaskService; + @Autowired + private final Map actionMap = new ConcurrentHashMap(); + + private static final int USER_LIMIT = 100; + + @Getter + private BaseAction action; + + public void setAction(BaseAction action){ + this.action = action; + } + + /** + * 节点校验 + * @param request + */ + public abstract void validate(EngineRequest request); + + + /** + * 节点流转 + * @param request + */ + public abstract EngineActionResult action(EngineRequest request); + + + /** + * 查询下面要流转的节点 + * @param request + * @return + */ + public void setNext(EngineRequest request){ + BaseAction action = this.actionMap.get(request.getAction()+"Action"); + if(action == null){ + + throw new WorkflowException(WorkflowCode.INVALID_OPERATION); + } + + List nextNodes = action.getNext(request); + Map> nodeMap = nextNodes.stream().collect(Collectors.groupingBy(Node::getType)); + + for(String nodeType : nodeMap.keySet()){ + request.getInstance().addNodes(NodeType.valueOf(nodeType),nodeMap.get(nodeType)); + } + + Map>> nodeUserMap = new HashMap<>(); + + //转交人 + if(OperateType.forward.equals(request.getAction())){ + Map> forwardUsers = new HashMap<>(); + SysUserVo forwardUser = userService.selectUserById(request.getForwardUser().getId()); + if(forwardUser != null){ + forwardUsers.put(request.getCurrent().getId(), Arrays.asList(new FlowUser(forwardUser.getUserId(),forwardUser.getNickName(),forwardUser.getUserName()))); + } + + nodeUserMap.put(HandleUserType.TaskForwardUser,forwardUsers); + + request.getInstance().setUsers(nodeUserMap); + return; + } + + if(CollUtil.isNotEmpty(nextNodes)){ + //审核人(包括开始节点-流程发起人) + Map> nextCheckers = getNextNodeUsers(request, nextNodes,HandleUserType.TaskChecker); + nodeUserMap.put(HandleUserType.TaskChecker,nextCheckers); + + //抄送人 + Map> nextTaskCcUsers = getNextNodeUsers(request, nextNodes, HandleUserType.TaskCcUser); + nodeUserMap.put(HandleUserType.TaskCcUser,nextTaskCcUsers); + } + + if(OperateType.submit.equals(request.getAction())){ + List nextCcNodes = nodeMap.get(NodeType.cc.name()); + + //抄送节点抄送人 + if(CollUtil.isNotEmpty(nextCcNodes)){ + request.getInstance().addNodes(NodeType.cc,nextCcNodes); + Map> nextCcUsers = getNextNodeUsers(request, nextCcNodes, HandleUserType.CcUser); + nodeUserMap.put(HandleUserType.CcUser,nextCcUsers); + } + } + + request.getInstance().setUsers(nodeUserMap); + } + + private Map> getNextNodeUsers(EngineRequest request, List nextNodes, HandleUserType type) { + Map> nextCheckers = new LinkedHashMap<>(); + nextNodes.forEach(node -> { + + if(StrUtil.equals(NodeType.start.name(),node.getId())){ + FlowUser instanceCreator = null; + if(StrUtil.equals(request.getCurrent().getId(),NodeType.preset.name())){ + instanceCreator = request.getHandlerUser(); + }else{ + instanceCreator = new FlowUser(request.getInstance().getCreateUser(), request.getInstance().getCreateName(),request.getInstance().getCreateAccount()); + } + nextCheckers.put(node.getId(),Arrays.asList(instanceCreator)); + }else{ + List checkUsers = instanceTaskService.parseNodeUser(type, request.getInstance().getCreateUser(),node,request.getForm().getData()); + if (CollUtil.isNotEmpty(checkUsers)) { + + //单节点审核人/抄送人数量不能超过100人 + if(checkUsers.size() > USER_LIMIT){ + throw new WorkflowException(HandleUserType.TaskChecker.equals(type) ? WorkflowCode.NODE_CHECKER_USER_LIMIT : WorkflowCode.NODE_CC_USER_LIMIT); + } + + nextCheckers.put(node.getId(), checkUsers); + } + } + + }); + return nextCheckers; + } + + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/node/CcNode.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/node/CcNode.java new file mode 100644 index 0000000..060e917 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/node/CcNode.java @@ -0,0 +1,39 @@ +package org.dromara.workflow.engine.model.node; + +import org.dromara.workflow.engine.exception.WorkflowCode; +import org.dromara.workflow.engine.exception.WorkflowException; +import org.dromara.workflow.param.engine.EngineRequest; +import org.dromara.workflow.result.engine.EngineActionResult; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * 抄送节点 + **/ +@Slf4j +@Component() +public class CcNode extends BaseNode { + + @Override + public void validate(EngineRequest request) { + // if(!OperateType.listNodeOperation(NodeType.end).contains(request.getOperate())){ + // + // throw new WorkflowException(WorkflowCode.INVALID_OPERATION); + // } + + //归档、激活 + if(request.getTaskId() == null){ + + throw new WorkflowException(WorkflowCode.ILLEGAL_ARGUMENT); + } + + this.getAction().validate(request); + } + + + public EngineActionResult action(EngineRequest request) { + + return this.getAction().action(request); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/node/EndNode.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/node/EndNode.java new file mode 100644 index 0000000..90fcd59 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/node/EndNode.java @@ -0,0 +1,36 @@ +package org.dromara.workflow.engine.model.node; + +import org.dromara.workflow.engine.exception.WorkflowCode; +import org.dromara.workflow.engine.exception.WorkflowException; +import org.dromara.workflow.param.engine.EngineRequest; +import org.dromara.workflow.result.engine.EngineActionResult; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * 结束节点 + **/ +@Slf4j +@Component +public class EndNode extends BaseNode { + + @Override + public void validate(EngineRequest request) { + + //归档、激活 + if(request.getTaskId() == null){ + + throw new WorkflowException(WorkflowCode.ILLEGAL_ARGUMENT); + } + + this.getAction().validate(request); + } + + @Override + public EngineActionResult action(EngineRequest request) { + + return this.getAction().action(request); + } + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/node/PresetNode.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/node/PresetNode.java new file mode 100644 index 0000000..f9b10df --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/node/PresetNode.java @@ -0,0 +1,29 @@ +package org.dromara.workflow.engine.model.node; + +import org.dromara.workflow.param.engine.EngineRequest; +import org.dromara.workflow.result.engine.EngineActionResult; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * 前置节点 + * 操作:暂存、创建流程实例 + */ +@Slf4j +@Component +public class PresetNode extends BaseNode { + + @Override + public void validate(EngineRequest request) { + + } + + @Override + public EngineActionResult action(EngineRequest request) { + + request.getInstance().setDefinitionId(request.getDefinitionId()); + + return this.getAction().action(request); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/node/StartNode.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/node/StartNode.java new file mode 100644 index 0000000..4155afb --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/node/StartNode.java @@ -0,0 +1,26 @@ +package org.dromara.workflow.engine.model.node; + +import org.dromara.workflow.param.engine.EngineRequest; +import org.dromara.workflow.result.engine.EngineActionResult; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class StartNode extends BaseNode { + + @Override + public void validate(EngineRequest request) { + + //节点操作校验 + this.getAction().validate(request); + } + + + @Override + public EngineActionResult action(EngineRequest request) { + + return this.getAction().action(request); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/node/TaskNode.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/node/TaskNode.java new file mode 100644 index 0000000..181601a --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/node/TaskNode.java @@ -0,0 +1,61 @@ +package org.dromara.workflow.engine.model.node; + +import org.dromara.workflow.engine.domain.InstanceTask; +import org.dromara.workflow.engine.enums.InstanceStage; +import org.dromara.workflow.engine.enums.TaskStatus; +import org.dromara.workflow.engine.exception.WorkflowCode; +import org.dromara.workflow.engine.exception.WorkflowException; +import org.dromara.workflow.param.engine.EngineRequest; +import org.dromara.workflow.result.engine.EngineActionResult; +import org.dromara.workflow.service.internal.InstanceTaskService; +import cn.hutool.extra.spring.SpringUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class TaskNode extends BaseNode { + + @Override + public void validate(EngineRequest request) { + + //实例不存在 + if(request.getInstance().getDeleted()){ + + throw new WorkflowException(WorkflowCode.INSTANCE_NOT_EXIST); + } + + //实例状态必须在进行中 + if(InstanceStage.finished == request.getInstance().getStage()){ + + throw new WorkflowException(WorkflowCode.INSTANCE_STAGE_FINISHED); + } + + if(InstanceStage.completed == request.getInstance().getStage()){ + + throw new WorkflowException(WorkflowCode.INSTANCE_STAGE_COMPETED); + } + + InstanceTask task = SpringUtil.getBean(InstanceTaskService.class).getById(request.getTaskId()); + if(task == null){ + + throw new WorkflowException(WorkflowCode.TASK_NOT_EXIST); + } + + if(!TaskStatus.unhandled.getCode().equals(task.getStatus())){ + + throw new WorkflowException(WorkflowCode.TASK_NOT_EXIST); + } + + this.getAction().validate(request); + + } + + + @Override + public EngineActionResult action(EngineRequest request) { + + return this.getAction().action(request); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/setting/Cell.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/setting/Cell.java new file mode 100644 index 0000000..6d40e64 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/setting/Cell.java @@ -0,0 +1,35 @@ +package org.dromara.workflow.engine.model.setting; + +import lombok.Data; + +import java.util.List; + +/** + * @Description: 流程图节点 + **/ +//流程节点基类 +@Data +public class Cell { + + //节点id + private String id; + + //节点名称 + private String name; + + //节点类型 + private String type; + + //节点左边坐标 + private String left; + + //节点顶部坐标 + private String top; + + //节点图标 + private String ico; + + //上一级节点 + private List prev; + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/setting/Edge.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/setting/Edge.java new file mode 100644 index 0000000..07d8224 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/setting/Edge.java @@ -0,0 +1,26 @@ +package org.dromara.workflow.engine.model.setting; + +import lombok.Data; + + +/** + * @Description: 连接线 + **/ +//流程设定连接线 +@Data +public class Edge { + + //from节点 + private String from; + + //to节点 + private String to; + + //标签 + private String label; + + //连接线类型 + private String type; + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/setting/EndSetting.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/setting/EndSetting.java new file mode 100644 index 0000000..9d36702 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/setting/EndSetting.java @@ -0,0 +1,35 @@ +package org.dromara.workflow.engine.model.setting; + +import org.dromara.workflow.engine.enums.nodeMoving.NodeFlowRuleEnum; +import lombok.Data; + +/** + * @Description: 结束条件 + **/ +@Data +public class EndSetting { + + /** + * 节点流转规则 + */ + private NodeFlowRule flowRule; + + + @Data + public static class NodeFlowRule{ + + /** + * 流转规则类型 + */ + private NodeFlowRuleEnum type; + + /** + * 流转规则具体数值 + * 按审核人比例通过后进入下一节点 -> 0.1 ~ 1 + * 按固定人数提交后进入下一节点 -> 1 ~ 100 + */ + private String value; + } + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/setting/Field.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/setting/Field.java new file mode 100644 index 0000000..abbdbec --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/setting/Field.java @@ -0,0 +1,66 @@ +package org.dromara.workflow.engine.model.setting; + +import lombok.Data; + +import java.util.List; + + +//字段权限 +@Data +public class Field { + + //字段id + private String id; + + //顶级字段id + private String rootId; + + //上级字段id + private String parentId; + + //字段类型 + private String type; + + //是否可见 + private Boolean view; + + //是否可编辑 + private Boolean edit; + + List children; + + //子表单操作权限 + private TableOperate tableOperate; + + + @Data + public static class TableOperate { + //可新增记录 + private Boolean creatable; + + //可插入记录 + private Boolean insertable; + + //可编辑记录 + private Boolean editable; + + //可删除记录 + private Boolean deletable; + + } + + /** + * 生成TableOperate + * + * @param enable + * @return + */ + public static TableOperate genTableOperate(boolean enable) { + TableOperate tableOperate = new TableOperate(); + tableOperate.setCreatable(enable); + tableOperate.setInsertable(enable); + tableOperate.setEditable(enable); + tableOperate.setDeletable(enable); + return tableOperate; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/setting/Model.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/setting/Model.java new file mode 100644 index 0000000..4f8340e --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/setting/Model.java @@ -0,0 +1,30 @@ +package org.dromara.workflow.engine.model.setting; + +import org.dromara.workflow.engine.enums.nodeMoving.AutoCommitEnum; +import lombok.Data; +import java.util.List; + +@Data +public class Model { + + private List nodeList; + + private DefinitionConfig config; + + @Data + public static class DefinitionConfig { + + private Boolean recall; + + private Boolean workflowLog; + + private Boolean urge; + + private List remindWays; + + private AutoCommitEnum autoCommit; + + private Boolean cancel = false; + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/setting/Node.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/setting/Node.java new file mode 100644 index 0000000..8a41691 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/setting/Node.java @@ -0,0 +1,196 @@ +package org.dromara.workflow.engine.model.setting; + +import org.dromara.workflow.engine.domain.base.EdgeInfo; +import cn.hutool.core.util.StrUtil; +import lombok.Data; + +import java.util.List; + +/** + * @Description: 新增/修改流程定义 节点数据 + **/ +@Data +//流程节点 +public class Node extends Cell { + + //启动条件 + private StartSetting start; + + //流转条件 + private EndSetting end; + + //字段权限 + private List field; + + //文本意见 + private Suggest suggest; + + //手写签名 + private Signature signature; + + //节点操作按钮 + private List operation; + + //节点流转条件 + private List next; + + //节点审核人 + private List checkUser; + + /** + * 审核节点用户ID + */ + private List checkUserIds; + + //节点抄送人 + private List ccUser; + + //节点转交人 + private List forwardUser; + + //回退节点key + private String rollbackKey; + + //查看时是否允许打印 + private Boolean print; + + @Data + public static class EdgeCondition { + + //连接线 + private EdgeInfo edge; + + //数据流转条件",notes="if else + private String source; + + //(最新)流转条件 + private String filters; + + //(最新)流转条件查询语句 + private String query; + + //(废弃)满足流转条件的数据,只有source为if时才出现,所有 all 任一 any + private String relation; + + //(已废弃)连接条件,只有source为 if 才出现 + private List condition; + + } + + @Data + public static class Condition { + + // @ApiModelProperty("是否开启") + // private Boolean open; + + //连接条件 eq ne gt lt + private String condition; + + //控件id input_1601255375605 + private String id; + + //控件名称 单行文本 + private String name; + + //控件填报值 + private String value; + + //控件类型 string decimal + private String type; + + } + + @Data + public static class CheckUser { + + /** + * 授权对象(1=用户,2=用户组,3=组织机构 4=动态负责人) + */ + private Integer type; + + /** + * 授权对象名称 + */ + private String title; + + /** + * 授权对象主键 + */ + private String key; + + /** + * 动态负责人 + */ + private Director director; + + public CheckUser(Integer targetType,String targetName,String targetId){ + this.key = targetId; + this.type = targetType; + this.title = targetName; + } + + @Data + public class Director{ + private Long id; + private String whose; + private Integer level; + } + + } + + + @Data + public static class Suggest { + + /** + * 是否必填 + */ + private Boolean required; + + + /** + * 快捷选项 + */ + private List option; + + public Suggest(){} + + public Suggest(Boolean required){ + this.required = required; + } + } + + @Data + public static class Signature { + /** + * 是否必填 + */ + private Boolean required; + + } + + + + + @Override + public boolean equals(Object obj) { + if(this == obj){ + return true; + } + + if(obj == null){ + return false; + } + + if(obj instanceof Node){ + Node node = (Node) obj; + //需要比较的字段相等,则这两个对象相等 + if(StrUtil.equals(this.getId(),node.getId())){ + return true; + } + } + + return false; + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/setting/Operate.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/setting/Operate.java new file mode 100644 index 0000000..64d3d41 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/setting/Operate.java @@ -0,0 +1,32 @@ +package org.dromara.workflow.engine.model.setting; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +//节点按钮 +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Operate { + + //按钮类型 + private String type; + +//自定义名称 + private String customName; + + //是否二次确认 + private boolean confirm; + + public static Operate newSubmit(){ + return new Operate("submit", "提交", false); + } + + public static Operate printOperate(){ + return new Operate("print", "打印", false); + } + + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/setting/StartSetting.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/setting/StartSetting.java new file mode 100644 index 0000000..6fb8275 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/model/setting/StartSetting.java @@ -0,0 +1,74 @@ +package org.dromara.workflow.engine.model.setting; + +import org.dromara.workflow.engine.enums.DataRuleEnum; +import org.dromara.workflow.engine.enums.TriggerScene; +import lombok.Data; + +import java.util.List; + +/** + * @Description: 启动条件 + **/ +@Data +public class StartSetting { + + /** + * 触发场景 + */ + private Trigger trigger; + + /** + * 节点数据校验 + */ + private DataRule dataRule; + + @Data + public class Trigger { + + + /** + * 触发场景值 + */ + private TriggerScene scene; + + /** + * 触发字段 + */ + private List fields; + + /** + * 数据筛选组件快照 + */ + private String filters; + + + /** + * {"bool":{"must":[{"term":{"input_1622722786706":""}}],"must_not":[]}} + */ + private String condition; + + } + + @Data + public class DataRule { + + /** + * 所有数据均可提交 / 满足条件的数据才可提交 + */ + private DataRuleEnum rule; + + /** + * 节点规则(计算公式) + */ + private List filter; + + } + + @Data + public class FormulaCheck { + private String message; + + private String formula; + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/operation/BaseAction.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/operation/BaseAction.java new file mode 100644 index 0000000..4668f09 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/operation/BaseAction.java @@ -0,0 +1,36 @@ +package org.dromara.workflow.engine.operation; + +import org.dromara.workflow.engine.model.setting.Node; +import org.dromara.workflow.param.engine.EngineRequest; +import org.dromara.workflow.result.engine.EngineActionResult; + +import java.util.List; + +public abstract class BaseAction { + + + /** + * 校验节点操作 + * @param request + * @return + */ + public abstract void validate(EngineRequest request); + + /** + * 查询接下来要流转的节点 + * @param request + * @return + */ + public abstract List getNext(EngineRequest request); + + + /** + * 节点业务操作 + * @param request + * @return + */ + public abstract EngineActionResult action(EngineRequest request); + + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/operation/CcOpr.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/operation/CcOpr.java new file mode 100644 index 0000000..bfc3c75 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/operation/CcOpr.java @@ -0,0 +1,41 @@ +package org.dromara.workflow.engine.operation; + +import org.dromara.workflow.engine.model.setting.Node; +import org.dromara.workflow.param.engine.EngineRequest; +import org.dromara.workflow.result.engine.EngineActionResult; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +@Slf4j +@Service("ccAction") +public class CcOpr extends BaseAction { + + /** + * 1、处理人是实例发起人(已校验) + * 2、流程属性允许撤回流程 + * 3、当前审核节点的上一节点是发起节点且所有审核人审核状态都是未审核 + * @param request + * @return + */ + @Override + public void validate(EngineRequest request) { + + } + + @Override + public List getNext(EngineRequest request) { + + return new ArrayList<>(); + } + + @Override + public EngineActionResult action(EngineRequest request) { + + return new EngineActionResult(false,false); + } + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/operation/CreateOpr.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/operation/CreateOpr.java new file mode 100644 index 0000000..464757e --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/operation/CreateOpr.java @@ -0,0 +1,85 @@ +package org.dromara.workflow.engine.operation; + +import org.dromara.workflow.engine.domain.InstanceTask; +import org.dromara.workflow.engine.domain.base.EdgeInfo; +import org.dromara.workflow.engine.enums.NodeStage; +import org.dromara.workflow.engine.enums.NodeType; +import org.dromara.workflow.engine.enums.FlowTaskType; +import org.dromara.workflow.engine.exception.WorkflowCode; +import org.dromara.workflow.engine.exception.WorkflowException; +import org.dromara.workflow.engine.model.setting.Node; +import org.dromara.workflow.param.engine.EngineRequest; +import org.dromara.workflow.result.engine.EngineActionResult; +import org.dromara.workflow.service.internal.DecisionService; +import org.dromara.workflow.service.internal.InstanceService; +import org.dromara.workflow.service.internal.InstanceTaskService; +import cn.hutool.core.collection.CollUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +@Slf4j +@Service("createAction") +public class CreateOpr extends BaseAction implements OprAction{ + + @Autowired + protected DecisionService decisionService; + @Autowired + private InstanceService instanceService; + @Autowired + private InstanceTaskService instanceTaskService; + + @Override + public void validate(EngineRequest request) { + if(request.getTaskId() != null){ + + throw new WorkflowException(WorkflowCode.TASK_PARAM_NOT_EXIST); + } + + //校验实例申请人是否是当前请求处理人 + if(!this.decisionService.checkInstanceHandler(request.getInstance(),request.getHandlerUser().getId())){ + + throw new WorkflowException(WorkflowCode.PERMISSION_SUBMIT_NO_PERMISSION); + } + } + + @Override + public List getNext(EngineRequest request) { + + return Arrays.asList(request.getModelStartNode()); + } + + @Override + public EngineActionResult action(EngineRequest request) { + request.setNodeStage(NodeStage.flowed); + + //创建流程实例 + request.getInstance().setNodeKeys(getActiveNodes(request)); + + instanceService.save(request.getInstance()); + + //开始节点待办任务 + Map taskData = instanceTaskService.createNodeTask(request); + + List taskList = (List)taskData.get(FlowTaskType.submit); + + if(CollUtil.isEmpty(taskList) || taskList.size() != 1){ + + throw new WorkflowException(WorkflowCode.TASK_NOT_EXIST); + } + + EngineActionResult result = new EngineActionResult(false,false); + result.fillStartNext(request.getInstance().getNextNodes().get(NodeType.start)); + + return result; + } + + @Override + public List getActiveNodes(EngineRequest request) { + + return Arrays.asList(new EdgeInfo(null, NodeType.start.name(),request.getModelStartNode().getName(),Arrays.asList(request.getHandlerUser()))); + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/operation/DraftOpr.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/operation/DraftOpr.java new file mode 100644 index 0000000..c18db4f --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/operation/DraftOpr.java @@ -0,0 +1,42 @@ +package org.dromara.workflow.engine.operation; + +import org.dromara.workflow.engine.domain.base.EdgeInfo; +import org.dromara.workflow.engine.enums.NodeType; +import org.dromara.workflow.engine.model.setting.Node; +import org.dromara.workflow.param.engine.EngineRequest; +import org.dromara.workflow.result.engine.EngineActionResult; +import cn.hutool.core.util.StrUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +@Slf4j +@Service("draftAction") +public class DraftOpr extends BaseAction implements OprAction{ + + @Override + public void validate(EngineRequest request) { + } + + @Override + public List getNext(EngineRequest request) { + return request.getModel().getNodeList().stream().filter(p -> StrUtil.equals(p.getId(), NodeType.start.name())).collect(Collectors.toList()); + } + + @Override + public EngineActionResult action(EngineRequest request) { + // TODO: 2022/5/16 暂存操作 + + return new EngineActionResult(); + } + + @Override + public List getActiveNodes(EngineRequest request) { + + return Arrays.asList(new EdgeInfo(null,NodeType.start.name(),request.getModelStartNode().getName())); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/operation/FinishOpr.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/operation/FinishOpr.java new file mode 100644 index 0000000..9686fac --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/operation/FinishOpr.java @@ -0,0 +1,80 @@ +package org.dromara.workflow.engine.operation; + +import org.dromara.workflow.engine.domain.InstanceTask; +import org.dromara.workflow.engine.domain.base.EdgeInfo; +import org.dromara.workflow.engine.enums.InstanceStage; +import org.dromara.workflow.engine.enums.NodeType; +import org.dromara.workflow.engine.enums.TaskStatus; +import org.dromara.workflow.engine.exception.WorkflowCode; +import org.dromara.workflow.engine.exception.WorkflowException; +import org.dromara.workflow.engine.model.setting.Node; +import org.dromara.workflow.param.engine.EngineRequest; +import org.dromara.workflow.result.engine.EngineActionResult; +import org.dromara.workflow.service.internal.InstanceService; +import org.dromara.workflow.service.internal.InstanceTaskService; +import cn.hutool.core.util.StrUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +@Slf4j +@Service("finishAction") +public class FinishOpr extends BaseAction implements OprAction{ + + @Autowired + private InstanceService instanceService; + @Autowired + private InstanceTaskService instanceTaskService; + + @Override + public void validate(EngineRequest request) { + + //流程状态必须是运行状态 + if(InstanceStage.processing != request.getInstance().getStage()){ + throw new WorkflowException(WorkflowCode.INSTANCE_STATUS_ERROR); + } + + if(request.getTaskId() != null){ + //校验待办任务状态 + InstanceTask task = instanceTaskService.getById(request.getTaskId()); + if(task == null){ + throw new WorkflowException(WorkflowCode.TASK_NOT_EXIST); + } + + if(!TaskStatus.unhandled.getCode().equals(task.getStatus())){ + + throw new WorkflowException(WorkflowCode.TASK_NOT_EXIST); + } + + } + + } + + @Override + public List getNext(EngineRequest request) { + + return request.getModel().getNodeList().stream().filter(p -> StrUtil.equals(p.getId(), NodeType.end.name())).collect(Collectors.toList()); + } + + @Override + public EngineActionResult action(EngineRequest request) { + //更新实例数据 + instanceService.update(request); + + //更新任务数据 + instanceTaskService.update(request); + + return new EngineActionResult(); + } + + @Override + public List getActiveNodes(EngineRequest request) { + + return Arrays.asList(new EdgeInfo(request.getCurrent().getId(),NodeType.end.name(),"流程结束")); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/operation/ForwardOpr.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/operation/ForwardOpr.java new file mode 100644 index 0000000..ab4b930 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/operation/ForwardOpr.java @@ -0,0 +1,96 @@ +package org.dromara.workflow.engine.operation; + + +import org.dromara.common.Exception.ServiceException; +import org.dromara.common.response.WorkflowResultCode; +import org.dromara.workflow.engine.domain.base.EdgeInfo; +import org.dromara.workflow.engine.enums.HandleUserType; +import org.dromara.workflow.engine.exception.WorkflowCode; +import org.dromara.workflow.engine.exception.WorkflowException; +import org.dromara.workflow.engine.model.setting.Node; +import org.dromara.workflow.param.engine.EngineRequest; +import org.dromara.workflow.param.model.FlowUser; +import org.dromara.workflow.result.engine.EngineActionResult; +import org.dromara.workflow.service.internal.InstanceService; +import org.dromara.workflow.service.internal.InstanceTaskService; +import cn.hutool.core.util.StrUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Slf4j +@Service("forwardAction") +public class ForwardOpr extends BaseAction implements OprAction{ + @Autowired + private InstanceService instanceService; + @Autowired + private InstanceTaskService instanceTaskService; + + /** + * 转交人必须在转交人范围内 + * @param request + * @return + */ + @Override + public void validate(EngineRequest request) { + if(request.getCurrent().getOperation().stream().noneMatch(p -> StrUtil.equals("forward",p.getType()))){ + + throw new WorkflowException(WorkflowCode.PERMISSION_FORWARD_NO_PERMISSION); + } + + if(request.getForwardUser() == null){ + + throw new ServiceException(WorkflowResultCode.FORWARD_USER_NOT_EXIST); + } + + List checkList = instanceTaskService.parseNodeUser(HandleUserType.TaskForwardUser, request.getInstance().getCreateUser(), request.getCurrent(),request.getForm().getData()); + + if(checkList.stream().noneMatch(user -> user.getId().equals(request.getForwardUser().getId()))){ + + throw new WorkflowException(WorkflowCode.PERMISSION_FORWARD_NO_PERMISSION); + } + } + + @Override + public List getNext(EngineRequest request) { + //转交操作-> 下一个节点也是当前节点 + return Arrays.asList(request.getCurrent()); + } + + @Override + public EngineActionResult action(EngineRequest request) { + + //更新实例数据 + instanceService.update(request); + + //更新任务数据 + instanceTaskService.update(request); + + return new EngineActionResult(); + } + + + @Override + public List getActiveNodes(EngineRequest request) { + Map> checkUsers = request.getInstance().getUsers().get(HandleUserType.TaskForwardUser); + for (EdgeInfo edgeInfo : request.getInstance().getNodeKeys()) { + if (StrUtil.equals(edgeInfo.getTarget(), request.getCurrent().getId())) { + FlowUser forwardUser = checkUsers.get(edgeInfo.getTarget()).get(0); + if(forwardUser != null) { + List currentUsers = edgeInfo.getUsers().stream().filter(p -> !p.getId().equals(request.getHandlerUser().getId())).collect(Collectors.toList()); + if (currentUsers.stream().noneMatch(p -> p.getId().equals(forwardUser.getId()))) { + currentUsers.add(forwardUser); + } + edgeInfo.setUsers(currentUsers); + } + break; + } + } + return request.getInstance().getNodeKeys(); + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/operation/OprAction.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/operation/OprAction.java new file mode 100644 index 0000000..1adbff4 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/operation/OprAction.java @@ -0,0 +1,14 @@ +package org.dromara.workflow.engine.operation; + +import org.dromara.workflow.engine.domain.base.EdgeInfo; +import org.dromara.workflow.param.engine.EngineRequest; + +import java.util.List; + +/** + * @Description: server + **/ +public interface OprAction { + + List getActiveNodes(EngineRequest request); +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/operation/RecallOpr.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/operation/RecallOpr.java new file mode 100644 index 0000000..e188ed7 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/operation/RecallOpr.java @@ -0,0 +1,85 @@ +package org.dromara.workflow.engine.operation; + +import org.dromara.workflow.engine.domain.base.EdgeInfo; +import org.dromara.workflow.engine.enums.NodeType; +import org.dromara.workflow.engine.exception.WorkflowCode; +import org.dromara.workflow.engine.exception.WorkflowException; +import org.dromara.workflow.engine.model.setting.Node; +import org.dromara.workflow.param.engine.EngineRequest; +import org.dromara.workflow.result.engine.EngineActionResult; +import org.dromara.workflow.service.external.FlowTaskService; +import org.dromara.workflow.service.internal.InstanceService; +import org.dromara.workflow.service.internal.InstanceTaskService; +import cn.hutool.core.util.StrUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +@Slf4j +@Service("recallAction") +public class RecallOpr extends BaseAction implements OprAction{ + @Autowired + private InstanceService instanceService; + @Autowired + private InstanceTaskService instanceTaskService; + @Autowired + private FlowTaskService taskService; + + /** + * 1、处理人是实例发起人(已校验) + * 2、流程属性允许撤回流程 + * 3、当前审核节点的上一节点是发起节点且所有审核人审核状态都是未审核 + * + * @param request + * @return + */ + @Override + public void validate(EngineRequest request) { + //当前处理人必须是实例发起人人 + if(!request.getInstance().getCreateUser().equals(request.getHandlerUser().getId())){ + + throw new WorkflowException(WorkflowCode.PERMISSION_RECALL_NO_PERMISSION); + } + + //流程属性允许撤回流程 + if (!request.getModel().getConfig().getRecall()) { + + throw new WorkflowException(WorkflowCode.PERMISSION_RECALL_NOT_OPEN); + } + + //当前所有任务节点的待办任务 状态都是未处理 + if (!taskService.checkInstanceCanRecall(request.getInstance().getId())) { + + throw new WorkflowException(WorkflowCode.PERMISSION_RECALL_APPROVAL_NO_PERMISSION); + } + + } + + @Override + public List getNext(EngineRequest request) { + + return request.getModel().getNodeList().stream().filter(p -> StrUtil.equals(p.getId(), NodeType.start.name())).collect(Collectors.toList()); + } + + @Override + public EngineActionResult action(EngineRequest request) { + + //更新实例数据 + instanceService.update(request); + + //发送任务数据 + instanceTaskService.update(request); + + return new EngineActionResult(); + } + + @Override + public List getActiveNodes(EngineRequest request) { + + return Arrays.asList(new EdgeInfo(request.getCurrent().getId(),NodeType.start.name(),request.getModelStartNode().getName(),Arrays.asList(request.getHandlerUser()))); + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/operation/RollbackOpr.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/operation/RollbackOpr.java new file mode 100644 index 0000000..1c4b5a4 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/operation/RollbackOpr.java @@ -0,0 +1,129 @@ +package org.dromara.workflow.engine.operation; + +import org.dromara.workflow.engine.domain.Instance; +import org.dromara.workflow.engine.domain.base.EdgeInfo; +import org.dromara.workflow.engine.enums.HandleUserType; +import org.dromara.workflow.engine.enums.NodeType; +import org.dromara.workflow.engine.enums.OperateType; +import org.dromara.workflow.engine.exception.WorkflowCode; +import org.dromara.workflow.engine.exception.WorkflowException; +import org.dromara.workflow.engine.model.setting.Node; +import org.dromara.workflow.param.engine.EngineRequest; +import org.dromara.workflow.param.model.FlowUser; +import org.dromara.workflow.result.engine.EngineActionResult; +import org.dromara.workflow.service.internal.DecisionService; +import org.dromara.workflow.service.internal.InstanceService; +import org.dromara.workflow.service.internal.InstanceTaskService; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + +@Slf4j +@Service("rollbackAction") +public class RollbackOpr extends BaseAction implements OprAction{ + + @Autowired + private InstanceService instanceService; + @Autowired + private InstanceTaskService instanceTaskService; + @Autowired + private DecisionService decisionService; + + /** + * 当前处理人是审核节点处理人(已校验) + * 当前节点是否允许退回 + * @param request + * @return + */ + @Override + public void validate(EngineRequest request) { + + if(StrUtil.isEmpty(request.getCurrent().getRollbackKey() )){ + + throw new WorkflowException(WorkflowCode.ROLLBACK_KEY_NOT_EXIST); + } + + if(request.getCurrent().getOperation().stream().noneMatch(p -> StrUtil.equals(OperateType.rollback.getCode(),p.getType()))){ + + throw new WorkflowException(WorkflowCode.ROLLBACK_KEY_NOT_EXIST); + } + Optional rollbackNode = request.getModel().getNodeList().stream().filter(p -> StrUtil.equals(p.getId(), request.getCurrent().getRollbackKey())).findAny(); + rollbackNode.orElseThrow(() -> new WorkflowException(WorkflowCode.ROLLBACK_KEY_NOT_EXIST)); + + + // 校验回退节点是否在实例当前节点之前 + Set nodeSet = decisionService.listNodesFromNode(request.getModel(),request.getCurrent().getId()); + if(!nodeSet.contains(request.getCurrent().getRollbackKey())){ + + throw new WorkflowException(WorkflowCode.ROLLBACK_NODE_NOT_PERMISSION); + } + + // 回退的节点是否有处理人 + if(StrUtil.equals(request.getCurrent().getRollbackKey(), NodeType.start.name())){ + Instance instance = instanceService.getById(request.getInstance().getId()); + if(instance.getCreateUser() == -1L){ + + throw new WorkflowException(WorkflowCode.ROLLBACK_START_USER_NOT_EXIST); + } + } + + if(StrUtil.contains(request.getCurrent().getRollbackKey(), NodeType.task.name())){ + + List rollbackUsers = instanceTaskService.parseNodeUser(HandleUserType.TaskChecker, + request.getInstance().getCreateUser(), + rollbackNode.get(), + request.getForm().getData()); + + if(CollUtil.isEmpty(rollbackUsers)){ + + throw new WorkflowException(WorkflowCode.ROLLBACK_TASK_USER_NOT_EXIST); + } + } + + + } + + @Override + public List getNext(EngineRequest request) { + + return request.getModel().getNodeList().stream().filter(p -> StrUtil.equals(p.getId(),request.getCurrent().getRollbackKey())).collect(Collectors.toList()); + } + + @Override + public EngineActionResult action(EngineRequest request) { + //更新实例数据 + instanceService.update(request); + + //更新任务数据 + instanceTaskService.update(request); + + return new EngineActionResult(); + } + + + @Override + public List getActiveNodes(EngineRequest request) { + + if(request.getCurrent().getRollbackKey().contains(NodeType.start.name())){ + + EdgeInfo startInfo = new EdgeInfo(request.getCurrent().getId(),NodeType.start.name(),request.getModelStartNode().getName()); + startInfo.setUsers(Collections.singletonList(new FlowUser(request.getInstance().getCreateUser(), request.getInstance().getCreateName(), request.getInstance().getCreateAccount()))); + return(Arrays.asList(startInfo)); + } + + Node rollbackNode = request.getModel().getNodeList().stream().filter(p -> StrUtil.equals(p.getId(),request.getCurrent().getRollbackKey())).findFirst().get(); + + List nodeUser = this.instanceTaskService.parseNodeUser(HandleUserType.TaskChecker,request.getInstance().getCreateUser(),rollbackNode,request.getForm().getData()); + + EdgeInfo rollbackInfo = new EdgeInfo(request.getCurrent().getId(),rollbackNode.getId(),rollbackNode.getName(),nodeUser); + List nodeKeys = request.getInstance().getNodeKeys().stream().filter(p -> !StrUtil.equals(p.getTarget(), request.getCurrent().getId())).collect(Collectors.toList()); + nodeKeys.add(rollbackInfo); + + return nodeKeys; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/operation/SubmitOpr.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/operation/SubmitOpr.java new file mode 100644 index 0000000..19d394f --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/engine/operation/SubmitOpr.java @@ -0,0 +1,161 @@ +package org.dromara.workflow.engine.operation; + +import org.dromara.workflow.engine.domain.base.EdgeInfo; +import org.dromara.workflow.engine.enums.HandleUserType; +import org.dromara.workflow.engine.enums.NodeStage; +import org.dromara.workflow.engine.enums.NodeType; +import org.dromara.workflow.engine.exception.WorkflowCode; +import org.dromara.workflow.engine.exception.WorkflowException; +import org.dromara.workflow.engine.model.setting.Node; +import org.dromara.workflow.param.engine.EngineRequest; +import org.dromara.workflow.param.model.FlowUser; +import org.dromara.workflow.result.engine.AutoSubmitResult; +import org.dromara.workflow.result.engine.EngineActionResult; +import org.dromara.workflow.service.internal.DecisionService; +import org.dromara.workflow.service.internal.InstanceService; +import org.dromara.workflow.service.internal.InstanceTaskService; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Slf4j +@Service("submitAction") +public class SubmitOpr extends BaseAction implements OprAction{ + + @Autowired + private InstanceService instanceService; + @Autowired + private InstanceTaskService instanceTaskService; + @Autowired + private DecisionService decisionService; + + @Override + public void validate(EngineRequest request) { + + //待办任务状态合法性校验 + if(request.getInstanceTask() != null){ + if(request.getInstanceTask().getStatus() == 1){ + + throw new WorkflowException(WorkflowCode.TASK_HAS_HANDLED); + } + if(!request.getInstanceTask().getUserId().equals(request.getHandlerUser().getId())){ + + throw new WorkflowException(WorkflowCode.USER_NOT_PERMISSION); + } + } + + //如果下面的节点包含结束节点 跳过校验 + if(CollUtil.isNotEmpty(request.getInstance().getNextNodes().get(NodeType.end))){ + + return; + } + + // 校验即将流转的下面节点是否存在负责人 + List taskNodes = request.getInstance().getNextNodes().get(NodeType.task); + if(CollUtil.isNotEmpty(taskNodes)){ + + boolean checkResult = instanceTaskService.checkTaskUser(taskNodes,request.getInstance().getCreateUser(),request.getForm().getData()); + if(!checkResult){ + + throw new WorkflowException(WorkflowCode.NODE_CHECKER_NOT_EXIST); + } + } + + } + + @Override + public List getNext(EngineRequest request) { + List nextTotalNodes = decisionService.getNextNodes(request); + + if(CollUtil.isNotEmpty(nextTotalNodes)){ + + log.info("##### workflow current {} next nodes :{} ######",request.getCurrent().getId(),nextTotalNodes.stream().map(Node::getId).collect(Collectors.toList())); + + AutoSubmitResult autoSubmitResult = decisionService.getNextActionNode(request,nextTotalNodes); + if(autoSubmitResult != null && CollUtil.isNotEmpty(autoSubmitResult.getNext())){ + request.getInstance().setAutoSubmitNodes(autoSubmitResult.getNext()); + }else{ + request.getInstance().setAutoSubmitNodes(null); + } + } + + Map> nodeMap = nextTotalNodes.stream().collect(Collectors.groupingBy(Node::getType)); + + if(decisionService.containNode(nodeMap.get(NodeType.task.name()), NodeType.end)){ + + return nextTotalNodes.stream().filter(p -> (StrUtil.equals(NodeType.task.name(),p.getType()) && StrUtil.equals(p.getId(),NodeType.end.name()))).collect(Collectors.toList()); + } + + return nextTotalNodes; + } + + @Override + public EngineActionResult action(EngineRequest request) { + //更新实例数据 + instanceService.update(request); + + //更新任务节点的节点负责人待办任务(更新当前节点任务状态、生成下面任务节点的待办任务) + //发送下面任务节点的抄送任务 + //发送下面抄送节点的的抄送提醒 + instanceTaskService.update(request); + + //校验是否需要自动流转到下面的节点 + if(CollUtil.isNotEmpty(request.getInstance().getNextNodes())){ + List taskNodes = request.getInstance().getNextNodes().get(NodeType.task); + return new EngineActionResult(taskNodes,request.getInstance().getAutoSubmitNodes()); + } + + return new EngineActionResult(); + } + + @Override + public List getActiveNodes(EngineRequest request) { + if(request.getInstance().getNextNodes().containsKey(NodeType.end)) { + + return Arrays.asList(new EdgeInfo(request.getCurrent().getId(), NodeType.end.name(), "流程结束")); + } + + List befNodes = request.getInstance().getNodeKeys(); + if(NodeStage.flowed.equals(request.getNodeStage())){ + befNodes = befNodes.stream().filter(p -> !StrUtil.equals(p.getTarget(),request.getCurrent().getId())).collect(Collectors.toList()); + } + + List nextNodes = request.getInstance().getNextNodes().get(NodeType.task); + + if(CollUtil.isNotEmpty(nextNodes)){ + List edgeInfos = nextNodes.stream().map(p -> { + EdgeInfo edgeInfo = new EdgeInfo(); + edgeInfo.setSource(request.getCurrent().getId()); + edgeInfo.setTarget(p.getId()); + edgeInfo.setTargetName(p.getName()); + + Map> checkUsers = request.getInstance().getUsers().get(HandleUserType.TaskChecker); + List flowUsers = checkUsers.get(p.getId()); + if(CollUtil.isNotEmpty(flowUsers)){ + edgeInfo.setUsers(flowUsers); + } + + return edgeInfo; + }).collect(Collectors.toList()); + + befNodes.addAll(edgeInfos); + }else{ + //当前节点的处理人将当前登录用户移除 + for (EdgeInfo edgeInfo : request.getInstance().getNodeKeys()) { + if (StrUtil.equals(edgeInfo.getTarget(), request.getCurrent().getId())) { + edgeInfo.setUsers(edgeInfo.getUsers().stream().filter(p -> !p.getId().equals(request.getHandlerUser().getId())).collect(Collectors.toList())); + break; + } + } + } + + return befNodes; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/mapper/DefinitionMapper.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/mapper/DefinitionMapper.java new file mode 100644 index 0000000..5efc442 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/mapper/DefinitionMapper.java @@ -0,0 +1,11 @@ +package org.dromara.workflow.mapper; + +import org.dromara.workflow.engine.domain.Definition; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Param; + +public interface DefinitionMapper extends BaseMapper { + + Integer countDefinitionVersion(@Param("formId")Long formId); + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/mapper/InstanceCcMapper.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/mapper/InstanceCcMapper.java new file mode 100644 index 0000000..3811e14 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/mapper/InstanceCcMapper.java @@ -0,0 +1,15 @@ +package org.dromara.workflow.mapper; + + +import org.dromara.workflow.engine.domain.InstanceCc; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +public interface InstanceCcMapper extends BaseMapper { + + int batchDelete(@Param("instanceIdList") List instanceIdList); + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/mapper/InstanceLogMapper.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/mapper/InstanceLogMapper.java new file mode 100644 index 0000000..669126f --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/mapper/InstanceLogMapper.java @@ -0,0 +1,14 @@ + +package org.dromara.workflow.mapper; + +import org.dromara.workflow.engine.domain.InstanceLog; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +public interface InstanceLogMapper extends BaseMapper { + + int batchDelete(@Param("instanceIdList") List instanceIdList); + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/mapper/InstanceMapper.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/mapper/InstanceMapper.java new file mode 100644 index 0000000..d5ab869 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/mapper/InstanceMapper.java @@ -0,0 +1,38 @@ +package org.dromara.workflow.mapper; + + +import org.dromara.workflow.engine.domain.Instance; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +public interface InstanceMapper extends BaseMapper { + + int batchDeleteInstance(@Param("instanceIdList") List instanceIdList); + /** + * 逻辑删除实例 + * @param instanceIdList + * @return + */ + int logicDeleteInstance(@Param("instanceIdList") List instanceIdList); + + /** + * 根据表单逻辑删除实例 + * @param formId + * @param dataIds + * @return + */ + int logicDeleteByForm(@Param("formId") Long formId, @Param("dataIds") String[] dataIds); + + + /** + * 根据表单恢复逻辑删除的实例数据 + * @param formId + * @param dataIds + * @return + */ + int logicRecoverByForm(@Param("formId") Long formId, @Param("dataIds") String[] dataIds); + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/mapper/InstanceTaskMapper.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/mapper/InstanceTaskMapper.java new file mode 100644 index 0000000..27219f5 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/mapper/InstanceTaskMapper.java @@ -0,0 +1,16 @@ +package org.dromara.workflow.mapper; + +import org.dromara.workflow.engine.domain.InstanceCc; +import org.dromara.workflow.engine.domain.InstanceTask; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +public interface InstanceTaskMapper extends BaseMapper { + + int batchInsertCc(@Param("ccTaskList") List instanceCcList); + + int batchInsertTask(@Param("taskList") List instanceTaskList); + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/mapper/mapping/DefinitionMapper.xml b/dk-common/common-workflow/src/main/java/org/dromara/workflow/mapper/mapping/DefinitionMapper.xml new file mode 100644 index 0000000..a0d7479 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/mapper/mapping/DefinitionMapper.xml @@ -0,0 +1,11 @@ + + + + + + + diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/mapper/mapping/InstanceCcMapper.xml b/dk-common/common-workflow/src/main/java/org/dromara/workflow/mapper/mapping/InstanceCcMapper.xml new file mode 100644 index 0000000..fb19833 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/mapper/mapping/InstanceCcMapper.xml @@ -0,0 +1,24 @@ + + + + + + + DELETE FROM + t_workflow_instance_cc + WHERE + instance_id IN + + #{instanceId} + + + + + + + + diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/mapper/mapping/InstanceLogMapper.xml b/dk-common/common-workflow/src/main/java/org/dromara/workflow/mapper/mapping/InstanceLogMapper.xml new file mode 100644 index 0000000..bd9e239 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/mapper/mapping/InstanceLogMapper.xml @@ -0,0 +1,16 @@ + + + + + + + DELETE FROM + t_workflow_instance_log + WHERE + instance_id IN + + #{instanceId} + + + + diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/mapper/mapping/InstanceMapper.xml b/dk-common/common-workflow/src/main/java/org/dromara/workflow/mapper/mapping/InstanceMapper.xml new file mode 100644 index 0000000..b1129ca --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/mapper/mapping/InstanceMapper.xml @@ -0,0 +1,82 @@ + + + + + + DELETE FROM + t_workflow_instance + WHERE + id IN + + #{instanceId} + ; + + DELETE FROM + t_workflow_instance_task + WHERE + instance_id IN + + #{instanceId} + ; + + DELETE FROM + t_workflow_instance_cc + WHERE + instance_id IN + + #{instanceId} + ; + + DELETE FROM + t_workflow_instance_log + WHERE + instance_id IN + + #{instanceId} + + + + + + + update t_workflow_instance + set deleted = 1 + WHERE + id IN + + #{instanceId} + + + + + + UPDATE + t_workflow_instance + SET + deleted = 1 + WHERE + form_id = #{formId} + + AND data_id IN + + #{dataId} + + + + + + + UPDATE + t_workflow_instance + SET + deleted = 0 + WHERE + form_id = #{formId} + + AND data_id IN + + #{dataId} + + + + diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/mapper/mapping/InstanceTaskMapper.xml b/dk-common/common-workflow/src/main/java/org/dromara/workflow/mapper/mapping/InstanceTaskMapper.xml new file mode 100644 index 0000000..e6e742d --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/mapper/mapping/InstanceTaskMapper.xml @@ -0,0 +1,27 @@ + + + + + + INSERT INTO + t_workflow_instance_cc (form_id, instance_id,node_key,node_name, + user_id,status,create_user,create_name,create_account,create_time) + VALUES + + (#{task.formId}, #{task.instanceId}, #{task.nodeKey}, #{task.nodeName}, #{task.userId}, + #{task.status},#{task.createUser}, #{task.createName}, #{task.createAccount},#{task.createTime}) + + + + + INSERT INTO + t_workflow_instance_task (form_id, instance_id,node_key,node_name,node_active, + user_id,user_name,user_account,status,priority,create_user,create_time) + VALUES + + (#{task.formId}, #{task.instanceId}, #{task.nodeKey}, #{task.nodeName},#{task.nodeActive}, #{task.userId} + , #{task.userName},#{task.userAccount}, #{task.status},#{task.priority}, #{task.createUser},#{task.createTime}) + + + + diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/param/engine/EngineRequest.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/param/engine/EngineRequest.java new file mode 100644 index 0000000..503a6d4 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/param/engine/EngineRequest.java @@ -0,0 +1,260 @@ +package org.dromara.workflow.param.engine; + +import org.dromara.workflow.engine.domain.Instance; +import org.dromara.workflow.engine.domain.InstanceTask; +import org.dromara.workflow.engine.enums.*; +import org.dromara.workflow.engine.model.setting.Model; +import org.dromara.workflow.engine.model.setting.Node; +import org.dromara.workflow.param.model.FlowUser; +import org.dromara.workflow.remind.flow.model.FlowRemindInstanceTask; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import lombok.Data; +import org.springframework.beans.BeanUtils; + +import java.util.*; + +/** + * @Description: 工作流引擎请求参数 + **/ +@Data +public class EngineRequest { + + public static final String pattern = "yyyyMMddHHmmss"; + + /** + * 操作类型 + */ + private OperateType action; + + /** + * 待办id + */ + private Long taskId; + + /** + * 上一个非自动提交的待办id + */ + private Long lastNotAutoSubmitNodeTaskId; + + /** + * 数据id + */ + private Long dataId; + + /** + * 流程定义id + */ + private Long definitionId; + + /** + * 流程定义配置 + */ + private Model model; + + /** + * 流程实例 + */ + private InstanceData instance; + + /** + * 实例待办任务 + */ + private InstanceTask instanceTask; + + /** + * 当前节点信息 + */ + private Node current; + + /** + * 上一个非自动流转节点 + */ + private Node lastNotAutoSubmitNode; + + /** + * 当前节点类型 + */ + private NodeType nodeType; + + /** + * 当前节点状态 + */ + private NodeStage nodeStage = NodeStage.flowed; + + /** + * 是否满足节点流转规则 + */ + private Boolean flowRule = true; + + /** + * 表单提交的业务数据 + */ + private FormData form; + + /** + * 处理人id + */ + private FlowUser handlerUser; + + /** + * 转交人 + */ + private FlowUser forwardUser; + + /** + * 请求时间(格式yyyyMMddHHmmss) + */ + private String requestTime; + + /** + * 当前节点是否自动提交 + */ + private Boolean autoSubmit = false; + + /** + * 是否批量操作 + */ + private Boolean isBatch = false; + + + /** + * 是否管理员操作 + */ + private Boolean isManage = false; + + /** + * 当前处理所涉及的任务 + */ + private List tasks; + + + public EngineRequest(){ + } + + public EngineRequest(Model model){ + this.model = model; + } + + public EngineRequest(Model model, Node current){ + this.model = model; + this.current = current; + } + + @Data + public static class FormData{ + + /** + * 表单id + */ + private Long formId; + + /** + * 表单code + */ + private String formCode; + + /** + * 表单名称 + */ + private String formName; + + /** + * 表单数据 + */ + private LinkedHashMap data; + + /** + * 审核文本意见 + */ + private String comment; + + /** + * 手写签名 + */ + private String signature; + + /** + * 数据改动字段 + */ + private Set changedWidgets; + + } + + @Data + public static class InstanceData extends Instance { + + /** + * 自动流转的节点 + */ + private List autoSubmitNodes; + + /** + * 即将流转的节点( preset,start,task,cc,end ) + */ + private Map> nextNodes; + + /** + * (任务节点审核人 任务节点抄送人 任务节点转交人 抄送节点抄送人) + */ + private Map>> users; + + /** + * 转交的节点负责人 + */ + private List forwardUsers; + + public InstanceData(EngineRequest request){ + this.setFormId(request.getForm().getFormId()); + if(ObjectUtil.isNotEmpty(request.getDataId())){ + this.setDataId(request.getDataId()); + } + this.setDefinitionId(request.getDefinitionId()); + this.setStage(InstanceStage.starting); + //所属应用 + this.setNodeKeys(new ArrayList<>()); + // this.setRoutes(new ArrayList<>()); + + this.setDeleted(false); + this.setCreateUser(request.getHandlerUser().getId()); + this.setCreateName(request.getHandlerUser().getName()); + this.setCreateAccount(request.getHandlerUser().getAccount()); + this.setCreateTime(DateUtil.parse(request.getRequestTime(),pattern)); + + this.nextNodes = new HashMap<>(); + this.users = new HashMap<>(); + } + + public InstanceData(Instance instance){ + BeanUtils.copyProperties(instance,this); + this.users = new HashMap<>(); + this.nextNodes = new HashMap<>(); + } + + public void addNodes(NodeType type,List nodeList){ + if(this.nextNodes == null){ + this.nextNodes = new HashMap<>(); + } + this.nextNodes.put(type,nodeList); + } + + } + + + public Node getModelStartNode(){ + return this.getModel().getNodeList().stream().filter(p -> StrUtil.equals(NodeType.start.name(),p.getId())).findFirst().get(); + } + public Node getModelEndNode(){ + return this.getModel().getNodeList().stream().filter(p -> StrUtil.equals(NodeType.end.name(),p.getId())).findFirst().get(); + } + + public void updateInstanceStage(InstanceStage stage){ + this.getInstance().setStage(stage); + } + + public void clearFormComment(){ + this.form.comment = null; + this.form.signature = null; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/param/instance/InstanceLogParam.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/param/instance/InstanceLogParam.java new file mode 100644 index 0000000..2d43502 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/param/instance/InstanceLogParam.java @@ -0,0 +1,91 @@ +package org.dromara.workflow.param.instance; + +import org.dromara.workflow.engine.domain.Instance; +import org.dromara.workflow.engine.domain.InstanceLog; +import org.dromara.workflow.engine.enums.NodeType; +import org.dromara.workflow.engine.enums.OperateType; +import org.dromara.workflow.engine.model.setting.Node; +import org.dromara.workflow.param.model.FlowUser; +import cn.hutool.core.util.StrUtil; +import lombok.Data; + +import java.util.Date; +import java.util.List; + +/** + * @Description: 流程日志dto + **/ +@Data +public class InstanceLogParam { + + private InstanceLog.HandlerType userType; + + private FlowUser userInfo; + + private Instance instance; + + private Node node; + + private OperateType action; + + private Boolean isBatch; + + private List nextNodes; + + private Boolean autoCommit; + + private SubmitContent content; + + private Date createTime; + + /** + * 提交附加内容 + */ + @Data + public class SubmitContent{ + //审核意见 + private String comment; + + //手写签名 + private String signatrue; + + } + + public InstanceLogParam(){} + + public InstanceLogParam(OperateType action,Instance instance,Node node,Boolean isAuto,Date createTime){ + if(StrUtil.equals(node.getId(), NodeType.start.name()) || StrUtil.equals(node.getId(), NodeType.preset.name())){ + this.userType = InstanceLog.HandlerType.CHARGER; + } + + this.userType = isAuto ? InstanceLog.HandlerType.ROBOT : InstanceLog.HandlerType.CHARGER ; + this.instance = instance; + this.node = node; + this.action = action; + this.autoCommit = isAuto; + this.isBatch = false; + this.createTime = createTime; + } + + public InstanceLogParam(OperateType action,Instance instance,Node node,Date createTime){ + this.userType = InstanceLog.HandlerType.SYSTEM ; + this.instance = instance; + this.node = node; + this.action = action; + this.autoCommit = false; + this.isBatch = false; + this.createTime = createTime; + } + + + public void addContent(String comment,String signatrue){ + SubmitContent sc = new SubmitContent(); + sc.setComment(comment); + sc.setSignatrue(signatrue); + this.content = sc; + } + public void addUser(Long userId,String userName,String userAccount){ + this.userInfo = new FlowUser(userId,userName,userAccount); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/param/model/DefinitionParam.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/param/model/DefinitionParam.java new file mode 100644 index 0000000..81b0f72 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/param/model/DefinitionParam.java @@ -0,0 +1,63 @@ +package org.dromara.workflow.param.model; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +/** + * @Description: 流程定义请求参数 + **/ +@Data +public class DefinitionParam { + + private Long id; + + private String appId; + + private String app; + + @NotNull(message = "表单id不能为空", + groups = {create.class,update.class,active.class,delete.class,detail.class}) + private Long formId; + + + @NotNull(message = "配置模型不能为空", groups = {create.class,update.class}) + private String model; + + public DefinitionParam(Long formId){ + this.formId = formId; + } + + public DefinitionParam(Long formId, Long id){ + this.formId = formId; + this.id = id; + } + + public DefinitionParam(){ + } + + /** + * 参数校验分组:创建 + */ + public @interface create {} + + /** + * 参数校验分组:更新 + */ + public @interface update {} + + /** + * 参数校验分组:激活 + */ + public @interface active {} + + + /** + * 参数校验分组:删除 + */ + public @interface delete {} + + /** + * 参数校验分组:详情 + */ + public @interface detail {} +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/param/model/FlowUser.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/param/model/FlowUser.java new file mode 100644 index 0000000..778e627 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/param/model/FlowUser.java @@ -0,0 +1,51 @@ +package org.dromara.workflow.param.model; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.Data; + +import java.util.List; + +/** + * @Author: yinzw + * @Date: 2021/7/29 + * @Description: 工作流用户对象 + **/ +@Data +public class FlowUser { + + /** + * 唯一标识 + */ + private Long id; + + /** + * 用户名称 + */ + private String name; + + /** + * 用户账号 + */ + private String account; + + /** + * 用户所在部门 + */ + @JsonIgnore + private List deptIds; + + public FlowUser(){} + + public FlowUser(Long id,String name,String account){ + this.id = id; + this.name = name; + this.account = account; + } + + public FlowUser(Long id,String name,String account,List deptIds){ + this.id = id; + this.name = name; + this.account = account; + this.deptIds = deptIds; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/param/operate/WorkflowParamWorkflow.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/param/operate/WorkflowParamWorkflow.java new file mode 100644 index 0000000..482b648 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/param/operate/WorkflowParamWorkflow.java @@ -0,0 +1 @@ +package org.dromara.workflow.param.operate; diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/remind/builder/BaseRemindBuilder.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/remind/builder/BaseRemindBuilder.java new file mode 100644 index 0000000..d77f2a9 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/remind/builder/BaseRemindBuilder.java @@ -0,0 +1,109 @@ +package org.dromara.workflow.remind.builder; + +import org.dromara.workflow.remind.model.Reminder; +import cn.hutool.core.util.StrUtil; +import lombok.Getter; + +import java.util.Date; +import java.util.List; + +/** + * 流程提醒builder + * @param + */ +@Getter +public class BaseRemindBuilder { + private String remindUrl; + // 流程实例ID + private Long instanceId; + + // 流程实例发起人名称 + private String instanceCreatorName; + + // 流程实例发起人账号 + private String instanceCreatorAccount; + + // 流程实例发起时间 + private Date instanceCreateTime; + + // 流程实例最后更新时间 + private Date instanceUpdateTime; + + // 流程实例状态 + private String instanceStatus; + + // 下个task节点名称 + private List nextNodes; + + // 表单id + private Long formId; + + /** + * 表单code + */ + private String formCode; + + // 表单名称 + private String formName; + + // 流程实例操作 + private String operate; + + // 提醒信息 + private List reminders; + + // 执行操作时间 + private Date operateTime; + + public T remindUrl(String remindUrl){ + this.remindUrl = remindUrl; + return (T)this; + } + + public T instance(Long instanceId, String instanceStatus, String createName, String createAccount, Date createTime, Date updateTime){ + this.instanceId = instanceId; + this.instanceStatus = instanceStatus; + this.instanceCreatorName = createName; + this.instanceCreatorAccount = createAccount; + this.instanceCreateTime = createTime; + this.instanceUpdateTime = updateTime; + return (T)this; + } + + public T operateTime(Date operateTime){ + this.operateTime =operateTime; + return (T)this; + } + + public T nextNodes(List nextNodes){ + this.nextNodes = nextNodes; + return (T) this; + } + + public T form(Long formId, String formCode,String formName){ + this.formCode = formCode; + this.formId = formId; + this.formName = formName; + return (T)this; + } + + public T operate(String operate){ + this.operate = operate; + return (T)this; + } + + public T reminders(List reminders){ + this.reminders = reminders; + return (T)this; + } + + public String getRemindUrl(String remindType, Long remindId){ + return StrUtil.format(remindUrl,remindType,remindId); + } + + public String getHandledUrl(Long remindId) { + return StrUtil.format(remindUrl,"handle",remindId); + } + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/remind/builder/RemindMessage.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/remind/builder/RemindMessage.java new file mode 100644 index 0000000..9deabd5 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/remind/builder/RemindMessage.java @@ -0,0 +1,8 @@ +package org.dromara.workflow.remind.builder; + +/** + * 流程提醒消息 + */ +public class RemindMessage { + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/remind/flow/FlowInstanceProducer.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/remind/flow/FlowInstanceProducer.java new file mode 100644 index 0000000..1a8ff16 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/remind/flow/FlowInstanceProducer.java @@ -0,0 +1,505 @@ +package org.dromara.workflow.remind.flow; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.compress.utils.Lists; +import org.dromara.dataManager.widget.convert.enums.FormColumnType; +import org.dromara.dataManager.widget.convert.model.FormDataConvert; +import org.dromara.dataManager.widget.convert.service.FormDataConvertService; +import org.dromara.formMaking.domain.FormSource; +import org.dromara.formMaking.service.FormSourceService; +import org.dromara.workflow.engine.domain.InstanceCc; +import org.dromara.workflow.engine.domain.InstanceTask; +import org.dromara.workflow.engine.enums.HandleUserType; +import org.dromara.workflow.engine.enums.InstanceStage; +import org.dromara.workflow.engine.enums.NodeType; +import org.dromara.workflow.engine.enums.OperateType; +import org.dromara.workflow.engine.model.setting.Cell; +import org.dromara.workflow.engine.model.setting.Field; +import org.dromara.workflow.engine.model.setting.Node; +import org.dromara.workflow.param.engine.EngineRequest; +import org.dromara.workflow.param.model.FlowUser; +import org.dromara.workflow.remind.flow.model.FlowInstanceMessage; +import org.dromara.workflow.remind.model.Reminder; +import org.dromara.workflow.result.instance.InstanceCcResult; +import org.dromara.workflow.service.external.FlowModelService; +import org.dromara.workflow.service.external.FlowTaskService; +import org.dromara.workflow.service.internal.InstanceTaskService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 流程实例消息provider + */ +@Slf4j +@Component +public class FlowInstanceProducer { + + private List RECALL_CANCEL_SCHOOLS = CollUtil.newArrayList(); + + + @Autowired + private FormSourceService formSourceService; + @Autowired + private FlowModelService flowModelService; + + @Autowired + private FlowTaskService workflowService; + @Autowired + private InstanceTaskService instanceTaskService; + @Autowired + private FormDataConvertService dataConvertService; + + private String REMIND_URL; + + + /** + * 刷新REMIND_URL + */ + private void refreshRemindUrl(){ + REMIND_URL = "/workplace/flowCenter/{}/{}"; + } + + //不显示字段6种字段:编辑器、分割线 子表单、关联查询、编辑器、关联数据 + private static final List unlessFields = Arrays.asList(FormColumnType.TABLE.getCode(),FormColumnType.LINK_QUERY.getCode(), + FormColumnType.DATA_LINK.getCode(),FormColumnType.EDITOR.getCode(),FormColumnType.DIVIDER.getCode(), FormColumnType.COORDINATES.getCode()); + + + + public void send(EngineRequest message){ + this.refreshRemindUrl(); + FlowInstanceMessage instanceMessage = transformInstanceMessage(message); + List remindWays = instanceMessage.getDefinition().getRemind().getWays(); + + //开通流程消息提醒 && 流程实例的操作是否需要提醒 + if (CollUtil.isNotEmpty(remindWays) && this.isRemindOperate(instanceMessage.getOperate())) { + + //流程表单 + FormSource form = this.formSourceService.getById(instanceMessage.getInstance().getFormId()); + if (form == null) { + log.error("流程提醒失败:指定的表单不存在 fromId = {}", instanceMessage.getInstance().getFormId()); + return; + } + log.debug("flow remind form {}", form.getCode()); + instanceMessage.getInstance().setFormCode(form.getCode()); + + // 获取节点提醒用户信息 + List reminderList = this.getReminderList(instanceMessage); + log.debug("reminderList size {}", reminderList == null ? 0 : reminderList.size()); + + if (!reminderList.isEmpty()) { + remindWays.stream().filter(c -> { + if (instanceMessage.getOperate().equals(OperateType.recall.getCode()) || instanceMessage.getOperate().equals(OperateType.cancel.getCode())) { + // 仅对指定的消息通知的撤回发起消息提醒 + return RECALL_CANCEL_SCHOOLS.contains(c); + } else { + return true; + } + }).forEach(c -> { + log.info("flow remind way {}", c); + }); + + } + } + } + + + + + private FlowInstanceMessage transformInstanceMessage(EngineRequest param) { + FlowInstanceMessage wrapMessage = new FlowInstanceMessage(); + wrapMessage.setTasks(param.getTasks()); + + //流程定义 + FlowInstanceMessage.Definition definition = new FlowInstanceMessage.Definition(); +// definition.getRemind().setWays(param.getModel().getConfig().getRemindWays().stream().filter(remind -> pluginConfigService.checkPluginActive(MessagePluginEnum.valueOf(remind).name())).collect(Collectors.toList())); + + // 设置流程定义的开始节点 + Node startNode = param.getModelStartNode(); + definition.setDefinitionId(param.getDefinitionId()); + definition.setStartNode(new FlowInstanceMessage.Node(startNode.getId(), startNode.getName())); + wrapMessage.setDefinition(definition); + + //流程实例 + FlowInstanceMessage.Instance instance = new FlowInstanceMessage.Instance(); + BeanUtil.copyProperties(param.getInstance(), instance); + + Set ccNodeIds = new HashSet<>(); + if(CollectionUtil.isNotEmpty(param.getInstance().getNextNodes().get(NodeType.start))){ + instance.setNextTaskNodeIds(param.getInstance().getNextNodes().get(NodeType.start).stream().map(Cell::getId).collect(Collectors.toList())); + }else if(CollectionUtil.isNotEmpty(param.getInstance().getNextNodes().get(NodeType.task))){ + List nextTaskIds = param.getInstance().getNextNodes().get(NodeType.task).stream().map(Cell::getId).collect(Collectors.toList()); + if(CollUtil.isNotEmpty(nextTaskIds)){ + instance.setNextTaskNodeIds(nextTaskIds); + Map> nodeCcUsers = param.getInstance().getUsers().get(HandleUserType.TaskCcUser); + for(String nodeId : nextTaskIds){ + if(nodeCcUsers != null && CollUtil.isNotEmpty(nodeCcUsers.get(nodeId))){ + ccNodeIds.add(nodeId); + } + } + } + } + + if(CollectionUtil.isNotEmpty(param.getInstance().getNextNodes().get(NodeType.cc))){ + ccNodeIds.addAll(param.getInstance().getNextNodes().get(NodeType.cc).stream().map(Cell::getId).collect(Collectors.toSet())); + } + instance.setNextCcNodeIds(new ArrayList<>(ccNodeIds)); + + //设置转交负责人 + if(OperateType.forward.equals(param.getAction())){ + instance.setForwardUsers(Arrays.asList(param.getInstance().getUsers().get(HandleUserType.TaskForwardUser).get(param.getCurrent().getId()).get(0).getId())); + } + if(OperateType.transfer.equals(param.getAction())){ + instance.setForwardUsers(param.getInstance().getForwardUsers()); + } + + instance.setStatus(param.getInstance().getStage().name()); + instance.setCounterSign(!param.getFlowRule()); + + //当前节点日志信息 + instance.setCurrentNode(generateNodeInfo(param)); + wrapMessage.setInstance(instance); + + // last not auto submit node + instance.setLastNotAutoSubmitNode(generateLastNotAutoSubmitNodeInfo(param)); + + //实例操作 + wrapMessage.setOperate(param.getAction().name()); + //是否批量操作 + wrapMessage.setIsBatch(param.getIsBatch()); + + FlowInstanceMessage.ManageInfo manageInfo = new FlowInstanceMessage.ManageInfo(); + + //设置管理员信息 + if(param.getAutoSubmit()){ + manageInfo.addSystemRobot(); + }else{ + manageInfo.addUser(param.getHandlerUser().getId(),param.getHandlerUser().getName(),param.getHandlerUser().getAccount()); + } + wrapMessage.setManageInfo(manageInfo); + + return wrapMessage; + } + + + public FlowInstanceMessage.Instance.NodeInfo generateNodeInfo(EngineRequest request){ + FlowInstanceMessage.Instance.NodeInfo nodeInfo = new FlowInstanceMessage.Instance.NodeInfo(); + if(request.getCurrent() != null){ + nodeInfo.setNodeKey(request.getCurrent().getId()); + nodeInfo.setNodeName(request.getCurrent().getName()); + if (request.getCurrent().getEnd() != null) { + nodeInfo.setNodeFlowRuleType(request.getCurrent().getEnd().getFlowRule().getType().getCode()); + } + } + nodeInfo.setHandlerId(request.getHandlerUser().getId()); + nodeInfo.setHandlerName(request.getHandlerUser().getName()); + nodeInfo.setHandlerAccount(request.getHandlerUser().getAccount()); + nodeInfo.setAutoCommit(request.getAutoSubmit() ? 1 : 0); + + if(StrUtil.isNotEmpty(request.getForm().getComment())){ + nodeInfo.setComment(request.getForm().getComment()); + } + if(StrUtil.isNotEmpty(request.getForm().getSignature())){ + nodeInfo.setSignature(request.getForm().getSignature()); + } + nodeInfo.setUpdateTime(DateUtil.parse(request.getRequestTime(),EngineRequest.pattern)); + nodeInfo.setTaskId(request.getTaskId()); + + return nodeInfo; + } + + public FlowInstanceMessage.Instance.NodeInfo generateLastNotAutoSubmitNodeInfo(EngineRequest request){ + if (request.getLastNotAutoSubmitNode() == null) { + return null; + } + FlowInstanceMessage.Instance.NodeInfo nodeInfo = new FlowInstanceMessage.Instance.NodeInfo(); + + nodeInfo.setNodeKey(request.getLastNotAutoSubmitNode().getId()); + nodeInfo.setNodeName(request.getLastNotAutoSubmitNode().getName()); + if (request.getLastNotAutoSubmitNode().getEnd() != null) { + nodeInfo.setNodeFlowRuleType(request.getLastNotAutoSubmitNode().getEnd().getFlowRule().getType().getCode()); + } + + nodeInfo.setHandlerId(request.getHandlerUser().getId()); + nodeInfo.setHandlerName(request.getHandlerUser().getName()); + nodeInfo.setHandlerAccount(request.getHandlerUser().getAccount()); + nodeInfo.setAutoCommit(request.getAutoSubmit() ? 1 : 0); + + if(StrUtil.isNotEmpty(request.getForm().getComment())){ + nodeInfo.setComment(request.getForm().getComment()); + } + if(StrUtil.isNotEmpty(request.getForm().getSignature())){ + nodeInfo.setSignature(request.getForm().getSignature()); + } + nodeInfo.setUpdateTime(DateUtil.parse(request.getRequestTime(),EngineRequest.pattern)); + nodeInfo.setTaskId(request.getLastNotAutoSubmitNodeTaskId()); + + return nodeInfo; + } + + + /** + * 是否为提醒操作 + * @param oper + * @return + */ + private boolean isRemindOperate(String oper){ + OperateType operate = OperateType.getOperate(oper); + if(operate != null){ + if(operate.equals(OperateType.submit) || operate.equals(OperateType.forward) || operate.equals(OperateType.rollback) + || operate.equals(OperateType.finish) || operate.equals(OperateType.active) || operate.equals(OperateType.transfer) + || operate.equals(OperateType.urge) || operate.equals(OperateType.recall) || operate.equals(OperateType.cancel)){ + return true; + } + } + return false; + } + + /** + * 获取提醒人信息 + * @param data + * @return + */ + private List getReminderList(FlowInstanceMessage data){ + List reminders = new LinkedList<>(); + OperateType operate = OperateType.getOperate(data.getOperate()); + switch (operate){ + case submit: + case active: + reminders = this.getReminderListByTaskCcNode(data.getDefinition(), data.getInstance()); + break; + case forward: + case transfer: + reminders = this.getReminderListByForwardUser(data.getDefinition(), data.getInstance()); + break; + case rollback: + reminders = this.getReminderListByRollbackNode(data.getDefinition(), data.getInstance()); + break; + case finish: + reminders = this.getReminderListByStartNode(data.getDefinition(), data.getInstance()); + break; + case urge: + reminders = this.getUrgeReminders(data.getInstance()); + case cancel: + case recall: + reminders = this.getReminderListByRecallCancelNode(data.getInstance()); + } + return reminders; + } + + private List getReminderListForCounterSign(FlowInstanceMessage.Instance instance) { + List reminders = new LinkedList<>(); + instance.getCurrentNode(); + Reminder reminder = new Reminder(instance.getCurrentNode().getNodeKey(), instance.getCurrentNode().getNodeName(), instance.getCurrentNode().getHandlerId(),instance.getCurrentNode().getHandlerAccount(), Reminder.TYPE_TODO, instance.getId(), null); + reminders.add(reminder); + return reminders; + } + + private List getReminderListByRecallCancelNode(FlowInstanceMessage.Instance instance) { + List reminders = new LinkedList<>(); + instance.getCurrentNode(); + Reminder reminder = new Reminder(instance.getCurrentNode().getNodeKey(), instance.getCurrentNode().getNodeName(), instance.getCurrentNode().getHandlerId(),instance.getCreateAccount(), Reminder.TYPE_CC, instance.getId(), null); + reminders.add(reminder); + return reminders; + } + + /** + * 查找下面的抄送节点抄送人以及接下来的流转节点启用抄送的抄送人 + * @param definition + * @param instance + * @return + */ + private List getReminderListByTaskCcNode(FlowInstanceMessage.Definition definition, FlowInstanceMessage.Instance instance){ + + + //如果审核操作, + List reminders = new LinkedList<>(); + if(InstanceStage.completed.name().equals(instance.getStatus())){ + + List formDataConverted = this.getFormDataConvert(instance.getFormId(), instance.getFormCode(),instance.getDataId(),definition.getDefinitionId(),NodeType.start.name()); + //提醒流程发起人任务 + List startTaskList = this.workflowService.listNodesHandledTask(instance.getId(),Arrays.asList(NodeType.start.name())); + if(CollUtil.isNotEmpty(startTaskList)){ + reminders.add(new Reminder(definition.getStartNode().getId(), definition.getStartNode().getName(), + instance.getCreateUser(),instance.getCreateAccount(), Reminder.TYPE_START, instance.getId(),formDataConverted)); + } + + }else if(CollectionUtil.isNotEmpty(instance.getNextTaskNodeIds())){ + //查询流程实例指定节点上的待办任务 + List tasks = this.workflowService.listNodesTask(instance.getId(), instance.getNextTaskNodeIds()); + if(tasks != null){ + tasks.forEach(t->{ + List formDataConverted = this.getFormDataConvert(instance.getFormId(), instance.getFormCode(),instance.getDataId(),definition.getDefinitionId(),t.getNodeKey()); + + reminders.add(new Reminder(t.getNodeKey(), t.getNodeName(), t.getUserId(), t.getUserAccount(), + Reminder.TYPE_TODO,t.getId(),formDataConverted)); + }); + } + } + + if(CollUtil.isNotEmpty(instance.getNextCcNodeIds())){ + + //查询流程实例抄送节点上的抄送任务 + Map> ccTask = this.workflowService.listNodesCc(instance.getId(),instance.getNextCcNodeIds()).stream().collect(Collectors.groupingBy(InstanceCc::getUserId)); + for(Long userId: ccTask.keySet()){ + List ccList = ccTask.get(userId); + if(CollUtil.isNotEmpty(ccList)){ + InstanceCcResult latestCc = ccList.get(0); + List formDataConverted = this.getFormDataConvert(instance.getFormId(), instance.getFormCode(),instance.getDataId(),definition.getDefinitionId(),latestCc.getNodeKey()); + + reminders.add(new Reminder(latestCc.getNodeKey(), latestCc.getNodeName(), userId,latestCc.getUserAccount(), Reminder.TYPE_CC,latestCc.getId(),formDataConverted)); + + } + } + } + + return reminders; + + } + + /** + * 查询下面审核节点的催办负责人 + * @param instance + * @return + */ + private List getUrgeReminders(FlowInstanceMessage.Instance instance){ + List reminders = new LinkedList<>(); + List priorityTodo = this.workflowService.listPriorityTodo(instance.getId()); + if(CollUtil.isNotEmpty(priorityTodo)){ + priorityTodo.forEach(t->{ + if(!t.getUserId().equals(instance.getCreateUser())){ + reminders.add(new Reminder(t.getNodeKey(), t.getNodeName(), t.getUserId(), t.getUserAccount(), Reminder.TYPE_TODO,t.getId(),null)); + } + }); + } + return reminders; + } + + /** + * 根据转交用户查询提醒数据 + * @param definition + * @param instance + * @return + */ + private List getReminderListByForwardUser(FlowInstanceMessage.Definition definition, FlowInstanceMessage.Instance instance){ + List reminders = new LinkedList<>(); + + if(CollUtil.isNotEmpty(instance.getForwardUsers())){ + List taskList = this.instanceTaskService.getUsersNodeUnHandleTask(instance.getId(),instance.getCurrentNode().getNodeKey(), instance.getForwardUsers()); + + if(CollUtil.isNotEmpty(taskList)){ + List formDataConverted = this.getFormDataConvert(instance.getFormId(),instance.getFormCode(),instance.getDataId(),definition.getDefinitionId(),instance.getCurrentNode().getNodeKey()); + + taskList.forEach(p -> { + reminders.add(new Reminder(p.getNodeKey(), p.getNodeName(), + p.getUserId(), + p.getUserAccount(), + Reminder.TYPE_TODO, + p.getId(), + formDataConverted)); + }); + + return reminders; + } + } + + return null; + } + + + + /** + * 从开始节点上获取提醒数据 + * @return + */ + private List getReminderListByStartNode(FlowInstanceMessage.Definition definition, FlowInstanceMessage.Instance instance){ + List reminders = new LinkedList<>(); + List formDataConverted = this.getFormDataConvert(instance.getFormId(), instance.getFormCode(),instance.getDataId(),definition.getDefinitionId(),NodeType.start.name()); + //提醒流程发起人任务 + reminders.add(new Reminder(definition.getStartNode().getId(), definition.getStartNode().getName(), + instance.getCreateUser(),instance.getCreateAccount(), Reminder.TYPE_START, instance.getId(),formDataConverted)); + + return reminders; + } + + /** + * 从回退节点上获取提醒数据 + * @return + */ + private List getReminderListByRollbackNode(FlowInstanceMessage.Definition definition, + FlowInstanceMessage.Instance instance){ + List taskNodeIds = instance.getNextTaskNodeIds(); + if(CollectionUtil.isNotEmpty(taskNodeIds)){ + + List reminders = new LinkedList<>(); + String nodeId = taskNodeIds.get(0); + if(NodeType.start.name().equals(nodeId)){ + InstanceTask task = this.workflowService.getUserTask(instance.getId(),nodeId,instance.getCreateUser()); + if(task != null){ + List formDataConverted = this.getFormDataConvert(instance.getFormId(), instance.getFormCode(),instance.getDataId(),definition.getDefinitionId(),NodeType.start.name()); + + reminders.add(new Reminder(task.getNodeKey(), task.getNodeName(), task.getUserId(),task.getUserAccount(),Reminder.TYPE_TODO, task.getId(),formDataConverted)); + } + }else { + List tasks = this.workflowService.listNodesTask(instance.getId(), instance.getNextTaskNodeIds()); + if(tasks != null){ + tasks.forEach(t->{ + List formDataConverted = this.getFormDataConvert(instance.getFormId(), instance.getFormCode(),instance.getDataId(),definition.getDefinitionId(),t.getNodeKey()); + + reminders.add(new Reminder(t.getNodeKey(), t.getNodeName(), t.getUserId(), t.getUserAccount(), Reminder.TYPE_TODO, t.getId(),formDataConverted)); + }); + } + } + + if(CollUtil.isNotEmpty(instance.getNextCcNodeIds())){ + + //查询流程实例抄送节点上的抄送任务 + Map> ccTask = this.workflowService.listNodesCc(instance.getId(),instance.getNextCcNodeIds()).stream().collect(Collectors.groupingBy(InstanceCc::getUserId)); + for(Long userId: ccTask.keySet()){ + List ccList = ccTask.get(userId); + if(CollUtil.isNotEmpty(ccList)){ + InstanceCc latestCc = ccList.get(0); + List formDataConverted = this.getFormDataConvert(instance.getFormId(), instance.getFormCode(),instance.getDataId(),definition.getDefinitionId(),latestCc.getNodeKey()); + + reminders.add(new Reminder(latestCc.getNodeKey(), latestCc.getNodeName(), userId,latestCc.getCreateAccount(), Reminder.TYPE_CC,latestCc.getId(),formDataConverted)); + + } + } + } + + return reminders; + } + + return null; + } + + + private List getFormDataConvert(Long formId,String formCode,Long dataId,Long definitionId, + String nodeId){ + if(ObjectUtil.hasEmpty(formId,formCode,dataId)){ + + return Lists.newArrayList(); + } + + List nodeFields = flowModelService.getNodeViewFields(definitionId,nodeId); + + List viewNodeFields = nodeFields.stream().filter( s -> !unlessFields.contains(s.getType())).map(Field::getId).collect(Collectors.toList()); + + if(CollUtil.isEmpty(viewNodeFields)){ + return Lists.newArrayList(); + } + + List convertedFields = viewNodeFields.subList(0,Math.min(viewNodeFields.size(),3)); + + return dataConvertService.convert(formId,formCode,dataId,convertedFields); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/remind/flow/FlowRemindHelper.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/remind/flow/FlowRemindHelper.java new file mode 100644 index 0000000..24eba32 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/remind/flow/FlowRemindHelper.java @@ -0,0 +1,37 @@ +package org.dromara.workflow.remind.flow; + +import org.dromara.workflow.engine.domain.InstanceTask; +import org.dromara.workflow.engine.enums.TaskStatus; +import org.dromara.workflow.remind.flow.model.FlowRemindInstanceTask; +import org.dromara.workflow.service.internal.InstanceTaskService; +import cn.hutool.core.collection.CollUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +@Component +public class FlowRemindHelper { + @Autowired + private InstanceTaskService instanceTaskService; + + public List getTasks(Long instanceId, String nodeId, TaskStatus status) { + List result = new ArrayList<>(); + List tasks = instanceTaskService.listInstanceTask(instanceId, nodeId, status); + if (CollUtil.isNotEmpty(tasks)) { + result = tasks.stream().map(t -> { + FlowRemindInstanceTask task = new FlowRemindInstanceTask(); + task.setId(t.getId()); + task.setUserId(t.getUserId()); + task.setUserName(t.getUserName()); + task.setUserAccount(t.getUserAccount()); + task.setNodeKey(t.getNodeKey()); + task.setNodeName(t.getNodeName()); + return task; + }).collect(Collectors.toList()); + } + return result; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/remind/flow/model/FlowInstanceMessage.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/remind/flow/model/FlowInstanceMessage.java new file mode 100644 index 0000000..2db842d --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/remind/flow/model/FlowInstanceMessage.java @@ -0,0 +1,206 @@ +package org.dromara.workflow.remind.flow.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class FlowInstanceMessage implements Serializable{ + + private static final long serialVersionUID = 8581036651376358671L; + + private Definition definition; + + private Instance instance; + + /** + * 操作类型 + */ + private String operate; + + /** + * 修改的数据 + */ + private String editData; + + /** + * 是否是批量操作 + */ + private Boolean isBatch; + + /** + * 流程监控管理员信息 + */ + private ManageInfo manageInfo; + + /** + * 当前处理所涉及的任务 + */ + private List tasks; + + /** + * 流程定义 + */ + @Data + public static class Definition implements Serializable{ + private static final long serialVersionUID = 2798105805023398628L; + private Long definitionId; + private Node startNode; + private Remind remind; + public Definition(){ + this.remind = new Remind(); + } + + + @Data + public class Remind implements Serializable{ + private static final long serialVersionUID = 5696444732184056746L; + private boolean open = false; + private List ways = new LinkedList(); + + public void setWays(List ways){ + if(ways != null && !ways.isEmpty()){ + this.open = true; + this.ways.addAll(ways); + } + } + } + } + + /** + * 流程实例 + */ + @Data + public static class Instance implements Serializable{ + private static final long serialVersionUID = -544283443570812529L; + //实例id + private Long id; + //表单id + private Long formId; + //表单code + private String formCode; + //数据id + private Long dataId; + // 实例发起人id + private Long createUser; + // 实例发起人账号 + private String createAccount; + // 实例发起人名称 + private String createName; + // 实例发起时间 + private Date createTime; + // 实例更新时间 + private Date updateTime; + //下个任务节点名称 + private List nextTaskNodeIds; + //下个抄送任务节点名称 + private List nextCcNodeIds; + //状态 + private String status; + //当前流转节点内容 + private NodeInfo currentNode; + // 上一个非自动流转节点 + private NodeInfo lastNotAutoSubmitNode; + //调整节点负责人 + private List forwardUsers; + // 是否会签 + private boolean isCounterSign = false; + /** + * 当前处理节点 + */ + @Data + public static class NodeInfo implements Serializable { + private static final long serialVersionUID = -544283443570812529L; + + private String nodeKey; + + private String nodeName; + + private Long handlerId; + + private String handlerAccount; + + private String handlerName; + + private String comment; + + private String signature; + + private String dataChange; + + private Integer autoCommit; + + private Date updateTime; + + private Long taskId; + + private Integer nodeFlowRuleType; + + } + } + + /** + * 操作 + */ + @Data + public static class Operate implements Serializable{ + private static final long serialVersionUID = 9124186366213391000L; + private String code; + private String name; + public Operate(String code, String name){ + this.code = code; + this.name = name; + } + } + + @Data + public static class ManageInfo implements Serializable{ + private static final long serialVersionUID = 9124186366213391001L; + private Long userId; + private String userName; + private String userAccount; + + public ManageInfo(){} + + public ManageInfo(Long userId, String userName,String userAccount){ + this.userId = userId; + this.userName = userName; + this.userAccount = userAccount; + } + + public void addSystemRobot(){ + this.userId = -1L; + this.userName = "系统机器人"; + } + + public void addUser(Long userId,String userName,String userAccount){ + this.userId = userId; + this.userName = userName; + this.userAccount = userAccount; + } + + } + + + + @Data + public static class Node implements Serializable{ + private static final long serialVersionUID = 9124186366213392000L; + // 节点id + private String id; + //节点名称 + private String name; + + public Node(String id, String name){ + this.id = id; + this.name = name; + } + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/remind/flow/model/FlowRemindInstanceTask.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/remind/flow/model/FlowRemindInstanceTask.java new file mode 100644 index 0000000..ad866fd --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/remind/flow/model/FlowRemindInstanceTask.java @@ -0,0 +1,18 @@ +package org.dromara.workflow.remind.flow.model; + +import lombok.Data; + +@Data +public class FlowRemindInstanceTask { + private Long id; + + private String nodeKey; + + private String nodeName; + + private Long userId; + + private String userName; + + private String userAccount; +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/remind/message/FlowRemindMessage.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/remind/message/FlowRemindMessage.java new file mode 100644 index 0000000..4088633 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/remind/message/FlowRemindMessage.java @@ -0,0 +1,19 @@ +package org.dromara.workflow.remind.message; + +import org.dromara.formMaking.domain.FormSource; +import org.dromara.workflow.remind.flow.model.FlowInstanceMessage; +import org.dromara.workflow.remind.model.Reminder; +import org.springframework.stereotype.Component; + +import java.util.List; + + +@Component +public abstract class FlowRemindMessage { + + + /** + * 发送提醒 + */ + public abstract void send(List reminders, FlowInstanceMessage instanceMessage, FormSource form, String remindUrl); +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/remind/model/RemindType.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/remind/model/RemindType.java new file mode 100644 index 0000000..ce723a6 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/remind/model/RemindType.java @@ -0,0 +1,30 @@ +package org.dromara.workflow.remind.model; + +/** + * 提醒类型 + */ +public enum RemindType { + SUBMIT("submit","提交"), + RESUBMIT("reSubmit", "再次提交"), + APPROVED("approved", "审核"), + FORWARD("forward", "转交"), + ROLLBACK("rollback", "退回"), + FINISHED("finished", "结束"); + private String operate; + private String name; + RemindType(String operate, String name){ + this.operate = operate; + this.name = name; + } + + public static boolean hasContain(String operate){ + if(operate != null && operate.length() > 0){ + for (RemindType type : RemindType.values()){ + if(type.operate.equals(operate)){ + return true; + } + } + } + return false; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/remind/model/Reminder.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/remind/model/Reminder.java new file mode 100644 index 0000000..bb37746 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/remind/model/Reminder.java @@ -0,0 +1,92 @@ +package org.dromara.workflow.remind.model; + +import lombok.Data; +import org.dromara.dataManager.widget.convert.model.FormDataConvert; + +import java.io.Serializable; +import java.util.List; + +/** + * 流程节点提醒人信息 + */ +@Data +public class Reminder implements Serializable { + private static final long serialVersionUID = 1371673680122514235L; + public static final String TYPE_TODO = "todo"; + public static final String TYPE_START = "start"; + public static final String TYPE_CC = "cc"; + + + /** + * 节点ID + */ + private String nodeId; + + /** + * 节点名称 + */ + private String nodeName; + + /** + * 用户ID + */ + private Long userId; + + /** + * 用户账号 + */ + private String userAccount; + + /** + * 手机号 + */ + private String mobile; + + /** + * 提醒类型 + */ + private String type; + + /** + * 待办任务id + */ + private Long remindId; + + /** + * 表单数据 + */ + private List formData; + + public Reminder(){ + super(); + } + public Reminder(String nodeId, String nodeName, Long userId, String userAccount,String type, Long remindId){ + this.nodeId = nodeId; + this.nodeName = nodeName; + this.userId = userId; + this.userAccount = userAccount; + this.type = type; + this.remindId = remindId; + } + + public Reminder(String nodeId, String nodeName, Long userId, String userAccount,String type, Long remindId, + List formData){ + this.nodeId = nodeId; + this.nodeName = nodeName; + this.userId = userId; + this.userAccount = userAccount; + this.type = type; + this.remindId = remindId; + this.formData = formData; + } + + /** + * 获取提醒用户唯一标识,默认返回用户account + * @return + */ + public String getReminderId(){ + return this.userAccount; + } + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/remind/plugin/MessagePluginEnum.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/remind/plugin/MessagePluginEnum.java new file mode 100644 index 0000000..5c8097e --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/remind/plugin/MessagePluginEnum.java @@ -0,0 +1,24 @@ +package org.dromara.workflow.remind.plugin; + +import lombok.Getter; + +/** + * @Description: 消息插件 + **/ +@Getter +public enum MessagePluginEnum { + + submail("赛邮短信"); + + + private String name; + + MessagePluginEnum(String name){ + this.name = name; + } + + public String code(){ + return this.name(); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/result/engine/ActionAutoSubmitResult.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/result/engine/ActionAutoSubmitResult.java new file mode 100644 index 0000000..d2814c2 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/result/engine/ActionAutoSubmitResult.java @@ -0,0 +1,65 @@ +package org.dromara.workflow.result.engine; + +import org.dromara.workflow.engine.exception.WorkflowCode; +import lombok.Data; + +import java.util.List; + +/** + * @Description: 流程引擎 + **/ +@Data +public class ActionAutoSubmitResult extends BaseActionResult { + + /** + * 响应对象 + */ + private List data; + + public ActionAutoSubmitResult() { + super(); + } + + public ActionAutoSubmitResult(String message) { + super(message); + } + + public ActionAutoSubmitResult(Integer code,String message) { + super(code,message); + } + + public ActionAutoSubmitResult(Integer code,String message,List data) { + this.setCode(code); + this.setMessage(message); + this.data = data; + } + + public ActionAutoSubmitResult(List data) { + super(); + this.data = data; + } + + public static ActionAutoSubmitResult success() { + return new ActionAutoSubmitResult(); + } + + public static ActionAutoSubmitResult success(List object) { + return new ActionAutoSubmitResult(object); + } + + public static ActionAutoSubmitResult success(Integer code, String message, List object) { + return new ActionAutoSubmitResult(code, message, object); + } + + public static ActionAutoSubmitResult error(WorkflowCode workflowCode) { + return new ActionAutoSubmitResult(workflowCode.code(),workflowCode.message()); + } + + public static ActionAutoSubmitResult error(String message) { + return new ActionAutoSubmitResult(message); + } + + public static ActionAutoSubmitResult error(Integer code, String message) { + return new ActionAutoSubmitResult(code, message); + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/result/engine/ActionNodeSubmitResult.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/result/engine/ActionNodeSubmitResult.java new file mode 100644 index 0000000..83fb4f8 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/result/engine/ActionNodeSubmitResult.java @@ -0,0 +1,64 @@ +package org.dromara.workflow.result.engine; + +import org.dromara.workflow.engine.exception.WorkflowCode; +import lombok.Data; + +/** + * @Description: 流程引擎 + **/ +@Data +public class ActionNodeSubmitResult extends BaseActionResult { + + /** + * 响应对象 + */ + private EngineDataResult data; + + + public ActionNodeSubmitResult() { + super(); + } + + public ActionNodeSubmitResult(String message) { + super(message); + } + + public ActionNodeSubmitResult(Integer code, String message) { + super(code,message); + } + + public ActionNodeSubmitResult(Integer code, String message, EngineDataResult data) { + this.setCode(code); + this.setMessage(message); + this.data = data; + } + + public ActionNodeSubmitResult(EngineDataResult data) { + this.data = data; + } + + public static ActionNodeSubmitResult success() { + return new ActionNodeSubmitResult(); + } + + public static ActionNodeSubmitResult success(EngineDataResult object) { + return new ActionNodeSubmitResult(object); + } + + public static ActionNodeSubmitResult success(Integer code, String message, EngineDataResult object) { + return new ActionNodeSubmitResult(code, message, object); + } + + public static ActionNodeSubmitResult error(WorkflowCode workflowCode) { + return new ActionNodeSubmitResult(workflowCode.code(),workflowCode.message()); + } + + public static ActionNodeSubmitResult error(String message) { + return new ActionNodeSubmitResult(message); + } + + public static ActionNodeSubmitResult error(Integer code, String message) { + return new ActionNodeSubmitResult(code, message); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/result/engine/AutoSubmitResult.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/result/engine/AutoSubmitResult.java new file mode 100644 index 0000000..aa209d9 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/result/engine/AutoSubmitResult.java @@ -0,0 +1,30 @@ +package org.dromara.workflow.result.engine; + +import org.dromara.workflow.engine.enums.nodeMoving.AutoCommitEnum; +import org.dromara.workflow.engine.model.setting.Node; +import lombok.Data; + +import java.util.List; + +/** + * @Description: 自动流转节点 + **/ +@Data +public class AutoSubmitResult { + + private AutoCommitEnum type; + + private List next; + + private AutoSubmitResult(){ + } + + public AutoSubmitResult(AutoCommitEnum type){ + this.type = type; + } + + public void addNext(List next){ + this.next = next; + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/result/engine/BaseActionResult.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/result/engine/BaseActionResult.java new file mode 100644 index 0000000..fea6ff6 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/result/engine/BaseActionResult.java @@ -0,0 +1,62 @@ +package org.dromara.workflow.result.engine; + +import org.dromara.workflow.engine.exception.WorkflowCode; +import lombok.Data; + +/** + * @Description: 流程引擎 + **/ +@Data +public class BaseActionResult { + + /** + * 请求是否成功 + */ + private Boolean success; + + /** + * 响应状态码 + */ + private Integer code; + + /** + * 响应信息 + */ + private String message; + + + public BaseActionResult() { + this.success = true; + this.code = WorkflowCode.SUCCESS.code(); + } + + + + public BaseActionResult(String message) { + this.success = false; + this.message = message; + } + + public BaseActionResult(Integer code, String message) { + this.success = false; + this.code = code; + this.message = message; + } + + public static BaseActionResult success() { + return new BaseActionResult(); + } + + public static BaseActionResult error(WorkflowCode workflowCode) { + return new BaseActionResult(workflowCode.code(),workflowCode.message()); + } + + public static BaseActionResult error(String message) { + return new BaseActionResult(message); + } + + public static BaseActionResult error(Integer code, String message) { + return new BaseActionResult(code, message); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/result/engine/EngineActionResult.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/result/engine/EngineActionResult.java new file mode 100644 index 0000000..83a70af --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/result/engine/EngineActionResult.java @@ -0,0 +1,75 @@ +package org.dromara.workflow.result.engine; + +import org.dromara.workflow.engine.model.setting.Node; +import lombok.Data; +import lombok.Getter; + +import java.util.*; + +/** + * @Description: 流程引擎结果结果 + **/ +@Data +public class EngineActionResult { + + /** + * 是否批量操作 + */ + private Boolean isBatch = false; + + /** + * 是否自动流转到下一节点 + */ + private Boolean isAuto = false; + + /** + * 是否发送节点消息推送 + */ + private Boolean isSend = false; + + /** + * 节点后面的节点 + */ + private List nextNodes; + + /** + * 接下来要自动流转的节点 + */ + private List autoSubmitNodes; + + + @Getter + public enum NodeType{ + NORMAL,AUTO + } + + public EngineActionResult(){ + this.isSend = true; + this.isAuto = false; + this.nextNodes = null; + this.autoSubmitNodes = null; + } + + + public EngineActionResult(Boolean isSend,Boolean isAuto){ + this.isSend = isSend; + this.isAuto = isAuto; + this.nextNodes = null; + this.autoSubmitNodes = null; + } + + + public EngineActionResult(List nextNodes,List autoSubmitNodes){ + this.isSend = true; + this.isAuto = true; + this.nextNodes = nextNodes; + this.autoSubmitNodes = autoSubmitNodes; + } + + + public void fillStartNext(List nodes){ + this.nextNodes = nodes; + this.autoSubmitNodes = nodes; + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/result/engine/EngineDataResult.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/result/engine/EngineDataResult.java new file mode 100644 index 0000000..aa248a3 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/result/engine/EngineDataResult.java @@ -0,0 +1,184 @@ +package org.dromara.workflow.result.engine; + +import org.dromara.workflow.engine.domain.Instance; +import org.dromara.workflow.engine.domain.InstanceTask; +import org.dromara.workflow.engine.enums.InstanceStage; +import org.dromara.workflow.engine.enums.OperateType; +import org.dromara.workflow.engine.enums.TaskStatus; +import org.dromara.workflow.param.engine.EngineRequest; +import org.dromara.workflow.remind.flow.model.FlowRemindInstanceTask; +import org.dromara.workflow.service.internal.InstanceTaskService; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.RandomUtil; +import cn.hutool.extra.spring.SpringUtil; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.google.common.base.Joiner; +import lombok.Data; + +import java.util.*; +import java.util.stream.Collectors; +import org.dromara.workflow.engine.domain.base.EdgeInfo; +/** + * @Description: 需要二次封装 + **/ +@Data +public class EngineDataResult { + + private static final String pattern = "yyyyMMddHHmmss"; + + private OperateType action; + + private Long taskId; + + private Long dataId; + + private Long instanceId; + + private EngineRequest.FormData formInfo; + + private String flowStage; + + private String nodeTitle; + + private String checkerName; + + private Map> nodeInfo; + + private Long createId; + + private String creator; + + private String creatorAccount; + + private Date createTime; + + private Long updatorId; + + private String updatorName; + + private String updatorAccount; + + private Date updateTime; + + /** + * 当前处理所涉及的任务 + */ + private List tasks; + + + @Data + public static class NodeHandler{ + @JsonIgnore + private Long taskId; + + private String nodeName; + + private Long handlerId; + + private String handlerName; + + private String handlerAccount; + + public NodeHandler(){} + + public NodeHandler(String nodeName,Long userId,String userName,String userAccount){ + this.nodeName = nodeName; + this.handlerId = userId; + this.handlerName = userName; + this.handlerAccount = userAccount; + } + } + + + public EngineDataResult(){ + } + + public EngineDataResult(Instance instance){ + this.instanceId = instance.getId(); + this.flowStage = instance.getStage().name(); + this.createTime = instance.getCreateTime(); + this.updateTime = instance.getUpdateTime(); + } + + + // TODO: 2022/5/30 节点处理返回结果数据结构要封装(和流程消息推送的数据结构一起) + public static EngineDataResult wrapResult(EngineRequest requestParam){ + Instance instance = requestParam.getInstance(); + if(ObjectUtil.isNull(instance)){ + + return null; + } + EngineDataResult result = new EngineDataResult(); + result.setAction(requestParam.getAction()); + result.setDataId(instance.getDataId()); + result.setFormInfo(requestParam.getForm()); + result.setInstanceId(instance.getId()); + result.setFlowStage(instance.getStage().name()); + result.setTasks(requestParam.getTasks()); + + if(instance.getStage().equals(InstanceStage.processing)){ + if(CollUtil.isNotEmpty(instance.getNodeKeys())){ + Set nodeTitle = new HashSet<>(); + result.setNodeInfo(transformNodeInfo(instance,nodeTitle)); + result.setNodeTitle(Joiner.on("、").skipNulls().join(nodeTitle)); + } + + if(CollUtil.isNotEmpty(result.getNodeInfo())){ + Set nodeSet = result.getNodeInfo().keySet(); + Map handlerMap = new LinkedHashMap<>(); + for(String key : nodeSet){ + List handlerList = result.getNodeInfo().get(key); + if(CollUtil.isNotEmpty(handlerList)){ + handlerList.forEach(user -> { + handlerMap.put(user.getHandlerId(),user.getHandlerName()); + }); + } + } + + result.setCheckerName(Joiner.on("、").skipNulls().join(new ArrayList<>(handlerMap.values()))); + } + }else{ + result.setCheckerName(""); + result.setNodeTitle("结束节点"); + } + + result.setCreateId(instance.getCreateUser()); + result.setCreator(instance.getCreateName()); + result.setCreatorAccount(instance.getCreateAccount()); + result.setCreateTime(instance.getCreateTime()); + + result.setUpdatorId(requestParam.getHandlerUser().getId()); + result.setUpdatorName(requestParam.getHandlerUser().getName()); + result.setUpdatorAccount(requestParam.getHandlerUser().getAccount()); + result.setUpdateTime(DateUtil.parse(requestParam.getRequestTime(),pattern)); + + return result; + } + + private static Map> transformNodeInfo(Instance instance,Set nodeTitles) { + InstanceTaskService taskService = SpringUtil.getBean(InstanceTaskService.class); + Map> nodeMap = new HashMap<>(); + List nodeKeys = instance.getNodeKeys().stream().map(EdgeInfo::getTarget).collect(Collectors.toList()); + nodeKeys.forEach(p -> { + List instanceTasks = taskService.listInstanceTask(instance.getId(),p, TaskStatus.unhandled); + if(CollUtil.isNotEmpty(instanceTasks)){ + List nodeHandlers = instanceTasks.stream().map(s -> { + NodeHandler item = new NodeHandler(); + item.setNodeName(s.getNodeName()); + item.setHandlerId(s.getUserId()); + item.setHandlerName(s.getUserName()); + item.setHandlerAccount(s.getUserAccount()); + item.setTaskId(s.getId()); + return item; + }).collect(Collectors.toList()); + nodeTitles.add(instanceTasks.get(0).getNodeName()); + nodeMap.put(p + RandomUtil.randomString(5),nodeHandlers); + } + }); + + return nodeMap; + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/result/instance/ChartResult.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/result/instance/ChartResult.java new file mode 100644 index 0000000..9fd1cfc --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/result/instance/ChartResult.java @@ -0,0 +1,81 @@ +package org.dromara.workflow.result.instance; + +import org.dromara.workflow.engine.domain.base.EdgeInfo; +import org.dromara.workflow.param.model.FlowUser; +import lombok.Data; +import lombok.Getter; + +import java.util.List; +import java.util.Map; + +/** + * @Description: 流程实例流转图 + **/ +@Data +public class ChartResult { + + /** + * 流程配置 + */ + private String model; + + /** + * 路由变化 + */ + private List routes; + + /** + * 实例运行节点 + */ + private List nodeKeys; + + /** + * 节点负责人 + */ + private Map checkers; + + /** + * 实例状态 + */ + private String stage; + + /** + * 流程版本 + */ + private Integer version; + + + + @Data + public class ChartNode{ + + /** + * 节点id + */ + private String nodeId; + + /** + * 节点名称 + */ + private String nodeName; + + /** + * 节点状态 + */ + private NodeStage stage; + + /** + * 节点处理人 + */ + private List handleUsers; + } + + @Getter + private enum NodeStage{ + + active,flowed,unFlowed + + } + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/result/instance/ChartResultV2.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/result/instance/ChartResultV2.java new file mode 100644 index 0000000..ab9c59c --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/result/instance/ChartResultV2.java @@ -0,0 +1,106 @@ +package org.dromara.workflow.result.instance; + +import org.dromara.workflow.engine.domain.base.EdgeInfo; +import org.dromara.workflow.engine.enums.InstanceStage; +import org.dromara.workflow.engine.model.setting.Node; +import org.dromara.workflow.param.model.FlowUser; +import lombok.Data; +import lombok.Getter; + +import java.util.List; + +/** + * @desc 流转图数据模型V2 + */ +@Data +public class ChartResultV2 { + + /** + * 流程实例节点 + */ + private List nodes; + + /** + * 流转连接线 + */ + private List routeLine; + + /** + * 流程实例状态 + */ + private InstanceStage stage; + + /** + * 流程定义版本 + */ + private Integer version; + + public ChartResultV2(InstanceStage stage,Integer version){ + this.stage = stage; + this.version = version; + } + + @Data + public static class ChartNode{ + + + /** + * 节点id + */ + private String id; + + /** + * 左侧坐标 + */ + private String left; + + /** + * 顶部坐标 + */ + private String top; + + /** + * 图标 + */ + private String ico; + + /** + * 节点名称 + */ + private String name; + + /** + * 接下来要流转的连接线 + */ + private List next; + + /** + * 节点状态 + */ + private NodeStage stage; + + /** + * 节点处理人 + */ + private List handleUsers; + + + public ChartNode(Node node){ + this.id = node.getId(); + this.name = node.getName(); + this.ico = node.getIco(); + this.left = node.getLeft(); + this.top = node.getTop(); + } + + } + + @Getter + public enum NodeStage{ + + active,flowed,unFlowed + + } + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/result/instance/InstanceCcResult.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/result/instance/InstanceCcResult.java new file mode 100644 index 0000000..68c4b01 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/result/instance/InstanceCcResult.java @@ -0,0 +1,8 @@ +package org.dromara.workflow.result.instance; +import org.dromara.workflow.engine.domain.InstanceCc; +import lombok.Data; + +@Data +public class InstanceCcResult extends InstanceCc { + private String userAccount; +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/result/instance/InstanceLogResult.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/result/instance/InstanceLogResult.java new file mode 100644 index 0000000..c018383 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/result/instance/InstanceLogResult.java @@ -0,0 +1,20 @@ +package org.dromara.workflow.result.instance; + +import org.dromara.workflow.engine.domain.InstanceLog; +import org.dromara.workflow.engine.enums.InstanceStage; +import lombok.Data; + +import java.util.List; + +/** + * @Description: 实例日志 + **/ +@Data +public class InstanceLogResult { + + private Long instanceId; + + private InstanceStage stage; + + private List logList; +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/result/instance/NodeResult.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/result/instance/NodeResult.java new file mode 100644 index 0000000..2b24fab --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/result/instance/NodeResult.java @@ -0,0 +1,20 @@ +package org.dromara.workflow.result.instance; + +import lombok.Data; + +/** + * @Description: server + **/ +@Data +public class NodeResult { + + private String id; + + private String name; + + + public NodeResult(String id,String name){ + this.id = id; + this.name = name; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/result/model/DefinitionResult.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/result/model/DefinitionResult.java new file mode 100644 index 0000000..20501cf --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/result/model/DefinitionResult.java @@ -0,0 +1,43 @@ +package org.dromara.workflow.result.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * @Description: 流程定义结果 + **/ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class DefinitionResult { + + private ModelData current; + + private List version; + + @Data + public static class ModelVersion{ + + private Long id; + + private Integer versionNo; + + private String stage; + } + + @Data + public static class ModelData{ + + private String model; + + private Long id; + + private Integer versionNo; + + private String stage; + + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/external/FlowInstanceService.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/external/FlowInstanceService.java new file mode 100644 index 0000000..954448d --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/external/FlowInstanceService.java @@ -0,0 +1,183 @@ +package org.dromara.workflow.service.external; + +import org.dromara.workflow.engine.domain.Instance; +import org.dromara.workflow.engine.domain.InstanceLog; +import org.dromara.workflow.engine.enums.OperateType; +import org.dromara.workflow.param.engine.EngineRequest; +import org.dromara.workflow.param.model.FlowUser; +import org.dromara.workflow.result.engine.ActionNodeSubmitResult; +import org.dromara.workflow.result.engine.BaseActionResult; +import org.dromara.workflow.result.engine.EngineDataResult; +import org.dromara.workflow.result.instance.ChartResult; +import org.dromara.workflow.result.instance.ChartResultV2; +import org.dromara.workflow.result.instance.InstanceLogResult; +import org.dromara.workflow.result.instance.NodeResult; + +import java.util.*; + +/** + * @Description: 流程实例服务 + **/ +public interface FlowInstanceService { + + /** + * 校验表单是否存在流程实例 + * @param formId + */ + boolean hasRunningInstance(Long formId); + + /** + * 查询流程实例 + * @param instanceId + * @return + */ + Instance getInstance(Long instanceId); + + + /** + * 查询流程实例 + * @param dataId + * @return + */ + Instance getInstance(String dataId); + + /** + * 查询实例日志 + * @param instanceId + * @return + */ + InstanceLogResult listLog(Long instanceId); + + /** + * 查询流程图 + * @param instanceId + * @return + */ + ChartResult getChart(Long instanceId); + + /** + * 查询流转图V2 + * @param instanceId + * @return + */ + ChartResultV2 getChartV2(Long instanceId); + + /** + * 实例流转 + * @param data + * @return + */ + ActionNodeSubmitResult action(EngineRequest data); + + /** + * 调整实例负责人 + * @param instance + * @param nodeId + * @param userIds + */ + BaseActionResult transferInstanceUser(Instance instance, String nodeId, List userIds); + + /** + * 流程催办 + * @param instanceId + * @return + */ + BaseActionResult urgeInstance(Long instanceId); + /** + * 流程结束 + * @return + */ + BaseActionResult finishInstance(Instance instance); + + /** + * 激活流程 + * @return + */ + BaseActionResult activeInstance(Instance instance, String activeNodeId,Map formData); + + /** + * 删除表单实例 + * @param formId + */ + void deleteInstanceByForm(Long formId); + + /** + * 删除表单实例 + * @param dataIds + */ + void deleteInstanceByData(Long formId,String... dataIds); + + + /** + * 逻辑删除实例 + * @param formId + * @param dataIds + */ + void logicDeleteInstance(Long formId, String... dataIds); + + /** + * 逻辑恢复实例 + * @param formId + * @param dataIds + */ + void logicRecoverInstance(Long formId, String... dataIds); + + /** + * 查询实例数据 + * @param result + * @return + */ + LinkedHashMap getInstanceData(EngineDataResult result); + + + EngineDataResult transformInstanceDataResult(Instance instance); + + + /** + * 查询实例操作日志 + * @param instanceId + * @param action + * @return + */ + List listLogByInstance(Long instanceId, OperateType action); + + /** + * 批量查询实例的流程日志 + * @param instanceIds + * @param type + * @return + */ + List listLogByInstances(List instanceIds,OperateType type); + + /** + * 查询待办任务的实例日志 + * @param taskId + * @param type + * @return + */ + List listLogByTask(Long taskId,OperateType type); + + /** + * 查询流程实例已处理的节点 + * @param instanceId + * @return + */ + List listInstanceHandledNodes(Long instanceId); + + /** + * 查询流程实例激活的节点 + * @param instanceId + * @return + */ + List listInstanceActiveNodes(Long instanceId); + + /** + * 查询实例节点负责人 + * @param instanceId + * @param nodeId + * @return + */ + List listInstanceNodeChecker(Long instanceId, String nodeId); + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/external/FlowModelService.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/external/FlowModelService.java new file mode 100644 index 0000000..c60b921 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/external/FlowModelService.java @@ -0,0 +1,153 @@ +package org.dromara.workflow.service.external; + + +import org.dromara.workflow.engine.domain.Definition; +import org.dromara.workflow.engine.model.setting.Field; +import org.dromara.workflow.engine.model.setting.Model; +import org.dromara.workflow.engine.model.setting.Node; +import org.dromara.workflow.param.model.DefinitionParam; +import org.dromara.workflow.result.model.DefinitionResult; + +import java.util.List; + +/** + * @Description: 流程模型服务 + **/ +public interface FlowModelService { + + /** + * 查询运行中的流程定义配置 + * @param formId + * @return + */ + Model getRunningModel(Long formId); + + + /** + * 校验流程定义是否启用 + * @param formId + * @return + */ + boolean checkHasActive(Long formId); + + + /** + * 查询流程配置节点 + * @param formId + * @return + */ + List listModelNodes(Long formId); + + /** + * 创建流程定义 + * @param param + * @return + */ + DefinitionResult create(DefinitionParam param); + + /** + * 拷贝流程定义 + * @param sourceId + * @param targetId + */ + void copy(Long sourceId, Long targetId); + + + /** + * 查询表单流程定义 + * @param formId + * @return + */ + DefinitionResult getByForm(Long formId); + + + /** + * 查询表单所有的流程定义 + * @param formId + * @return + */ + List getDefByForm(Long formId); + + + /** + * 根据版本查询流程定义 + * @param versionId + * @return + */ + DefinitionResult getByVersion(Long versionId); + + /** + * 更新流程定义 + * @param param + * @return + */ + DefinitionResult update(DefinitionParam param); + + /** + * 启用流程定义 + * @param param + * @return + */ + DefinitionResult active(DefinitionParam param); + + /** + * 删除流程定义 + * @param param + * @return + */ + DefinitionResult delete(DefinitionParam param); + + /** + * 删除设计中的流程定义 + * @param formId + */ + void deleteDesignDefinition(Long formId); + + + /** + * 查询表单启用中的流程定义 + * @param formId + * @return + */ + Definition getRunningDefinition(Long formId); + + /** + * 查询流程定义模型 + * @param definitionId + * @return + */ + Model getDefinitionModel(Long definitionId); + + /** + * 查询流程定义节点配置 + * @param definitionId + * @param nodeKey + * @return + */ + Node getDefinitionNode(Long definitionId, String nodeKey); + + /** + * 查询节点字段 + * @param formId + * @param nodeKey + * @return + */ + List listNodeField(Long formId, String nodeKey); + + + /** + * 查询流程节点可见字段 + * @param definitionId + * @param nodeId + * @return + */ + List getNodeViewFields(Long definitionId, String nodeId); + + /** + * 获取当前流程的所有节点信息 + * @param sourceId + * @return + */ + List listNodeTitles(Long sourceId); + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/external/FlowTaskService.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/external/FlowTaskService.java new file mode 100644 index 0000000..b89c0af --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/external/FlowTaskService.java @@ -0,0 +1,110 @@ +package org.dromara.workflow.service.external; + +import org.dromara.workflow.engine.domain.Instance; +import org.dromara.workflow.engine.domain.InstanceTask; +import org.dromara.workflow.result.instance.InstanceCcResult; + +import java.util.LinkedHashMap; +import java.util.List; + +/** + * @Description: 流程待办任务服务 + **/ +public interface FlowTaskService { + + /** + * 保存任务草稿数据 + * @param instance + * @param data + * @return + */ + InstanceTask saveTaskDraft(Instance instance,InstanceTask instanceTask, LinkedHashMap data); + + /** + * 更新抄送任务状态(已读) + * @param ccId + * @return + */ + boolean updateCcStatus(Long ccId); + + /** + * 查询节点上用户的具体待办任务 + * @param instanceId + * @param nodeId + * @param userId + * @return + */ + InstanceTask getUserTask(Long instanceId, String nodeId, Long userId); + + /** + * 查询节点上全部的待办任务 + * @param instanceId + * @param nodes + * @return + */ + List listNodesTask(Long instanceId, List nodes); + + /** + * 更新实例的待办任务为高优先级 + * @param instance + * @return + */ + boolean updateTaskPriority(Instance instance); + + /** + * 查询实例高优先级的待办任务 + * @param instanceId + * @return + */ + List listPriorityTodo(Long instanceId); + + /** + * 查询节点上已处理的待办任务 + * @param instanceId + * @param nodes + * @return + */ + List listNodesHandledTask(Long instanceId, List nodes); + + + + /** + * 查询节点上全部的抄送任务 + * @param instanceId + * @param nodes + * @return + */ + List listNodesCc(Long instanceId, List nodes); + + /** + * 查询待办任务详情 + * @param taskId + * @return + */ + InstanceTask getTaskInfo(Long taskId); + + + /** + * 校验实例某节点的待办任务是否被处理 + * @param instanceId + * @param nodes + * @return + */ + boolean checkNodeHandledTask(Long instanceId,List nodes); + + /** + * 判断用户是否允许撤回 + * @param instanceId + * @return + */ + boolean checkInstanceCanRecall(Long instanceId); + + + /** + * 校验流程实例是否已经处理过 + * @param instanceId + * @return + */ + boolean checkInstanceSubmitted(Long instanceId); + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/external/impl/FlowInstanceServiceImpl.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/external/impl/FlowInstanceServiceImpl.java new file mode 100644 index 0000000..2a937de --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/external/impl/FlowInstanceServiceImpl.java @@ -0,0 +1,848 @@ +package org.dromara.workflow.service.external.impl; + +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.service.ISysUserService; +import org.dromara.common.Exception.ServiceException; +import org.dromara.common.response.WorkflowResultCode; +import org.dromara.dataManager.service.FormDataService; +import org.dromara.formMaking.domain.FormSource; +import org.dromara.formMaking.service.FormSourceService; + +import org.dromara.taskCenter.service.action.impl.CreateHandler; +import org.dromara.workflow.engine.domain.Definition; +import org.dromara.workflow.engine.domain.Instance; +import org.dromara.workflow.engine.domain.InstanceLog; +import org.dromara.workflow.engine.domain.InstanceTask; +import org.dromara.workflow.engine.domain.base.EdgeInfo; +import org.dromara.workflow.engine.enums.*; +import org.dromara.workflow.engine.exception.WorkflowCode; +import org.dromara.workflow.engine.exception.WorkflowException; +import org.dromara.workflow.engine.factory.FlowEngine; +import org.dromara.workflow.engine.model.setting.Model; +import org.dromara.workflow.engine.model.setting.Node; +import org.dromara.workflow.param.engine.EngineRequest; +import org.dromara.workflow.param.instance.InstanceLogParam; +import org.dromara.workflow.param.model.FlowUser; +import org.dromara.workflow.remind.flow.FlowRemindHelper; +import org.dromara.workflow.remind.flow.model.FlowRemindInstanceTask; +import org.dromara.workflow.result.engine.ActionNodeSubmitResult; +import org.dromara.workflow.result.engine.BaseActionResult; +import org.dromara.workflow.result.engine.EngineDataResult; +import org.dromara.workflow.result.instance.ChartResult; +import org.dromara.workflow.result.instance.ChartResultV2; +import org.dromara.workflow.result.instance.InstanceLogResult; +import org.dromara.workflow.result.instance.NodeResult; +import org.dromara.workflow.service.external.FlowInstanceService; +import org.dromara.workflow.service.external.FlowTaskService; +import org.dromara.workflow.service.internal.*; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.google.common.base.Joiner; +import com.google.common.collect.Sets; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.compress.utils.Lists; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + +@Service +@Slf4j +public class FlowInstanceServiceImpl implements FlowInstanceService { + + @Autowired + private DefinitionService definitionService; + @Autowired + private InstanceService instanceService; + @Autowired + private InstanceTaskService instanceTaskService; + @Autowired + private InstanceLogService instanceLogService; + @Autowired + private FlowEngine workflowEngine; + @Autowired + private FormDataService formDataService; + @Autowired + private FormSourceService sourceQueryService; + @Autowired + private ISysUserService userService; + @Autowired + private DecisionService decisionService; + @Autowired + private FlowTaskService flowTaskService; + @Autowired + private FlowRemindHelper flowRemindHelper; + + @Override + public ActionNodeSubmitResult action(EngineRequest data) { + + return workflowEngine.action(data); + } + + @Override + public boolean hasRunningInstance(Long formId) { + + return this.instanceService.count(new LambdaQueryWrapper() + .eq(Instance::getFormId,formId) + .eq(Instance::getStage, InstanceStage.processing) + .eq(Instance::getDeleted,false)) > 0; + } + + @Override + public Instance getInstance(Long instanceId) { + + return instanceService.getById(instanceId); + } + + @Override + public Instance getInstance(String dataId) { + return this.instanceService.getOne(new LambdaQueryWrapper() + .eq(Instance::getDataId,dataId) + .eq(Instance::getDeleted,false)); + } + + @Override + public InstanceLogResult listLog(Long instanceId) { + + return instanceLogService.listFlowLog(instanceId, null); + } + + + + @Override + public ChartResultV2 getChartV2(Long instanceId) { + //查询流程图数据 + Instance instance = instanceService.getById(instanceId); + if (instance == null) { + + throw new ServiceException(WorkflowResultCode.FLOW_INSTANCE_NOT_EXIST); + } + + Definition definition = definitionService.getById(instance.getDefinitionId()); + if(definition == null){ + + throw new ServiceException(WorkflowResultCode.FLOW_DEFINITION_VERSION_NOT_EXIST); + } + + ChartResultV2 result = new ChartResultV2(instance.getStage(),definition.getVersion()); + InstanceLogResult instanceLogs = instanceLogService.listFlowLog(instanceId,null); + List lines = new ArrayList<>(); + instanceLogs.getLogList().stream().filter(p -> CollUtil.isNotEmpty(p.getNextNodes())).forEach(p -> { + p.getNextNodes().forEach(s -> lines.add(StrUtil.format("{}_{}",p.getNodeKey(),s))); + }); + result.setRouteLine(lines); + + Model model = JSONUtil.toBean(definition.getSnapshots(),Model.class); + + List nodeList =model.getNodeList().stream().filter(p -> !StrUtil.contains(p.getId(), NodeType.cc.name())).collect(Collectors.toList()); + List chartNodes = new ArrayList<>(); + + //查询实例当前激活节点到开始节点之间的节点 + Set nodeKeys = new HashSet<>(); + instance.getNodeKeys().forEach(node -> { + nodeKeys.addAll(decisionService.listNodesFromNode(model,node.getTarget())); + }); + + Set allSubmitNodes; + Set reactiveSubmitNodes = instanceLogService.listReactiveSubmitNodes(instanceId); + // 如果是被重新激活的流程并且又被手动结束,则已流转的节点是激活节点后的节点 + if (CollectionUtil.isNotEmpty(reactiveSubmitNodes) && InstanceStage.finished.equals(instance.getStage())) { + allSubmitNodes = reactiveSubmitNodes; + } else { + allSubmitNodes = instanceLogService.listSubmitNodes(instanceId); + } + + List activeNodes = instance.getNodeKeys(); + for(Node node: nodeList){ + ChartResultV2.ChartNode chartNode = new ChartResultV2.ChartNode(node); + + chartNode.setNext(node.getNext().stream().map(Node.EdgeCondition::getEdge).collect(Collectors.toList())); + + //未流转节点 + chartNode.setStage(ChartResultV2.NodeStage.unFlowed); + + if(activeNodes.stream().anyMatch(s -> s.getTarget().equals(node.getId()))){ + if(StrUtil.equals(node.getId(),NodeType.end.name())){ + chartNode.setStage(ChartResultV2.NodeStage.flowed); + }else{ + //激活的节点 + chartNode.setStage(ChartResultV2.NodeStage.active); + chartNode.setHandleUsers(activeNodes.stream().filter(s -> StrUtil.equals(s.getTarget(), node.getId())).map(EdgeInfo::getUsers).flatMap(Collection::stream).distinct().collect(Collectors.toList())); + } + }else if(allSubmitNodes.contains(node.getId())){ + + //已流转节点(特殊情况:已处理节点到开始节点之间不能有激活节点) + Set rightNodes = instance.getNodeKeys().stream().map(EdgeInfo::getTarget).collect(Collectors.toSet()); + if (!decisionService.checkNodeActiveToStart(model,rightNodes,node.getId())) { + if(!InstanceStage.finished.equals(instance.getStage())){ + chartNode.setStage(ChartResultV2.NodeStage.flowed); + }else if(!instance.getNodeKeys().stream().map(EdgeInfo::getSource).collect(Collectors.toList()).contains(node.getId())){ + chartNode.setStage(ChartResultV2.NodeStage.flowed); + } else if (activeNodes.stream().map(EdgeInfo::getSource).collect(Collectors.toList()).contains(node.getId()) && CollectionUtil.isNotEmpty(reactiveSubmitNodes)) { + chartNode.setStage(ChartResultV2.NodeStage.flowed); + } + } + } + + chartNodes.add(chartNode); + } + + result.setNodes(chartNodes); + + return result; + } + + + @Override + public ChartResult getChart(Long instanceId) { + ChartResult result = new ChartResult(); + //查询流程图数据 + Instance instance = instanceService.getById(instanceId); + if (instance == null) { + + throw new ServiceException(WorkflowResultCode.FLOW_INSTANCE_NOT_EXIST); + } + + result.setStage(instance.getStage().name()); + List activeNodeList = instance.getNodeKeys().stream().map(EdgeInfo::getTarget).collect(Collectors.toList()); + Definition definition = definitionService.getById(instance.getDefinitionId()); + result.setModel(definition.getSnapshots()); + // result.setRoutes(instance.getRoutes()); + result.setNodeKeys(instance.getNodeKeys()); + result.setVersion(definition.getVersion()); + List instanceTaskList = instanceTaskService.list(new LambdaQueryWrapper().eq(InstanceTask + ::getInstanceId, instanceId).ne(InstanceTask::getStatus, TaskStatus.outDated.getCode())); + + Map nodeHandlers = new HashMap<>(); + if (CollUtil.isNotEmpty(instanceTaskList)) { + Set nodeKeySet = instanceTaskList.stream().map(InstanceTask::getNodeKey).collect(Collectors.toSet()); + for (String nodeKey : nodeKeySet) { + + if (activeNodeList.contains(nodeKey)) { + //判断这个节点的状态是否激活节点 -> 待处理负责人 完成节点 -> 已处理负责人 + List unhandledCheckers = instanceTaskList.stream().filter(p -> StrUtil.equals(nodeKey, + p.getNodeKey()) && TaskStatus.unhandled.getCode().equals(p.getStatus())).map(InstanceTask::getUserName).distinct().collect(Collectors.toList()); + if (CollUtil.isNotEmpty(unhandledCheckers)) { + nodeHandlers.put(nodeKey, Joiner.on("、").skipNulls().join(unhandledCheckers)); + } + + } else { + + List handledCheckers = instanceTaskList.stream().filter(p -> StrUtil.equals(nodeKey, + p.getNodeKey()) && TaskStatus.handled.getCode().equals(p.getStatus())).map(InstanceTask::getUserName).distinct().collect(Collectors.toList()); + if (CollUtil.isNotEmpty(handledCheckers)) { + nodeHandlers.put(nodeKey, Joiner.on("、").skipNulls().join(handledCheckers)); + } + } + } + nodeHandlers.put("start", instance.getCreateName()); + } + result.setCheckers(nodeHandlers); + + return result; + } + + + @Override + public BaseActionResult urgeInstance(Long instanceId) { + if(instanceId == null){ + + return BaseActionResult.error(WorkflowCode.PARAM_IS_BLANK); + } + Instance instance = this.instanceService.getById(instanceId); + if(instance == null){ + + return BaseActionResult.error(WorkflowCode.INSTANCE_NOT_EXIST); + } + FormSource formInfo = this.sourceQueryService.getById(instance.getFormId()); + if(formInfo == null){ + + return BaseActionResult.error(WorkflowCode.FORM_DATA_HAS_DELETE); + } + + //提交用户必须是流程发起人 + if(!LoginHelper.getUserId().equals(instance.getCreateUser())){ + + return BaseActionResult.error(WorkflowCode.USER_NOT_PERMISSION); + } + + //实例状态必须是进行中 + if(!InstanceStage.processing.equals(instance.getStage())){ + + return BaseActionResult.error(WorkflowCode.FLOW_INSTANCE_URGE_NODE_ERROR); + } + + //实例当前节点不能为开始节点 + if(instance.getNodeKeys().stream().anyMatch(p -> StrUtil.equals(p.getTarget(),NodeType.start.name()))){ + + return BaseActionResult.error(WorkflowCode.FLOW_INSTANCE_URGE_NODE_ERROR); + } + + EngineRequest remindParam = transformRemindParam(formInfo,instance, NodeType.start.name(), new Date(), OperateType.urge,null); + + if(!remindParam.getModel().getConfig().getUrge()){ + + return BaseActionResult.error(WorkflowCode.FLOW_INSTANCE_URGE_CLOSED); + } + + //更新实例待办任务状态为高优先级 + this.flowTaskService.updateTaskPriority(instance); + + FlowEngine.sendFlowMessage(remindParam); + + return BaseActionResult.success(); + } + + private EngineRequest transformRemindParam(FormSource formInfo,Instance instance,String nodeId, + Date updateTime,OperateType operateType,List forwardUsers) { + Model flowModel = this.definitionService.getInstanceModel(instance.getDefinitionId()); + EngineRequest requestParam = new EngineRequest(flowModel); + requestParam.setAction(operateType); + requestParam.setHandlerUser(new FlowUser(LoginHelper.getUserId(),LoginHelper.getLoginUser().getNickname(),LoginHelper.getLoginUser().getUsername())); + requestParam.setIsBatch(false); + requestParam.setAutoSubmit(false); + Node curNode =flowModel.getNodeList().stream().filter(p -> StrUtil.equals(nodeId,p.getId())).findFirst().get(); + requestParam.setCurrent(curNode); + requestParam.setRequestTime(DateUtil.format(updateTime,EngineRequest.pattern)); + + EngineRequest.InstanceData instanceData = new EngineRequest.InstanceData(instance); + instanceData.setDefinitionId(instance.getDefinitionId()); + if(CollUtil.isNotEmpty(forwardUsers)){ + instanceData.setForwardUsers(new ArrayList<>(forwardUsers)); + } + requestParam.setInstance(instanceData); + requestParam.setDefinitionId(instance.getDefinitionId()); + + EngineRequest.FormData instanceFormData = new EngineRequest.FormData(); + instanceFormData.setFormId(formInfo.getId()); + instanceFormData.setFormCode(formInfo.getCode()); + instanceFormData.setFormName(formInfo.getTitle()); + instanceFormData.setData(new LinkedHashMap(formDataService.getById(instance.getDataId()).getFormData())); + requestParam.setForm(instanceFormData); + return requestParam; + } + + + @Override + public BaseActionResult transferInstanceUser(Instance instance, String nodeId, List transferUsers) { + FormSource formInfo = this.sourceQueryService.getById(instance.getFormId()); + if(formInfo == null){ + + throw new ServiceException(WorkflowResultCode.FORM_NOT_EXIST); + } + if(CollUtil.isEmpty(transferUsers)){ + + return BaseActionResult.error(WorkflowCode.NODE_TRANSFER_CHECKER_EMPTY); + } + + if(StrUtil.equals(nodeId,NodeType.start.name()) && transferUsers.size() > 1){ + + return BaseActionResult.error(WorkflowCode.NODE_TRANSFER_START_CHECKER_LIMITED); + } + + Set userIds = new HashSet<>(transferUsers); + + List preTransferUsers = this.instanceTaskService.listInstanceTask(instance.getId(),nodeId,TaskStatus.unhandled); + Set preTransferUserSet = preTransferUsers.stream().map(InstanceTask::getUserId).collect(Collectors.toSet()); + + if(ObjectUtil.equal(userIds,preTransferUserSet)){ + + return BaseActionResult.error(WorkflowCode.NODE_TRANSFER_CHECKER_NOT_CHANGE); + } + + //query out dated task users + Set outDatedTaskUsers = Sets.difference(preTransferUserSet, userIds); + + //query new tasks users + Set newTaskUsers = Sets.difference(userIds,preTransferUserSet); + + if(CollUtil.isEmpty(outDatedTaskUsers) && CollUtil.isEmpty(newTaskUsers)){ + + return BaseActionResult.error(WorkflowCode.NODE_TRANSFER_CHECKER_EMPTY); + } + + Node currentNode = definitionService.getModelNode(instance.getDefinitionId(),nodeId); + if(currentNode == null){ + throw new ServiceException(WorkflowResultCode.FLOW_DEFINITION_NODE_NOT_EXIST); + } + + //delete out dated tasks + instanceTaskService.deleteInstanceTaskByUsers(instance.getId(),nodeId,outDatedTaskUsers); + + //更新实例运行节点用户信息 + instance.getNodeKeys().forEach(node -> { + if(StrUtil.equals(node.getTarget(),nodeId)){ + if(CollUtil.isNotEmpty(transferUsers)){ + List instanceFlowUsers = transferUsers.stream().map(p -> { + SysUserVo user = userService.selectUserById(p); + return new FlowUser(user.getUserId(),user.getNickName(),user.getUserName()); + }).collect(Collectors.toList()); + node.setUsers(instanceFlowUsers); + } + } + }); + + this.instanceService.updateById(instance); + + //add instance logs + InstanceLogParam instanceLog = new InstanceLogParam(OperateType.transfer,instance,currentNode,instance.getUpdateTime()); + FlowUser handler = new FlowUser(LoginHelper.getUserId(),LoginHelper.getLoginUser().getNickname(),LoginHelper.getLoginUser().getUsername()); + instanceLog.addUser(handler.getId(),handler.getName(),handler.getAccount()); + this.instanceLogService.create(instanceLog); + + //allocation tasks to users + if(CollUtil.isNotEmpty(newTaskUsers)){ + List flowUsers = userService.selectUserByIds(new ArrayList<>(newTaskUsers),null).stream().map(p -> new FlowUser(p.getUserId(),p.getNickName(),p.getUserName())).collect(Collectors.toList()); + instanceTaskService.createUserTask(instance,currentNode,flowUsers); + + EngineRequest remindParam = transformRemindParam(formInfo,instance,nodeId,instance.getUpdateTime(), OperateType.transfer,new ArrayList<>(newTaskUsers)); + FlowEngine.sendFlowMessage(remindParam); + } + + + return BaseActionResult.success(); + } + + @Override + public BaseActionResult finishInstance(Instance instance) { + + if(instance == null){ + + throw new ServiceException(WorkflowResultCode.FLOW_INSTANCE_NOT_EXIST); + } + + if(!InstanceStage.processing.equals(instance.getStage())){ + + throw new ServiceException(WorkflowResultCode.FLOW_INSTANCE_STATUS_ERROR); + } + + List unhandledTasks = flowRemindHelper.getTasks(instance.getId(), null, TaskStatus.unhandled); + + + FlowUser handler = new FlowUser(LoginHelper.getUserId(),LoginHelper.getLoginUser().getNickname(),LoginHelper.getLoginUser().getUsername()); + + //更新流程实例 + List currentNodeKeys = instance.getNodeKeys(); + List nextNodeKeys = currentNodeKeys.stream().map(node -> { + return new EdgeInfo(node.getTarget(),NodeType.end.name(),"流程结束"); + }).collect(Collectors.toList()); + + instance.setNodeKeys(nextNodeKeys); + instance.setStage(InstanceStage.finished); + instance.setUpdateTime(new Date()); + instance.setUpdateUser(handler.getId()); + this.instanceService.updateById(instance); + + //更新待办任务 + this.instanceTaskService.deleteInstanceUnHandledTask(instance.getId()); + + //添加流程日志 + Model instanceModel = this.definitionService.getInstanceModel(instance.getDefinitionId()); + Node endNode = instanceModel.getNodeList().stream().filter(p -> StrUtil.equals(p.getId(),NodeType.end.name())).findFirst().get(); + InstanceLogParam instanceLog = new InstanceLogParam(OperateType.finish,instance,endNode,instance.getUpdateTime()); + instanceLog.addUser(handler.getId(),handler.getName(),handler.getAccount()); + instanceLog.setNextNodes(Arrays.asList(NodeType.end.name())); + this.instanceLogService.create(instanceLog); + + //流程提醒 + FormSource formInfo = this.sourceQueryService.getById(instance.getFormId()); + + + EngineRequest remindParam = transformRemindParam(formInfo,instance,NodeType.end.name(),instance.getUpdateTime(), OperateType.finish,null); + remindParam.setTasks(unhandledTasks); + FlowEngine.sendFlowMessage(remindParam); + + + return BaseActionResult.success(); + } + + @Override + public BaseActionResult activeInstance(Instance instance, String activeNodeId,Map formData) { + + if(instance == null){ + + throw new ServiceException(WorkflowResultCode.FLOW_INSTANCE_NOT_EXIST); + } + + //更新流程实例 + FlowUser handler = new FlowUser(LoginHelper.getUserId(),LoginHelper.getLoginUser().getNickname(),LoginHelper.getLoginUser().getUsername()); + + Model instanceModel = this.definitionService.getInstanceModel(instance.getDefinitionId()); + Node activeNode = instanceModel.getNodeList().stream().filter(p -> StrUtil.equals(p.getId(),activeNodeId)).findFirst().get(); + List nodeTask = this.instanceTaskService.createNodeTask(instance,activeNode,handler,formData); + if(CollUtil.isEmpty(nodeTask)){ + throw new ServiceException(WorkflowResultCode.FLOW_DEFINITION_NOT_APPROVER); + } + + EdgeInfo activeInfo = new EdgeInfo(NodeType.end.name(), activeNode.getId(),activeNode.getName()); + List taskUsers = nodeTask.stream().map(p -> new FlowUser(p.getUserId(),p.getUserName(),p.getUserAccount())).collect(Collectors.toList()); + activeInfo.setUsers(taskUsers); + instance.setNodeKeys(Arrays.asList(activeInfo)); + instance.setStage(InstanceStage.processing); + instance.setUpdateTime(new Date()); + instance.setUpdateUser(handler.getId()); + this.instanceService.updateById(instance); + + //添加流程日志 + InstanceLogParam instanceLog = new InstanceLogParam(OperateType.active,instance,activeNode,instance.getUpdateTime()); + instanceLog.addUser(handler.getId(),handler.getName(),handler.getAccount()); + this.instanceLogService.create(instanceLog); + + //流程提醒 + EngineRequest requestParam = new EngineRequest(instanceModel); + requestParam.setAction(OperateType.active); + requestParam.setHandlerUser(handler); + requestParam.setIsBatch(false); + requestParam.setAutoSubmit(false); + requestParam.setRequestTime(DateUtil.format(instance.getUpdateTime(),EngineRequest.pattern)); + requestParam.setCurrent(activeNode); + + EngineRequest.InstanceData instanceData = new EngineRequest.InstanceData(instance); + instanceData.addNodes(NodeType.task,Arrays.asList(activeNode)); + instanceData.setDefinitionId(instance.getDefinitionId()); + requestParam.setInstance(instanceData); + requestParam.setDefinitionId(instance.getDefinitionId()); + FormSource formInfo = this.sourceQueryService.getById(instance.getFormId()); + + EngineRequest.FormData instanceFormData = new EngineRequest.FormData(); + instanceFormData.setFormId(formInfo.getId()); + instanceFormData.setFormCode(formInfo.getCode()); + instanceFormData.setFormName(formInfo.getTitle()); + instanceFormData.setData(new LinkedHashMap(formData)); + requestParam.setForm(instanceFormData); + + List unhandledTasks = flowRemindHelper.getTasks(instance.getId(), null, TaskStatus.unhandled); + requestParam.setTasks(unhandledTasks); + + FlowEngine.sendFlowMessage(requestParam); + + return BaseActionResult.success(); + } + + @Override + public void deleteInstanceByForm(Long formId) { + if(ObjectUtil.hasEmpty(formId)){ + + throw new WorkflowException(WorkflowCode.PARAM_MISSING); + } + + this.instanceService.deleteByForm(formId); + } + + @Override + public void deleteInstanceByData(Long formId,String... dataIds) { + if(ObjectUtil.hasEmpty(dataIds)){ + + throw new WorkflowException(WorkflowCode.PARAM_MISSING); + } + + this.instanceService.deleteByData(formId, dataIds); + } + + + @Override + public void logicDeleteInstance(Long formId, String... dataIds){ + if(ObjectUtil.hasEmpty(formId,dataIds)){ + + throw new WorkflowException(WorkflowCode.PARAM_MISSING); + } + + this.instanceService.logicDeleteByForm(formId, dataIds); + } + + @Override + public void logicRecoverInstance(Long formId, String... dataIds){ + if(ObjectUtil.hasEmpty(formId,dataIds)){ + + throw new WorkflowException(WorkflowCode.PARAM_MISSING); + } + + this.instanceService.logicRecoverByForm(formId, dataIds); + } + + + + @Override + public LinkedHashMap getInstanceData(EngineDataResult result) { + LinkedHashMap instanceParam = new LinkedHashMap<>(); + //实例id + instanceParam.put(ESDefaultFieldConst.FLOW_INSTANCE_ID, result.getInstanceId()); + instanceParam.put(ESDefaultFieldConst.FLOW_STAGE, result.getFlowStage()); + instanceParam.put(ESDefaultFieldConst.UPDATE_TIME,result.getUpdateTime()); + + if(CollUtil.isNotEmpty(result.getNodeInfo())){ + //节点名称 + instanceParam.put(ESDefaultFieldConst.FLOW_NODE_TITLE,result.getNodeTitle()); + + //当前负责人 + if(result.getNodeInfo().containsKey(NodeType.start.name())){ + instanceParam.put(ESDefaultFieldConst.FLOW_CHECKER_NAME,result.getCreator()); + }else{ + instanceParam.put(ESDefaultFieldConst.FLOW_CHECKER_NAME,result.getCheckerName()); + } + }else{ + if(StrUtil.equals(InstanceStage.processing.name(),result.getFlowStage())){ + instanceParam.put(ESDefaultFieldConst.FLOW_CHECKER_NAME, null); + }else{ + instanceParam.put(ESDefaultFieldConst.FLOW_NODE_TITLE,"流程结束"); + instanceParam.put(ESDefaultFieldConst.FLOW_CHECKER_NAME, null); + } + } + + return instanceParam; + } + + + /** + * @author lifen + * @description 打印模板 + */ + @Override + public List listLogByInstance(Long instanceId, OperateType action) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.select( + InstanceLog::getOpName, + InstanceLog::getId, + InstanceLog::getOpType, + InstanceLog::getHandlerName, + InstanceLog::getHandlerType, + InstanceLog::getComment, + InstanceLog::getNodeKey, + InstanceLog::getNodeName, + InstanceLog::getSignature, + InstanceLog::getCreateTime + ); + wrapper.eq(InstanceLog::getInstanceId,instanceId); + wrapper.eq(InstanceLog::getOpType,action.name()); + wrapper.ne(InstanceLog::getNodeKey,NodeType.preset); + wrapper.ne(InstanceLog::getNodeKey,NodeType.start); + + return this.instanceLogService.list(wrapper); + } + + + @Override + public List listLogByInstances(List instanceIds,OperateType type) { + + List results = null; + + LambdaQueryWrapper logLambdaQueryWrapper = new LambdaQueryWrapper<>(); + logLambdaQueryWrapper.in(InstanceLog::getInstanceId, instanceIds); + + if(type!=null) + { + logLambdaQueryWrapper.eq(InstanceLog::getOpType, type); + } + + logLambdaQueryWrapper.select( + InstanceLog::getOpName, + InstanceLog::getId, + InstanceLog::getInstanceId, + InstanceLog::getOpType, + InstanceLog::getHandlerName, + InstanceLog::getHandlerType, + InstanceLog::getComment, + InstanceLog::getNodeKey, + InstanceLog::getNodeName, + InstanceLog::getSignature, + InstanceLog::getCreateTime + ); + results = this.instanceLogService.list(logLambdaQueryWrapper); + + return results; + } + + @Override + public List listLogByTask(Long taskId,OperateType type) { + + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.eq(InstanceTask::getId, taskId); + lambdaQueryWrapper.select(InstanceTask::getInstanceId); + InstanceTask task = instanceTaskService.getOne(lambdaQueryWrapper); + + List results = null; + if(task!=null) { + + results = this.listLogByInstance(task.getInstanceId(),type); + } + return results; + } + + @Override + public List listInstanceHandledNodes(Long instanceId) { + if(instanceId == null){ + + throw new ServiceException(WorkflowResultCode.PARAM_IS_BLANK); + } + Instance instance = instanceService.getById(instanceId); + if(instance == null){ + + throw new ServiceException(WorkflowResultCode.FLOW_INSTANCE_NOT_EXIST); + } + if(InstanceStage.processing.equals(instance.getStage())){ + + throw new ServiceException(WorkflowResultCode.FLOW_INSTANCE_STATUS_ERROR); + } + + Model model = definitionService.getInstanceModel(instance.getDefinitionId()); + Set nodeKeys = new HashSet<>(); + + //查询目标节点向上回溯到开始节点之间的所有节点 + + if(InstanceStage.completed.equals(instance.getStage())) { + nodeKeys.addAll(decisionService.listNodesFromNode(model,NodeType.end.name())); + }else if(InstanceStage.finished.equals(instance.getStage())) { + instance.getNodeKeys().forEach(node -> { + nodeKeys.addAll(decisionService.listNodesFromNode(model, node.getSource())); + }); + } + + Set submitNodes = instanceLogService.listSubmitNodes(instanceId); + + //已处理节点到开始节点之间不能有激活节点 + Set rightNodes = new HashSet<>(); + Set activeNodes = instance.getNodeKeys().stream().map(EdgeInfo::getTarget).collect(Collectors.toSet()); + for(String nodeId : submitNodes){ + if (!decisionService.checkNodeActiveToStart(model,activeNodes, nodeId)) { + rightNodes.add(nodeId); + } + } + + Set handledNodes = Sets.intersection(nodeKeys,rightNodes); + if(CollUtil.isNotEmpty(handledNodes)){ + // log.info("###### handled nodes {} ######", model.getNodeList().stream().filter(p -> handledNodes.contains(p.getId())).map(Cell::getName).collect(Collectors.toList())); + + List totalNodes = sortNodeByLayout(model,handledNodes); + + // log.info("###### handled nodes sorted result {} ######",totalNodes.stream().map(Node::getName).collect(Collectors.toList())); + + return totalNodes.stream().map(p -> new NodeResult(p.getId(),p.getName())).collect(Collectors.toList()); + } + + return Lists.newArrayList(); + } + + @Override + public List listInstanceActiveNodes(Long instanceId) { + if(instanceId == null){ + + throw new ServiceException(WorkflowResultCode.PARAM_IS_BLANK); + } + Instance instance = instanceService.getById(instanceId); + if(instance == null){ + + throw new ServiceException(WorkflowResultCode.FLOW_INSTANCE_NOT_EXIST); + } + if(!InstanceStage.processing.equals(instance.getStage())){ + + throw new ServiceException(WorkflowResultCode.FLOW_INSTANCE_STATUS_ERROR); + } + + Model model = definitionService.getInstanceModel(instance.getDefinitionId()); + List nodeKeys =instance.getNodeKeys().stream().map(EdgeInfo::getTarget).collect(Collectors.toList()); + if(CollUtil.isNotEmpty(nodeKeys)){ + List nodeList = model.getNodeList().stream().filter(p -> nodeKeys.contains(p.getId())).collect(Collectors.toList()); + + return nodeList.stream().map(node ->new NodeResult(node.getId(),node.getName())).collect(Collectors.toList()); + } + + return null; + } + + @Override + public List listInstanceNodeChecker(Long instanceId,String nodeId) { + //没有的话查询实例节点审核人 + List currentNodeTasks = instanceTaskService.listInstanceTask(instanceId,nodeId,TaskStatus.unhandled); + if(CollUtil.isNotEmpty(currentNodeTasks)){ + + return currentNodeTasks.stream().map(p -> new FlowUser(p.getUserId(),p.getUserName(), p.getUserAccount())).collect(Collectors.toList()); + } + + return new ArrayList<>(); + } + + + @Override + public EngineDataResult transformInstanceDataResult(Instance instance) { + //更新es表单流程数据 + Map> nodeInfo = new HashMap<>(); + instance.getNodeKeys().forEach(node -> { + List users = node.getUsers(); + if(CollUtil.isNotEmpty(users)){ + nodeInfo.put(node.getTarget(),users.stream().map(user -> new EngineDataResult.NodeHandler(node.getTarget(),user.getId(), user.getName(),user.getAccount())).collect(Collectors.toList())); + } + }); + + EngineDataResult result = new EngineDataResult(instance); + result.setNodeTitle(Joiner.on("、").skipNulls().join(instance.getNodeKeys().stream().map(EdgeInfo::getTargetName).distinct().collect(Collectors.toList()))); + result.setNodeInfo(nodeInfo); + + Set nodeSet = result.getNodeInfo().keySet(); + Map handlerMap = new LinkedHashMap<>(); + for(String key : nodeSet){ + List handlerList = result.getNodeInfo().get(key); + if(CollUtil.isNotEmpty(handlerList)){ + handlerList.forEach(user -> { + handlerMap.put(user.getHandlerId(),user.getHandlerName()); + }); + } + } + if(nodeSet.contains(NodeType.start.name())){ + result.setCreator(Joiner.on("、").skipNulls().join(new ArrayList<>(handlerMap.values()))); + } + result.setCheckerName(Joiner.on("、").skipNulls().join(new ArrayList<>(handlerMap.values()))); + + + return result; + } + + /** + * 根据流程设定布局排列节点 + */ + private List sortNodeByLayout(Model model,Set handled){ + List nodes = new ArrayList<>(); + Node start = model.getNodeList().stream().filter(p -> StrUtil.equals(p.getId(),NodeType.start.name())).findFirst().get(); + recursionNodes(handled,model.getNodeList(),nodes,start); + + return nodes; + } + + private void recursionNodes(Set handled,List total,List result,Node node){ + + List nodeIds = result.stream().map(Node::getId).collect(Collectors.toList()); + + Set allowPrevNodes = node.getPrev().stream().filter(handled::contains).collect(Collectors.toSet()); + + boolean preNodesCollected = Sets.difference(allowPrevNodes,new HashSet<>(nodeIds)).isEmpty(); + if(preNodesCollected && handled.contains(node.getId()) && result.stream().noneMatch(p -> StrUtil.equals(p.getId(), node.getId()))){ + result.add(node); + } + + if(CollUtil.isEmpty(node.getNext())){ + return; + } + + List nextNodes = total.stream().filter(p -> StrUtil.startWith(p.getId(),"task") && node.getNext().stream().map(s -> s.getEdge().getTarget()) + .collect(Collectors.toList()).contains(p.getId())) + .collect(Collectors.toList()); + nextNodes.forEach(next -> recursionNodes(handled,total,result,next)); + } + + + + public static void main(String[] args) { + Set test = new HashSet<>(); + test.addAll(Arrays.asList("111","222","333")); + Set test2 = new HashSet<>(); + test2.addAll(Arrays.asList("222","333","4444")); + + System.out.println(" = " + Sets.difference(test,test2)); + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/external/impl/FlowModelServiceImpl.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/external/impl/FlowModelServiceImpl.java new file mode 100644 index 0000000..233494d --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/external/impl/FlowModelServiceImpl.java @@ -0,0 +1,427 @@ +package org.dromara.workflow.service.external.impl; + + +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.Exception.ServiceException; +import org.dromara.common.response.WorkflowResultCode; +import org.dromara.workflow.engine.domain.Definition; +import org.dromara.workflow.engine.enums.DefinitionStage; +import org.dromara.workflow.engine.exception.WorkflowCode; +import org.dromara.workflow.engine.exception.WorkflowException; +import org.dromara.workflow.engine.model.setting.Field; +import org.dromara.workflow.engine.model.setting.Model; +import org.dromara.workflow.engine.model.setting.Node; +import org.dromara.workflow.param.model.DefinitionParam; +import org.dromara.workflow.result.model.DefinitionResult; +import org.dromara.workflow.service.external.FlowModelService; +import org.dromara.workflow.service.internal.DefinitionService; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + + +@Service +@Slf4j +public class FlowModelServiceImpl implements FlowModelService { + + @Autowired + private DefinitionService definitionService; + + @Override + public Model getRunningModel(Long formId) { + Definition definition = definitionService.getStartingDefinition(formId); + if(definition != null){ + + return JSONUtil.toBean(definition.getSnapshots(),Model.class); + } + + return null; + } + + @Override + public boolean checkHasActive(Long formId) { + + return ObjectUtil.isNotNull(definitionService.getStartingDefinition(formId)); + } + + + @Override + public List listModelNodes(Long formId){ + Definition definition = definitionService.getStartingDefinition(formId); + if(definition == null){ + + throw new WorkflowException(WorkflowCode.DEFINITION_RUNNING_NODE_NOT_EXIST); + } + + return listModelNodes(definition.getSnapshots()); + } + + private List listModelNodes(String snapshots){ + Model model = JSONUtil.toBean(snapshots,Model.class); + + if(model == null){ + + throw new WorkflowException(WorkflowCode.DEFINITION_NOT_EXIST); + } + + return model.getNodeList(); + } + + @Override + public DefinitionResult create(DefinitionParam param) { + + Definition definition = new Definition(); + definition.setFormId(param.getFormId()); + + Definition startDefinition = definitionService.getStartingDefinition(param.getFormId()); + + //查看正在启动的流程定义 + if(startDefinition != null){ + definition.setSnapshots(startDefinition.getSnapshots()); + }else{ + definition.setSnapshots(param.getModel()); + } + + definition.setStage(DefinitionStage.design); + definition.setVersion(definitionService.countDefinitionVersion(param.getFormId())+1); + definition.setCreateName(LoginHelper.getLoginUser().getNickname()); + this.definitionService.save(definition); + + //保存 + return wrapResult(param.getFormId(),definition); + } + + /** + * 复制表单流程配置 + * + * @param sourceId + * @param targetId + */ + @Override + public void copy(Long sourceId, Long targetId) { + // 查询原表单流程定义 + List formDefinitions = this.getDefByForm(sourceId).stream().filter(p -> !DefinitionStage.design.equals(p.getStage())).collect(Collectors.toList()); + if(CollUtil.isNotEmpty(formDefinitions)){ + List newDefinition = new ArrayList<>(); + for(Definition definition : formDefinitions){ + Definition newDef = new Definition(); + newDef.setFormId(targetId); + newDef.setStage(definition.getStage()); + newDef.setSnapshots(definition.getSnapshots()); + newDef.setVersion(definition.getVersion()); + newDefinition.add(newDef); + } + + this.definitionService.saveBatch(newDefinition); + } + } + + /** + * 根据表单 查询流程定义 + * @param formId + * @return + */ + @Override + public DefinitionResult getByForm(Long formId) { + + return wrapResult(formId,null); + } + + @Override + public List getDefByForm(Long formId) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper() + .eq(Definition::getFormId, formId).orderByAsc(Definition::getVersion); + + return definitionService.list(wrapper); + } + + /** + * 根据版本 查询流程定义 + * @param versionId + * @return + */ + @Override + public DefinitionResult getByVersion(Long versionId) { + Definition definition = definitionService.getById(versionId); + + return wrapResult(definition.getFormId(),definition); + } + + /** + * 更新 流程定义 + * @param param + * @return + */ + @Override + public DefinitionResult update(DefinitionParam param) { + Definition definition = definitionService.getById(param.getId()); + definition.setSnapshots(param.getModel()); + + this.definitionService.updateById(definition); + + return wrapResult(param.getFormId(),definition); + } + + + /** + * 激活 流程定义 + * @param param + * @return + */ + @Override + @Transactional(rollbackFor = Exception.class) + public DefinitionResult active(DefinitionParam param) { + Definition current = this.definitionService.getById(param.getId()); + + if(DefinitionStage.running.equals(current.getStage())){ + + throw new ServiceException(WorkflowResultCode.FLOW_DEFINITION_VERSION_STAGE_ERROR); + } + Definition running = definitionService.getStartingDefinition(param.getFormId()); + if(running != null){ + running.setStage(DefinitionStage.history); + this.definitionService.updateById(running); + } + current.setSnapshots(param.getModel()); + current.setStage(DefinitionStage.running); + this.definitionService.updateById(current); + + return wrapResult(param.getFormId(),current); + } + + + /** + * 删除单个流程定义配置 + * @param param + * @return + */ + @Override + public DefinitionResult delete(DefinitionParam param) { + Definition definition = this.definitionService.getById(param.getId()); + if(definition != null){ + if(!DefinitionStage.design.equals(definition.getStage())){ + + throw new ServiceException(WorkflowResultCode.FLOW_DEFINITION_VERSION_STAGE_ERROR); + } + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(Definition::getId,param.getId()); + wrapper.eq(Definition::getFormId,param.getFormId()); + this.definitionService.remove(wrapper); + + return wrapResult(param.getFormId(),null); + } + return null; + } + + + /** + * 删除表单设计 中的流程定义配置 + * @param formId + * @return + */ + @Override + public void deleteDesignDefinition(Long formId) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(Definition::getFormId,formId); + wrapper.eq(Definition::getStage,DefinitionStage.design); + this.definitionService.remove(wrapper); + } + + /** + * 查询正在启动的流程定义 + * @param formId + * @return + */ + @Override + public Definition getRunningDefinition(Long formId) { + + return definitionService.getStartingDefinition(formId); + } + + /** + * 查询流程定义模型 + * @param definitionId + * @return + */ + @Override + public Model getDefinitionModel(Long definitionId) { + + Definition definition = definitionService.getById(definitionId); + if(definition != null){ + + return JSONUtil.toBean(definition.getSnapshots(),Model.class); + } + + return null; + } + + /** + * 查询流程定义节点 + * @param definitionId + * @param nodeKey + * @return + */ + @Override + public Node getDefinitionNode(Long definitionId,String nodeKey) { + + Definition definition = definitionService.getById(definitionId); + if (definition != null) { + + Model model = JSONUtil.toBean(definition.getSnapshots(), Model.class); + + return model.getNodeList().stream().filter(p -> StrUtil.equals(nodeKey, p.getId())).findFirst().get(); + } + + return null; + } + + + // public Node getNodeInfo(Long instanceId,String nodeKey){ + // Instance instance = instanceService.getById(instanceId); + // Model model = JSONUtil.toBean(definitionService.getById(instance.getDefinitionId()).getSnapshots(),Model.class); + // + // return definitionService.getNodeData(model,nodeKey); + // } + + /** + * 查询表单节点字段 + * @param formId + * @param nodeKey + * @return + */ + @Override + public List listNodeField(Long formId, String nodeKey) { + if(ObjectUtil.hasEmpty(formId,nodeKey)){ + throw new WorkflowException(WorkflowCode.PARAM_MISSING); + } + List nodeList = this.listModelNodes(formId); + if(CollUtil.isNotEmpty(nodeList)){ + Optional optional = nodeList.stream().filter(p -> StrUtil.equals(nodeKey,p.getId())).findFirst(); + if(optional.isPresent()){ + + return optional.get().getField(); + } + } + + return CollUtil.newArrayList(); + } + + /** + * 查询 + * @param definitionId + * @param nodeId + * @return + */ + @Override + public List getNodeViewFields(Long definitionId, String nodeId) { + + //节点字段权限过滤 + Model definitionConfig = getDefinitionModel(definitionId); + if(definitionConfig != null){ + List nodeList = definitionConfig.getNodeList(); + + if(CollUtil.isNotEmpty(nodeList)){ + Optional optional = nodeList.stream().filter(p -> StrUtil.equals(p.getId(),nodeId)).findFirst(); + if(optional.isPresent()){ + List fieldList = optional.get().getField().stream().filter(s -> ObjectUtil.isEmpty(s.getParentId()) && + s.getView()).collect(Collectors.toList()); + + return fieldList; + } + } + + } + + return com.google.common.collect.Lists.newArrayList(); + } + + @Override + public List listNodeTitles(Long sourceId) { + List definitionList = + definitionService.list(new LambdaQueryWrapper() + .eq(Definition::getFormId, sourceId) + .orderByAsc(Definition::getVersion) + ); + if(CollUtil.isEmpty(definitionList)){ + return new ArrayList<>(); + } + + Optional defOption = definitionList.stream() + .filter(p -> DefinitionStage.running == p.getStage()).findFirst(); + DefinitionResult.ModelData current; + if(defOption.isPresent()){ + current = getModelData(defOption.get()); + }else{ + current = getModelData(definitionList.get(0)); + } + + JSONObject model = JSONUtil.parseObj(current.getModel()); + List nodeList = JSONUtil.toList(model.getJSONArray("nodeList"), JSONObject.class); + return nodeList.stream().map(node -> node.getStr("name")).collect(Collectors.toList()); + } + + private DefinitionResult wrapResult(Long formId, Definition currentDef) { + List definitionList = + definitionService.list(new LambdaQueryWrapper() + .eq(Definition::getFormId, formId) + .orderByAsc(Definition::getVersion) + ); + if(CollUtil.isEmpty(definitionList)){ + + return new DefinitionResult(null, CollUtil.newArrayList()); + } + + DefinitionResult result = new DefinitionResult(); + if(currentDef != null){ + + result.setCurrent(getModelData(currentDef)); + }else{ + Optional defOption = definitionList.stream() + .filter(p -> DefinitionStage.running == p.getStage()).findFirst(); + if(defOption.isPresent()){ + + result.setCurrent(getModelData(defOption.get())); + }else{ + result.setCurrent(getModelData(definitionList.get(0))); + } + } + + List versionList = definitionList.stream().map(p -> { + DefinitionResult.ModelVersion item = new DefinitionResult.ModelVersion(); + item.setId(p.getId()); + item.setVersionNo(p.getVersion()); + item.setStage(p.getStage().name()); + + return item; + }).collect(Collectors.toList()); + + result.setVersion(versionList); + + return result; + } + + private DefinitionResult.ModelData getModelData(Definition currentDef) { + DefinitionResult.ModelData modelData = new DefinitionResult.ModelData(); + modelData.setModel(currentDef.getSnapshots()); + modelData.setId(currentDef.getId()); + modelData.setVersionNo(currentDef.getVersion()); + modelData.setStage(currentDef.getStage().name()); + return modelData; + } + + + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/external/impl/FlowTaskServiceImpl.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/external/impl/FlowTaskServiceImpl.java new file mode 100644 index 0000000..58e483e --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/external/impl/FlowTaskServiceImpl.java @@ -0,0 +1,178 @@ +package org.dromara.workflow.service.external.impl; + +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.service.ISysUserService; +import org.dromara.dataManager.domain.FormData; +import org.dromara.dataManager.service.FormDataService; +import org.dromara.workflow.engine.domain.Instance; +import org.dromara.workflow.engine.domain.InstanceCc; +import org.dromara.workflow.engine.domain.InstanceTask; +import org.dromara.workflow.engine.enums.NodeType; +import org.dromara.workflow.engine.enums.TaskStatus; +import org.dromara.workflow.result.instance.InstanceCcResult; +import org.dromara.workflow.service.external.FlowTaskService; +import org.dromara.workflow.service.internal.InstanceCcService; +import org.dromara.workflow.service.internal.InstanceTaskService; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * @Description: server + **/ +@Service +@Slf4j +public class FlowTaskServiceImpl implements FlowTaskService { + + @Autowired + private InstanceCcService ccService; + @Autowired + private InstanceTaskService taskService; + @Autowired + private ISysUserService userService; + @Autowired + private FormDataService formDataService; + + @Override + @Transactional(rollbackFor = Exception.class) + public InstanceTask saveTaskDraft(Instance instance,InstanceTask instanceTask, LinkedHashMap data) { + instanceTask.setDrafting(true); + this.taskService.updateById(instanceTask); + + FormData instanceFormData = formDataService.getById(instance.getDataId()); + if(instanceFormData != null){ + LinkedHashMap befFormData = instanceFormData.getFormData(); + befFormData.putAll(data); + instanceFormData.setFormData(befFormData); + this.formDataService.updateById(instanceFormData); + } + + return instanceTask; + } + + @Override + public boolean updateCcStatus(Long ccId) { + InstanceCc instanceCc = ccService.getById(ccId); + instanceCc.setStatus(TaskStatus.handled.getCode()); + return ccService.updateById(instanceCc); + } + + + @Override + public InstanceTask getUserTask(Long instanceId, String nodeId, Long userId) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(InstanceTask::getInstanceId,instanceId); + wrapper.eq(InstanceTask::getNodeKey,nodeId); + wrapper.eq(InstanceTask::getUserId,userId); + wrapper.eq(InstanceTask::getStatus, TaskStatus.unhandled.getCode()); + + return this.taskService.getOne(wrapper); + } + + @Override + public List listNodesTask(Long instanceId, List nodes) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(InstanceTask::getInstanceId,instanceId); + wrapper.in(InstanceTask::getNodeKey, nodes); + wrapper.eq(InstanceTask::getStatus,TaskStatus.unhandled.getCode()); + + return this.taskService.list(wrapper); + } + + @Override + public boolean updateTaskPriority(Instance instance) { + LambdaUpdateWrapper wrapper = new LambdaUpdateWrapper<>(); + wrapper.eq(InstanceTask::getInstanceId,instance.getId()); + wrapper.eq(InstanceTask::getStatus,TaskStatus.unhandled.getCode()); + wrapper.ne(InstanceTask::getUserId,instance.getCreateUser()); + wrapper.set(InstanceTask::getPriority,true); + wrapper.set(InstanceTask::getUpdateTime,new Date()); + + return this.taskService.update(wrapper); + } + + @Override + public List listPriorityTodo(Long instanceId) { + LambdaUpdateWrapper wrapper = new LambdaUpdateWrapper<>(); + wrapper.eq(InstanceTask::getInstanceId,instanceId); + wrapper.eq(InstanceTask::getStatus,TaskStatus.unhandled.getCode()); + wrapper.eq(InstanceTask::getPriority,true); + + return this.taskService.list(wrapper); + } + + @Override + public List listNodesHandledTask(Long instanceId, List nodes) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(InstanceTask::getInstanceId,instanceId); + wrapper.in(InstanceTask::getNodeKey, nodes); + wrapper.eq(InstanceTask::getStatus,TaskStatus.handled.getCode()); + + return this.taskService.list(wrapper); + } + + @Override + public List listNodesCc(Long instanceId, List nodes) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(InstanceCc::getInstanceId,instanceId); + wrapper.eq(InstanceCc::getStatus,TaskStatus.unhandled.getCode()); + wrapper.in(InstanceCc::getNodeKey, nodes); + wrapper.orderByDesc(InstanceCc::getCreateTime); + List ccList = this.ccService.list(wrapper); + List ccResults = new ArrayList<>(); + if (ccList != null) { + List users = userService.selectUserByIds(ccList.stream().map(cc -> cc.getUserId()).collect(Collectors.toList()),null); + if (users != null) { + Map idAccountMap = users.stream().collect(Collectors.toMap(SysUserVo::getUserId, SysUserVo::getUserName)); + ccList.forEach(cc -> { + InstanceCcResult ccr = new InstanceCcResult(); + BeanUtils.copyProperties(cc, ccr); + ccr.setUserAccount(idAccountMap.get(cc.getUserId())); + ccResults.add(ccr); + }); + } + } + return ccResults; + } + + @Override + public InstanceTask getTaskInfo(Long taskId) { + return taskService.getById(taskId); + } + + @Override + public boolean checkNodeHandledTask(Long instanceId,List nodes){ + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(InstanceTask::getInstanceId,instanceId); + wrapper.in(InstanceTask::getNodeKey,nodes); + wrapper.eq(InstanceTask::getStatus, TaskStatus.handled.getCode()); + + return taskService.count(wrapper) > 0; + } + + @Override + public boolean checkInstanceCanRecall(Long instanceId) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(InstanceTask::getInstanceId,instanceId); + wrapper.eq(InstanceTask::getStatus, TaskStatus.handled.getCode()); + wrapper.notIn(InstanceTask::getNodeKey, Arrays.asList(NodeType.start.name(), NodeType.preset.name())); + + return taskService.count(wrapper) == 0; + } + @Override + public boolean checkInstanceSubmitted(Long instanceId) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(InstanceTask::getInstanceId,instanceId); + wrapper.eq(InstanceTask::getStatus, TaskStatus.handled.getCode()); + wrapper.notIn(InstanceTask::getNodeKey, Arrays.asList(NodeType.start.name(),NodeType.preset.name())); + + return taskService.count(wrapper) > 0; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/DecisionService.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/DecisionService.java new file mode 100644 index 0000000..7dc0e1a --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/DecisionService.java @@ -0,0 +1,124 @@ +package org.dromara.workflow.service.internal; + +import org.dromara.workflow.engine.domain.Instance; +import org.dromara.workflow.engine.enums.NodeType; +import org.dromara.workflow.engine.model.setting.Model; +import org.dromara.workflow.engine.model.setting.Node; +import org.dromara.workflow.param.engine.EngineRequest; +import org.dromara.workflow.param.model.FlowUser; +import org.dromara.workflow.result.engine.AutoSubmitResult; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Set; + +/** + + * @Description: 节点决策方法 + **/ +public interface DecisionService { + + /** + * 配置流程定义 + * @param request + */ + void initModel(EngineRequest request); + + /** + * 查询实例基础信息 + * @param request + */ + void initInstance(EngineRequest request); + + /** + * 初始化当前节点 + * @param request + */ + void initCurrent(EngineRequest request); + + + /** + * 校验下面的节点是否包含某种节点 + * @param type + * @return + */ + boolean containNode(List nodes, NodeType type); + + /** + * 从目标节点向上回溯到开始节点,判断所有分支上的节点是否存在激活节点 + * @return + */ + boolean checkNodeActiveToStart(Model model, Set activeNodes, Node currentNode, Node targetNode); + + /** + * 从目标节点向上回溯到开始节点,判断所有分支上的节点是否存在激活节点 + * @param model + * @param activeNodes + * @param targetNodeId + * @return + */ + boolean checkNodeActiveToStart(Model model,Set activeNodes, String targetNodeId); + + /** + * 查询满足流转条件的流转节点 + * @return + */ + List getConditionNextNodes(Model model, Node node, FlowUser user, String formCode, LinkedHashMap formData); + + + /** + * 查询满足流转条件&满足合流规则的流转节点 + * @param request + * @return + */ + List getNextNodes(EngineRequest request); + + + /** + * 校验 + * @param request + * @return + */ + boolean checkNodeProcessRule(EngineRequest request); + + + /** + * 查询即将流转的自动提交节点 + * @param request + * @return + */ + AutoSubmitResult getNextActionNode(EngineRequest request, List nextNodes); + + + /** + * 从目标节点向上回溯到开始节点,查询所有节点 + * @param model + * @param nodeId + * @return + */ + Set listNodesFromNode(Model model, String nodeId); + + /** + * 查询流程节点 + * @param model + * @return + */ + Node getNodeInfo(Model model, String nodeId); + + /** + * 查询当前节点上一节点 + * @param request + * @return + */ + Node getPrevNode(EngineRequest request); + + + /** + * 校验实例申请人是否是当前请求处理人 + * @param instance + * @param handlerId + * @return + */ + boolean checkInstanceHandler(Instance instance, Long handlerId); + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/DefinitionService.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/DefinitionService.java new file mode 100644 index 0000000..fddc598 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/DefinitionService.java @@ -0,0 +1,48 @@ +package org.dromara.workflow.service.internal; + +import org.dromara.workflow.engine.domain.Definition; +import org.dromara.workflow.engine.model.setting.Model; +import org.dromara.workflow.engine.model.setting.Node; +import com.baomidou.mybatisplus.extension.service.IService; + +public interface DefinitionService extends IService { + + + /** + * 查询启用的流程定义 + * @param formId + * @return + */ + Definition getStartingDefinition(Long formId); + + /** + * 查询流程定义版本 + * @param formId + * @return + */ + Integer countDefinitionVersion(Long formId); + + + /** + * 获取实例的流程配置 + * @param definitionId + * @return + */ + Model getInstanceModel(Long definitionId); + + /** + * 获取启用的流程配置 + * @param formId + * @return + */ + Model getStartingModel(Long formId); + + /** + * 获取流程定义节点信息 + * @param definitionId + * @param nodeId + * @return + */ + Node getModelNode(Long definitionId, String nodeId); + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/InstanceCcService.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/InstanceCcService.java new file mode 100644 index 0000000..ec6342b --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/InstanceCcService.java @@ -0,0 +1,19 @@ +package org.dromara.workflow.service.internal; + +import org.dromara.workflow.engine.domain.InstanceCc; +import com.baomidou.mybatisplus.extension.service.IService; + +public interface InstanceCcService extends IService { + + // /** + // * 发送下面抄送节点抄送数据 + // * @param request + // */ + // void handlerNextCc(EngineRequest request); + // + // /** + // * 批量删除实例的抄送数据 + // * @param instanceIds + // */ + // boolean batchDeleteInstance(List instanceIds); +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/InstanceLogService.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/InstanceLogService.java new file mode 100644 index 0000000..d6964f8 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/InstanceLogService.java @@ -0,0 +1,63 @@ +package org.dromara.workflow.service.internal; + +import org.dromara.workflow.engine.domain.InstanceLog; +import org.dromara.workflow.param.instance.InstanceLogParam; +import org.dromara.workflow.remind.flow.model.FlowInstanceMessage; +import org.dromara.workflow.result.instance.InstanceLogResult; +import com.baomidou.mybatisplus.extension.service.IService; + +import java.util.List; +import java.util.Set; + +public interface InstanceLogService extends IService { + + /** + * 验证用户在实例流转过程中是否执行过某种操作 + * @param instanceId + * @param userIds + * @return + */ + boolean checkUserSubmit(Long instanceId, List userIds); + + /** + * 新增流程动态 + * @param data + * @return + */ + InstanceLog create(InstanceLogParam data); + + /** + * 生成开始节点日志 + * @param param + */ + void saveFlowLog(FlowInstanceMessage param); + + /** + * 查询节点流转日志 + * @param instanceId + * @return + */ + InstanceLogResult listFlowLog(Long instanceId, String nodeKey); + + /** + * 批量删除实例日志 + * @param instanceIds + */ + boolean batchDeleteInstance(List instanceIds); + + /** + * 查询历史已提交节点 + * @param instanceId + * @return + */ + Set listSubmitNodes(Long instanceId); + + /** + * 查询重新激活的已处理的节点 + * @param instanceId instanceId + * @return + */ + Set listReactiveSubmitNodes(Long instanceId); + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/InstanceMessageService.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/InstanceMessageService.java new file mode 100644 index 0000000..3c66775 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/InstanceMessageService.java @@ -0,0 +1,18 @@ +package org.dromara.workflow.service.internal; + + +import org.dromara.workflow.engine.model.setting.Node; +import org.dromara.workflow.param.engine.EngineRequest; + +import java.util.List; + +public interface InstanceMessageService{ + + /** + * 发送流程变动消息提醒 + * @param request + */ + void sendMessage(List nextNodes, EngineRequest request); + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/InstanceService.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/InstanceService.java new file mode 100644 index 0000000..2c733dc --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/InstanceService.java @@ -0,0 +1,88 @@ +package org.dromara.workflow.service.internal; + + +import org.dromara.workflow.engine.domain.Instance; +import org.dromara.workflow.param.engine.EngineRequest; +import com.baomidou.mybatisplus.extension.service.IService; + +public interface InstanceService extends IService { + + /** + * 查询单个实例 + * @param instanceId + * @return + */ + Instance getById(Long instanceId); + + /** + * 根据dataId查询流程实例 + * @param dataId + * @return + */ + Instance getByDataId(Long dataId); + + /** + * 更新实例 + * @param request + */ + Instance update(EngineRequest request); + + /** + * 激活实例 + * @param request + * @return + */ + // Instance activeInstance(EngineRequestParam request); + + + // /** + // * 回退实例 + // * @param request + // * @return + // */ + // Instance rollback(EngineRequest request); + // + // /** + // * 更新撤回实例 + // * @param request + // * @return + // */ + // Instance recall(EngineRequest request); + // + // /** + // * 结束撤回实例 + // * @param request + // * @return + // */ + // Instance finish(EngineRequest request); + + /** + * 删除表单流程实例 + * @param formId + */ + void deleteByForm(Long formId); + + + /** + * 删除流程实例 + * @param formId + * @param dataIds + */ + void deleteByData(Long formId, String... dataIds); + + /** + * 逻辑删除流程实例 + * @param formId + * @param dataIds + */ + void logicDeleteByForm(Long formId, String... dataIds); + + + /** + * 恢复逻辑删除的流程实例 + * @param formId + * @param dataIds + */ + void logicRecoverByForm(Long formId, String... dataIds); + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/InstanceTaskService.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/InstanceTaskService.java new file mode 100644 index 0000000..90355a1 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/InstanceTaskService.java @@ -0,0 +1,199 @@ +package org.dromara.workflow.service.internal; + +import org.dromara.workflow.engine.domain.Instance; +import org.dromara.workflow.engine.domain.InstanceTask; +import org.dromara.workflow.engine.enums.HandleUserType; +import org.dromara.workflow.engine.enums.TaskStatus; +import org.dromara.workflow.engine.enums.FlowTaskType; +import org.dromara.workflow.engine.model.setting.Node; +import org.dromara.workflow.param.engine.EngineRequest; +import org.dromara.workflow.param.model.FlowUser; +import com.baomidou.mybatisplus.extension.service.IService; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +public interface InstanceTaskService extends IService { + + /** + * 查询用户列表在某节点上的待办任务 + * @param instanceId + * @param nodeId + * @param users + * @return + */ + List getUsersNodeUnHandleTask(Long instanceId,String nodeId,List users); + + + /** + * 查询用户在某节点上的待办任务 + * @param instanceId + * @param nodeId + * @param userId + * @return + */ + InstanceTask getUserNodeUnHandleTask(Long instanceId, String nodeId, Long userId ); + + /** + * 校验用户是否在节点审核人范围内 + * @return + */ + boolean checkTaskUser(List taskNodes,Long instanceUser,Map formData); + + + /** + * 查询实例(节点)待办任务 + * @param nodeId + * @return + */ + List listInstanceTask(Long instanceId,String nodeId,TaskStatus status); + + /** + * 查询实例节点用户的待办任务 + * @param instanceId + * @param nodeId + * @param userId + * @param status + * @return + */ + List listInstanceNodeUserTask(Long instanceId, String nodeId, Long userId, TaskStatus status); + + + /** + * 查询节点负责人 + * @param node + * @param createUser + * @param formData + * @return + */ + List parseNodeUser(HandleUserType type, Long createUser, Node node, Map formData); + + + /** + * 流程引擎节点任务 + * 生成下面任务节点-待办任务 + * 生成下面任务节点-抄送待办任务 + * 生成下面任务节点-抄送提醒 + * 发送下面任务节点抄送提醒 + * @param request + */ + Map createNodeTask(EngineRequest request); + + /** + * 创建节点待办任务(待办任务和抄送任务) + * @param instance + * @param node + * @param handler + * @param formData + */ + List createNodeTask(Instance instance, Node node, FlowUser handler, Map formData); + + + /** + * 创建成员待办任务 + * @param instance + * @param node + * @param users + * @return + */ + List createUserTask(Instance instance, Node node, List users); + + /** + * 处理待办节点业务 + * ①处理当前节点待办任务状态 + * ②生成下面任务节点状态 + * ③发送下面任务节点抄送提醒 + * @param request + */ + void update(EngineRequest request); + + /** + * 更新待办任务处理状态 + * @param taskId + * @return + */ + InstanceTask updateTaskProcessing(Long taskId); + + void batchUpdateTaskProcessing(List taskIds); + + + /** + * 删除实例删除未处理待办任务 + * @param instanceId + */ + void deleteInstanceUnHandledTask(Long instanceId); + + /** + * 根据任务id删除待办任务 + * @param taskIds + */ + void deleteInstanceTaskByIds(Set taskIds); + + /** + * 删除实例节点用户的待办任务 + * @param instanceId + * @param nodeId + * @param userIds + */ + void deleteInstanceTaskByUsers(Long instanceId,String nodeId,Set userIds); + + /** + * 获取实例的所有任务ID + * @param instanceId + * @return + */ + List getTaskIdsOf(Long instanceId); + + /** + * 获取当前节点的所有任务,用于或签 + * @param instanceId + * @param nodeKey + * @return + */ + List getTaskIdOfNode(Long instanceId, String nodeKey); + + + /********************************* 已废弃 ***************************************/ + + // * + // * 更新下面节点审核人 + // * @param request + // void updateNextChecker(EngineRequest request); + + // /** + // * 添加转发审核人 + // * @param request + // */ + // void updateForwardChecker(EngineRequest request); + + // /** + // * 校验审核节点状态 + // * @param request + // * @param status + // * @return + // */ + // boolean checkTaskNodeCheckStatus(EngineRequest request, TaskStatus status); + + + // /** + // * 查询个人节点待处理任务 + // * @param instanceId + // * @param node + // * @param handlerId + // * @return + // */ + // InstanceTask getNodeTask(Long instanceId,Node node,Long handlerId); + + + // /** + // * 查询实例处理过的审核人 + // * @param requestParam + // * @param nextNode + // * @return + // */ + // List checkUserHandled(EngineRequest requestParam, Node nextNode); + + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/impl/DecisionServiceImpl.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/impl/DecisionServiceImpl.java new file mode 100644 index 0000000..5584c92 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/impl/DecisionServiceImpl.java @@ -0,0 +1,585 @@ +package org.dromara.workflow.service.internal.impl; + +import org.dromara.workflow.engine.domain.Definition; +import org.dromara.workflow.engine.domain.Instance; +import org.dromara.workflow.engine.domain.InstanceTask; +import org.dromara.workflow.engine.domain.base.EdgeInfo; +import org.dromara.workflow.engine.enums.*; +import org.dromara.workflow.engine.enums.nodeMoving.AutoCommitEnum; +import org.dromara.workflow.engine.enums.nodeMoving.NodeFlowRuleEnum; +import org.dromara.workflow.engine.exception.WorkflowCode; +import org.dromara.workflow.engine.exception.WorkflowException; +import org.dromara.workflow.engine.model.setting.EndSetting; +import org.dromara.workflow.engine.model.setting.Model; +import org.dromara.workflow.engine.model.setting.Node; +import org.dromara.workflow.param.engine.EngineRequest; +import org.dromara.workflow.param.model.FlowUser; +import org.dromara.workflow.remind.flow.FlowRemindHelper; +import org.dromara.workflow.result.engine.AutoSubmitResult; +import org.dromara.workflow.service.internal.*; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.google.common.base.Splitter; +import com.google.common.collect.Sets; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.util.*; +import java.util.stream.Collectors; + +@Slf4j +@Service +public class DecisionServiceImpl implements DecisionService { + + @Autowired + private InstanceService instanceService; + @Autowired + private InstanceTaskService instanceTaskService; + @Autowired + private DefinitionService definitionService; + @Autowired + private InstanceLogService instanceLogService; + @Autowired + private FlowEsDataDecisionService esDataDecisionService; + + @Autowired + private FlowRemindHelper flowRemindHelper; + + /** + * 设置当前流程配置 + * @param request + */ + @Override + public void initModel(EngineRequest request){ + Definition definition; + if(request.getTaskId() == null){ + definition = definitionService.getStartingDefinition(request.getForm().getFormId()); + }else{ + definition = definitionService.getById(request.getInstance().getDefinitionId()); + } + + if(definition == null || StrUtil.isEmpty(definition.getSnapshots())){ + throw new WorkflowException(WorkflowCode.DEFINITION_NOT_EXIST); + } + + request.setModel(JSONUtil.toBean(definition.getSnapshots(), Model.class)); + + request.setDefinitionId(definition.getId()); + } + + /** + * 初始化流程实例(实例数据、待办数据) + * @param request + */ + @Override + public void initInstance(EngineRequest request) { + //前置节点 + if(OperateType.create.equals(request.getAction())){ + + request.setInstanceTask(null); + request.setInstance(new EngineRequest.InstanceData(request)); + return; + } + + if(request.getTaskId() == null){ + throw new WorkflowException(WorkflowCode.TASK_PARAM_NOT_EXIST); + } + + //查询待办任务(只有从待办中心进行操作才会出现) + InstanceTask task = instanceTaskService.getById(request.getTaskId()); + if(task == null){ + throw new WorkflowException(WorkflowCode.TASK_NOT_EXIST); + } + request.setInstanceTask(task); + + + if(request.getInstance() == null){ + Instance instance = instanceService.getById(request.getInstanceTask().getInstanceId()); + if(instance == null){ + throw new WorkflowException(WorkflowCode.INSTANCE_NOT_EXIST); + } + EngineRequest.InstanceData instanceData = new EngineRequest.InstanceData(instance); + request.setInstance(instanceData); + }else{ + request.setInstance(new EngineRequest.InstanceData(request.getInstance())); + } + request.setTasks(flowRemindHelper.getTasks(request.getInstance().getId(), request.getInstanceTask().getNodeKey(), TaskStatus.unhandled)); + + } + + /** + * 初始化流程实例(实例数据、待办数据) + * @param request + */ + @Override + public void initCurrent(EngineRequest request) { + if(OperateType.create.equals(request.getAction())){ + Node preNode = new Node(); + preNode.setId(NodeType.preset.name()); + request.setCurrent(preNode); + return; + } + + //实例当前运行节点 + Optional currentNode = + request.getModel().getNodeList().stream().filter(p -> StrUtil.equals(request.getInstanceTask().getNodeKey(), p.getId())).findFirst(); + if(!currentNode.isPresent()){ + throw new WorkflowException(WorkflowCode.NODE_NOT_EXIST); + } + + request.setCurrent(currentNode.get()); + + } + + + @Override + public boolean checkInstanceHandler(Instance instance, Long handlerId){ + if(ObjectUtil.isNull(instance.getId())){ + return true; + } + + return instance.getCreateUser().equals(handlerId); + } + + @Override + public Set listNodesFromNode(Model model, String nodeId){ + if(ObjectUtil.isEmpty(model)){ + throw new IllegalArgumentException(WorkflowCode.ILLEGAL_ARGUMENT.message()); + } + Set nodeKeList = new HashSet<>(); + recursionNodeKey(nodeKeList,model,nodeId); + + return nodeKeList; + } + + @Override + public boolean checkNodeActiveToStart(Model model,Set activeNodes, Node currentNode,Node targetNode) { + Set nodeKeList = new HashSet<>(); + recursionNodeKey(nodeKeList,model,targetNode.getId()); + + Set activeNodeSet = new HashSet<>(); + + if(CollUtil.isNotEmpty(activeNodes)){ + activeNodeSet = CollUtil.newHashSet(activeNodes); + } + + if(ObjectUtil.isNotNull(currentNode)){ + activeNodeSet.remove(currentNode.getId()); + } + + return CollUtil.isNotEmpty(Sets.intersection(nodeKeList, activeNodeSet)); + } + + @Override + public boolean checkNodeActiveToStart(Model model,Set activeNodes, String targetNodeId) { + Set nodeKeList = new HashSet<>(); + recursionNodeKey(nodeKeList,model,targetNodeId); + + Set activeNodeSet = new HashSet<>(); + + if(CollUtil.isNotEmpty(activeNodes)){ + activeNodeSet = CollUtil.newHashSet(activeNodes); + } + + log.info("###### {} ######",CollUtil.isNotEmpty(Sets.intersection(nodeKeList, activeNodeSet))); + return CollUtil.isNotEmpty(Sets.intersection(nodeKeList, activeNodeSet)); + } + + @Override + public Node getNodeInfo(Model model, String nodeId) { + List nodeList = model.getNodeList(); + + return Optional.of(nodeList.stream().filter(p -> StrUtil.equals(nodeId,p.getId())).findAny().get()) + .orElseThrow(() -> new WorkflowException(WorkflowCode.NODE_START_NOT_EXIST)); + } + + + @Override + public Node getPrevNode(EngineRequest request) { + Instance instance = request.getInstance(); + List edgeInfoList = instance.getNodeKeys(); + EdgeInfo currentEdge = edgeInfoList.stream().filter(p -> StrUtil.equals(request.getCurrent().getId(), + p.getTarget())).findAny().get(); + + return getNodeInfo(request.getModel(),currentEdge.getSource()); + } + + @Override + public boolean containNode(List nodeList,NodeType type) { + if(CollUtil.isEmpty(nodeList)){ + return false; + } + return nodeList.stream().anyMatch(p -> StrUtil.startWith(p.getId(),type.name())); + } + + + + /** + * 查询满足条件的流转节点 + * @param model + * @param node + * @param formData + * @return + */ + @Override + public List getConditionNextNodes(Model model, Node node, FlowUser flowUser, String formCode, LinkedHashMap formData){ + List edges = node.getNext(); + List nextNodeId = new ArrayList<>(); + + if(CollUtil.isNotEmpty(edges)) { + List nextFilterLines = edges.stream().filter(p -> StrUtil.equals("if",p.getSource())).collect(Collectors.toList()); + if(CollUtil.isNotEmpty(nextFilterLines)){ + for(Node.EdgeCondition line : nextFilterLines){ + if(CollUtil.isNotEmpty(line.getCondition())){ + // 第一版流转条件校验 + if(checkEdgeCondition(line,formData)){ + nextNodeId.add(line.getEdge().getTarget()); + } + }else{ + nextNodeId.add(line.getEdge().getTarget()); + } + } + } + + List elseLines = edges.stream().filter(p -> StrUtil.equals("else",p.getSource())).collect(Collectors.toList()); + + boolean hasTaskNode = nextNodeId.stream().anyMatch(p -> p.contains(NodeType.task.name())); + + if(!hasTaskNode && CollUtil.isNotEmpty(elseLines)){ + nextNodeId = elseLines.stream().map(p -> p.getEdge().getTarget()).collect(Collectors.toList()); + } + + // 没有else条件,并且其他条件不满足 + if(CollUtil.isEmpty(elseLines) && CollUtil.isEmpty(nextNodeId)){ + + throw new WorkflowException(WorkflowCode.NODE_FLOW_ERROR); + } + + List tempNextNodeId = nextNodeId; + + return model.getNodeList().stream() .filter(p -> tempNextNodeId.contains(p.getId())).collect(Collectors.toList()); + } + + return Collections.emptyList(); + } + + + + @Override + public List getNextNodes(EngineRequest request){ + //流程定义中连接线连接的节点 + List nextConditionNodes = getConditionNextNodes(request.getModel(),request.getCurrent(), request.getHandlerUser(), request.getForm().getFormCode(), request.getForm().getData()); + + List nextNodes = new ArrayList<>(); + + Node currentNode = request.getCurrent(); + Set activeNodes = request.getInstance().getNodeKeys().stream().map(EdgeInfo::getTarget).collect(Collectors.toSet()); + + //当前节点没有可流转节点 && 实例其他分支上没有已激活的节点 => 提交失败,不符合流转条件 + boolean conditionNodesCount =nextConditionNodes.stream().filter(p -> !StrUtil.contains(p.getId(),NodeType.cc.name())).count() > 0; + if (!conditionNodesCount) { + if (!checkInstanceNodeActive(request.getInstance(), currentNode)) { + + throw new WorkflowException(WorkflowCode.NODE_FLOW_ERROR); + } + } else { + Boolean flowRule = checkNodeProcessRule(request); + request.setFlowRule(flowRule); + if(flowRule){ + //筛选节点向上回溯到开始节点所有的连接线上的节点有没有正在处理的节点,有,不流转,更新实例运行节点 无,正常流转 + for (Node nextNode : nextConditionNodes) { + if (!checkNodeActiveToStart(request.getModel(),activeNodes,request.getCurrent(), nextNode) && nextNodes.stream().noneMatch(node -> StrUtil.equals(node.getId(),nextNode.getId()))) { + nextNodes.add(nextNode); + } + } + } + } + + Set nodeIds = nextNodes.stream().map(Node::getId).collect(Collectors.toSet()); + + if(CollUtil.isNotEmpty(nextNodes)){ + if(nodeIds.contains(NodeType.end.name()) && nodeIds.stream().noneMatch(p -> StrUtil.contains(p,NodeType.task.name()))){ + + + return request.getModel().getNodeList().stream().filter(p -> nodeIds.contains(p.getId())).collect(Collectors.toList()); + } + + return request.getModel().getNodeList().stream().filter(p -> !StrUtil.equals(NodeType.end.name(),p.getId()) && nodeIds.contains(p.getId())).collect(Collectors.toList()); + } + + return new ArrayList<>(); + } + + + /** + * 节点流转规则设置 + */ + @Override + public boolean checkNodeProcessRule(EngineRequest request){ + EndSetting endSetting = request.getCurrent().getEnd(); + + if(endSetting != null && endSetting.getFlowRule() != null){ + // 任意负责人提交后进入下一节点 + if(NodeFlowRuleEnum.anyOnApproved.equals(endSetting.getFlowRule().getType())){ + request.setNodeStage(NodeStage.flowed); + return true; + } + + // 所有负责人提交后进入下一节点 + if(NodeFlowRuleEnum.allApproved.equals(endSetting.getFlowRule().getType())){ + long checkedCount = instanceTaskService.count(new LambdaQueryWrapper() + .eq(InstanceTask::getInstanceId,request.getInstance().getId()) + .eq(InstanceTask::getNodeKey,request.getCurrent().getId()) + .eq(InstanceTask::getStatus, TaskStatus.unhandled.getCode()) + .ne(InstanceTask::getUserId,request.getHandlerUser().getId()) + ); + + request.setNodeStage(checkedCount == 0 ? NodeStage.flowed : NodeStage.active); + return checkedCount == 0; + } + + if(endSetting.getFlowRule().getValue() == null){ + + throw new WorkflowException(WorkflowCode.DEFINITION_NODE_FLOW_RULE_NOT_EXIST); + } + + //按审核人比例通过后进入下一节点 + if(NodeFlowRuleEnum.voteForPercent.equals(endSetting.getFlowRule().getType())){ + long handledCount = instanceTaskService.list(new LambdaQueryWrapper() + .eq(InstanceTask::getInstanceId,request.getInstance().getId()) + .eq(InstanceTask::getNodeKey,request.getCurrent().getId()) + .eq(InstanceTask::getNodeActive,true) + .eq(InstanceTask::getStatus, TaskStatus.handled.getCode()) + ).stream().map(InstanceTask::getUserId).count() + 1; + + + long totalCount = instanceTaskService.list(new LambdaQueryWrapper() + .eq(InstanceTask::getInstanceId,request.getInstance().getId()) + .eq(InstanceTask::getNodeKey,request.getCurrent().getId()) + .eq(InstanceTask::getNodeActive,true) + .ne(InstanceTask::getStatus, TaskStatus.outDated.getCode())) + .stream().map(InstanceTask::getUserId).count(); + + double allowCount = Math.ceil(totalCount*Double.parseDouble(endSetting.getFlowRule().getValue())); + + log.info("###### workflow vote result 总人数:{},已提交人数:{},阈值人数:{}, ######",totalCount,handledCount,allowCount); + + boolean compareResult = handledCount >= allowCount; + + request.setNodeStage(compareResult ? NodeStage.flowed : NodeStage.active); + + return compareResult; + } + + //按固定人数提交后进入下一节点 + if(NodeFlowRuleEnum.voteForFixCount.equals(endSetting.getFlowRule().getType())){ + + long handledCount = instanceTaskService.list(new LambdaQueryWrapper() + .eq(InstanceTask::getInstanceId,request.getInstance().getId()) + .eq(InstanceTask::getNodeKey,request.getCurrent().getId()) + .eq(InstanceTask::getNodeActive,true) + .eq(InstanceTask::getStatus, TaskStatus.handled.getCode()) + ).stream().map(InstanceTask::getUserId).count()+1; + + boolean compareResult = handledCount >= Double.parseDouble(endSetting.getFlowRule().getValue()); + + request.setNodeStage(compareResult ? NodeStage.flowed : NodeStage.active); + + return compareResult; + } + } + + return true; + } + + + + /** + * 校验边的各个连接线是否满足条件 + * @param condition + * @param value + * @return + */ + public boolean validateCondition(Node.Condition condition, String value){ + String conditionValue = condition.getValue(); + String conditionMethod = condition.getCondition() == null ? "" : condition.getCondition(); + if(StrUtil.equals("input",condition.getType())) { + boolean result = StrUtil.equals(conditionValue, value); + if(StrUtil.equals(conditionMethod,"eq")){ + return result; + } + if(StrUtil.equals(conditionMethod,"ne")){ + return !result; + } + }else{ + try{ + if(StrUtil.equals(conditionMethod,"range")){ + List range = Splitter.on("-").omitEmptyStrings().splitToList(condition.getValue()); + if(CollUtil.isNotEmpty(range) && range.size() == 2){ + Double minNum = Double.parseDouble(range.get(0)); + Double maxNUm = Double.parseDouble(range.get(1)); + return minNum <= Double.parseDouble(value) && maxNUm >= Double.parseDouble(value); + } + return false; + } + int compareResult = BigDecimal.valueOf(Double.parseDouble(value)).compareTo(new BigDecimal(condition.getValue())); + if(StrUtil.equals(conditionMethod,"gt")){ + return compareResult > 0 ; + } + if(StrUtil.equals(conditionMethod,"gteq")){ + return compareResult >= 0; + } + if(StrUtil.equals(conditionMethod,"eq")){ + return compareResult == 0; + } + if(StrUtil.equals(conditionMethod,"lt")){ + return compareResult < 0; + } + if(StrUtil.equals(conditionMethod,"lteq")){ + return compareResult <= 0; + } + }catch (Exception e){ + return false; + } + } + return false; + } + + + + /** + * 校验边条件是否成立 + * @param edge + * @param formData + * @return + */ + private boolean checkEdgeCondition(Node.EdgeCondition edge, Map formData){ + String relation = edge.getRelation(); + if(edge.getCondition() == null){ + return true; + } + List fieldCondition = edge.getCondition().stream().filter(p -> ObjectUtil.isAllNotEmpty(p.getCondition(),p.getValue())).collect(Collectors.toList()); + if(CollUtil.isEmpty(fieldCondition)){ + return true; + } + + boolean result = false; + Integer count = 0; + for(Node.Condition item: fieldCondition){ + boolean checkResult = validateCondition(item,formData.get(item.getId())+""); + if(checkResult){ + if(StrUtil.equals(relation, "any")){ + result = true; + break; + }else{ + count ++; + } + } + } + + if(StrUtil.equals(relation, "all")){ + return count == fieldCondition.size(); + } + + return result; + } + + + + /** + * 自动提交规则 + * @param request + * @return + */ + @Override + public AutoSubmitResult getNextActionNode(EngineRequest request, List nextNodes){ + if(CollUtil.isNotEmpty(nextNodes)){ + + AutoCommitEnum autoCommitRule = request.getModel().getConfig().getAutoCommit(); + if(AutoCommitEnum.none.equals(autoCommitRule) || autoCommitRule == null){ + + return null; + } + AutoSubmitResult result = new AutoSubmitResult(autoCommitRule); + + List next = new ArrayList<>(); + nextNodes.forEach(node -> { + // 校验当前处理人和下面节点的处理人是否一致 + if(AutoCommitEnum.lastChecker.equals(autoCommitRule)){ + if(checkNextNodeSubmitted(request,node)){ + next.add(node); + } + } + + //校验下面的节点负责人是否之前提交过该流程 + if(AutoCommitEnum.handlered.equals(autoCommitRule)){ + + List nextNodeUsers = this.instanceTaskService.parseNodeUser(HandleUserType.TaskChecker,request.getInstance().getCreateUser(),node,request.getForm().getData()); + + if(CollUtil.isNotEmpty(nextNodeUsers)){ + List userIds = nextNodeUsers.stream().map(FlowUser::getId).collect(Collectors.toList()); + boolean hasSubmitted = instanceLogService.checkUserSubmit(request.getInstance().getId(),userIds); + if(hasSubmitted || userIds.contains(request.getHandlerUser().getId())){ + next.add(node); + } + } + } + }); + result.addNext(next); + return result; + } + + return null; + } + + + private void recursionNodeKey(Set nodeKeyList, Model model, String target){ + Node node = model.getNodeList().stream().filter(p -> StrUtil.equals(target,p.getId())).findAny().get(); + + List prevNodes = node.getPrev(); + + if(CollUtil.isNotEmpty(prevNodes)){ + nodeKeyList.addAll(prevNodes); + prevNodes.forEach(p -> recursionNodeKey(nodeKeyList,model,p)); + } + } + + public boolean checkInstanceNodeActive(Instance instance, Node ignoredNode) { + List instanceTargets = + instance.getNodeKeys().stream().map(EdgeInfo::getTarget).collect(Collectors.toList()); + + instanceTargets.remove(ignoredNode.getId()); + + return CollUtil.isNotEmpty(instanceTargets); + } + + /** + * 校验下面的流程节点是否提交 + * @param param + * @param nextNode + * @return + */ + public boolean checkNextNodeSubmitted(EngineRequest param, Node nextNode) { + List nextUsers = new ArrayList<>(); + try{ + nextUsers = this.instanceTaskService.parseNodeUser(HandleUserType.TaskChecker, + param.getInstance().getCreateUser(),nextNode,param.getForm().getData()); + }catch (Exception e){ + log.error("###### workflow query next node user exception {} ######",e.getMessage()); + } + + if(CollUtil.isEmpty(nextUsers)){ + + return false; + } + + return nextUsers.stream().anyMatch(p -> p.getId().equals(param.getHandlerUser().getId())); + } + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/impl/DefinitionServiceImpl.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/impl/DefinitionServiceImpl.java new file mode 100644 index 0000000..57f530f --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/impl/DefinitionServiceImpl.java @@ -0,0 +1,81 @@ +package org.dromara.workflow.service.internal.impl; + +import org.dromara.workflow.engine.domain.Definition; +import org.dromara.workflow.engine.enums.DefinitionStage; +import org.dromara.workflow.engine.model.setting.Model; +import org.dromara.workflow.engine.model.setting.Node; +import org.dromara.workflow.service.internal.DefinitionService; +import org.dromara.workflow.mapper.DefinitionMapper; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import java.util.Optional; + +@Slf4j +@Service +public class DefinitionServiceImpl extends ServiceImpl implements DefinitionService { + + @Override + public Definition getStartingDefinition(Long formId) { + + return getOne(getDefinitionLambdaQueryWrapper(formId)); + } + + + + @Override + public Integer countDefinitionVersion(Long formId) { + return this.baseMapper.countDefinitionVersion(formId); + } + + @Override + public Model getInstanceModel(Long definitionId) { + Definition definition = this.getById(definitionId); + if(definition != null){ + + return JSONUtil.toBean(definition.getSnapshots(),Model.class); + } + + return null; + } + + @Override + public Model getStartingModel(Long formId) { + + Definition definition = getOne(getDefinitionLambdaQueryWrapper(formId)); + if(definition != null){ + + return JSONUtil.toBean(definition.getSnapshots(),Model.class); + } + + return null; + } + + @Override + public Node getModelNode(Long definitionId, String nodeId) { + Definition definition = this.getById(definitionId); + if(definition != null){ + + Model model = JSONUtil.toBean(definition.getSnapshots(),Model.class); + Optional nodeOptional = model.getNodeList().stream().filter(p -> StrUtil.equals(nodeId,p.getId())).findFirst(); + if(nodeOptional.isPresent()){ + + return nodeOptional.get(); + } + } + + return null; + } + + private LambdaQueryWrapper getDefinitionLambdaQueryWrapper(Long formId) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(Definition::getFormId,formId); + wrapper.eq(Definition::getStage, DefinitionStage.running.name()); + wrapper.ne(Definition::getSnapshots,""); + wrapper.isNotNull(Definition::getSnapshots); + return wrapper; + } +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/impl/FlowEsDataDecisionService.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/impl/FlowEsDataDecisionService.java new file mode 100644 index 0000000..ce6d2f4 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/impl/FlowEsDataDecisionService.java @@ -0,0 +1,113 @@ +package org.dromara.workflow.service.internal.impl; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import lombok.Data; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + + +import java.util.List; +import java.util.stream.Collectors; + +/** + * @Description: server + **/ +@Slf4j +@Service +public class FlowEsDataDecisionService { + + + @Data + public class DataQueryDSL { + + private String formCode; + + private String dataId; + + private String query; + + + public DataQueryDSL(String formCode, String dataId, String query) { + this.formCode = formCode; + this.dataId = dataId; + this.query = query; + } + + public void updateDsl(Long userId, List deptIds, String account) { + this.query = wrappedQueryDSL(query, dataId); + log.info("###### workflow query result {} ######",query); + + replaceDynamicField(userId, deptIds, account); + } + + private String wrappedQueryDSL(String queryData, String dataId) { + if (ObjectUtil.hasEmpty(dataId)) { + return null; + } + + String query = StrUtil.isEmpty(queryData) ? "{}" : queryData; + + log.info("###### workflow query {} ######",query); + + JSONObject queryObject = new JSONObject(); + JSONObject conditionObject = JSONUtil.parseObj(query); + + JSONObject parentBoolObject = (JSONObject) conditionObject.get("query"); + + JSONObject boolObject = (JSONObject) parentBoolObject.get("bool"); + if (boolObject == null) { + boolObject = new JSONObject(); + } + JSONArray mustObj = (JSONArray) boolObject.get("must"); + if (mustObj == null) { + mustObj = new JSONArray(); + } + JSONObject idItem = new JSONObject(); + JSONObject idObj = new JSONObject(); + String[] dataIdArr = new String[1]; + dataIdArr[0] = dataId; + idObj.set("values", dataIdArr); + idItem.set("ids", idObj); + mustObj.add(idItem); + + boolObject.set("must", mustObj); + parentBoolObject.set("bool", boolObject); + queryObject.set("query", parentBoolObject); + + return JSONUtil.toJsonStr(queryObject); + } + + public void replaceDynamicField(Long userId, List deptIds, String account) { + if (query != null && query.length() > 0) { + if (deptIds != null) { + query = query.replaceAll(String.format("\"%s\"", DynamicField.LOGIN_DEPARTMENT.getCode()), deptIds.stream().map(String::valueOf).collect(Collectors.joining(","))); + } + query = query.replaceAll(DynamicField.LOGIN_USER_ACCOUNT.getCode(), account) + .replaceAll(DynamicField.LOGIN_USER.getCode(), userId.toString()); + + //动态替换日期 + // query = DateExpReplacer.replace(query); + } + } + } + + @Getter + enum DynamicField{ + LOGIN_USER_ACCOUNT("CURRENT_LOGIN_USER_ACCOUNT", "当前登录用户账号"), + LOGIN_USER("CURRENT_LOGIN_USER", "当前登录用户"), + LOGIN_DEPARTMENT("CURRENT_LOGIN_USER_DEPARTMENT","当前登录用户所在部门"); + private final String code; + private final String message; + + DynamicField(String code, String message) { + this.code = code; + this.message = message; + } + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/impl/InstanceCcServiceImpl.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/impl/InstanceCcServiceImpl.java new file mode 100644 index 0000000..9501885 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/impl/InstanceCcServiceImpl.java @@ -0,0 +1,93 @@ +package org.dromara.workflow.service.internal.impl; + +import org.dromara.workflow.engine.domain.InstanceCc; +import org.dromara.workflow.service.internal.InstanceCcService; +import org.dromara.workflow.mapper.InstanceCcMapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/** + * Created by 尹志伟 + */ +@Service +@Slf4j +public class InstanceCcServiceImpl extends ServiceImpl implements InstanceCcService { + + // @Autowired + // private InstanceTaskService instanceTaskService; + // @Autowired + // private DecisionService decisionService; + // @Autowired + // private UserService userService; + // + // @Override + // public void handlerNextCc(EngineRequest request) { + // try { + // List nextCcRemindNodes = new ArrayList<>(); + // + // //给即将流转已开启抄送的审批节点发送抄送 + // List nextTaskNodes = request.getInstance().getNextNodes().get(NodeType.task); + // if (CollUtil.isNotEmpty(nextTaskNodes)) { + // List nextTaskNodesWithUser = nextTaskNodes.stream().filter(p -> CollUtil.isNotEmpty(p.getCcUser())) + // .collect(Collectors.toList()); + // if(CollUtil.isNotEmpty(nextTaskNodesWithUser)){ + // nextCcRemindNodes.addAll(nextTaskNodesWithUser); + // + // nextTaskNodesWithUser.parallelStream().forEach(p -> handleTask(false,p, request)); + // } + // } + // + // //给下面的抄送节点发送抄送数据 + // List nextCcNodes = request.getInstance().getNextNodes().get(NodeType.cc); + // if (CollUtil.isNotEmpty(nextCcNodes)) { + // nextCcRemindNodes.addAll(nextCcNodes); + // nextCcNodes.parallelStream().forEach(p -> handleTask(true,p, request)); + // } + // + // }catch (Exception e){ + // e.printStackTrace(); + // log.error("发送抄送数据异常{}",e.getMessage()); + // } + // } + // + // private void handleTask(Boolean ccNode, Node node, EngineRequest request) { + // List userIdList = ccNode ? request.getInstance().getUsers().get(HandleUserType.CcUser).get(node.getId()) + // : instanceTaskService.parseNodeUser(HandleUserType.TaskCcUser,request.getInstance().getCreateUser() ,node, + // request.getForm().getData()); + // + // sendCcTask(node, request, userIdList); + // } + // + // private void sendCcTask(Node ccNode, EngineRequest request, List userIdList) { + // if(CollUtil.isNotEmpty(userIdList)){ + // List userList = userService.getByIds(userIdList); + // + // List instanceCcUsers = userList.stream().map(p -> { + // InstanceCc item = new InstanceCc(); + // item.setInstanceId(request.getInstance().getId()); + // item.setFormId(request.getInstance().getFormId()); + // item.setStatus(CcStatus.unread.getCode()); + // item.setNodeKey(ccNode.getId()); + // item.setNodeName(ccNode.getName()); + // item.setUserId(p.getId()); + // item.setUserName(p.getName()); + // FlowUserParam handlerUser = request.getHandlerUser(); + // item.setCreateUser(handlerUser.getId()); + // item.setCreateName(handlerUser.getName()); + // item.setCreateAccount(handlerUser.getAccount()); + // item.setCreateTime(new Date()); + // return item; + // }).collect(Collectors.toList()); + // + // this.saveBatch(instanceCcUsers); + // } + // } + // + // + // @Override + // public boolean batchDeleteInstance(List instanceIdList) { + // return this.baseMapper.batchDelete(instanceIdList) > 0; + // } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/impl/InstanceLogServiceImpl.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/impl/InstanceLogServiceImpl.java new file mode 100644 index 0000000..60d2752 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/impl/InstanceLogServiceImpl.java @@ -0,0 +1,185 @@ +package org.dromara.workflow.service.internal.impl; + +import cn.hutool.core.util.ObjectUtil; +import org.dromara.common.Exception.ServiceException; +import org.dromara.common.response.WorkflowResultCode; +import org.dromara.workflow.engine.domain.Instance; +import org.dromara.workflow.engine.domain.InstanceLog; +import org.dromara.workflow.engine.enums.NodeType; +import org.dromara.workflow.engine.enums.OperateType; +import org.dromara.workflow.param.instance.InstanceLogParam; +import org.dromara.workflow.remind.flow.model.FlowInstanceMessage; +import org.dromara.workflow.result.instance.InstanceLogResult; +import org.dromara.workflow.service.internal.InstanceLogService; +import org.dromara.workflow.service.internal.InstanceService; +import org.dromara.workflow.mapper.InstanceLogMapper; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +@Service +public class InstanceLogServiceImpl extends ServiceImpl implements InstanceLogService { + + @Autowired + private InstanceService instanceService; + + @Override + public InstanceLog create(InstanceLogParam data) { + InstanceLog instanceLog = new InstanceLog(); + + instanceLog.setHandlerType(data.getUserType()); + instanceLog.setHandlerId(data.getUserInfo().getId()); + instanceLog.setHandlerAccount(data.getUserInfo().getAccount()); + instanceLog.setHandlerName(data.getUserInfo().getName()); + if(CollUtil.isNotEmpty(data.getNextNodes())){ + instanceLog.setNextNodes(data.getNextNodes()); + } + instanceLog.setCreateTime(data.getCreateTime()); + + instanceLog.setFormId(data.getInstance().getFormId()); + instanceLog.setInstanceId(data.getInstance().getId()); + instanceLog.setNodeKey(data.getNode().getId()); + + if(StrUtil.equals(data.getNode().getId(), NodeType.preset.name())){ + instanceLog.setNodeName("前置节点"); + }else { + instanceLog.setNodeName(data.getNode().getName()); + } + + instanceLog.setOpType(data.getAction().getCode()); + instanceLog.setOpName(data.getAction().getName()); + instanceLog.setIsBatch(data.getIsBatch()); + instanceLog.setAutoCommit(data.getAutoCommit()); + + if(data.getContent() != null){ + instanceLog.setComment(data.getContent().getComment()); + instanceLog.setSignature(data.getContent().getSignatrue()); + } + + this.save(instanceLog); + + return instanceLog; + } + + @Override + public boolean checkUserSubmit(Long instanceId, List users) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(InstanceLog::getInstanceId,instanceId); + wrapper.in(InstanceLog::getHandlerId,users); + wrapper.eq(InstanceLog::getOpType, OperateType.submit); + wrapper.ne(InstanceLog::getNodeKey,NodeType.preset); + return this.count(wrapper) > 0; + } + + @Override + public InstanceLogResult listFlowLog(Long instanceId, String nodeKey){ + Instance instance = instanceService.getById(instanceId); + if(instance == null){ + + throw new ServiceException(WorkflowResultCode.FLOW_INSTANCE_NOT_EXIST); + } + InstanceLogResult result = new InstanceLogResult(); + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(InstanceLog::getInstanceId,instanceId); + if(StrUtil.isNotEmpty(nodeKey)){ + wrapper.eq(InstanceLog::getNodeKey,nodeKey); + } + wrapper.ne(InstanceLog::getNodeKey,NodeType.preset.name()); + wrapper.orderByDesc(InstanceLog::getCreateTime,InstanceLog::getId); + + result.setLogList(this.list(wrapper)); + result.setInstanceId(instance.getId()); + result.setStage(instance.getStage()); + + return result; + } + + + + + @Override + public boolean batchDeleteInstance(List instanceIdList) { + return this.baseMapper.batchDelete(instanceIdList) > 0; + } + + @Override + public Set listSubmitNodes(Long instanceId) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.select(InstanceLog::getNodeKey); + wrapper.eq(InstanceLog::getInstanceId,instanceId); + wrapper.eq(InstanceLog::getOpType,OperateType.submit); + + return this.list(wrapper).stream().map(InstanceLog::getNodeKey).collect(Collectors.toSet()); + } + + @Override + public Set listReactiveSubmitNodes(Long instanceId) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.select(InstanceLog::getNodeKey, InstanceLog::getOpType); + wrapper.eq(InstanceLog::getInstanceId,instanceId); + wrapper.orderByDesc(InstanceLog::getCreateTime); + List logs = this.list(wrapper); + if (logs != null) { + Optional optional = logs.stream().filter(log -> log.getOpType().equals(OperateType.active.getCode())).findFirst(); + if (optional.isPresent()) { + int index = logs.indexOf(optional.get()); + return logs.subList(0, index).stream().map(InstanceLog::getNodeKey).collect(Collectors.toSet()); + } + } + return new HashSet<>(); + } + + /** + * @param message + */ + @Override + public void saveFlowLog(FlowInstanceMessage message) { + InstanceLog workflowLog = new InstanceLog(); + workflowLog.setFormId(message.getInstance().getFormId()); + workflowLog.setInstanceId(message.getInstance().getId()); + + FlowInstanceMessage.Instance.NodeInfo nodeInfo = message.getInstance().getCurrentNode(); + workflowLog.setNodeKey(nodeInfo.getNodeKey()); + workflowLog.setNodeName(nodeInfo.getNodeName()); + workflowLog.setOpName(OperateType.getOperate(message.getOperate()).getName()); + workflowLog.setOpType(OperateType.getOperate(message.getOperate()).getCode()); + workflowLog.setIsBatch(message.getIsBatch()); + + workflowLog.addHandlerType(message.getManageInfo()); + if(message.getManageInfo() != null){ + workflowLog.setHandlerId(message.getManageInfo().getUserId()); + workflowLog.setHandlerName(message.getManageInfo().getUserName()); + workflowLog.setHandlerAccount(message.getManageInfo().getUserAccount()); + }else{ + workflowLog.setHandlerId(nodeInfo.getHandlerId()); + workflowLog.setHandlerName(nodeInfo.getHandlerName()); + workflowLog.setHandlerAccount(nodeInfo.getHandlerAccount()); + } + + workflowLog.setCreateTime(nodeInfo.getUpdateTime()); + workflowLog.setAutoCommit(nodeInfo.getAutoCommit() == 1); + + if(ObjectUtil.isNotEmpty(nodeInfo)){ + if(StrUtil.isNotEmpty(nodeInfo.getComment())){ + workflowLog.setComment(nodeInfo.getComment()); + } + if(StrUtil.isNotEmpty(nodeInfo.getSignature())){ + workflowLog.setSignature(nodeInfo.getSignature()); + } + } + + this.save(workflowLog); + } + + + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/impl/InstanceServiceImpl.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/impl/InstanceServiceImpl.java new file mode 100644 index 0000000..e5f78a3 --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/impl/InstanceServiceImpl.java @@ -0,0 +1,148 @@ +package org.dromara.workflow.service.internal.impl; + +import org.dromara.workflow.engine.domain.Instance; +import org.dromara.workflow.engine.domain.base.EdgeInfo; +import org.dromara.workflow.engine.enums.InstanceStage; +import org.dromara.workflow.engine.enums.NodeType; +import org.dromara.workflow.engine.enums.OperateType; +import org.dromara.workflow.engine.operation.OprAction; +import org.dromara.workflow.param.engine.EngineRequest; +import org.dromara.workflow.service.internal.InstanceService; +import org.dromara.workflow.mapper.InstanceMapper; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +@Slf4j +@Service +public class InstanceServiceImpl extends ServiceImpl implements InstanceService { + + @Autowired + private final Map actionMap = new ConcurrentHashMap(); + + @Override + public Instance getById(Long instanceId) { + return this.getOne(new LambdaQueryWrapper() + .eq(Instance::getId,instanceId)); + } + + @Override + public Instance getByDataId(Long dataId) { + return this.getOne(new LambdaQueryWrapper() + .eq(Instance::getDataId,dataId)); + } + + /** + * 更新实例信息 + * @param request + */ + @Override + public Instance update(EngineRequest request) { + Instance instance = request.getInstance(); + + //更新实例运行状态 + updateStage(request); + + //更新实例激活节点 + updateNodeKey(request); + + //更新实例基础数据 + instance.setUpdateUser(request.getHandlerUser().getId()); + instance.setUpdateTime(DateUtil.parse(request.getRequestTime(), DatePattern.PURE_DATETIME_PATTERN)); + this.updateById(instance); + + return instance; + } + + /** + * 更新实例节点 + * @param request + */ + private void updateNodeKey(EngineRequest request) { + Instance instance = request.getInstance(); + + OprAction action = this.actionMap.get(request.getAction()+"Action"); + if(action != null){ + List activeNodes = action.getActiveNodes(request); + if(CollUtil.isNotEmpty(activeNodes)){ + instance.setNodeKeys(activeNodes); + } + } + } + + /** + * 更新实例状态 + * @param request + */ + private void updateStage(EngineRequest request) { + Instance instance = request.getInstance(); + + //流程手动结束 + if(OperateType.finish.equals(request.getAction())){ + request.updateInstanceStage(InstanceStage.finished); + return; + } + + //正常流转结束 + if (request.getInstance().getNextNodes().containsKey(NodeType.end)) { + request.updateInstanceStage(InstanceStage.completed); + }else { + //运行中 + if (OperateType.create.equals(request.getAction()) || OperateType.draft.equals(request.getAction())) { + instance.setStage(InstanceStage.starting); + } else { + instance.setStage(InstanceStage.processing); + } + } + } + + + @Override + public void deleteByForm(Long formId) { + if(formId != null){ + List instanceList = this.baseMapper.selectList(new LambdaQueryWrapper().select(Instance::getId).eq(Instance::getFormId,formId)); + if(instanceList != null && !instanceList.isEmpty()){ + List instIds = instanceList.stream().map(Instance::getId).collect(Collectors.toList()); + this.baseMapper.batchDeleteInstance(instIds); + } + } + } + + @Override + public void deleteByData(Long formId, String... dataIds) { + if(formId != null && dataIds != null && dataIds.length > 0 && dataIds[0] != null){ + List instanceList = this.baseMapper.selectList(new LambdaQueryWrapper().eq(Instance::getFormId, formId).in(Instance::getDataId, dataIds)); + if(instanceList != null && !instanceList.isEmpty()){ + List instIds = instanceList.stream().map(Instance::getId).collect(Collectors.toList()); + this.baseMapper.batchDeleteInstance(instIds); + } + } + } + + @Override + public void logicDeleteByForm(Long formId, String... dataIds) { + String[] dataIdArray = null; + if(dataIds != null && dataIds.length > 0 && dataIds[0] != null){ + dataIdArray = dataIds.clone(); + } + this.baseMapper.logicDeleteByForm(formId, dataIdArray); + } + + @Override + public void logicRecoverByForm(Long formId, String... dataIds) { + String[] dataIdArray = null; + if(dataIds != null && dataIds.length > 0 && dataIds[0] != null){ + dataIdArray = dataIds.clone(); + } + this.baseMapper.logicRecoverByForm(formId, dataIdArray); + } + +} diff --git a/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/impl/InstanceTaskServiceImpl.java b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/impl/InstanceTaskServiceImpl.java new file mode 100644 index 0000000..c978f4d --- /dev/null +++ b/dk-common/common-workflow/src/main/java/org/dromara/workflow/service/internal/impl/InstanceTaskServiceImpl.java @@ -0,0 +1,780 @@ +package org.dromara.workflow.service.internal.impl; + + +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.service.ISysUserService; +import org.dromara.common.Exception.ServiceException; +import org.dromara.common.response.WorkflowResultCode; +import org.dromara.workflow.engine.domain.Instance; +import org.dromara.workflow.engine.domain.InstanceCc; +import org.dromara.workflow.engine.domain.InstanceTask; +import org.dromara.workflow.engine.enums.*; +import org.dromara.workflow.engine.enums.nodeMoving.DynamicType; +import org.dromara.workflow.engine.exception.WorkflowCode; +import org.dromara.workflow.engine.exception.WorkflowException; +import org.dromara.workflow.engine.listener.TaskHandledListener; +import org.dromara.workflow.engine.model.setting.Node; +import org.dromara.workflow.param.engine.EngineRequest; +import org.dromara.workflow.param.model.FlowUser; +import org.dromara.workflow.service.internal.InstanceTaskService; +import org.dromara.workflow.mapper.InstanceTaskMapper; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.compress.utils.Lists; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * @Description: server + **/ +@Slf4j +@Service +public class InstanceTaskServiceImpl extends ServiceImpl implements InstanceTaskService { + + @Autowired + private ISysUserService userService; + @Autowired(required = false) + private TaskHandledListener taskHandledListener; + + + @Override + public InstanceTask getUserNodeUnHandleTask(Long instanceId, String nodeId, Long userId ) { + if(ObjectUtil.hasEmpty(instanceId,nodeId,userId)){ + + throw new WorkflowException(WorkflowCode.PARAM_IS_BLANK); + } + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(InstanceTask::getInstanceId,instanceId); + wrapper.eq(InstanceTask::getNodeKey,nodeId); + wrapper.eq(InstanceTask::getUserId,userId); + wrapper.eq(InstanceTask::getStatus, TaskStatus.unhandled.getCode()); + return this.getOne(wrapper); + } + + @Override + public List getUsersNodeUnHandleTask(Long instanceId, String nodeId, List users) { + if(ObjectUtil.hasEmpty(instanceId,nodeId,users)){ + + throw new WorkflowException(WorkflowCode.PARAM_IS_BLANK); + } + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(InstanceTask::getInstanceId,instanceId); + wrapper.eq(InstanceTask::getNodeKey,nodeId); + wrapper.in(InstanceTask::getUserId,users); + wrapper.eq(InstanceTask::getStatus,TaskStatus.unhandled.getCode()); + return this.list(wrapper); + } + + @Override + public boolean checkTaskUser(List taskNodes,Long instanceUser,Map formData) { + if(CollUtil.isEmpty(taskNodes)){ + return true; + } + boolean flag = true; + for(Node node : taskNodes){ + List userCount = parseNodeUser(HandleUserType.TaskChecker,instanceUser,node,formData); + + flag = CollUtil.isNotEmpty(userCount); + if(!flag){ + break; + } + } + + return flag; + } + + @Override + public List listInstanceTask(Long instanceId,String nodeId,TaskStatus status) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(InstanceTask::getInstanceId,instanceId); + if(StrUtil.isNotEmpty(nodeId)){ + wrapper.eq(InstanceTask::getNodeKey,nodeId); + } + if(ObjectUtil.isNotNull(status)){ + wrapper.eq(InstanceTask::getStatus, status.getCode()); + }else{ + wrapper.ne(InstanceTask::getStatus, TaskStatus.outDated.getCode()); + } + wrapper.eq(InstanceTask::getNodeActive, true); + wrapper.orderByDesc(InstanceTask::getCreateTime); + return this.list(wrapper); + } + + + @Override + public List listInstanceNodeUserTask(Long instanceId,String nodeId,Long userId,TaskStatus status) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(InstanceTask::getInstanceId,instanceId); + if(StrUtil.isNotEmpty(nodeId)){ + wrapper.eq(InstanceTask::getNodeKey,nodeId); + } + wrapper.eq(InstanceTask::getUserId,userId); + + if(ObjectUtil.isNotNull(status)){ + wrapper.eq(InstanceTask::getStatus, status.getCode()); + } + wrapper.orderByDesc(InstanceTask::getCreateTime); + + return this.list(wrapper); + } + + /** + * 生成下面任务节点-审核待办任务 + * 生成下面任务节点-抄送待办任务 + * 生成下面任务节点-转交待办任务 + * 生成下面抄送节点-抄送待办任务 + * @param request + */ + @Override + public Map createNodeTask(EngineRequest request) { + Map result = new HashMap<>(); + + List submitTasks = new ArrayList<>(); + List ccTasks = new ArrayList<>(); + + Map> nodeMapData = request.getInstance().getNextNodes(); + for(NodeType nodeType : nodeMapData.keySet()){ + List nextTaskNodes = request.getInstance().getNextNodes().get(nodeType); + if(CollUtil.isNotEmpty(nextTaskNodes) ){ + + if(NodeType.start.equals(nodeType)){ + submitTasks.addAll(saveNodeTask(HandleUserType.TaskChecker,request,nextTaskNodes)); + } + if(NodeType.task.equals(nodeType)){ + submitTasks.addAll(saveNodeTask(HandleUserType.TaskChecker,request,nextTaskNodes)); + submitTasks.addAll(saveNodeTask(HandleUserType.TaskForwardUser,request,nextTaskNodes)); + ccTasks.addAll(saveCcNodeCcTask(HandleUserType.TaskCcUser,request,nextTaskNodes)); + } + if(NodeType.cc.equals(nodeType)){ + ccTasks.addAll(saveCcNodeCcTask(HandleUserType.CcUser,request,nextTaskNodes)); + } + } + } + + result.put(FlowTaskType.submit,submitTasks); + result.put(FlowTaskType.cc,ccTasks); + + return result; + } + + /** + * 创建任务节点的待办任务和抄送任务 + * @param instance + * @param node + * @param handler + * @param formData + * @return + */ + @Override + public List createNodeTask(Instance instance, Node node, FlowUser handler, Map formData) { + List taskList = new ArrayList<>(); + + List taskUsers = this.parseNodeUser(HandleUserType.TaskChecker,instance.getCreateUser(),node,formData); + if(CollUtil.isNotEmpty(taskUsers)){ + taskList.addAll(transformTask(instance, node, taskUsers, handler, new Date(),false)); + if(CollUtil.isNotEmpty(taskList)){ + this.baseMapper.batchInsertTask(taskList); + } + } + + List ccList = new ArrayList<>(); + + List ccUsers = this.parseNodeUser(HandleUserType.TaskCcUser,instance.getCreateUser(),node,formData); + if(CollUtil.isNotEmpty(ccUsers)){ + ccList.addAll(transformCc(instance, node, ccUsers, handler)); + if(CollUtil.isNotEmpty(ccList)){ + this.baseMapper.batchInsertCc(ccList); + } + } + + return taskList; + } + + + /** + * 创建用户待办任务 + * @param instance + * @param node + * @param users + * @return + */ + @Override + public List createUserTask(Instance instance,Node node,List users){ + if(CollUtil.isEmpty(users)){ + + return Lists.newArrayList(); + } + List result = new ArrayList<>(); + + users.forEach(user -> { + InstanceTask nodeTask = new InstanceTask(); + nodeTask.setNodeKey(node.getId()); + nodeTask.setNodeName(node.getName()); + nodeTask.setNodeActive(true); + nodeTask.setPriority(false); + nodeTask.setInstanceId(instance.getId()); + nodeTask.setFormId(instance.getFormId()); + nodeTask.setUserId(user.getId()); + nodeTask.setUserName(user.getName()); + nodeTask.setUserAccount(user.getAccount()); + nodeTask.setStatus(TaskStatus.unhandled.getCode()); + nodeTask.setCreateUser(LoginHelper.getUserId()); + nodeTask.setCreateTime(new Date()); + nodeTask.setUpdateTime(new Date()); + + result.add(nodeTask); + }); + + this.baseMapper.batchInsertTask(result); + + return result; + } + + + @Override + public void update(EngineRequest request) { + //处理当前节点待办任务状态 + List tasks = this.handleCurrentTask(request); + + //处理节点任务 + Map ntasks = this.createNodeTask(request); + + // task handled listener + try { + if (this.taskHandledListener != null) { + tasks.addAll((List) ntasks.get(FlowTaskType.submit)); + // 过滤首次创建流程实例 start 节点创建的task任务 + if(NodeType.start.name().equals(request.getCurrent().getId()) && request.getAction() == OperateType.submit){ + Optional optional = tasks.stream().filter(t -> t.getCreateTime().getTime() == request.getInstance().getCreateTime().getTime() && NodeType.start.name().equals(t.getNodeKey())).findFirst(); + if(optional.isPresent()){ + InstanceTask startTask = optional.get(); + tasks = tasks.stream().filter(t -> t.getId() != startTask.getId()).collect(Collectors.toList()); + } + } + this.taskHandledListener.onTaskHandledEvent(request.getAction(), request.getForm().getFormId(), request.getInstance(), request.getTaskId(), tasks); + } + }catch (Exception e){ + log.error("待办任务更新 listener 执行失败:{}", e.getMessage()); + } + } + + @Override + public InstanceTask updateTaskProcessing(Long taskId) { + InstanceTask task = this.getById(taskId); + if(task == null){ + + throw new ServiceException(WorkflowResultCode.TASK_NOT_EXIST); + } + if(!Objects.equals(task.getStatus(), TaskStatus.unhandled.getCode())){ + + throw new ServiceException(WorkflowResultCode.TASK_HAS_HANDLED); + } + if(task.getProcessing().equals(true)){ + + throw new ServiceException(WorkflowResultCode.TASK_PROCESSING_HAS_CHANGED); + } + task.setProcessing(true); + this.updateById(task); + + return task; + } + + @Override + public void batchUpdateTaskProcessing(List taskIds) { + if(CollUtil.isNotEmpty(taskIds)){ + LambdaUpdateWrapper wrapper = new LambdaUpdateWrapper<>(); + wrapper.set(InstanceTask::getProcessing,true); + wrapper.in(InstanceTask::getId,taskIds); + + this.update(wrapper); + } + } + + @Override + public void deleteInstanceUnHandledTask(Long instanceId){ + if(ObjectUtil.isEmpty(instanceId)){ + + return; + } + LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); + updateWrapper.set(InstanceTask::getStatus, TaskStatus.outDated.getCode()) + .eq(InstanceTask::getInstanceId, instanceId) + .eq(InstanceTask::getStatus, TaskStatus.unhandled.getCode()); + this.update(updateWrapper); + } + + @Override + public void deleteInstanceTaskByIds(Set taskIds) { + if(CollUtil.isEmpty(taskIds)){ + + return; + } + LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); + updateWrapper.set(InstanceTask::getStatus, TaskStatus.outDated.getCode()) + .in(InstanceTask::getId, taskIds); + this.update(updateWrapper); + } + + @Override + public void deleteInstanceTaskByUsers(Long instanceId,String nodeId,Set userIds) { + if(ObjectUtil.hasEmpty(instanceId,nodeId,userIds)){ + + return; + } + LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); + updateWrapper.set(InstanceTask::getStatus, TaskStatus.outDated.getCode()) + .eq(InstanceTask::getInstanceId, instanceId) + .eq(InstanceTask::getNodeKey, nodeId) + .in(InstanceTask::getUserId, userIds); + this.update(updateWrapper); + } + + @Override + public List getTaskIdsOf(Long instanceId) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(InstanceTask::getInstanceId, instanceId); + List tasks = list(queryWrapper); + return CollectionUtil.isNotEmpty(tasks) ? tasks.stream().map(t -> t.getId()).collect(Collectors.toList()) : new ArrayList<>(); + } + + @Override + public List getTaskIdOfNode(Long instanceId, String nodeKey) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(InstanceTask::getInstanceId, instanceId) + .eq(InstanceTask::getNodeKey, nodeKey); + List tasks = list(queryWrapper); + return CollectionUtil.isNotEmpty(tasks) ? tasks.stream().map(t -> t.getId()).collect(Collectors.toList()) : new ArrayList<>(); + } + + /** + * 处理当前待办任务状态 + * 抄送、暂存、创建 -> 无 + * 撤回 -> 删除当前实例全部待办任务 + * 回退、转交、提交 -> 更新当前待办任务状态(未处理 -> 已处理) + * 回退、提交 -> 节点流转到其他节点 -> 删除当前实例节点未处理的待办任务 + * 结束 -> 更新当前待办任务状态、删除当前实例其他未处理任务 + */ + private List handleCurrentTask(EngineRequest request){ + List res = new LinkedList(); + + if(OperateType.submit.equals(request.getAction())){ + InstanceTask currentTask = this.getById(request.getTaskId()); + currentTask.setStatus(TaskStatus.handled.getCode()); + currentTask.setDrafting(false); + currentTask.setProcessing(false); + //回退重新提交 & 撤回重新提交:待办任务的生成时间更新为提交时间 + if(StrUtil.equals(request.getCurrent().getId(),NodeType.start.name())){ + currentTask.setCreateTime(DateUtil.parse(request.getRequestTime(),EngineRequest.pattern)); + //删除开始节点当前流程发起人已办理的待办任务 + this.remove(new LambdaQueryWrapper().eq(InstanceTask::getNodeKey,NodeType.start.name()) + .eq(InstanceTask::getInstanceId,request.getInstance().getId()) + .eq(InstanceTask::getStatus,TaskStatus.handled.getCode())); + } + this.updateById(currentTask); + res.add(currentTask); + + //删除当前节点其他待处理的待办任务:当前节点已不处于激活节点 + if(StrUtil.startWith(request.getCurrent().getId(),NodeType.task.name()) + && request.getInstance().getNodeKeys().stream().noneMatch(p -> StrUtil.equals(request.getCurrent().getId(),p.getTarget()))){ + List ts = this.list(new LambdaQueryWrapper() + .eq(InstanceTask::getInstanceId, request.getInstance().getId()) + .eq(InstanceTask::getNodeKey, request.getCurrent().getId()) + .eq(InstanceTask::getStatus,TaskStatus.unhandled.getCode())); + if(CollUtil.isNotEmpty(ts)){ + ts.forEach(t -> { + t.setStatus(TaskStatus.outDated.getCode()); + t.setDrafting(false); + t.setProcessing(false); + }); + this.updateBatchById(ts); + + res.addAll(ts); + } + } + } + + if(OperateType.forward.equals(request.getAction())){ + InstanceTask currentTask = this.getById(request.getTaskId()); + currentTask.setStatus(TaskStatus.outDated.getCode()); + currentTask.setDrafting(false); + currentTask.setProcessing(false); + this.updateById(currentTask); + res.add(currentTask); + } + + if(OperateType.rollback.equals(request.getAction())){ + InstanceTask currentTask = this.getById(request.getTaskId()); + currentTask.setStatus(TaskStatus.handled.getCode()); + currentTask.setDrafting(false); + currentTask.setProcessing(false); + this.updateById(currentTask); + res.add(currentTask); + + List ts = this.list(new LambdaQueryWrapper() + .eq(InstanceTask::getInstanceId, request.getInstance().getId()) + .eq(InstanceTask::getNodeKey, request.getCurrent().getId()) + .eq(InstanceTask::getStatus,TaskStatus.unhandled.getCode())); + if(CollUtil.isNotEmpty(ts)){ + ts.forEach(t -> { + t.setStatus(TaskStatus.outDated.getCode()); + t.setDrafting(false); + t.setProcessing(false); + }); + this.updateBatchById(ts,500); + + res.addAll(ts); + } + + } + + if(OperateType.finish.equals(request.getAction())){ + InstanceTask currentTask = this.getById(request.getTaskId()); + currentTask.setStatus(TaskStatus.handled.getCode()); + currentTask.setDrafting(false); + currentTask.setProcessing(false); + this.updateById(currentTask); + res.add(currentTask); + + List ts = this.list(new LambdaQueryWrapper() + .eq(InstanceTask::getInstanceId, request.getInstance().getId()) + .eq(InstanceTask::getStatus,TaskStatus.unhandled.getCode())); + if(CollUtil.isNotEmpty(ts)){ + ts.forEach(t -> { + t.setStatus(TaskStatus.outDated.getCode()); + t.setDrafting(false); + t.setProcessing(false); + }); + this.updateBatchById(ts,500); + res.addAll(ts); + } + } + + //如果实例激活节点不包含当前处理节点,当前节点的任务激活状态设置为未激活 & 清空当前节点负责人配置 + if(request.getInstance().getNodeKeys().stream().noneMatch(p -> StrUtil.equals(request.getCurrent().getId(),p.getTarget()))){ + List ts = this.list(new LambdaQueryWrapper() + .eq(InstanceTask::getInstanceId, request.getInstance().getId()) + .eq(InstanceTask::getNodeKey, request.getCurrent().getId()) + .eq(InstanceTask::getNodeActive,true)); + if(CollUtil.isNotEmpty(ts)) { + ts.forEach(t -> { + t.setNodeActive(false); + }); + this.updateBatchById(ts); + } + + } + + return res; + } + + + private List saveNodeTask(HandleUserType userType,EngineRequest request, List nextNodes) { + List taskList = new ArrayList<>(); + Date handleTime = DateUtil.parse(request.getRequestTime(), DatePattern.PURE_DATETIME_PATTERN); + nextNodes.forEach(node -> { + Map> nodeUsers = request.getInstance().getUsers().get(userType); + if(MapUtil.isNotEmpty(nodeUsers)){ + List users = nodeUsers.get(node.getId()); + taskList.addAll(transformTask(request.getInstance(), node, users,request.getHandlerUser(),handleTime,HandleUserType.TaskForwardUser.equals(userType) && request.getInstanceTask().getPriority())); + } + }); + + if(CollUtil.isNotEmpty(taskList)){ + this.baseMapper.batchInsertTask(taskList); + } + + return taskList; + } + + + private List saveCcNodeCcTask(HandleUserType userType,EngineRequest request, List nextCcNodes) { + List ccTaskList = new ArrayList<>(); + + nextCcNodes.forEach(node -> { + Map> nodeUsers = request.getInstance().getUsers().get(userType); + if(MapUtil.isNotEmpty(nodeUsers)) { + List users = nodeUsers.get(node.getId()); + ccTaskList.addAll(transformCc(request.getInstance(), node, users,request.getHandlerUser())); + } + }); + + if(CollUtil.isNotEmpty(ccTaskList)) { + this.baseMapper.batchInsertCc(ccTaskList); + } + + return ccTaskList; + } + + /** + * 封装抄送任务 + * @param node + * @param users + */ + private List transformCc(Instance instance,Node node,List users,FlowUser handler) { + List result = new ArrayList<>(); + if (CollUtil.isNotEmpty(users)) { + users.forEach(user -> { + InstanceCc item = new InstanceCc(); + item.setInstanceId(instance.getId()); + item.setFormId(instance.getFormId()); + item.setStatus(CcStatus.unread.getCode()); + item.setNodeKey(node.getId()); + item.setNodeName(node.getName()); + item.setUserId(user.getId()); + item.setCreateUser(handler.getId()); + item.setCreateName(handler.getName()); + item.setCreateAccount(handler.getAccount()); + item.setCreateTime(new Date()); + result.add(item); + }); + } + + return result; + } + + /** + * 封装提交任务 + * @param instance + * @param node + * @param users + * @param handler + * @return + */ + private List transformTask(Instance instance, Node node, List users, FlowUser handler, + Date requestTime, Boolean priority) { + List result = new ArrayList<>(); + if (CollUtil.isNotEmpty(users)) { + List taskList = this.getUsersNodeUnHandleTask(instance.getId(),node.getId(), users.stream().map(FlowUser::getId).collect(Collectors.toList())); + if(CollUtil.isNotEmpty(taskList)){ + taskList.forEach(p -> { + p.setNodeActive(true); + p.setStatus(TaskStatus.unhandled.getCode()); + p.setPriority(priority); + p.setUpdateTime(requestTime); + this.baseMapper.updateById(p); + }); + } + + //保证每个节点每个用户只能有一个待处理任务 + List restUsers =users.stream().filter(user -> !taskList.stream().map(InstanceTask::getUserId).collect(Collectors.toList()).contains(user.getId())).collect(Collectors.toList()); + if(CollUtil.isNotEmpty(restUsers)){ + restUsers.forEach(user -> { + InstanceTask nodeTask = new InstanceTask(); + nodeTask.setNodeKey(node.getId()); + nodeTask.setNodeName(node.getName()); + nodeTask.setNodeActive(true); + nodeTask.setInstanceId(instance.getId()); + nodeTask.setFormId(instance.getFormId()); + nodeTask.setUserId(user.getId()); + nodeTask.setUserName(user.getName()); + nodeTask.setUserAccount(user.getAccount()); + nodeTask.setStatus(TaskStatus.unhandled.getCode()); + nodeTask.setPriority(priority); + nodeTask.setCreateUser(handler.getId()); + nodeTask.setCreateTime(requestTime); + nodeTask.setUpdateTime(requestTime); + result.add(nodeTask); + }); + } + } + + return result; + } + + + /** + * 授权对象(1(部门)|2(用户组)|3(成员)|5(动态负责人) + * 用户类型 (1=审核人 2=抄送人 3=转交人) + * @param node + * @param formData + * @return + */ + @Override + public List parseNodeUser(HandleUserType type, Long instanceUser, Node node, Map formData){ + if(HandleUserType.TaskChecker.equals(type) && StrUtil.equals(node.getId(),NodeType.start.name())){ + + SysUserVo user = userService.selectUserById(instanceUser); + if(user == null){ + throw new WorkflowException(WorkflowCode.FLOW_INSTANCE_STARTER_NOT_FOUND); + } + + return Arrays.asList(new FlowUser(user.getUserId(),user.getNickName(),user.getUserName())); + } + + List checkUsers = new ArrayList<>(); + if(HandleUserType.TaskChecker.equals(type)){ + checkUsers = node.getCheckUser(); + } + if(HandleUserType.TaskCcUser.equals(type) || HandleUserType.CcUser.equals(type)){ + checkUsers = node.getCcUser(); + } + if(HandleUserType.TaskForwardUser.equals(type)){ + checkUsers = node.getForwardUser(); + } + + if(CollUtil.isNotEmpty(checkUsers)) { + List userIdList = new ArrayList<>(); + + for (Node.CheckUser user : checkUsers) { + //授权对象(1=用户,2=用户组,3=组织机构 5=动态负责人(流程发起人、成员部门字段、动态主管)) + if (user.getType() == 1) { + userIdList.addAll(userService.selectUserByIds(null,Long.parseLong(user.getKey())).stream().map(SysUserVo::getUserId).collect(Collectors.toList())); + } +// if (user.getType() == 2) { +// userIdList.addAll(groupUserService.getUserIdsByGroupId(Long.parseLong(user.getKey()))); +// } + if (user.getType() == 3) { + userIdList.add(Long.parseLong(user.getKey())); + } +// if (user.getType() == 5) { +// if (!StrUtil.contains(user.getKey(), "director")) { +// userIdList.addAll(queryDynamicUser(user, instanceUser, formData)); +// } else if(ObjectUtil.isAllNotEmpty(user.getDirector(),user.getDirector().getId(),user.getDirector().getLevel(),user.getDirector().getWhose())){ +// userIdList.addAll(getDirectorUsers(user, instanceUser, formData)); +// } +// } + } + + List userIds = userIdList.stream().distinct().filter(Objects::nonNull).collect(Collectors.toList()); + + if (CollUtil.isNotEmpty(userIds)) { + List users = userService.selectUserByIds(userIds,null); + + return users.stream().map(p -> new FlowUser(p.getUserId(), p.getNickName(), p.getUserName())).collect(Collectors.toList()); + } + + } + + return Lists.newArrayList(); + } + + /** + * 查询动态负责人 + * @param user + * @param formData + * @return + */ + private List queryDynamicUser(Node.CheckUser user,Long createUser, Map formData){ + if(user != null && user.getType() == 5){ + try{ + return getDynamicUser(user.getKey(), createUser, formData); + }catch (Exception e){ + + log.error("###### workflow queryDynamicUser exception {} ######",Arrays.toString(e.getStackTrace())); + } + } + + return Lists.newArrayList(); + } + + + /** + * 查询动态负责人-动态主管 + * @param createUser + * @param formData + * @return + */ +// private List getDirectorUsers(Node.CheckUser user,Long createUser, Map formData){ +// if(user != null && user.getDirector() != null){ +// +// try { +// List totalUsers = new ArrayList<>(); +// List userIds = getDynamicUser(user.getDirector().getWhose(), createUser, formData); +// if (CollUtil.isNotEmpty(userIds)) { +// userIds.forEach(userId -> { +// totalUsers.addAll(this.departmentUserService.selectDirectors(userId, user.getDirector().getLevel())); +// }); +// } +// +// return totalUsers; +// +// }catch (Exception e){ +// log.error("###### workflow getDirectorUsers exception {} ######",Arrays.toString(e.getStackTrace())); +// } +// +// } +// +// return Lists.newArrayList(); +// } + + private List getDynamicUser(String key, Long createUser, Map formData) { + DynamicType dynamicType = DynamicType.getColumnType(key); + + //流程发起人 + if(DynamicType.starter.equals(dynamicType)){ + return Arrays.asList(createUser); + } + + //成员单选 + if(DynamicType.singlemember.equals(dynamicType)){ + if(MapUtil.isNotEmpty(formData)){ + HashMap singleMember = (HashMap) formData.get(key); + if(CollUtil.isNotEmpty(singleMember)){ + return Arrays.asList(Long.parseLong(singleMember.get("key")+"")); + } + } + } + + //成员多选 + if(DynamicType.multiplemembers.equals(dynamicType)){ + if(MapUtil.isNotEmpty(formData)) { + ArrayList> result = (ArrayList>) formData.get(key); + if(CollUtil.isNotEmpty(result)){ + return result.stream().map(s -> Long.parseLong(s.get("key")+"")).collect(Collectors.toList()); + } + } + + } + + //部门单选 + if(DynamicType.singledepatment.equals(dynamicType)){ + if(MapUtil.isNotEmpty(formData)) { + + HashMap userMap = (HashMap) formData.get(key); + if (userMap != null) { + Long departId = Long.parseLong(userMap.get("key")+""); + List userList = userService.selectUserByIds(null,departId).stream().map(SysUserVo::getUserId).collect(Collectors.toList()); + if (CollUtil.isNotEmpty(userList)) { + return userList; + } + } + } + } + + //部门多选 + if(DynamicType.multipledepartment.equals(dynamicType)){ + if(MapUtil.isNotEmpty(formData)) { + ArrayList> result = (ArrayList>) formData.get(key); + if (CollUtil.isNotEmpty(result)) { + List total = new ArrayList<>(); + result.forEach(s -> { + if (s != null) { + Long departId = Long.parseLong(s.get("key")+""); + List userList = userService.selectUserByIds(null,departId).stream().map(SysUserVo::getUserId).collect(Collectors.toList()); + if (CollUtil.isNotEmpty(userList)) { + total.addAll(userList); + } + } + }); + + return total; + } + } + } + + return Lists.newArrayList(); + } +} diff --git a/dk-common/pom.xml b/dk-common/pom.xml index a0eb4a7..3812968 100644 --- a/dk-common/pom.xml +++ b/dk-common/pom.xml @@ -46,6 +46,7 @@ common-bus common-sse common-cloudsdk + common-workflow dk-common diff --git a/dk-modules/business/pom.xml b/dk-modules/business/pom.xml index 00a3349..d0f9e07 100644 --- a/dk-modules/business/pom.xml +++ b/dk-modules/business/pom.xml @@ -102,6 +102,13 @@ api-resource + + + org.dromara + common-workflow + 2.2.2 + + diff --git a/dk-modules/business/src/main/resources/application.yml b/dk-modules/business/src/main/resources/application.yml index a07a448..95cf7ee 100644 --- a/dk-modules/business/src/main/resources/application.yml +++ b/dk-modules/business/src/main/resources/application.yml @@ -31,4 +31,4 @@ spring: import: - optional:nacos:application-common.yml - optional:nacos:datasource.yml -# - optional:nacos:${spring.application.name}.yml + - optional:nacos:${spring.application.name}.yml diff --git a/dk-modules/pom.xml b/dk-modules/pom.xml index b715fd4..03bff4d 100644 --- a/dk-modules/pom.xml +++ b/dk-modules/pom.xml @@ -13,7 +13,6 @@ gen job resource - workflow sample business diff --git a/dk-modules/workflow/Dockerfile b/dk-modules/workflow/Dockerfile deleted file mode 100644 index 696278d..0000000 --- a/dk-modules/workflow/Dockerfile +++ /dev/null @@ -1,25 +0,0 @@ -# 贝尔实验室 Spring 官方推荐镜像 JDK下载地址 https://bell-sw.com/pages/downloads/ -FROM bellsoft/liberica-openjdk-debian:17.0.11-cds -#FROM bellsoft/liberica-openjdk-debian:21.0.3-cds -#FROM findepi/graalvm:java17-native - -LABEL maintainer="Lion Li" - -RUN mkdir -p /dk/workflow/logs \ - /dk/workflow/temp \ - /dk/skywalking/agent - -WORKDIR /dk/workflow - -ENV SERVER_PORT=9205 LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS="" - -EXPOSE ${SERVER_PORT} - -ADD ./target/dk-workflow.jar ./app.jar - -ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom -Dserver.port=${SERVER_PORT} \ - #-Dskywalking.agent.service_name=ruoyi-system \ - #-javaagent:/ruoyi/skywalking/agent/skywalking-agent.jar \ - -XX:+HeapDumpOnOutOfMemoryError -XX:+UseZGC ${JAVA_OPTS} \ - -jar app.jar - diff --git a/dk-modules/workflow/pom.xml b/dk-modules/workflow/pom.xml deleted file mode 100644 index c800eba..0000000 --- a/dk-modules/workflow/pom.xml +++ /dev/null @@ -1,163 +0,0 @@ - - - - org.dromara - dk-modules - ${revision} - - 4.0.0 - - workflow - - - 工作流模块 - - - - - - org.dromara - common-nacos - - - - - org.flowable - flowable-spring-boot-autoconfigure - - - org.flowable - flowable-spring-security - - - - - - org.flowable - flowable-spring-configurator - - - - org.flowable - flowable-spring-boot-starter-actuator - - - - - org.flowable - flowable-image-generator - - - - - org.flowable - flowable-json-converter - 6.8.0 - - - - - org.apache.xmlgraphics - batik-all - 1.17 - - - xalan - xalan - - - - - - org.dromara - common-websocket - - - - org.dromara - common-mail - - - - org.dromara - common-sms - - - - org.dromara - common-mybatis - - - org.dromara - common-web - - - org.dromara - common-log - - - org.dromara - common-idempotent - - - org.dromara - common-excel - - - org.dromara - common-translation - - - org.dromara - common-tenant - - - - org.dromara - common-dubbo - - - - org.dromara - common-security - - - - org.dromara - common-seata - - - - org.dromara - api-workflow - - - - commons-io - commons-io - 2.15.0 - - - - - ${project.artifactId} - - - org.springframework.boot - spring-boot-maven-plugin - ${spring-boot.version} - - - - repackage - - - - - - - - - diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/DKWorkflowApplication.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/DKWorkflowApplication.java deleted file mode 100644 index 214f0eb..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/DKWorkflowApplication.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.dromara.workflow; - -import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup; - -/** - * 系统模块 - * - * @author ruoyi - */ -@EnableDubbo -@SpringBootApplication -public class DKWorkflowApplication { - public static void main(String[] args) { - SpringApplication application = new SpringApplication(DKWorkflowApplication.class); - application.setApplicationStartup(new BufferingApplicationStartup(2048)); - application.run(args); - System.out.println("(♥◠‿◠)ノ゙ 工作流模块启动成功 ლ(´ڡ`ლ)゙ "); - } -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java deleted file mode 100644 index c3fcafa..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java +++ /dev/null @@ -1,137 +0,0 @@ -package org.dromara.workflow.common.constant; - - -/** - * 工作流常量 - * - * @author may - */ -public interface FlowConstant { - - String MESSAGE_CURRENT_TASK_IS_NULL = "当前任务不存在或你不是任务办理人!"; - - String MESSAGE_SUSPENDED = "当前任务已挂起不可审批!"; - - /** - * 连线 - */ - String SEQUENCE_FLOW = "sequenceFlow"; - - /** - * 并行网关 - */ - String PARALLEL_GATEWAY = "parallelGateway"; - - /** - * 排它网关 - */ - String EXCLUSIVE_GATEWAY = "exclusiveGateway"; - - /** - * 包含网关 - */ - String INCLUSIVE_GATEWAY = "inclusiveGateway"; - - /** - * 结束节点 - */ - String END_EVENT = "endEvent"; - - - /** - * 流程委派标识 - */ - String PENDING = "PENDING"; - - /** - * 候选人标识 - */ - String CANDIDATE = "candidate"; - - /** - * 会签任务总数 - */ - String NUMBER_OF_INSTANCES = "nrOfInstances"; - - /** - * 正在执行的会签总数 - */ - String NUMBER_OF_ACTIVE_INSTANCES = "nrOfActiveInstances"; - - /** - * 已完成的会签任务总数 - */ - String NUMBER_OF_COMPLETED_INSTANCES = "nrOfCompletedInstances"; - - /** - * 循环的索引值,可以使用elementIndexVariable属性修改loopCounter的变量名 - */ - String LOOP_COUNTER = "loopCounter"; - - String ZIP = "ZIP"; - - /** - * 业务与流程实例关联对象 - */ - String BUSINESS_INSTANCE_DTO = "businessInstanceDTO"; - - /** - * 流程定义配置 - */ - String WF_DEFINITION_CONFIG_VO = "wfDefinitionConfigVo"; - - /** - * 节点配置 - */ - String WF_NODE_CONFIG_VO = "wfNodeConfigVo"; - - /** - * 流程发起人 - */ - String INITIATOR = "initiator"; - - /** - * 流程实例id - */ - String PROCESS_INSTANCE_ID = "processInstanceId"; - - /** - * 业务id - */ - String BUSINESS_KEY = "businessKey"; - - /** - * 流程定义id - */ - String PROCESS_DEFINITION_ID = "processDefinitionId"; - - /** - * 开启跳过表达式变量 - */ - String FLOWABLE_SKIP_EXPRESSION_ENABLED = "_FLOWABLE_SKIP_EXPRESSION_ENABLED"; - - /** - * 模型标识key命名规范正则表达式 - */ - String MODEL_KEY_PATTERN = "^[a-zA-Z][a-zA-Z0-9_]{0,254}$"; - - /** - * 用户任务 - */ - String USER_TASK = "userTask"; - - /** - * 会签 - */ - String MULTI_INSTANCE = "multiInstance"; - - /** - * 是 - */ - String TRUE = "0"; - - /** - * 否 - */ - String FALSE = "1"; -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/common/enums/FormTypeEnum.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/common/enums/FormTypeEnum.java deleted file mode 100644 index 083ab7b..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/common/enums/FormTypeEnum.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.dromara.workflow.common.enums; - -import cn.hutool.core.util.StrUtil; -import lombok.AllArgsConstructor; -import lombok.Getter; -import org.apache.commons.lang3.StringUtils; - -import java.util.Arrays; - -/** - * 任务状态枚举 - * - * @author may - */ -@Getter -@AllArgsConstructor -public enum FormTypeEnum { - /** - * 自定义表单 - */ - STATIC("static", "自定义表单"), - /** - * 动态表单 - */ - DYNAMIC("dynamic", "动态表单"); - - /** - * 类型 - */ - private final String type; - - /** - * 描述 - */ - private final String desc; - - /** - * 表单类型 - * - * @param formType 表单类型 - */ - public static String findByType(String formType) { - if (StringUtils.isBlank(formType)) { - return StrUtil.EMPTY; - } - - return Arrays.stream(FormTypeEnum.values()) - .filter(statusEnum -> statusEnum.getType().equals(formType)) - .findFirst() - .map(FormTypeEnum::getDesc) - .orElse(StrUtil.EMPTY); - } -} - diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/common/enums/MessageTypeEnum.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/common/enums/MessageTypeEnum.java deleted file mode 100644 index a282958..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/common/enums/MessageTypeEnum.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.dromara.workflow.common.enums; - -import lombok.AllArgsConstructor; -import lombok.Getter; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -/** - * 消息类型枚举 - * - * @author may - */ -@Getter -@AllArgsConstructor -public enum MessageTypeEnum { - /** - * 站内信 - */ - SYSTEM_MESSAGE("1", "站内信"), - /** - * 邮箱 - */ - EMAIL_MESSAGE("2", "邮箱"), - /** - * 短信 - */ - SMS_MESSAGE("3", "短信"); - - private final String code; - - private final String desc; - - private final static Map MESSAGE_TYPE_ENUM_MAP = new ConcurrentHashMap<>(MessageTypeEnum.values().length); - - static { - for (MessageTypeEnum messageType : MessageTypeEnum.values()) { - MESSAGE_TYPE_ENUM_MAP.put(messageType.code, messageType); - } - } - - /** - * 根据消息类型 code 获取 MessageTypeEnum - * @param code 消息类型code - * @return MessageTypeEnum - */ - public static MessageTypeEnum getByCode(String code) { - return MESSAGE_TYPE_ENUM_MAP.get(code); - } -} - diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/common/enums/TaskStatusEnum.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/common/enums/TaskStatusEnum.java deleted file mode 100644 index 7b2f55c..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/common/enums/TaskStatusEnum.java +++ /dev/null @@ -1,94 +0,0 @@ -package org.dromara.workflow.common.enums; - -import cn.hutool.core.util.StrUtil; -import lombok.AllArgsConstructor; -import lombok.Getter; -import org.apache.commons.lang3.StringUtils; - -import java.util.Arrays; - -/** - * 任务状态枚举 - * - * @author may - */ -@Getter -@AllArgsConstructor -public enum TaskStatusEnum { - /** - * 撤销 - */ - CANCEL("cancel", "撤销"), - /** - * 通过 - */ - PASS("pass", "通过"), - /** - * 待审核 - */ - WAITING("waiting", "待审核"), - /** - * 作废 - */ - INVALID("invalid", "作废"), - /** - * 退回 - */ - BACK("back", "退回"), - /** - * 终止 - */ - TERMINATION("termination", "终止"), - /** - * 转办 - */ - TRANSFER("transfer", "转办"), - /** - * 委托 - */ - PENDING("pending", "委托"), - /** - * 抄送 - */ - COPY("copy", "抄送"), - /** - * 加签 - */ - SIGN("sign", "加签"), - /** - * 减签 - */ - SIGN_OFF("sign_off", "减签"), - /** - * 超时 - */ - TIMEOUT("timeout", "超时"); - - /** - * 状态 - */ - private final String status; - - /** - * 描述 - */ - private final String desc; - - /** - * 任务业务状态 - * - * @param status 状态 - */ - public static String findByStatus(String status) { - if (StringUtils.isBlank(status)) { - return StrUtil.EMPTY; - } - - return Arrays.stream(TaskStatusEnum.values()) - .filter(statusEnum -> statusEnum.getStatus().equals(status)) - .findFirst() - .map(TaskStatusEnum::getDesc) - .orElse(StrUtil.EMPTY); - } -} - diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/controller/ActModelController.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/controller/ActModelController.java deleted file mode 100644 index a4532e1..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/controller/ActModelController.java +++ /dev/null @@ -1,148 +0,0 @@ -package org.dromara.workflow.controller; - -import jakarta.servlet.http.HttpServletResponse; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotEmpty; -import lombok.RequiredArgsConstructor; -import org.dromara.common.core.domain.R; -import org.dromara.common.core.validate.AddGroup; -import org.dromara.common.core.validate.EditGroup; -import org.dromara.common.idempotent.annotation.RepeatSubmit; -import org.dromara.common.log.annotation.Log; -import org.dromara.common.log.enums.BusinessType; -import org.dromara.common.mybatis.core.page.PageQuery; -import org.dromara.common.mybatis.core.page.TableDataInfo; -import org.dromara.common.web.core.BaseController; -import org.dromara.workflow.domain.bo.ModelBo; -import org.dromara.workflow.domain.vo.ModelVo; -import org.dromara.workflow.service.IActModelService; -import org.flowable.engine.RepositoryService; -import org.flowable.engine.repository.Model; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import java.util.Arrays; -import java.util.List; - -/** - * 模型管理 控制层 - * - * @author may - */ -@Validated -@RequiredArgsConstructor -@RestController -@RequestMapping("/model") -public class ActModelController extends BaseController { - - @Autowired(required = false) - private RepositoryService repositoryService; - private final IActModelService actModelService; - - - /** - * 分页查询模型 - * - * @param modelBo 模型参数 - */ - @GetMapping("/list") - public TableDataInfo page(ModelBo modelBo, PageQuery pageQuery) { - return actModelService.page(modelBo, pageQuery); - } - - /** - * 新增模型 - * - * @param modelBo 模型请求对象 - */ - @Log(title = "模型管理", businessType = BusinessType.INSERT) - @RepeatSubmit() - @PostMapping("/save") - public R saveNewModel(@Validated(AddGroup.class) @RequestBody ModelBo modelBo) { - return toAjax(actModelService.saveNewModel(modelBo)); - } - - /** - * 查询模型 - * - * @param id 模型id - */ - @GetMapping("/getInfo/{id}") - public R getInfo(@NotBlank(message = "模型id不能为空") @PathVariable String id) { - return R.ok(actModelService.getInfo(id)); - } - - /** - * 修改模型信息 - * - * @param modelBo 模型数据 - */ - @Log(title = "模型管理", businessType = BusinessType.UPDATE) - @RepeatSubmit() - @PutMapping(value = "/update") - public R update(@RequestBody ModelBo modelBo) { - return toAjax(actModelService.update(modelBo)); - } - - /** - * 编辑XMl模型 - * - * @param modelBo 模型数据 - */ - @Log(title = "模型管理", businessType = BusinessType.UPDATE) - @RepeatSubmit() - @PutMapping(value = "/editModelXml") - public R editModel(@Validated(EditGroup.class) @RequestBody ModelBo modelBo) { - return toAjax(actModelService.editModelXml(modelBo)); - } - - /** - * 删除流程模型 - * - * @param ids 模型id - */ - @Log(title = "模型管理", businessType = BusinessType.DELETE) - @RepeatSubmit() - @DeleteMapping("/{ids}") - @Transactional(rollbackFor = Exception.class) - public R delete(@NotEmpty(message = "主键不能为空") @PathVariable String[] ids) { - Arrays.stream(ids).parallel().forEachOrdered(repositoryService::deleteModel); - return R.ok(); - } - - /** - * 模型部署 - * - * @param id 模型id - */ - @Log(title = "模型管理", businessType = BusinessType.INSERT) - @RepeatSubmit() - @PostMapping("/modelDeploy/{id}") - public R deploy(@NotBlank(message = "模型id不能为空") @PathVariable("id") String id) { - return toAjax(actModelService.modelDeploy(id)); - } - - /** - * 导出模型zip压缩包 - * - * @param modelIds 模型id - * @param response 相应 - */ - @GetMapping("/export/zip/{modelIds}") - public void exportZip(@NotEmpty(message = "模型id不能为空") @PathVariable List modelIds, - HttpServletResponse response) { - actModelService.exportZip(modelIds, response); - } - - /** - * 复制模型 - * - * @param modelBo 模型数据 - */ - @PostMapping("/copyModel") - public R copyModel(@RequestBody ModelBo modelBo) { - return toAjax(actModelService.copyModel(modelBo)); - } -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/controller/ActProcessDefinitionController.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/controller/ActProcessDefinitionController.java deleted file mode 100644 index f38b21f..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/controller/ActProcessDefinitionController.java +++ /dev/null @@ -1,147 +0,0 @@ -package org.dromara.workflow.controller; - -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotEmpty; -import jakarta.validation.constraints.NotNull; -import lombok.RequiredArgsConstructor; -import org.dromara.common.core.domain.R; -import org.dromara.common.idempotent.annotation.RepeatSubmit; -import org.dromara.common.log.annotation.Log; -import org.dromara.common.log.enums.BusinessType; -import org.dromara.common.mybatis.core.page.PageQuery; -import org.dromara.common.mybatis.core.page.TableDataInfo; -import org.dromara.common.web.core.BaseController; -import org.dromara.workflow.domain.bo.ProcessDefinitionBo; -import org.dromara.workflow.domain.vo.ProcessDefinitionVo; -import org.dromara.workflow.service.IActProcessDefinitionService; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.multipart.MultipartFile; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - - -/** - * 流程定义管理 控制层 - * - * @author may - */ -@Validated -@RequiredArgsConstructor -@RestController -@RequestMapping("/processDefinition") -public class ActProcessDefinitionController extends BaseController { - - private final IActProcessDefinitionService actProcessDefinitionService; - - /** - * 分页查询 - * - * @param bo 参数 - */ - @GetMapping("/list") - public TableDataInfo page(ProcessDefinitionBo bo, PageQuery pageQuery) { - return actProcessDefinitionService.page(bo, pageQuery); - } - - /** - * 查询历史流程定义列表 - * - * @param key 流程定义key - */ - @GetMapping("/getListByKey/{key}") - public R> getListByKey(@NotEmpty(message = "流程定义key不能为空") @PathVariable String key) { - return R.ok("操作成功", actProcessDefinitionService.getListByKey(key)); - } - - /** - * 查看流程定义图片 - * - * @param processDefinitionId 流程定义id - */ - @GetMapping("/definitionImage/{processDefinitionId}") - public R definitionImage(@PathVariable String processDefinitionId) { - return R.ok("操作成功", actProcessDefinitionService.definitionImage(processDefinitionId)); - } - - /** - * 查看流程定义xml文件 - * - * @param processDefinitionId 流程定义id - */ - @GetMapping("/definitionXml/{processDefinitionId}") - public R> definitionXml(@NotBlank(message = "流程定义id不能为空") @PathVariable String processDefinitionId) { - Map map = new HashMap<>(); - String xmlStr = actProcessDefinitionService.definitionXml(processDefinitionId); - map.put("xml", Arrays.asList(xmlStr.split("\n"))); - map.put("xmlStr", xmlStr); - return R.ok(map); - } - - /** - * 删除流程定义 - * - * @param deploymentIds 部署id - * @param processDefinitionIds 流程定义id - */ - @Log(title = "流程定义管理", businessType = BusinessType.DELETE) - @DeleteMapping("/{deploymentIds}/{processDefinitionIds}") - public R deleteDeployment(@NotNull(message = "流程部署id不能为空") @PathVariable List deploymentIds, - @NotNull(message = "流程定义id不能为空") @PathVariable List processDefinitionIds) { - return toAjax(actProcessDefinitionService.deleteDeployment(deploymentIds, processDefinitionIds)); - } - - /** - * 激活或者挂起流程定义 - * - * @param processDefinitionId 流程定义id - */ - @Log(title = "流程定义管理", businessType = BusinessType.UPDATE) - @RepeatSubmit() - @PutMapping("/updateDefinitionState/{processDefinitionId}") - public R updateDefinitionState(@NotBlank(message = "流程定义id不能为空") @PathVariable String processDefinitionId) { - return toAjax(actProcessDefinitionService.updateDefinitionState(processDefinitionId)); - } - - /** - * 迁移流程定义 - * - * @param currentProcessDefinitionId 当前流程定义id - * @param fromProcessDefinitionId 需要迁移到的流程定义id - */ - @Log(title = "流程定义管理", businessType = BusinessType.UPDATE) - @RepeatSubmit() - @PutMapping("/migrationDefinition/{currentProcessDefinitionId}/{fromProcessDefinitionId}") - public R migrationDefinition(@NotBlank(message = "当前流程定义id") @PathVariable String currentProcessDefinitionId, - @NotBlank(message = "需要迁移到的流程定义id") @PathVariable String fromProcessDefinitionId) { - return toAjax(actProcessDefinitionService.migrationDefinition(currentProcessDefinitionId, fromProcessDefinitionId)); - } - - /** - * 流程定义转换为模型 - * - * @param processDefinitionId 流程定义id - */ - @Log(title = "流程定义管理", businessType = BusinessType.UPDATE) - @RepeatSubmit() - @PutMapping("/convertToModel/{processDefinitionId}") - public R convertToModel(@NotEmpty(message = "流程定义id不能为空") @PathVariable String processDefinitionId) { - return toAjax(actProcessDefinitionService.convertToModel(processDefinitionId)); - } - - /** - * 通过zip或xml部署流程定义 - * - * @param file 文件 - * @param categoryCode 分类 - */ - @Log(title = "流程定义管理", businessType = BusinessType.INSERT) - @PostMapping("/deployByFile") - public void deployByFile(@RequestParam("file") MultipartFile file, @RequestParam("categoryCode") String categoryCode) { - actProcessDefinitionService.deployByFile(file, categoryCode); - } - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/controller/ActProcessInstanceController.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/controller/ActProcessInstanceController.java deleted file mode 100644 index 927c09b..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/controller/ActProcessInstanceController.java +++ /dev/null @@ -1,160 +0,0 @@ -package org.dromara.workflow.controller; - -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; -import lombok.RequiredArgsConstructor; -import org.dromara.common.core.domain.R; -import org.dromara.common.core.validate.AddGroup; -import org.dromara.common.idempotent.annotation.RepeatSubmit; -import org.dromara.common.log.annotation.Log; -import org.dromara.common.log.enums.BusinessType; -import org.dromara.common.mybatis.core.page.PageQuery; -import org.dromara.common.mybatis.core.page.TableDataInfo; -import org.dromara.common.web.core.BaseController; -import org.dromara.workflow.domain.bo.ProcessInstanceBo; -import org.dromara.workflow.domain.bo.ProcessInvalidBo; -import org.dromara.workflow.domain.bo.TaskUrgingBo; -import org.dromara.workflow.domain.vo.ActHistoryInfoVo; -import org.dromara.workflow.domain.vo.ProcessInstanceVo; -import org.dromara.workflow.service.IActProcessInstanceService; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import java.util.Arrays; -import java.util.List; -import java.util.Map; - -/** - * 流程实例管理 控制层 - * - * @author may - */ -@Validated -@RequiredArgsConstructor -@RestController -@RequestMapping("/processInstance") -public class ActProcessInstanceController extends BaseController { - - private final IActProcessInstanceService actProcessInstanceService; - - /** - * 分页查询正在运行的流程实例 - * - * @param bo 参数 - */ - @GetMapping("/getPageByRunning") - public TableDataInfo getPageByRunning(ProcessInstanceBo bo, PageQuery pageQuery) { - return actProcessInstanceService.getPageByRunning(bo, pageQuery); - } - - /** - * 分页查询已结束的流程实例 - * - * @param bo 参数 - */ - @GetMapping("/getPageByFinish") - public TableDataInfo getPageByFinish(ProcessInstanceBo bo, PageQuery pageQuery) { - return actProcessInstanceService.getPageByFinish(bo, pageQuery); - } - - /** - * 通过业务id获取历史流程图 - * - * @param businessKey 业务id - */ - @GetMapping("/getHistoryImage/{businessKey}") - public R getHistoryImage(@NotBlank(message = "业务id不能为空") @PathVariable String businessKey) { - return R.ok("操作成功", actProcessInstanceService.getHistoryImage(businessKey)); - } - - /** - * 通过业务id获取历史流程图运行中,历史等节点 - * - * @param businessKey 业务id - */ - @GetMapping("/getHistoryList/{businessKey}") - public R> getHistoryList(@NotBlank(message = "业务id不能为空") @PathVariable String businessKey) { - return R.ok("操作成功", actProcessInstanceService.getHistoryList(businessKey)); - } - - /** - * 获取审批记录 - * - * @param businessKey 业务id - */ - @GetMapping("/getHistoryRecord/{businessKey}") - public R> getHistoryRecord(@NotBlank(message = "业务id不能为空") @PathVariable String businessKey) { - return R.ok(actProcessInstanceService.getHistoryRecord(businessKey)); - } - - /** - * 作废流程实例,不会删除历史记录(删除运行中的实例) - * - * @param processInvalidBo 参数 - */ - @Log(title = "流程实例管理", businessType = BusinessType.DELETE) - @RepeatSubmit() - @PostMapping("/deleteRunInstance") - public R deleteRunInstance(@Validated(AddGroup.class) @RequestBody ProcessInvalidBo processInvalidBo) { - return toAjax(actProcessInstanceService.deleteRunInstance(processInvalidBo)); - } - - /** - * 运行中的实例 删除程实例,删除历史记录,删除业务与流程关联信息 - * - * @param businessKeys 业务id - */ - @Log(title = "流程实例管理", businessType = BusinessType.DELETE) - @RepeatSubmit() - @DeleteMapping("/deleteRunAndHisInstance/{businessKeys}") - public R deleteRunAndHisInstance(@NotNull(message = "业务id不能为空") @PathVariable String[] businessKeys) { - return toAjax(actProcessInstanceService.deleteRunAndHisInstance(Arrays.asList(businessKeys))); - } - - /** - * 已完成的实例 删除程实例,删除历史记录,删除业务与流程关联信息 - * - * @param businessKeys 业务id - */ - @Log(title = "流程实例管理", businessType = BusinessType.DELETE) - @RepeatSubmit() - @DeleteMapping("/deleteFinishAndHisInstance/{businessKeys}") - public R deleteFinishAndHisInstance(@NotNull(message = "业务id不能为空") @PathVariable String[] businessKeys) { - return toAjax(actProcessInstanceService.deleteFinishAndHisInstance(Arrays.asList(businessKeys))); - } - - /** - * 撤销流程申请 - * - * @param businessKey 业务id - */ - @Log(title = "流程实例管理", businessType = BusinessType.INSERT) - @RepeatSubmit() - @PostMapping("/cancelProcessApply/{businessKey}") - public R cancelProcessApply(@NotBlank(message = "业务id不能为空") @PathVariable String businessKey) { - return toAjax(actProcessInstanceService.cancelProcessApply(businessKey)); - } - - /** - * 分页查询当前登录人单据 - * - * @param bo 参数 - */ - @GetMapping("/getPageByCurrent") - public TableDataInfo getPageByCurrent(ProcessInstanceBo bo, PageQuery pageQuery) { - return actProcessInstanceService.getPageByCurrent(bo, pageQuery); - } - - /** - * 任务催办(给当前任务办理人发送站内信,邮件,短信等) - * - * @param taskUrgingBo 任务催办 - */ - @Log(title = "流程实例管理", businessType = BusinessType.INSERT) - @RepeatSubmit() - @PostMapping("/taskUrging") - public R taskUrging(@RequestBody TaskUrgingBo taskUrgingBo) { - return toAjax(actProcessInstanceService.taskUrging(taskUrgingBo)); - } - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/controller/ActTaskController.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/controller/ActTaskController.java deleted file mode 100644 index 4eccf8f..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/controller/ActTaskController.java +++ /dev/null @@ -1,295 +0,0 @@ -package org.dromara.workflow.controller; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.convert.Convert; -import jakarta.validation.constraints.NotBlank; -import lombok.RequiredArgsConstructor; -import org.dromara.common.core.domain.R; -import org.dromara.common.core.validate.AddGroup; -import org.dromara.common.idempotent.annotation.RepeatSubmit; -import org.dromara.common.log.annotation.Log; -import org.dromara.common.log.enums.BusinessType; -import org.dromara.common.mybatis.core.page.PageQuery; -import org.dromara.common.mybatis.core.page.TableDataInfo; -import org.dromara.common.satoken.utils.LoginHelper; -import org.dromara.common.web.core.BaseController; -import org.dromara.workflow.domain.WfTaskBackNode; -import org.dromara.workflow.domain.bo.*; -import org.dromara.workflow.domain.vo.TaskVo; -import org.dromara.workflow.domain.vo.VariableVo; -import org.dromara.workflow.service.IActTaskService; -import org.dromara.workflow.service.IWfTaskBackNodeService; -import org.dromara.workflow.utils.QueryUtils; -import org.flowable.engine.TaskService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import java.util.List; -import java.util.Map; - -/** - * 任务管理 控制层 - * - * @author may - */ -@Validated -@RequiredArgsConstructor -@RestController -@RequestMapping("/task") -public class ActTaskController extends BaseController { - - @Autowired(required = false) - private TaskService taskService; - private final IActTaskService actTaskService; - private final IWfTaskBackNodeService wfTaskBackNodeService; - - - /** - * 启动任务 - * - * @param startProcessBo 启动流程参数 - */ - @Log(title = "任务管理", businessType = BusinessType.INSERT) - @RepeatSubmit() - @PostMapping("/startWorkFlow") - public R> startWorkFlow(@Validated(AddGroup.class) @RequestBody StartProcessBo startProcessBo) { - Map map = actTaskService.startWorkFlow(startProcessBo); - return R.ok("提交成功", map); - } - - /** - * 办理任务 - * - * @param completeTaskBo 办理任务参数 - */ - @Log(title = "任务管理", businessType = BusinessType.INSERT) - @RepeatSubmit() - @PostMapping("/completeTask") - public R completeTask(@Validated(AddGroup.class) @RequestBody CompleteTaskBo completeTaskBo) { - return toAjax(actTaskService.completeTask(completeTaskBo)); - } - - /** - * 查询当前用户的待办任务 - * - * @param taskBo 参数 - */ - @GetMapping("/getPageByTaskWait") - public TableDataInfo getPageByTaskWait(TaskBo taskBo, PageQuery pageQuery) { - return actTaskService.getPageByTaskWait(taskBo, pageQuery); - } - - /** - * 查询当前租户所有待办任务 - * - * @param taskBo 参数 - */ - @GetMapping("/getPageByAllTaskWait") - public TableDataInfo getPageByAllTaskWait(TaskBo taskBo, PageQuery pageQuery) { - return actTaskService.getPageByAllTaskWait(taskBo, pageQuery); - } - - /** - * 查询当前用户的已办任务 - * - * @param taskBo 参数 - */ - @GetMapping("/getPageByTaskFinish") - public TableDataInfo getPageByTaskFinish(TaskBo taskBo, PageQuery pageQuery) { - return actTaskService.getPageByTaskFinish(taskBo, pageQuery); - } - - /** - * 查询当前用户的抄送 - * - * @param taskBo 参数 - */ - @GetMapping("/getPageByTaskCopy") - public TableDataInfo getPageByTaskCopy(TaskBo taskBo, PageQuery pageQuery) { - return actTaskService.getPageByTaskCopy(taskBo, pageQuery); - } - - /** - * 查询当前租户所有已办任务 - * - * @param taskBo 参数 - */ - @GetMapping("/getPageByAllTaskFinish") - public TableDataInfo getPageByAllTaskFinish(TaskBo taskBo, PageQuery pageQuery) { - return actTaskService.getPageByAllTaskFinish(taskBo, pageQuery); - } - - /** - * 签收(拾取)任务 - * - * @param taskId 任务id - */ - @Log(title = "任务管理", businessType = BusinessType.INSERT) - @RepeatSubmit() - @PostMapping("/claim/{taskId}") - public R claimTask(@NotBlank(message = "任务id不能为空") @PathVariable String taskId) { - try { - taskService.claim(taskId, Convert.toStr(LoginHelper.getUserId())); - return R.ok(); - } catch (Exception e) { - e.printStackTrace(); - return R.fail("签收任务失败:" + e.getMessage()); - } - } - - /** - * 归还(拾取的)任务 - * - * @param taskId 任务id - */ - @Log(title = "任务管理", businessType = BusinessType.INSERT) - @RepeatSubmit() - @PostMapping("/returnTask/{taskId}") - public R returnTask(@NotBlank(message = "任务id不能为空") @PathVariable String taskId) { - try { - taskService.setAssignee(taskId, null); - return R.ok(); - } catch (Exception e) { - e.printStackTrace(); - return R.fail("归还任务失败:" + e.getMessage()); - } - } - - /** - * 委派任务 - * - * @param delegateBo 参数 - */ - @Log(title = "任务管理", businessType = BusinessType.INSERT) - @RepeatSubmit() - @PostMapping("/delegateTask") - public R delegateTask(@Validated({AddGroup.class}) @RequestBody DelegateBo delegateBo) { - return toAjax(actTaskService.delegateTask(delegateBo)); - } - - /** - * 终止任务 - * - * @param terminationBo 参数 - */ - @Log(title = "任务管理", businessType = BusinessType.DELETE) - @RepeatSubmit() - @PostMapping("/terminationTask") - public R terminationTask(@RequestBody TerminationBo terminationBo) { - return toAjax(actTaskService.terminationTask(terminationBo)); - } - - /** - * 转办任务 - * - * @param transmitBo 参数 - */ - @Log(title = "任务管理", businessType = BusinessType.INSERT) - @RepeatSubmit() - @PostMapping("/transferTask") - public R transferTask(@Validated({AddGroup.class}) @RequestBody TransmitBo transmitBo) { - return toAjax(actTaskService.transferTask(transmitBo)); - } - - /** - * 会签任务加签 - * - * @param addMultiBo 参数 - */ - @Log(title = "任务管理", businessType = BusinessType.INSERT) - @RepeatSubmit() - @PostMapping("/addMultiInstanceExecution") - public R addMultiInstanceExecution(@Validated({AddGroup.class}) @RequestBody AddMultiBo addMultiBo) { - return toAjax(actTaskService.addMultiInstanceExecution(addMultiBo)); - } - - /** - * 会签任务减签 - * - * @param deleteMultiBo 参数 - */ - @Log(title = "任务管理", businessType = BusinessType.INSERT) - @RepeatSubmit() - @PostMapping("/deleteMultiInstanceExecution") - public R deleteMultiInstanceExecution(@Validated({AddGroup.class}) @RequestBody DeleteMultiBo deleteMultiBo) { - return toAjax(actTaskService.deleteMultiInstanceExecution(deleteMultiBo)); - } - - /** - * 驳回审批 - * - * @param backProcessBo 参数 - */ - @Log(title = "任务管理", businessType = BusinessType.INSERT) - @RepeatSubmit() - @PostMapping("/backProcess") - public R backProcess(@Validated({AddGroup.class}) @RequestBody BackProcessBo backProcessBo) { - return R.ok(actTaskService.backProcess(backProcessBo)); - } - - /** - * 获取当前任务 - * - * @param taskId 任务id - */ - @GetMapping("/getTaskById/{taskId}") - public R getTaskById(@PathVariable String taskId) { - return R.ok(QueryUtils.getTask(taskId)); - } - - - /** - * 修改任务办理人 - * - * @param taskIds 任务id - * @param userId 办理人id - */ - @Log(title = "任务管理", businessType = BusinessType.UPDATE) - @RepeatSubmit() - @PutMapping("/updateAssignee/{taskIds}/{userId}") - public R updateAssignee(@PathVariable String[] taskIds, @PathVariable String userId) { - return toAjax(actTaskService.updateAssignee(taskIds, userId)); - } - - /** - * 查询流程变量 - * - * @param taskId 任务id - */ - @GetMapping("/getInstanceVariable/{taskId}") - public R> getProcessInstVariable(@PathVariable String taskId) { - return R.ok(actTaskService.getInstanceVariable(taskId)); - } - - /** - * 获取可驳回得任务节点 - * - * @param processInstanceId 流程实例id - */ - @GetMapping("/getTaskNodeList/{processInstanceId}") - public R> getNodeList(@PathVariable String processInstanceId) { - return R.ok(CollUtil.reverse(wfTaskBackNodeService.getListByInstanceId(processInstanceId))); - } - - /** - * 查询工作流任务用户选择加签人员 - * - * @param taskId 任务id - */ - @GetMapping("/getTaskUserIdsByAddMultiInstance/{taskId}") - public R getTaskUserIdsByAddMultiInstance(@PathVariable String taskId) { - return R.ok(actTaskService.getTaskUserIdsByAddMultiInstance(taskId)); - } - - /** - * 查询工作流选择减签人员 - * - * @param taskId 任务id - */ - @GetMapping("/getListByDeleteMultiInstance/{taskId}") - public R> getListByDeleteMultiInstance(@PathVariable String taskId) { - return R.ok(actTaskService.getListByDeleteMultiInstance(taskId)); - } - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/controller/TestLeaveController.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/controller/TestLeaveController.java deleted file mode 100644 index ad77fdf..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/controller/TestLeaveController.java +++ /dev/null @@ -1,106 +0,0 @@ -package org.dromara.workflow.controller; - -import cn.dev33.satoken.annotation.SaCheckPermission; -import jakarta.servlet.http.HttpServletResponse; -import jakarta.validation.constraints.NotEmpty; -import jakarta.validation.constraints.NotNull; -import lombok.RequiredArgsConstructor; -import org.dromara.common.core.domain.R; -import org.dromara.common.core.validate.AddGroup; -import org.dromara.common.core.validate.EditGroup; -import org.dromara.common.excel.utils.ExcelUtil; -import org.dromara.common.idempotent.annotation.RepeatSubmit; -import org.dromara.common.log.annotation.Log; -import org.dromara.common.log.enums.BusinessType; -import org.dromara.common.mybatis.core.page.PageQuery; -import org.dromara.common.mybatis.core.page.TableDataInfo; -import org.dromara.common.web.core.BaseController; -import org.dromara.workflow.domain.bo.TestLeaveBo; -import org.dromara.workflow.domain.vo.TestLeaveVo; -import org.dromara.workflow.service.ITestLeaveService; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import java.util.List; - -/** - * 请假 - * - * @author may - * @date 2023-07-21 - */ -@Validated -@RequiredArgsConstructor -@RestController -@RequestMapping("/leave") -public class TestLeaveController extends BaseController { - - private final ITestLeaveService testLeaveService; - - /** - * 查询请假列表 - */ - @SaCheckPermission("workflow:leave:list") - @GetMapping("/list") - public TableDataInfo list(TestLeaveBo bo, PageQuery pageQuery) { - return testLeaveService.queryPageList(bo, pageQuery); - } - - /** - * 导出请假列表 - */ - @SaCheckPermission("workflow:leave:export") - @Log(title = "请假", businessType = BusinessType.EXPORT) - @PostMapping("/export") - public void export(TestLeaveBo bo, HttpServletResponse response) { - List list = testLeaveService.queryList(bo); - ExcelUtil.exportExcel(list, "请假", TestLeaveVo.class, response); - } - - /** - * 获取请假详细信息 - * - * @param id 主键 - */ - @SaCheckPermission("workflow:leave:query") - @GetMapping("/{id}") - public R getInfo(@NotNull(message = "主键不能为空") - @PathVariable Long id) { - return R.ok(testLeaveService.queryById(id)); - } - - /** - * 新增请假 - */ - @SaCheckPermission("workflow:leave:add") - @Log(title = "请假", businessType = BusinessType.INSERT) - @RepeatSubmit() - @PostMapping() - public R add(@Validated(AddGroup.class) @RequestBody TestLeaveBo bo) { - return R.ok(testLeaveService.insertByBo(bo)); - } - - /** - * 修改请假 - */ - @SaCheckPermission("workflow:leave:edit") - @Log(title = "请假", businessType = BusinessType.UPDATE) - @RepeatSubmit() - @PutMapping() - public R edit(@Validated(EditGroup.class) @RequestBody TestLeaveBo bo) { - return R.ok(testLeaveService.updateByBo(bo)); - } - - /** - * 删除请假 - * - * @param ids 主键串 - */ - @SaCheckPermission("workflow:leave:remove") - @Log(title = "请假", businessType = BusinessType.DELETE) - @DeleteMapping("/{ids}") - public R remove(@NotEmpty(message = "主键不能为空") - @PathVariable Long[] ids) { - return toAjax(testLeaveService.deleteWithValidByIds(List.of(ids))); - } -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/controller/WfCategoryController.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/controller/WfCategoryController.java deleted file mode 100644 index 216ac04..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/controller/WfCategoryController.java +++ /dev/null @@ -1,106 +0,0 @@ -package org.dromara.workflow.controller; - -import cn.dev33.satoken.annotation.SaCheckPermission; -import jakarta.servlet.http.HttpServletResponse; -import jakarta.validation.constraints.NotEmpty; -import jakarta.validation.constraints.NotNull; -import lombok.RequiredArgsConstructor; -import org.dromara.common.core.domain.R; -import org.dromara.common.core.validate.AddGroup; -import org.dromara.common.core.validate.EditGroup; -import org.dromara.common.excel.utils.ExcelUtil; -import org.dromara.common.idempotent.annotation.RepeatSubmit; -import org.dromara.common.log.annotation.Log; -import org.dromara.common.log.enums.BusinessType; -import org.dromara.common.web.core.BaseController; -import org.dromara.workflow.domain.bo.WfCategoryBo; -import org.dromara.workflow.domain.vo.WfCategoryVo; -import org.dromara.workflow.service.IWfCategoryService; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import java.util.List; - -/** - * 流程分类 - * - * @author may - * @date 2023-06-28 - */ -@Validated -@RequiredArgsConstructor -@RestController -@RequestMapping("/category") -public class WfCategoryController extends BaseController { - - private final IWfCategoryService wfCategoryService; - - /** - * 查询流程分类列表 - */ - @SaCheckPermission("workflow:category:list") - @GetMapping("/list") - public R> list(WfCategoryBo bo) { - List list = wfCategoryService.queryList(bo); - return R.ok(list); - - } - - /** - * 导出流程分类列表 - */ - @SaCheckPermission("workflow:category:export") - @Log(title = "流程分类", businessType = BusinessType.EXPORT) - @PostMapping("/export") - public void export(WfCategoryBo bo, HttpServletResponse response) { - List list = wfCategoryService.queryList(bo); - ExcelUtil.exportExcel(list, "流程分类", WfCategoryVo.class, response); - } - - /** - * 获取流程分类详细信息 - * - * @param id 主键 - */ - @SaCheckPermission("workflow:category:query") - @GetMapping("/{id}") - public R getInfo(@NotNull(message = "主键不能为空") - @PathVariable Long id) { - return R.ok(wfCategoryService.queryById(id)); - } - - /** - * 新增流程分类 - */ - @SaCheckPermission("workflow:category:add") - @Log(title = "流程分类", businessType = BusinessType.INSERT) - @RepeatSubmit() - @PostMapping() - public R add(@Validated(AddGroup.class) @RequestBody WfCategoryBo bo) { - return toAjax(wfCategoryService.insertByBo(bo)); - } - - /** - * 修改流程分类 - */ - @SaCheckPermission("workflow:category:edit") - @Log(title = "流程分类", businessType = BusinessType.UPDATE) - @RepeatSubmit() - @PutMapping() - public R edit(@Validated(EditGroup.class) @RequestBody WfCategoryBo bo) { - return toAjax(wfCategoryService.updateByBo(bo)); - } - - /** - * 删除流程分类 - * - * @param ids 主键串 - */ - @SaCheckPermission("workflow:category:remove") - @Log(title = "流程分类", businessType = BusinessType.DELETE) - @DeleteMapping("/{ids}") - public R remove(@NotEmpty(message = "主键不能为空") - @PathVariable Long[] ids) { - return toAjax(wfCategoryService.deleteWithValidByIds(List.of(ids), true)); - } -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/controller/WfDefinitionConfigController.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/controller/WfDefinitionConfigController.java deleted file mode 100644 index d44a0c3..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/controller/WfDefinitionConfigController.java +++ /dev/null @@ -1,79 +0,0 @@ -package org.dromara.workflow.controller; - -import java.util.List; - -import lombok.RequiredArgsConstructor; -import jakarta.validation.constraints.*; -import org.dromara.workflow.domain.bo.WfDefinitionConfigBo; -import org.springframework.web.bind.annotation.*; -import org.springframework.validation.annotation.Validated; -import org.dromara.common.idempotent.annotation.RepeatSubmit; -import org.dromara.common.log.annotation.Log; -import org.dromara.common.web.core.BaseController; -import org.dromara.common.core.domain.R; -import org.dromara.common.core.validate.AddGroup; -import org.dromara.common.log.enums.BusinessType; -import org.dromara.workflow.domain.vo.WfDefinitionConfigVo; -import org.dromara.workflow.service.IWfDefinitionConfigService; - -/** - * 流程定义配置 - * - * @author may - * @date 2024-03-18 - */ -@Validated -@RequiredArgsConstructor -@RestController -@RequestMapping("/definitionConfig") -public class WfDefinitionConfigController extends BaseController { - - private final IWfDefinitionConfigService wfDefinitionConfigService; - - - /** - * 获取流程定义配置详细信息 - * - * @param definitionId 主键 - */ - @GetMapping("/getByDefId/{definitionId}") - public R getByDefId(@NotBlank(message = "流程定义ID不能为空") - @PathVariable String definitionId) { - return R.ok(wfDefinitionConfigService.getByDefId(definitionId)); - } - - /** - * 新增流程定义配置 - */ - @Log(title = "流程定义配置", businessType = BusinessType.INSERT) - @RepeatSubmit() - @PostMapping("/saveOrUpdate") - public R saveOrUpdate(@Validated(AddGroup.class) @RequestBody WfDefinitionConfigBo bo) { - return toAjax(wfDefinitionConfigService.saveOrUpdate(bo)); - } - - /** - * 删除流程定义配置 - * - * @param ids 主键串 - */ - @Log(title = "流程定义配置", businessType = BusinessType.DELETE) - @DeleteMapping("/{ids}") - public R remove(@NotEmpty(message = "主键不能为空") - @PathVariable Long[] ids) { - return toAjax(wfDefinitionConfigService.deleteByIds(List.of(ids))); - } - - /** - * 查询流程定义配置排除当前查询的流程定义 - * - * @param tableName 表名 - * @param definitionId 流程定义id - */ - @GetMapping("/getByTableNameNotDefId/{tableName}/{definitionId}") - public R> getByTableNameNotDefId(@NotBlank(message = "表名不能为空") @PathVariable String tableName, - @NotBlank(message = "流程定义ID不能为空") @PathVariable String definitionId) { - return R.ok(wfDefinitionConfigService.getByTableNameNotDefId(tableName, definitionId)); - } - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/controller/WfFormManageController.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/controller/WfFormManageController.java deleted file mode 100644 index d88ace4..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/controller/WfFormManageController.java +++ /dev/null @@ -1,115 +0,0 @@ -package org.dromara.workflow.controller; - -import cn.dev33.satoken.annotation.SaCheckPermission; -import jakarta.servlet.http.HttpServletResponse; -import jakarta.validation.constraints.NotEmpty; -import jakarta.validation.constraints.NotNull; -import lombok.RequiredArgsConstructor; -import org.dromara.common.core.domain.R; -import org.dromara.common.core.validate.AddGroup; -import org.dromara.common.core.validate.EditGroup; -import org.dromara.common.excel.utils.ExcelUtil; -import org.dromara.common.idempotent.annotation.RepeatSubmit; -import org.dromara.common.log.annotation.Log; -import org.dromara.common.log.enums.BusinessType; -import org.dromara.common.mybatis.core.page.PageQuery; -import org.dromara.common.mybatis.core.page.TableDataInfo; -import org.dromara.common.web.core.BaseController; -import org.dromara.workflow.domain.bo.WfFormManageBo; -import org.dromara.workflow.domain.vo.WfFormManageVo; -import org.dromara.workflow.service.IWfFormManageService; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import java.util.List; - -/** - * 表单管理 - * - * @author may - * @date 2024-03-29 - */ -@Validated -@RequiredArgsConstructor -@RestController -@RequestMapping("/formManage") -public class WfFormManageController extends BaseController { - - private final IWfFormManageService wfFormManageService; - - /** - * 查询表单管理列表 - */ - @SaCheckPermission("workflow:formManage:list") - @GetMapping("/list") - public TableDataInfo list(WfFormManageBo bo, PageQuery pageQuery) { - return wfFormManageService.queryPageList(bo, pageQuery); - } - - /** - * 查询表单管理列表 - */ - @SaCheckPermission("workflow:formManage:list") - @GetMapping("/list/selectList") - public R> selectList() { - return R.ok(wfFormManageService.selectList()); - } - - /** - * 导出表单管理列表 - */ - @SaCheckPermission("workflow:formManage:export") - @Log(title = "表单管理", businessType = BusinessType.EXPORT) - @PostMapping("/export") - public void export(WfFormManageBo bo, HttpServletResponse response) { - List list = wfFormManageService.queryList(bo); - ExcelUtil.exportExcel(list, "表单管理", WfFormManageVo.class, response); - } - - /** - * 获取表单管理详细信息 - * - * @param id 主键 - */ - @SaCheckPermission("workflow:formManage:query") - @GetMapping("/{id}") - public R getInfo(@NotNull(message = "主键不能为空") - @PathVariable Long id) { - return R.ok(wfFormManageService.queryById(id)); - } - - /** - * 新增表单管理 - */ - @SaCheckPermission("workflow:formManage:add") - @Log(title = "表单管理", businessType = BusinessType.INSERT) - @RepeatSubmit() - @PostMapping() - public R add(@Validated(AddGroup.class) @RequestBody WfFormManageBo bo) { - return toAjax(wfFormManageService.insertByBo(bo)); - } - - /** - * 修改表单管理 - */ - @SaCheckPermission("workflow:formManage:edit") - @Log(title = "表单管理", businessType = BusinessType.UPDATE) - @RepeatSubmit() - @PutMapping() - public R edit(@Validated(EditGroup.class) @RequestBody WfFormManageBo bo) { - return toAjax(wfFormManageService.updateByBo(bo)); - } - - /** - * 删除表单管理 - * - * @param ids 主键串 - */ - @SaCheckPermission("workflow:formManage:remove") - @Log(title = "表单管理", businessType = BusinessType.DELETE) - @DeleteMapping("/{ids}") - public R remove(@NotEmpty(message = "主键不能为空") - @PathVariable Long[] ids) { - return toAjax(wfFormManageService.deleteByIds(List.of(ids))); - } -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/ActHiProcinst.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/ActHiProcinst.java deleted file mode 100644 index e87fb92..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/ActHiProcinst.java +++ /dev/null @@ -1,152 +0,0 @@ -package org.dromara.workflow.domain; - -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import lombok.Data; - -import java.io.Serial; -import java.io.Serializable; -import java.util.Date; - -/** - * 流程实例对象 act_hi_procinst - * - * @author may - * @date 2023-07-22 - */ -@Data -@TableName("act_hi_procinst") -public class ActHiProcinst implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * - */ - @TableId(value = "ID_") - private String id; - - /** - * - */ - @TableField(value = "REV_") - private Long rev; - - /** - * - */ - @TableField(value = "PROC_INST_ID_") - private String procInstId; - - /** - * - */ - @TableField(value = "BUSINESS_KEY_") - private String businessKey; - - /** - * - */ - @TableField(value = "PROC_DEF_ID_") - private String procDefId; - - /** - * - */ - @TableField(value = "START_TIME_") - private Date startTime; - - /** - * - */ - @TableField(value = "END_TIME_") - private Date endTime; - - /** - * - */ - @TableField(value = "DURATION_") - private Long duration; - - /** - * - */ - @TableField(value = "START_USER_ID_") - private String startUserId; - - /** - * - */ - @TableField(value = "START_ACT_ID_") - private String startActId; - - /** - * - */ - @TableField(value = "END_ACT_ID_") - private String endActId; - - /** - * - */ - @TableField(value = "SUPER_PROCESS_INSTANCE_ID_") - private String superProcessInstanceId; - - /** - * - */ - @TableField(value = "DELETE_REASON_") - private String deleteReason; - - /** - * - */ - @TableField(value = "TENANT_ID_") - private String tenantId; - - /** - * - */ - @TableField(value = "NAME_") - private String name; - - /** - * - */ - @TableField(value = "CALLBACK_ID_") - private String callbackId; - - /** - * - */ - @TableField(value = "CALLBACK_TYPE_") - private String callbackType; - - /** - * - */ - @TableField(value = "REFERENCE_ID_") - private String referenceId; - - /** - * - */ - @TableField(value = "REFERENCE_TYPE_") - private String referenceType; - - /** - * - */ - @TableField(value = "PROPAGATED_STAGE_INST_ID_") - private String propagatedStageInstId; - - /** - * - */ - @TableField(value = "BUSINESS_STATUS_") - private String businessStatus; - - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/ActHiTaskinst.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/ActHiTaskinst.java deleted file mode 100644 index abc17b5..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/ActHiTaskinst.java +++ /dev/null @@ -1,193 +0,0 @@ -package org.dromara.workflow.domain; - -import com.baomidou.mybatisplus.annotation.*; -import lombok.Data; - -import java.io.Serializable; -import java.util.Date; - -import java.io.Serial; - -/** - * 流程历史任务对象 act_hi_taskinst - * - * @author may - * @date 2024-03-02 - */ -@Data -@TableName("act_hi_taskinst") -public class ActHiTaskinst implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * - */ - @TableId(value = "ID_") - private String id; - - /** - * 版本 - */ - @TableField(value = "REV_") - private Long rev; - - /** - * 流程定义id - */ - @TableField(value = "PROC_DEF_ID_") - private String procDefId; - - /** - * - */ - @TableField(value = "TASK_DEF_ID_") - private String taskDefId; - - /** - * 任务节点id - */ - @TableField(value = "TASK_DEF_KEY_") - private String taskDefKey; - - /** - * 流程实例id - */ - @TableField(value = "PROC_INST_ID_") - private String procInstId; - - /** - * 流程执行id - */ - @TableField(value = "EXECUTION_ID") - private String executionId; - - /** - * - */ - @TableField(value = "SCOPE_ID_") - private String scopeId; - - /** - * - */ - @TableField(value = "SUB_SCOPE_ID_") - private String subScopeId; - - /** - * 先用当前字段标识抄送类型 - */ - @TableField(value = "SCOPE_TYPE_") - private String scopeType; - - /** - * - */ - @TableField(value = "SCOPE_DEFINITION_ID_") - private String scopeDefinitionId; - - /** - * - */ - @TableField(value = "PROPAGATED_STAGE_INST_ID_") - private String propagatedStageInstId; - - /** - * 任务名称 - */ - @TableField(value = "NAME_") - private String name; - - /** - * 父级id - */ - @TableField(value = "PARENT_TASK_ID_") - private String parentTaskId; - - /** - * 描述 - */ - @TableField(value = "DESCRIPTION_") - private String description; - - /** - * 办理人 - */ - @TableField(value = "OWNER_") - private String owner; - - /** - * 办理人 - */ - @TableField(value = "ASSIGNEE_") - private String assignee; - - /** - * 开始事件 - */ - @TableField(value = "START_TIME_") - private Date startTime; - - /** - * 认领时间 - */ - @TableField(value = "CLAIM_TIME_") - private Date claimTime; - - /** - * 结束时间 - */ - @TableField(value = "END_TIME_") - private Date endTime; - - /** - * 持续时间 - */ - @TableField(value = "DURATION_") - private Long duration; - - /** - * 删除原因 - */ - @TableField(value = "DELETE_REASON_") - private String deleteReason; - - /** - * 优先级 - */ - @TableField(value = "PRIORITY_") - private Long priority; - - /** - * 到期时间 - */ - @TableField(value = "DUE_DATE_") - private Date dueDate; - - /** - * - */ - @TableField(value = "FORM_KEY_") - private String formKey; - - /** - * 分类 - */ - @TableField(value = "CATEGORY_") - private String category; - - /** - * 最后修改时间 - */ - @TableField(value = "LAST_UPDATED_TIME_") - private Date lastUpdatedTime; - - /** - * 租户id - */ - @TableField(value = "TENANT_ID_") - private String tenantId; - - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/TestLeave.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/TestLeave.java deleted file mode 100644 index 18e1c8a..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/TestLeave.java +++ /dev/null @@ -1,62 +0,0 @@ -package org.dromara.workflow.domain; - -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.dromara.common.mybatis.core.domain.BaseEntity; - -import java.io.Serial; -import java.util.Date; - -/** - * 请假对象 test_leave - * - * @author may - * @date 2023-07-21 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@TableName("test_leave") -public class TestLeave extends BaseEntity { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 主键 - */ - @TableId(value = "id") - private Long id; - - /** - * 请假类型 - */ - private String leaveType; - - /** - * 开始时间 - */ - private Date startDate; - - /** - * 结束时间 - */ - private Date endDate; - - /** - * 请假天数 - */ - private Integer leaveDays; - - /** - * 请假原因 - */ - private String remark; - - /** - * 状态 - */ - private String status; - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/WfCategory.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/WfCategory.java deleted file mode 100644 index 94a7cf5..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/WfCategory.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.dromara.workflow.domain; - -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.dromara.common.tenant.core.TenantEntity; - -import java.io.Serial; - -/** - * 流程分类对象 wf_category - * - * @author may - * @date 2023-06-27 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@TableName("wf_category") -public class WfCategory extends TenantEntity { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 主键 - */ - @TableId(value = "id") - private Long id; - - /** - * 分类名称 - */ - private String categoryName; - - /** - * 分类编码 - */ - private String categoryCode; - - /** - * 父级id - */ - private Long parentId; - - /** - * 排序 - */ - private Long sortNum; - - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/WfDefinitionConfig.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/WfDefinitionConfig.java deleted file mode 100644 index 11dcaa0..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/WfDefinitionConfig.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.dromara.workflow.domain; - -import org.dromara.common.mybatis.core.domain.BaseEntity; -import com.baomidou.mybatisplus.annotation.*; -import lombok.Data; -import lombok.EqualsAndHashCode; - -import java.io.Serial; - -/** - * 流程定义配置对象 wf_definition_config - * - * @author may - * @date 2024-03-18 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@TableName("wf_definition_config") -public class WfDefinitionConfig extends BaseEntity { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 主键 - */ - @TableId(value = "id") - private Long id; - - /** - * 表名 - */ - private String tableName; - - /** - * 流程定义ID - */ - private String definitionId; - - /** - * 流程KEY - */ - private String processKey; - - /** - * 流程版本 - */ - private Integer version; - - /** - * 备注 - */ - private String remark; - - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/WfFormManage.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/WfFormManage.java deleted file mode 100644 index 47f0d7a..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/WfFormManage.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.dromara.workflow.domain; - -import org.dromara.common.tenant.core.TenantEntity; -import com.baomidou.mybatisplus.annotation.*; -import lombok.Data; -import lombok.EqualsAndHashCode; - -import java.io.Serial; - -/** - * 表单管理对象 wf_form_manage - * - * @author may - * @date 2024-03-29 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@TableName("wf_form_manage") -public class WfFormManage extends TenantEntity { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 主键 - */ - @TableId(value = "id") - private Long id; - - /** - * 表单名称 - */ - private String formName; - - /** - * 表单类型 - */ - private String formType; - - /** - * 路由地址/表单ID - */ - private String router; - - /** - * 备注 - */ - private String remark; - - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/WfNodeConfig.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/WfNodeConfig.java deleted file mode 100644 index 999425f..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/WfNodeConfig.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.dromara.workflow.domain; - -import org.dromara.common.tenant.core.TenantEntity; -import com.baomidou.mybatisplus.annotation.*; -import lombok.Data; -import lombok.EqualsAndHashCode; - -import java.io.Serial; - -/** - * 节点配置对象 wf_node_config - * - * @author may - * @date 2024-03-30 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@TableName("wf_node_config") -public class WfNodeConfig extends TenantEntity { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 主键 - */ - @TableId(value = "id") - private Long id; - - /** - * 表单id - */ - private Long formId; - - /** - * 表单类型 - */ - private String formType; - - /** - * 节点名称 - */ - private String nodeName; - - /** - * 节点id - */ - private String nodeId; - - /** - * 流程定义id - */ - private String definitionId; - - /** - * 是否为申请人节点 (0是 1否) - */ - private String applyUserTask; - - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/WfTaskBackNode.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/WfTaskBackNode.java deleted file mode 100644 index 6f59727..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/WfTaskBackNode.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.dromara.workflow.domain; - -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.dromara.common.tenant.core.TenantEntity; - -import java.io.Serial; - -/** - * 节点驳回记录 wf_task_back_node - * - * @author may - * @date 2024-03-13 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@TableName("wf_task_back_node") -public class WfTaskBackNode extends TenantEntity { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 主键 - */ - @TableId(value = "id") - private Long id; - - /** - * 实例id - */ - private String instanceId; - - /** - * 节点id - */ - private String nodeId; - - /** - * 节点名称 - */ - private String nodeName; - - /** - * 排序 - */ - private Integer orderNo; - - /** - * 节点类型 - */ - private String taskType; - - /** - * 办理人 - */ - private String assignee; - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/AddMultiBo.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/AddMultiBo.java deleted file mode 100644 index 320ec64..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/AddMultiBo.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.dromara.workflow.domain.bo; - -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotEmpty; -import lombok.Data; -import org.dromara.common.core.validate.AddGroup; - -import java.io.Serial; -import java.io.Serializable; -import java.util.List; - -/** - * 加签参数请求 - * - * @author may - */ -@Data -public class AddMultiBo implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 任务ID - */ - @NotBlank(message = "任务ID不能为空", groups = AddGroup.class) - private String taskId; - - /** - * 加签人员id - */ - @NotEmpty(message = "加签人员不能为空", groups = AddGroup.class) - private List assignees; - - /** - * 加签人员名称 - */ - @NotEmpty(message = "加签人员不能为空", groups = AddGroup.class) - private List assigneeNames; -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java deleted file mode 100644 index d0f4369..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.dromara.workflow.domain.bo; - -import jakarta.validation.constraints.NotBlank; -import lombok.Data; -import org.dromara.common.core.validate.AddGroup; - -import java.io.Serial; -import java.io.Serializable; -import java.util.List; - - -/** - * 驳回参数请求 - * - * @author may - */ -@Data -public class BackProcessBo implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 任务ID - */ - @NotBlank(message = "任务ID不能为空", groups = AddGroup.class) - private String taskId; - - /** - * 消息类型 - */ - private List messageType; - - /** - * 驳回的节点id(目前未使用,直接驳回到申请人) - */ - @NotBlank(message = "驳回的节点不能为空", groups = AddGroup.class) - private String targetActivityId; - - /** - * 办理意见 - */ - private String message; -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/CompleteTaskBo.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/CompleteTaskBo.java deleted file mode 100644 index 0623905..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/CompleteTaskBo.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.dromara.workflow.domain.bo; - -import jakarta.validation.constraints.NotBlank; -import lombok.Data; -import org.dromara.common.core.validate.AddGroup; -import org.dromara.workflow.domain.vo.WfCopy; - -import java.io.Serial; -import java.io.Serializable; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -/** - * 办理任务请求对象 - * - * @author may - */ -@Data -public class CompleteTaskBo implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 任务id - */ - @NotBlank(message = "任务id不能为空", groups = {AddGroup.class}) - private String taskId; - - /** - * 附件id - */ - private String fileId; - - /** - * 抄送人员 - */ - private List wfCopyList; - - /** - * 消息类型 - */ - private List messageType; - - /** - * 办理意见 - */ - private String message; - - /** - * 流程变量 - */ - private Map variables; - - public Map getVariables() { - if (variables == null) { - return new HashMap<>(16); - } - variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue())); - return variables; - } - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/DelegateBo.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/DelegateBo.java deleted file mode 100644 index a6846a6..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/DelegateBo.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.dromara.workflow.domain.bo; - -import jakarta.validation.constraints.NotBlank; -import lombok.Data; -import org.dromara.common.core.validate.AddGroup; - -import java.io.Serial; -import java.io.Serializable; - -/** - * 委派任务请求对象 - * - * @author may - */ -@Data -public class DelegateBo implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 委派人id - */ - @NotBlank(message = "委派人id不能为空", groups = {AddGroup.class}) - private String userId; - - /** - * 委派人名称 - */ - @NotBlank(message = "委派人名称不能为空", groups = {AddGroup.class}) - private String nickName; - - /** - * 任务id - */ - @NotBlank(message = "任务id不能为空", groups = {AddGroup.class}) - private String taskId; -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/DeleteMultiBo.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/DeleteMultiBo.java deleted file mode 100644 index e533167..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/DeleteMultiBo.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.dromara.workflow.domain.bo; - -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotEmpty; -import lombok.Data; -import org.dromara.common.core.validate.AddGroup; - -import java.io.Serial; -import java.io.Serializable; -import java.util.List; - -/** - * 减签参数请求 - * - * @author may - */ -@Data -public class DeleteMultiBo implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 任务ID - */ - @NotBlank(message = "任务ID不能为空", groups = AddGroup.class) - private String taskId; - - /** - * 减签人员 - */ - @NotEmpty(message = "减签人员不能为空", groups = AddGroup.class) - private List taskIds; - - /** - * 执行id - */ - @NotEmpty(message = "执行id不能为空", groups = AddGroup.class) - private List executionIds; - - /** - * 人员id - */ - @NotEmpty(message = "减签人员id不能为空", groups = AddGroup.class) - private List assigneeIds; - - /** - * 人员名称 - */ - @NotEmpty(message = "减签人员不能为空", groups = AddGroup.class) - private List assigneeNames; -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/ModelBo.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/ModelBo.java deleted file mode 100644 index efe9acd..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/ModelBo.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.dromara.workflow.domain.bo; - -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.Pattern; -import lombok.Data; -import org.dromara.common.core.validate.AddGroup; -import org.dromara.common.core.validate.EditGroup; -import org.dromara.workflow.common.constant.FlowConstant; - -import java.io.Serial; -import java.io.Serializable; - -/** - * 模型请求对象 - * - * @author may - */ -@Data -public class ModelBo implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 模型id - */ - @NotBlank(message = "模型ID不能为空", groups = {EditGroup.class}) - private String id; - - /** - * 模型名称 - */ - @NotBlank(message = "模型名称不能为空", groups = {AddGroup.class}) - private String name; - - /** - * 模型标识key - */ - @NotBlank(message = "模型标识key不能为空", groups = {AddGroup.class}) - @Pattern(regexp = FlowConstant.MODEL_KEY_PATTERN, message = "模型标识key只能字符或者下划线开头", groups = {AddGroup.class}) - private String key; - - /** - * 模型分类 - */ - @NotBlank(message = "模型分类不能为空", groups = {AddGroup.class}) - private String categoryCode; - - /** - * 模型XML - */ - @NotBlank(message = "模型XML不能为空", groups = {AddGroup.class}) - private String xml; - - /** - * 模型SVG图片 - */ - @NotBlank(message = "模型SVG不能为空", groups = {EditGroup.class}) - private String svg; - - /** - * 备注 - */ - private String description; - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessDefinitionBo.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessDefinitionBo.java deleted file mode 100644 index 2025932..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessDefinitionBo.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.dromara.workflow.domain.bo; - -import lombok.Data; - -import java.io.Serial; -import java.io.Serializable; - -/** - * 流程定义请求对象 - * - * @author may - */ -@Data -public class ProcessDefinitionBo implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 流程定义名称key - */ - private String key; - - /** - * 流程定义名称 - */ - private String name; - - /** - * 模型分类 - */ - private String categoryCode; - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessInstanceBo.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessInstanceBo.java deleted file mode 100644 index 2833b3e..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessInstanceBo.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.dromara.workflow.domain.bo; - -import lombok.Data; - -import java.io.Serial; -import java.io.Serializable; - -/** - * 流程实例请求对象 - * - * @author may - */ -@Data -public class ProcessInstanceBo implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 流程名称 - */ - private String name; - - /** - * 流程key - */ - private String key; - - /** - * 任务发起人 - */ - private String startUserId; - - /** - * 业务id - */ - private String businessKey; - - /** - * 模型分类 - */ - private String categoryCode; -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessInvalidBo.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessInvalidBo.java deleted file mode 100644 index 41e51c2..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessInvalidBo.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.dromara.workflow.domain.bo; - -import jakarta.validation.constraints.NotBlank; -import lombok.Data; -import org.dromara.common.core.validate.AddGroup; - -import java.io.Serial; -import java.io.Serializable; - -/** - * 流程实例作废请求对象 - * - * @author may - */ -@Data -public class ProcessInvalidBo implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 业务id - */ - @NotBlank(message = "业务id不能为空", groups = {AddGroup.class}) - private String businessKey; - - /** - * 作废原因 - */ - private String deleteReason; -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/StartProcessBo.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/StartProcessBo.java deleted file mode 100644 index 7af7935..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/StartProcessBo.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.dromara.workflow.domain.bo; - - -import jakarta.validation.constraints.NotBlank; -import lombok.Data; -import org.dromara.common.core.validate.AddGroup; - -import java.io.Serial; -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; - -/** - * 启动流程对象 - * - * @author may - */ -@Data -public class StartProcessBo implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 业务唯一值id - */ - @NotBlank(message = "业务ID不能为空", groups = {AddGroup.class}) - private String businessKey; - - /** - * 表名 - */ - @NotBlank(message = "表名不能为空", groups = {AddGroup.class}) - private String tableName; - - /** - * 流程变量,前端会提交一个元素{'entity': {业务详情数据对象}} - */ - private Map variables; - - public Map getVariables() { - if (variables == null) { - return new HashMap<>(16); - } - variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue())); - return variables; - } -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/SysUserMultiBo.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/SysUserMultiBo.java deleted file mode 100644 index e4d99e4..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/SysUserMultiBo.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.dromara.workflow.domain.bo; - -import lombok.Data; - -import java.io.Serial; -import java.io.Serializable; - - -/** - * 用户加签查询 - * - * @author may - */ -@Data -public class SysUserMultiBo implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 人员名称 - */ - private String userName; - - /** - * 人员名称 - */ - private String nickName; - - /** - * 部门id - */ - private String deptId; - - /** - * 任务id - */ - private String taskId; -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/TaskBo.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/TaskBo.java deleted file mode 100644 index 3037479..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/TaskBo.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.dromara.workflow.domain.bo; - -import lombok.Data; - -import java.io.Serial; -import java.io.Serializable; - -/** - * 任务请求对象 - * - * @author may - */ -@Data -public class TaskBo implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 任务名称 - */ - private String name; - - /** - * 流程定义名称 - */ - private String processDefinitionName; - - /** - * 流程定义key - */ - private String processDefinitionKey; -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/TaskUrgingBo.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/TaskUrgingBo.java deleted file mode 100644 index 20856ef..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/TaskUrgingBo.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.dromara.workflow.domain.bo; - -import lombok.Data; - -import java.io.Serial; -import java.io.Serializable; -import java.util.List; - -/** - * 任务催办 - * - * @author may - */ -@Data -public class TaskUrgingBo implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 流程实例id - */ - private String processInstanceId; - - /** - * 消息类型 - */ - private List messageType; - - /** - * 催办内容(为空默认系统内置信息) - */ - private String message; -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/TerminationBo.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/TerminationBo.java deleted file mode 100644 index 8f2206e..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/TerminationBo.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.dromara.workflow.domain.bo; - -import jakarta.validation.constraints.NotBlank; -import lombok.Data; -import org.dromara.common.core.validate.AddGroup; - -import java.io.Serial; -import java.io.Serializable; - -/** - * 终止任务请求对象 - * - * @author may - */ -@Data -public class TerminationBo implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 任务id - */ - @NotBlank(message = "任务id为空", groups = AddGroup.class) - private String taskId; - - /** - * 审批意见 - */ - private String comment; -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/TestLeaveBo.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/TestLeaveBo.java deleted file mode 100644 index 877e981..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/TestLeaveBo.java +++ /dev/null @@ -1,80 +0,0 @@ -package org.dromara.workflow.domain.bo; - -import com.fasterxml.jackson.annotation.JsonFormat; -import io.github.linpeilie.annotations.AutoMapper; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.dromara.common.core.validate.AddGroup; -import org.dromara.common.core.validate.EditGroup; -import org.dromara.common.mybatis.core.domain.BaseEntity; -import org.dromara.workflow.domain.TestLeave; - -import java.util.Date; - -/** - * 请假业务对象 test_leave - * - * @author may - * @date 2023-07-21 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@AutoMapper(target = TestLeave.class, reverseConvertGenerate = false) -public class TestLeaveBo extends BaseEntity { - - /** - * 主键 - */ - @NotNull(message = "主键不能为空", groups = {EditGroup.class}) - private Long id; - - /** - * 请假类型 - */ - @NotBlank(message = "请假类型不能为空", groups = {AddGroup.class, EditGroup.class}) - private String leaveType; - - /** - * 开始时间 - */ - @NotNull(message = "开始时间不能为空", groups = {AddGroup.class, EditGroup.class}) - @JsonFormat(pattern = "yyyy-MM-dd") - private Date startDate; - - /** - * 结束时间 - */ - @NotNull(message = "结束时间不能为空", groups = {AddGroup.class, EditGroup.class}) - @JsonFormat(pattern = "yyyy-MM-dd") - private Date endDate; - - /** - * 请假天数 - */ - @NotNull(message = "请假天数不能为空", groups = {AddGroup.class, EditGroup.class}) - private Integer leaveDays; - - /** - * 开始时间 - */ - private Integer startLeaveDays; - - /** - * 结束时间 - */ - private Integer endLeaveDays; - - /** - * 请假原因 - */ - private String remark; - - /** - * 状态 - */ - private String status; - - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/TransmitBo.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/TransmitBo.java deleted file mode 100644 index 3eb6609..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/TransmitBo.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.dromara.workflow.domain.bo; - -import jakarta.validation.constraints.NotBlank; -import lombok.Data; -import org.dromara.common.core.validate.AddGroup; - -import java.io.Serial; -import java.io.Serializable; - -/** - * 终转办务请求对象 - * - * @author may - */ -@Data -public class TransmitBo implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 任务id - */ - @NotBlank(message = "任务id为空", groups = AddGroup.class) - private String taskId; - - /** - * 转办人id - */ - @NotBlank(message = "转办人不能为空", groups = AddGroup.class) - private String userId; - - /** - * 审批意见 - */ - private String comment; -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/WfCategoryBo.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/WfCategoryBo.java deleted file mode 100644 index 69608fd..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/WfCategoryBo.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.dromara.workflow.domain.bo; - -import io.github.linpeilie.annotations.AutoMapper; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.dromara.common.core.validate.AddGroup; -import org.dromara.common.core.validate.EditGroup; -import org.dromara.common.mybatis.core.domain.BaseEntity; -import org.dromara.workflow.domain.WfCategory; - -/** - * 流程分类业务对象 wf_category - * - * @author may - * @date 2023-06-27 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@AutoMapper(target = WfCategory.class, reverseConvertGenerate = false) -public class WfCategoryBo extends BaseEntity { - - /** - * 主键 - */ - @NotNull(message = "主键不能为空", groups = {EditGroup.class}) - private Long id; - - /** - * 分类名称 - */ - @NotBlank(message = "分类名称不能为空", groups = {AddGroup.class, EditGroup.class}) - private String categoryName; - - /** - * 分类编码 - */ - @NotBlank(message = "分类编码不能为空", groups = {AddGroup.class, EditGroup.class}) - private String categoryCode; - - /** - * 父级id - */ - @NotNull(message = "父级id不能为空", groups = {AddGroup.class, EditGroup.class}) - private Long parentId; - - /** - * 排序 - */ - private Long sortNum; - - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/WfDefinitionConfigBo.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/WfDefinitionConfigBo.java deleted file mode 100644 index fac1770..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/WfDefinitionConfigBo.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.dromara.workflow.domain.bo; - -import org.dromara.workflow.domain.WfDefinitionConfig; -import org.dromara.common.mybatis.core.domain.BaseEntity; -import org.dromara.common.core.validate.AddGroup; -import org.dromara.common.core.validate.EditGroup; -import io.github.linpeilie.annotations.AutoMapper; -import lombok.Data; -import lombok.EqualsAndHashCode; -import jakarta.validation.constraints.*; - -/** - * 流程定义配置业务对象 wf_form_definition - * - * @author may - * @date 2024-03-18 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@AutoMapper(target = WfDefinitionConfig.class, reverseConvertGenerate = false) -public class WfDefinitionConfigBo extends BaseEntity { - - /** - * 主键 - */ - @NotNull(message = "主键不能为空", groups = {EditGroup.class}) - private Long id; - - /** - * 表名 - */ - @NotBlank(message = "表名不能为空", groups = {AddGroup.class}) - private String tableName; - - /** - * 流程定义ID - */ - @NotBlank(message = "流程定义ID不能为空", groups = {AddGroup.class}) - private String definitionId; - - /** - * 流程KEY - */ - @NotBlank(message = "流程KEY不能为空", groups = {AddGroup.class}) - private String processKey; - - /** - * 流程版本 - */ - @NotNull(message = "流程版本不能为空", groups = {AddGroup.class}) - private Integer version; - - /** - * 备注 - */ - private String remark; - - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/WfFormManageBo.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/WfFormManageBo.java deleted file mode 100644 index 8afc286..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/WfFormManageBo.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.dromara.workflow.domain.bo; - -import org.dromara.workflow.domain.WfFormManage; -import org.dromara.common.mybatis.core.domain.BaseEntity; -import org.dromara.common.core.validate.AddGroup; -import org.dromara.common.core.validate.EditGroup; -import io.github.linpeilie.annotations.AutoMapper; -import lombok.Data; -import lombok.EqualsAndHashCode; -import jakarta.validation.constraints.*; - -/** - * 表单管理业务对象 wf_form_manage - * - * @author may - * @date 2024-03-29 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@AutoMapper(target = WfFormManage.class, reverseConvertGenerate = false) -public class WfFormManageBo extends BaseEntity { - - /** - * 主键 - */ - @NotNull(message = "主键不能为空", groups = { EditGroup.class }) - private Long id; - - /** - * 表单名称 - */ - @NotBlank(message = "表单名称不能为空", groups = { AddGroup.class, EditGroup.class }) - private String formName; - - /** - * 表单类型 - */ - @NotBlank(message = "表单类型不能为空", groups = { AddGroup.class, EditGroup.class }) - private String formType; - /** - * 路由地址/表单ID - */ - @NotBlank(message = "路由地址/表单ID不能为空", groups = { AddGroup.class, EditGroup.class }) - private String router; - - - /** - * 备注 - */ - private String remark; - - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/WfNodeConfigBo.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/WfNodeConfigBo.java deleted file mode 100644 index de518d3..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/bo/WfNodeConfigBo.java +++ /dev/null @@ -1,63 +0,0 @@ -package org.dromara.workflow.domain.bo; - -import org.dromara.workflow.domain.WfNodeConfig; -import org.dromara.common.mybatis.core.domain.BaseEntity; -import org.dromara.common.core.validate.AddGroup; -import org.dromara.common.core.validate.EditGroup; -import io.github.linpeilie.annotations.AutoMapper; -import lombok.Data; -import lombok.EqualsAndHashCode; -import jakarta.validation.constraints.*; - -/** - * 节点配置业务对象 wf_node_config - * - * @author may - * @date 2024-03-30 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@AutoMapper(target = WfNodeConfig.class, reverseConvertGenerate = false) -public class WfNodeConfigBo extends BaseEntity { - - /** - * 主键 - */ - @NotNull(message = "主键不能为空", groups = {EditGroup.class}) - private Long id; - - /** - * 表单id - */ - private Long formId; - - /** - * 表单类型 - */ - private String formType; - - /** - * 节点名称 - */ - @NotBlank(message = "节点名称不能为空", groups = {AddGroup.class, EditGroup.class}) - private String nodeName; - - /** - * 节点id - */ - @NotBlank(message = "节点id不能为空", groups = {AddGroup.class, EditGroup.class}) - private String nodeId; - - /** - * 流程定义id - */ - @NotBlank(message = "流程定义id不能为空", groups = {AddGroup.class, EditGroup.class}) - private String definitionId; - - /** - * 是否为申请人节点 (0是 1否) - */ - @NotBlank(message = "是否为申请人节点不能为空", groups = {AddGroup.class, EditGroup.class}) - private String applyUserTask; - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/ActHistoryInfoVo.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/ActHistoryInfoVo.java deleted file mode 100644 index e4c1142..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/ActHistoryInfoVo.java +++ /dev/null @@ -1,93 +0,0 @@ -package org.dromara.workflow.domain.vo; - -import lombok.Data; -import org.dromara.common.translation.annotation.Translation; -import org.dromara.common.translation.constant.TransConstant; -import org.flowable.engine.task.Attachment; - -import java.io.Serial; -import java.io.Serializable; -import java.util.Date; -import java.util.List; - -/** - * 流程审批记录视图 - * - * @author may - */ -@Data -public class ActHistoryInfoVo implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - /** - * 任务id - */ - private String id; - /** - * 节点id - */ - private String taskDefinitionKey; - /** - * 任务名称 - */ - private String name; - /** - * 流程实例id - */ - private String processInstanceId; - /** - * 版本 - */ - private Integer version; - /** - * 开始时间 - */ - private Date startTime; - /** - * 结束时间 - */ - private Date endTime; - /** - * 运行时长 - */ - private String runDuration; - /** - * 状态 - */ - private String status; - /** - * 状态 - */ - private String statusName; - /** - * 办理人id - */ - private String assignee; - - /** - * 办理人名称 - */ - @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "assignee") - private String nickName; - - /** - * 办理人id - */ - private String owner; - - /** - * 审批信息id - */ - private String commentId; - - /** - * 审批信息 - */ - private String comment; - - /** - * 审批附件 - */ - private List attachmentList; -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/GraphicInfoVo.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/GraphicInfoVo.java deleted file mode 100644 index 7636131..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/GraphicInfoVo.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.dromara.workflow.domain.vo; - -import lombok.Data; - -import java.io.Serial; -import java.io.Serializable; - -/** - * 节点图形信息 - * - * @author may - */ -@Data -public class GraphicInfoVo implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - /** - * x坐标 - */ - private double x; - - /** - * y坐标 - */ - private double y; - - /** - * 节点高度 - */ - private double height; - - /** - * 节点宽度 - */ - private double width; - - /** - * 节点id - */ - private String nodeId; - - /** - * 节点名称 - */ - private String nodeName; -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/ModelVo.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/ModelVo.java deleted file mode 100644 index b2ce811..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/ModelVo.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.dromara.workflow.domain.vo; - -import lombok.Data; - -import java.io.Serial; -import java.io.Serializable; - -/** - * 模型视图对象 - * - * @author may - */ -@Data -public class ModelVo implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 模型id - */ - private String id; - - /** - * 模型名称 - */ - private String name; - - /** - * 模型标识key - */ - private String key; - - /** - * 模型分类 - */ - private String categoryCode; - - /** - * 模型XML - */ - private String xml; - - /** - * 备注 - */ - private String description; -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/MultiInstanceVo.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/MultiInstanceVo.java deleted file mode 100644 index b998396..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/MultiInstanceVo.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.dromara.workflow.domain.vo; - -import lombok.Data; - -import java.io.Serial; -import java.io.Serializable; - -/** - * 多实例信息 - * - * @author may - */ -@Data -public class MultiInstanceVo implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 会签类型(串行,并行) - */ - private Object type; - - /** - * 会签人员KEY - */ - private String assignee; - - /** - * 会签人员集合KEY - */ - private String assigneeList; -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/ParticipantVo.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/ParticipantVo.java deleted file mode 100644 index c5876f6..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/ParticipantVo.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.dromara.workflow.domain.vo; - -import lombok.Data; - -import java.io.Serial; -import java.io.Serializable; -import java.util.List; - -/** - * 参与者 - * - * @author may - */ -@Data -public class ParticipantVo implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 组id(角色id) - */ - private List groupIds; - - /** - * 候选人id(用户id) 当组id不为空时,将组内人员查出放入candidate - */ - private List candidate; - - /** - * 候选人名称(用户名称) 当组id不为空时,将组内人员查出放入candidateName - */ - private List candidateName; - - /** - * 是否认领标识 - * 当为空时默认当前任务不需要认领 - * 当为true时当前任务说明为候选模式并且有人已经认领了任务可以归还, - * 当为false时当前任务说明为候选模式该任务未认领, - */ - private Boolean claim; - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/ProcessDefinitionVo.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/ProcessDefinitionVo.java deleted file mode 100644 index 034adbb..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/ProcessDefinitionVo.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.dromara.workflow.domain.vo; - -import lombok.Data; - -import java.io.Serial; -import java.io.Serializable; -import java.util.Date; - -/** - * 流程定义视图 - * - * @author may - */ -@Data -public class ProcessDefinitionVo implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 流程定义id - */ - private String id; - - /** - * 流程定义名称 - */ - private String name; - - /** - * 流程定义标识key - */ - private String key; - - /** - * 流程定义版本 - */ - private int version; - - /** - * 流程定义挂起或激活 1激活 2挂起 - */ - private int suspensionState; - - /** - * 流程xml名称 - */ - private String resourceName; - - /** - * 流程图片名称 - */ - private String diagramResourceName; - - /** - * 流程部署id - */ - private String deploymentId; - - /** - * 流程部署时间 - */ - private Date deploymentTime; - - /** - * 流程定义配置 - */ - private WfDefinitionConfigVo wfDefinitionConfigVo; - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/ProcessInstanceVo.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/ProcessInstanceVo.java deleted file mode 100644 index ab3e7a1..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/ProcessInstanceVo.java +++ /dev/null @@ -1,100 +0,0 @@ -package org.dromara.workflow.domain.vo; - -import lombok.Data; - -import java.io.Serial; -import java.io.Serializable; -import java.util.Date; -import java.util.List; - -/** - * 流程实例视图 - * - * @author may - */ -@Data -public class ProcessInstanceVo implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 流程实例id - */ - private String id; - - /** - * 流程定义id - */ - private String processDefinitionId; - - /** - * 流程定义名称 - */ - private String processDefinitionName; - - /** - * 流程定义key - */ - private String processDefinitionKey; - - /** - * 流程定义版本 - */ - private Integer processDefinitionVersion; - - /** - * 部署id - */ - private String deploymentId; - - /** - * 业务id - */ - private String businessKey; - - /** - * 是否挂起 - */ - private Boolean isSuspended; - - /** - * 租户id - */ - private String tenantId; - - /** - * 启动时间 - */ - private Date startTime; - - /** - * 结束时间 - */ - private Date endTime; - - /** - * 启动人id - */ - private String startUserId; - - /** - * 流程状态 - */ - private String businessStatus; - - /** - * 流程状态 - */ - private String businessStatusName; - - /** - * 待办任务集合 - */ - private List taskVoList; - - /** - * 节点配置 - */ - private WfNodeConfigVo wfNodeConfigVo; -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/TaskVo.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/TaskVo.java deleted file mode 100644 index 466e776..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/TaskVo.java +++ /dev/null @@ -1,173 +0,0 @@ -package org.dromara.workflow.domain.vo; - -import lombok.Data; -import org.dromara.common.translation.annotation.Translation; -import org.dromara.common.translation.constant.TransConstant; - -import java.io.Serial; -import java.io.Serializable; -import java.util.Date; - -/** - * 任务视图 - * - * @author may - */ -@Data -public class TaskVo implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 任务id - */ - private String id; - - /** - * 任务名称 - */ - private String name; - - /** - * 描述 - */ - private String description; - - /** - * 优先级 - */ - private Integer priority; - - /** - * 负责此任务的人员的用户id - */ - private String owner; - - /** - * 办理人id - */ - private Long assignee; - - /** - * 办理人 - */ - @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "assignee") - private String assigneeName; - - - /** - * 流程实例id - */ - private String processInstanceId; - - /** - * 执行id - */ - private String executionId; - - /** - * 无用 - */ - private String taskDefinitionId; - - /** - * 流程定义id - */ - private String processDefinitionId; - - /** - * 创建时间 - */ - private Date createTime; - - /** - * 已办任务-创建时间 - */ - private Date startTime; - - /** - * 结束时间 - */ - private Date endTime; - - /** - * 节点id - */ - private String taskDefinitionKey; - - /** - * 任务截止日期 - */ - private Date dueDate; - - /** - * 流程类别 - */ - private String category; - - /** - * 父级任务id - */ - private String parentTaskId; - - /** - * 租户id - */ - private String tenantId; - - /** - * 认领时间 - */ - private Date claimTime; - - /** - * 流程状态 - */ - private String businessStatus; - - /** - * 流程状态 - */ - private String businessStatusName; - - /** - * 流程定义名称 - */ - private String processDefinitionName; - - /** - * 流程定义key - */ - private String processDefinitionKey; - - /** - * 流程定义版本 - */ - private Integer processDefinitionVersion; - - /** - * 参与者 - */ - private ParticipantVo participantVo; - - /** - * 是否会签 - */ - private Boolean multiInstance; - - /** - * 业务id - */ - private String businessKey; - - /** - * 流程定义配置 - */ - private WfDefinitionConfigVo wfDefinitionConfigVo; - - /** - * 节点配置 - */ - private WfNodeConfigVo wfNodeConfigVo; -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/TestLeaveVo.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/TestLeaveVo.java deleted file mode 100644 index 47886d7..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/TestLeaveVo.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.dromara.workflow.domain.vo; - -import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; -import com.alibaba.excel.annotation.ExcelProperty; -import io.github.linpeilie.annotations.AutoMapper; -import lombok.Data; -import org.dromara.workflow.domain.TestLeave; - -import java.io.Serial; -import java.io.Serializable; -import java.util.Date; - - -/** - * 请假视图对象 test_leave - * - * @author may - * @date 2023-07-21 - */ -@Data -@ExcelIgnoreUnannotated -@AutoMapper(target = TestLeave.class) -public class TestLeaveVo implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 主键 - */ - @ExcelProperty(value = "主键") - private Long id; - - /** - * 请假类型 - */ - @ExcelProperty(value = "请假类型") - private String leaveType; - - /** - * 开始时间 - */ - @ExcelProperty(value = "开始时间") - private Date startDate; - - /** - * 结束时间 - */ - @ExcelProperty(value = "结束时间") - private Date endDate; - - /** - * 请假天数 - */ - @ExcelProperty(value = "请假天数") - private Integer leaveDays; - - /** - * 备注 - */ - @ExcelProperty(value = "请假原因") - private String remark; - - /** - * 状态 - */ - @ExcelProperty(value = "状态") - private String status; - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/VariableVo.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/VariableVo.java deleted file mode 100644 index 6a26c82..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/VariableVo.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.dromara.workflow.domain.vo; - -import lombok.Data; - -import java.io.Serial; -import java.io.Serializable; - -/** - * 流程变量 - * - * @author may - */ -@Data -public class VariableVo implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 变量key - */ - private String key; - - /** - * 变量值 - */ - private String value; -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/WfCategoryVo.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/WfCategoryVo.java deleted file mode 100644 index 362f646..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/WfCategoryVo.java +++ /dev/null @@ -1,58 +0,0 @@ -package org.dromara.workflow.domain.vo; - -import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; -import com.alibaba.excel.annotation.ExcelProperty; -import io.github.linpeilie.annotations.AutoMapper; -import lombok.Data; -import org.dromara.workflow.domain.WfCategory; - -import java.io.Serial; -import java.io.Serializable; - - -/** - * 流程分类视图对象 wf_category - * - * @author may - * @date 2023-06-27 - */ -@Data -@ExcelIgnoreUnannotated -@AutoMapper(target = WfCategory.class) -public class WfCategoryVo implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 主键 - */ - @ExcelProperty(value = "主键") - private Long id; - - /** - * 分类名称 - */ - @ExcelProperty(value = "分类名称") - private String categoryName; - - /** - * 分类编码 - */ - @ExcelProperty(value = "分类编码") - private String categoryCode; - - /** - * 父级id - */ - @ExcelProperty(value = "父级id") - private Long parentId; - - /** - * 排序 - */ - @ExcelProperty(value = "排序") - private Long sortNum; - - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/WfCopy.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/WfCopy.java deleted file mode 100644 index 88a5a21..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/WfCopy.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.dromara.workflow.domain.vo; - -import lombok.Data; - -import java.io.Serial; -import java.io.Serializable; - -/** - * 抄送 - * - * @author may - */ -@Data -public class WfCopy implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 用户id - */ - private Long userId; - - /** - * 用户名称 - */ - private String userName; - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/WfDefinitionConfigVo.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/WfDefinitionConfigVo.java deleted file mode 100644 index 9c7b0d7..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/WfDefinitionConfigVo.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.dromara.workflow.domain.vo; - -import org.dromara.workflow.domain.WfDefinitionConfig; -import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; -import com.alibaba.excel.annotation.ExcelProperty; -import io.github.linpeilie.annotations.AutoMapper; -import lombok.Data; - -import java.io.Serial; -import java.io.Serializable; - - -/** - * 流程定义配置视图对象 wf_definition_config - * - * @author may - * @date 2024-03-18 - */ -@Data -@ExcelIgnoreUnannotated -@AutoMapper(target = WfDefinitionConfig.class) -public class WfDefinitionConfigVo implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 主键 - */ - @ExcelProperty(value = "主键") - private Long id; - - /** - * 表名 - */ - @ExcelProperty(value = "表名") - private String tableName; - - /** - * 流程定义ID - */ - @ExcelProperty(value = "流程定义ID") - private String definitionId; - - /** - * 流程KEY - */ - @ExcelProperty(value = "流程KEY") - private String processKey; - - - /** - * 流程版本 - */ - @ExcelProperty(value = "流程版本") - private Integer version; - - /** - * 备注 - */ - @ExcelProperty(value = "备注") - private String remark; - - /** - * 表单管理 - */ - private WfFormManageVo wfFormManageVo; - - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/WfFormManageVo.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/WfFormManageVo.java deleted file mode 100644 index 302df23..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/WfFormManageVo.java +++ /dev/null @@ -1,63 +0,0 @@ -package org.dromara.workflow.domain.vo; - -import org.dromara.workflow.domain.WfFormManage; -import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; -import com.alibaba.excel.annotation.ExcelProperty; -import io.github.linpeilie.annotations.AutoMapper; -import lombok.Data; - -import java.io.Serial; -import java.io.Serializable; - - -/** - * 表单管理视图对象 wf_form_manage - * - * @author may - * @date 2024-03-29 - */ -@Data -@ExcelIgnoreUnannotated -@AutoMapper(target = WfFormManage.class) -public class WfFormManageVo implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 主键 - */ - @ExcelProperty(value = "主键") - private Long id; - - /** - * 表单名称 - */ - @ExcelProperty(value = "表单名称") - private String formName; - - /** - * 表单类型 - */ - @ExcelProperty(value = "表单类型") - private String formType; - - /** - * 表单类型名称 - */ - private String formTypeName; - - /** - * 路由地址/表单ID - */ - @ExcelProperty(value = "路由地址/表单ID") - private String router; - - /** - * 备注 - */ - @ExcelProperty(value = "备注") - private String remark; - - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/WfNodeConfigVo.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/WfNodeConfigVo.java deleted file mode 100644 index 89e9d9b..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/domain/vo/WfNodeConfigVo.java +++ /dev/null @@ -1,75 +0,0 @@ -package org.dromara.workflow.domain.vo; - -import org.dromara.workflow.domain.WfNodeConfig; -import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; -import com.alibaba.excel.annotation.ExcelProperty; -import io.github.linpeilie.annotations.AutoMapper; -import lombok.Data; - -import java.io.Serial; -import java.io.Serializable; - - -/** - * 节点配置视图对象 wf_node_config - * - * @author may - * @date 2024-03-30 - */ -@Data -@ExcelIgnoreUnannotated -@AutoMapper(target = WfNodeConfig.class) -public class WfNodeConfigVo implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 主键 - */ - @ExcelProperty(value = "主键") - private Long id; - - /** - * 表单id - */ - @ExcelProperty(value = "表单id") - private Long formId; - - /** - * 表单类型 - */ - @ExcelProperty(value = "表单类型") - private String formType; - - /** - * 节点名称 - */ - @ExcelProperty(value = "节点名称") - private String nodeName; - - /** - * 节点id - */ - @ExcelProperty(value = "节点id") - private String nodeId; - - /** - * 流程定义id - */ - @ExcelProperty(value = "流程定义id") - private String definitionId; - - /** - * 是否为申请人节点 (0是 1否) - */ - @ExcelProperty(value = "是否为申请人节点 (0是 1否)") - private String applyUserTask; - - /** - * 表单管理 - */ - private WfFormManageVo wfFormManageVo; - - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/dubbo/RemoteWorkflowServiceImpl.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/dubbo/RemoteWorkflowServiceImpl.java deleted file mode 100644 index a354b5e..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/dubbo/RemoteWorkflowServiceImpl.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.dromara.workflow.dubbo; - -import lombok.RequiredArgsConstructor; -import org.apache.dubbo.config.annotation.DubboService; -import org.dromara.workflow.api.domain.RemoteWorkflowService; -import org.dromara.workflow.service.IActHiProcinstService; -import org.dromara.workflow.service.WorkflowService; - -import java.util.List; -import java.util.Map; - -/** - * RemoteWorkflowServiceImpl - * - * @Author ZETA - * @Date 2024/6/3 - */ -@DubboService -@RequiredArgsConstructor -public class RemoteWorkflowServiceImpl implements RemoteWorkflowService { - - private final WorkflowService workflowService; - private final IActHiProcinstService actHiProcinstService; - - @Override - public boolean deleteRunAndHisInstance(List businessKeys) { - return workflowService.deleteRunAndHisInstance(businessKeys); - } - - @Override - public String getBusinessStatusByTaskId(String taskId) { - return workflowService.getBusinessStatusByTaskId(taskId); - } - - @Override - public String getBusinessStatus(String businessKey) { - return workflowService.getBusinessStatus(businessKey); - } - - @Override - public void setVariable(String taskId, String variableName, Object value) { - workflowService.setVariable(taskId, variableName, value); - } - - @Override - public void setVariables(String taskId, Map variables) { - workflowService.setVariables(taskId, variables); - } - - @Override - public void setVariableLocal(String taskId, String variableName, Object value) { - workflowService.setVariableLocal(taskId, variableName, value); - } - - @Override - public void setVariablesLocal(String taskId, Map variables) { - workflowService.setVariablesLocal(taskId, variables); - } - - /** - * 按照业务id查询流程实例id - * - * @param businessKey 业务id - * @return 结果 - */ - @Override - public String getInstanceIdByBusinessKey(String businessKey) { - return workflowService.getInstanceIdByBusinessKey(businessKey); - } -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/CustomDefaultProcessDiagramCanvas.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/CustomDefaultProcessDiagramCanvas.java deleted file mode 100644 index 39fd9d3..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/CustomDefaultProcessDiagramCanvas.java +++ /dev/null @@ -1,108 +0,0 @@ -package org.dromara.workflow.flowable; - -import org.flowable.bpmn.model.AssociationDirection; -import org.flowable.image.impl.DefaultProcessDiagramCanvas; - -import java.awt.*; -import java.awt.geom.Line2D; -import java.awt.geom.RoundRectangle2D; - -public class CustomDefaultProcessDiagramCanvas extends DefaultProcessDiagramCanvas { - //设置高亮线的颜色 这里我设置成绿色 - protected static Color HIGHLIGHT_SEQUENCEFLOW_COLOR = Color.GREEN; - - public CustomDefaultProcessDiagramCanvas(int width, int height, int minX, int minY, String imageType, String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) { - super(width, height, minX, minY, imageType, activityFontName, labelFontName, annotationFontName, customClassLoader); - } - - /** - * 画线颜色设置 - */ - public void drawConnection(int[] xPoints, int[] yPoints, boolean conditional, boolean isDefault, String connectionType, - AssociationDirection associationDirection, boolean highLighted, double scaleFactor) { - - Paint originalPaint = g.getPaint(); - Stroke originalStroke = g.getStroke(); - - g.setPaint(CONNECTION_COLOR); - if (connectionType.equals("association")) { - g.setStroke(ASSOCIATION_STROKE); - } else if (highLighted) { - //设置线的颜色 - g.setPaint(HIGHLIGHT_SEQUENCEFLOW_COLOR); - g.setStroke(HIGHLIGHT_FLOW_STROKE); - } - - for (int i = 1; i < xPoints.length; i++) { - Integer sourceX = xPoints[i - 1]; - Integer sourceY = yPoints[i - 1]; - Integer targetX = xPoints[i]; - Integer targetY = yPoints[i]; - Line2D.Double line = new Line2D.Double(sourceX, sourceY, targetX, targetY); - g.draw(line); - } - - if (isDefault) { - Line2D.Double line = new Line2D.Double(xPoints[0], yPoints[0], xPoints[1], yPoints[1]); - drawDefaultSequenceFlowIndicator(line, scaleFactor); - } - - if (conditional) { - Line2D.Double line = new Line2D.Double(xPoints[0], yPoints[0], xPoints[1], yPoints[1]); - drawConditionalSequenceFlowIndicator(line, scaleFactor); - } - - if (associationDirection == AssociationDirection.ONE || associationDirection == AssociationDirection.BOTH) { - Line2D.Double line = new Line2D.Double(xPoints[xPoints.length - 2], yPoints[xPoints.length - 2], xPoints[xPoints.length - 1], yPoints[xPoints.length - 1]); - drawArrowHead(line, scaleFactor); - } - if (associationDirection == AssociationDirection.BOTH) { - Line2D.Double line = new Line2D.Double(xPoints[1], yPoints[1], xPoints[0], yPoints[0]); - drawArrowHead(line, scaleFactor); - } - g.setPaint(originalPaint); - g.setStroke(originalStroke); - } - - /** - * 高亮节点设置 - */ - public void drawHighLight(int x, int y, int width, int height) { - Paint originalPaint = g.getPaint(); - Stroke originalStroke = g.getStroke(); - //设置高亮节点的颜色 - g.setPaint(HIGHLIGHT_COLOR); - g.setStroke(THICK_TASK_BORDER_STROKE); - - RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 20, 20); - g.draw(rect); - - g.setPaint(originalPaint); - g.setStroke(originalStroke); - } - - /** - * @description: 高亮节点红色 - * @param: x - * @param: y - * @param: width - * @param: height - * @return: void - * @author: gssong - * @date: 2022/4/12 - */ - public void drawHighLightRed(int x, int y, int width, int height) { - Paint originalPaint = g.getPaint(); - Stroke originalStroke = g.getStroke(); - //设置高亮节点的颜色 - g.setPaint(Color.green); - g.setStroke(THICK_TASK_BORDER_STROKE); - - RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 20, 20); - g.draw(rect); - - g.setPaint(originalPaint); - g.setStroke(originalStroke); - } - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/CustomDefaultProcessDiagramGenerator.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/CustomDefaultProcessDiagramGenerator.java deleted file mode 100644 index e4793a2..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/CustomDefaultProcessDiagramGenerator.java +++ /dev/null @@ -1,1120 +0,0 @@ -/* Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.dromara.workflow.flowable; - -import org.flowable.bpmn.model.Event; -import org.flowable.bpmn.model.Process; -import org.flowable.bpmn.model.*; -import org.flowable.image.ProcessDiagramGenerator; - -import java.awt.*; -import java.awt.image.BufferedImage; -import java.io.InputStream; -import java.util.List; -import java.util.*; - -/** - * Class to generate an image based the diagram interchange information in a BPMN 2.0 process. - * - * @author Joram Barrez - * @author Tijs Rademakers - * @author Zheng Ji - */ -public class CustomDefaultProcessDiagramGenerator implements ProcessDiagramGenerator { - - protected Map, ActivityDrawInstruction> activityDrawInstructions = new HashMap<>(); - protected Map, ArtifactDrawInstruction> artifactDrawInstructions = new HashMap<>(); - - public CustomDefaultProcessDiagramGenerator() { - this(1.0); - } - - // The instructions on how to draw a certain construct is - // created statically and stored in a map for performance. - public CustomDefaultProcessDiagramGenerator(final double scaleFactor) { - // start event - activityDrawInstructions.put(StartEvent.class, new ActivityDrawInstruction() { - - @Override - public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - StartEvent startEvent = (StartEvent) flowNode; - if (startEvent.getEventDefinitions() != null && !startEvent.getEventDefinitions().isEmpty()) { - EventDefinition eventDefinition = startEvent.getEventDefinitions().get(0); - if (eventDefinition instanceof TimerEventDefinition) { - processDiagramCanvas.drawTimerStartEvent(graphicInfo, scaleFactor); - } else if (eventDefinition instanceof ErrorEventDefinition) { - processDiagramCanvas.drawErrorStartEvent(graphicInfo, scaleFactor); - } else if (eventDefinition instanceof EscalationEventDefinition) { - processDiagramCanvas.drawEscalationStartEvent(graphicInfo, scaleFactor); - } else if (eventDefinition instanceof ConditionalEventDefinition) { - processDiagramCanvas.drawConditionalStartEvent(graphicInfo, scaleFactor); - } else if (eventDefinition instanceof SignalEventDefinition) { - processDiagramCanvas.drawSignalStartEvent(graphicInfo, scaleFactor); - } else if (eventDefinition instanceof MessageEventDefinition) { - processDiagramCanvas.drawMessageStartEvent(graphicInfo, scaleFactor); - } else { - processDiagramCanvas.drawNoneStartEvent(graphicInfo); - } - } else { - List eventTypeElements = startEvent.getExtensionElements().get("eventType"); - if (eventTypeElements != null && eventTypeElements.size() > 0) { - processDiagramCanvas.drawEventRegistryStartEvent(graphicInfo, scaleFactor); - - } else { - processDiagramCanvas.drawNoneStartEvent(graphicInfo); - } - } - } - }); - - // signal catch - activityDrawInstructions.put(IntermediateCatchEvent.class, new ActivityDrawInstruction() { - - @Override - public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - IntermediateCatchEvent intermediateCatchEvent = (IntermediateCatchEvent) flowNode; - if (intermediateCatchEvent.getEventDefinitions() != null && !intermediateCatchEvent.getEventDefinitions().isEmpty()) { - - if (intermediateCatchEvent.getEventDefinitions().get(0) instanceof SignalEventDefinition) { - processDiagramCanvas.drawCatchingSignalEvent(flowNode.getName(), graphicInfo, true, scaleFactor); - } else if (intermediateCatchEvent.getEventDefinitions().get(0) instanceof TimerEventDefinition) { - processDiagramCanvas.drawCatchingTimerEvent(flowNode.getName(), graphicInfo, true, scaleFactor); - } else if (intermediateCatchEvent.getEventDefinitions().get(0) instanceof MessageEventDefinition) { - processDiagramCanvas.drawCatchingMessageEvent(flowNode.getName(), graphicInfo, true, scaleFactor); - } else if (intermediateCatchEvent.getEventDefinitions().get(0) instanceof ConditionalEventDefinition) { - processDiagramCanvas.drawCatchingConditionalEvent(flowNode.getName(), graphicInfo, true, scaleFactor); - } - } - } - }); - - // signal throw - activityDrawInstructions.put(ThrowEvent.class, new ActivityDrawInstruction() { - - @Override - public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - ThrowEvent throwEvent = (ThrowEvent) flowNode; - if (throwEvent.getEventDefinitions() != null && !throwEvent.getEventDefinitions().isEmpty()) { - if (throwEvent.getEventDefinitions().get(0) instanceof SignalEventDefinition) { - processDiagramCanvas.drawThrowingSignalEvent(graphicInfo, scaleFactor); - } else if (throwEvent.getEventDefinitions().get(0) instanceof EscalationEventDefinition) { - processDiagramCanvas.drawThrowingEscalationEvent(graphicInfo, scaleFactor); - } else if (throwEvent.getEventDefinitions().get(0) instanceof CompensateEventDefinition) { - processDiagramCanvas.drawThrowingCompensateEvent(graphicInfo, scaleFactor); - } else { - processDiagramCanvas.drawThrowingNoneEvent(graphicInfo, scaleFactor); - } - } else { - processDiagramCanvas.drawThrowingNoneEvent(graphicInfo, scaleFactor); - } - } - }); - - // end event - activityDrawInstructions.put(EndEvent.class, new ActivityDrawInstruction() { - - @Override - public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - EndEvent endEvent = (EndEvent) flowNode; - if (endEvent.getEventDefinitions() != null && !endEvent.getEventDefinitions().isEmpty()) { - if (endEvent.getEventDefinitions().get(0) instanceof ErrorEventDefinition) { - processDiagramCanvas.drawErrorEndEvent(flowNode.getName(), graphicInfo, scaleFactor); - } else if (endEvent.getEventDefinitions().get(0) instanceof EscalationEventDefinition) { - processDiagramCanvas.drawEscalationEndEvent(flowNode.getName(), graphicInfo, scaleFactor); - } else { - processDiagramCanvas.drawNoneEndEvent(graphicInfo, scaleFactor); - } - } else { - processDiagramCanvas.drawNoneEndEvent(graphicInfo, scaleFactor); - } - } - }); - - // task - activityDrawInstructions.put(Task.class, new ActivityDrawInstruction() { - - @Override - public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawTask(flowNode.getName(), graphicInfo, scaleFactor); - } - }); - - // user task - activityDrawInstructions.put(UserTask.class, new ActivityDrawInstruction() { - - @Override - public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawUserTask(flowNode.getName(), graphicInfo, scaleFactor); - } - }); - - // script task - activityDrawInstructions.put(ScriptTask.class, new ActivityDrawInstruction() { - - @Override - public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawScriptTask(flowNode.getName(), graphicInfo, scaleFactor); - } - }); - - // service task - activityDrawInstructions.put(ServiceTask.class, new ActivityDrawInstruction() { - - @Override - public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - ServiceTask serviceTask = (ServiceTask) flowNode; - if ("camel".equalsIgnoreCase(serviceTask.getType())) { - processDiagramCanvas.drawCamelTask(serviceTask.getName(), graphicInfo, scaleFactor); - }else if (ServiceTask.HTTP_TASK.equalsIgnoreCase(serviceTask.getType())) { - processDiagramCanvas.drawHttpTask(serviceTask.getName(), graphicInfo, scaleFactor); - } else if (ServiceTask.DMN_TASK.equalsIgnoreCase(serviceTask.getType())) { - processDiagramCanvas.drawDMNTask(serviceTask.getName(), graphicInfo, scaleFactor); - } else if (ServiceTask.SHELL_TASK.equalsIgnoreCase(serviceTask.getType())) { - processDiagramCanvas.drawShellTask(serviceTask.getName(), graphicInfo, scaleFactor); - } else { - processDiagramCanvas.drawServiceTask(serviceTask.getName(), graphicInfo, scaleFactor); - } - } - }); - - // http service task - activityDrawInstructions.put(HttpServiceTask.class, new ActivityDrawInstruction() { - - @Override - public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawHttpTask(flowNode.getName(), graphicInfo, scaleFactor); - } - }); - - // receive task - activityDrawInstructions.put(ReceiveTask.class, new ActivityDrawInstruction() { - - @Override - public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawReceiveTask(flowNode.getName(), graphicInfo, scaleFactor); - } - }); - - // send task - activityDrawInstructions.put(SendTask.class, new ActivityDrawInstruction() { - - @Override - public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawSendTask(flowNode.getName(), graphicInfo, scaleFactor); - } - }); - - // manual task - activityDrawInstructions.put(ManualTask.class, new ActivityDrawInstruction() { - - @Override - public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawManualTask(flowNode.getName(), graphicInfo, scaleFactor); - } - }); - - // send event service task - activityDrawInstructions.put(SendEventServiceTask.class, new ActivityDrawInstruction() { - - @Override - public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawSendEventServiceTask(flowNode.getName(), graphicInfo, scaleFactor); - } - }); - - // external worker service task - activityDrawInstructions.put(ExternalWorkerServiceTask.class, new ActivityDrawInstruction() { - - @Override - public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - ServiceTask serviceTask = (ServiceTask) flowNode; - processDiagramCanvas.drawServiceTask(serviceTask.getName(), graphicInfo, scaleFactor); - } - }); - - // case service task - activityDrawInstructions.put(CaseServiceTask.class, new ActivityDrawInstruction() { - - @Override - public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawCaseServiceTask(flowNode.getName(), graphicInfo, scaleFactor); - } - }); - - // businessRuleTask task - activityDrawInstructions.put(BusinessRuleTask.class, new ActivityDrawInstruction() { - - @Override - public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawBusinessRuleTask(flowNode.getName(), graphicInfo, scaleFactor); - } - }); - - // exclusive gateway - activityDrawInstructions.put(ExclusiveGateway.class, new ActivityDrawInstruction() { - - @Override - public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawExclusiveGateway(graphicInfo, scaleFactor); - } - }); - - // inclusive gateway - activityDrawInstructions.put(InclusiveGateway.class, new ActivityDrawInstruction() { - - @Override - public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawInclusiveGateway(graphicInfo, scaleFactor); - } - }); - - // parallel gateway - activityDrawInstructions.put(ParallelGateway.class, new ActivityDrawInstruction() { - - @Override - public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawParallelGateway(graphicInfo, scaleFactor); - } - }); - - // event based gateway - activityDrawInstructions.put(EventGateway.class, new ActivityDrawInstruction() { - - @Override - public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawEventBasedGateway(graphicInfo, scaleFactor); - } - }); - - // Boundary timer - activityDrawInstructions.put(BoundaryEvent.class, new ActivityDrawInstruction() { - - @Override - public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - BoundaryEvent boundaryEvent = (BoundaryEvent) flowNode; - if (boundaryEvent.getEventDefinitions() != null && !boundaryEvent.getEventDefinitions().isEmpty()) { - EventDefinition eventDefinition = boundaryEvent.getEventDefinitions().get(0); - if (eventDefinition instanceof TimerEventDefinition) { - processDiagramCanvas.drawCatchingTimerEvent(flowNode.getName(), graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor); - - } else if (eventDefinition instanceof ConditionalEventDefinition) { - processDiagramCanvas.drawCatchingConditionalEvent(graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor); - - } else if (eventDefinition instanceof ErrorEventDefinition) { - processDiagramCanvas.drawCatchingErrorEvent(graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor); - - } else if (eventDefinition instanceof EscalationEventDefinition) { - processDiagramCanvas.drawCatchingEscalationEvent(graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor); - - } else if (eventDefinition instanceof SignalEventDefinition) { - processDiagramCanvas.drawCatchingSignalEvent(flowNode.getName(), graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor); - - } else if (eventDefinition instanceof MessageEventDefinition) { - processDiagramCanvas.drawCatchingMessageEvent(flowNode.getName(), graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor); - - } else if (eventDefinition instanceof CompensateEventDefinition) { - processDiagramCanvas.drawCatchingCompensateEvent(graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor); - } - - } else { - List eventTypeElements = boundaryEvent.getExtensionElements().get("eventType"); - if (eventTypeElements != null && eventTypeElements.size() > 0) { - processDiagramCanvas.drawCatchingEventRegistryEvent(flowNode.getName(), graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor); - } - } - } - }); - - // subprocess - activityDrawInstructions.put(SubProcess.class, new ActivityDrawInstruction() { - - @Override - public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - if (graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) { - processDiagramCanvas.drawCollapsedSubProcess(flowNode.getName(), graphicInfo, false, scaleFactor); - } else { - processDiagramCanvas.drawExpandedSubProcess(flowNode.getName(), graphicInfo, false, scaleFactor); - } - } - }); - - // transaction - activityDrawInstructions.put(Transaction.class, new ActivityDrawInstruction() { - - @Override - public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - if (graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) { - processDiagramCanvas.drawCollapsedSubProcess(flowNode.getName(), graphicInfo, false, scaleFactor); - } else { - processDiagramCanvas.drawExpandedTransaction(flowNode.getName(), graphicInfo, scaleFactor); - } - } - }); - - // Event subprocess - activityDrawInstructions.put(EventSubProcess.class, new ActivityDrawInstruction() { - - @Override - public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - if (graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) { - processDiagramCanvas.drawCollapsedSubProcess(flowNode.getName(), graphicInfo, true, scaleFactor); - } else { - processDiagramCanvas.drawExpandedSubProcess(flowNode.getName(), graphicInfo, true, scaleFactor); - } - } - }); - - // Adhoc subprocess - activityDrawInstructions.put(AdhocSubProcess.class, new ActivityDrawInstruction() { - - @Override - public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - if (graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) { - processDiagramCanvas.drawCollapsedSubProcess(flowNode.getName(), graphicInfo, false, scaleFactor); - } else { - processDiagramCanvas.drawExpandedSubProcess(flowNode.getName(), graphicInfo, false, scaleFactor); - } - } - }); - - // call activity - activityDrawInstructions.put(CallActivity.class, new ActivityDrawInstruction() { - - @Override - public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawCollapsedCallActivity(flowNode.getName(), graphicInfo, scaleFactor); - } - }); - - // text annotation - artifactDrawInstructions.put(TextAnnotation.class, new ArtifactDrawInstruction() { - - @Override - public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, Artifact artifact) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(artifact.getId()); - TextAnnotation textAnnotation = (TextAnnotation) artifact; - processDiagramCanvas.drawTextAnnotation(textAnnotation.getText(), graphicInfo, scaleFactor); - } - }); - - // association - artifactDrawInstructions.put(Association.class, new ArtifactDrawInstruction() { - - @Override - public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, Artifact artifact) { - Association association = (Association) artifact; - String sourceRef = association.getSourceRef(); - String targetRef = association.getTargetRef(); - - // source and target can be instance of FlowElement or Artifact - BaseElement sourceElement = bpmnModel.getFlowElement(sourceRef); - BaseElement targetElement = bpmnModel.getFlowElement(targetRef); - if (sourceElement == null) { - sourceElement = bpmnModel.getArtifact(sourceRef); - } - if (targetElement == null) { - targetElement = bpmnModel.getArtifact(targetRef); - } - List graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(artifact.getId()); - graphicInfoList = connectionPerfectionizer(processDiagramCanvas, bpmnModel, sourceElement, targetElement, graphicInfoList); - int[] xPoints = new int[graphicInfoList.size()]; - int[] yPoints = new int[graphicInfoList.size()]; - for (int i = 1; i < graphicInfoList.size(); i++) { - GraphicInfo graphicInfo = graphicInfoList.get(i); - GraphicInfo previousGraphicInfo = graphicInfoList.get(i - 1); - - if (i == 1) { - xPoints[0] = (int) previousGraphicInfo.getX(); - yPoints[0] = (int) previousGraphicInfo.getY(); - } - xPoints[i] = (int) graphicInfo.getX(); - yPoints[i] = (int) graphicInfo.getY(); - } - - AssociationDirection associationDirection = association.getAssociationDirection(); - processDiagramCanvas.drawAssociation(xPoints, yPoints, associationDirection, false, scaleFactor); - } - }); - } - - @Override - public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, List highLightedActivities, List highLightedFlows, - String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) { - - return generateProcessDiagram(bpmnModel, imageType, highLightedActivities, highLightedFlows, - activityFontName, labelFontName, annotationFontName, customClassLoader, scaleFactor, drawSequenceFlowNameWithNoLabelDI).generateImage(imageType); - } - - @Override - public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, List highLightedActivities, List highLightedFlows, boolean drawSequenceFlowNameWithNoLabelDI) { - return generateDiagram(bpmnModel, imageType, highLightedActivities, highLightedFlows, null, null, null, null, 1.0, drawSequenceFlowNameWithNoLabelDI); - } - - @Override - public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, - List highLightedActivities, List highLightedFlows, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) { - return generateDiagram(bpmnModel, imageType, highLightedActivities, highLightedFlows, null, null, null, null, scaleFactor, drawSequenceFlowNameWithNoLabelDI); - } - - @Override - public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, List highLightedActivities, boolean drawSequenceFlowNameWithNoLabelDI) { - return generateDiagram(bpmnModel, imageType, highLightedActivities, Collections.emptyList(), drawSequenceFlowNameWithNoLabelDI); - } - - @Override - public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, List highLightedActivities, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) { - return generateDiagram(bpmnModel, imageType, highLightedActivities, Collections.emptyList(), scaleFactor, drawSequenceFlowNameWithNoLabelDI); - } - - @Override - public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, String activityFontName, - String labelFontName, String annotationFontName, ClassLoader customClassLoader, boolean drawSequenceFlowNameWithNoLabelDI) { - - return generateDiagram(bpmnModel, imageType, Collections.emptyList(), Collections.emptyList(), - activityFontName, labelFontName, annotationFontName, customClassLoader, 1.0, drawSequenceFlowNameWithNoLabelDI); - } - - @Override - public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, String activityFontName, - String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) { - - return generateDiagram(bpmnModel, imageType, Collections.emptyList(), Collections.emptyList(), - activityFontName, labelFontName, annotationFontName, customClassLoader, scaleFactor, drawSequenceFlowNameWithNoLabelDI); - } - - @Override - public InputStream generatePngDiagram(BpmnModel bpmnModel, boolean drawSequenceFlowNameWithNoLabelDI) { - return generatePngDiagram(bpmnModel, 1.0, drawSequenceFlowNameWithNoLabelDI); - } - - @Override - public InputStream generatePngDiagram(BpmnModel bpmnModel, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) { - return generateDiagram(bpmnModel, "png", Collections.emptyList(), Collections.emptyList(), scaleFactor, drawSequenceFlowNameWithNoLabelDI); - } - - @Override - public InputStream generateJpgDiagram(BpmnModel bpmnModel) { - return generateJpgDiagram(bpmnModel, 1.0, false); - } - - @Override - public InputStream generateJpgDiagram(BpmnModel bpmnModel, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) { - return generateDiagram(bpmnModel, "jpg", Collections.emptyList(), Collections.emptyList(), drawSequenceFlowNameWithNoLabelDI); - } - - public BufferedImage generateImage(BpmnModel bpmnModel, String imageType, List highLightedActivities, List highLightedFlows, - String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) { - - return generateProcessDiagram(bpmnModel, imageType, highLightedActivities, highLightedFlows, - activityFontName, labelFontName, annotationFontName, customClassLoader, scaleFactor, drawSequenceFlowNameWithNoLabelDI).generateBufferedImage(imageType); - } - - public BufferedImage generateImage(BpmnModel bpmnModel, String imageType, - List highLightedActivities, List highLightedFlows, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) { - - return generateImage(bpmnModel, imageType, highLightedActivities, highLightedFlows, null, null, null, null, scaleFactor, drawSequenceFlowNameWithNoLabelDI); - } - - @Override - public BufferedImage generatePngImage(BpmnModel bpmnModel, double scaleFactor) { - return generateImage(bpmnModel, "png", Collections.emptyList(), Collections.emptyList(), scaleFactor, false); - } - - protected CustomDefaultProcessDiagramCanvas generateProcessDiagram(BpmnModel bpmnModel, String imageType, - List highLightedActivities, List highLightedFlows, - String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) { - - prepareBpmnModel(bpmnModel); - - CustomDefaultProcessDiagramCanvas processDiagramCanvas = initProcessDiagramCanvas(bpmnModel, imageType, activityFontName, labelFontName, annotationFontName, customClassLoader); - - // Draw pool shape, if process is participant in collaboration - for (Pool pool : bpmnModel.getPools()) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(pool.getId()); - processDiagramCanvas.drawPoolOrLane(pool.getName(), graphicInfo, scaleFactor); - } - - // Draw lanes - for (Process process : bpmnModel.getProcesses()) { - for (Lane lane : process.getLanes()) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(lane.getId()); - processDiagramCanvas.drawPoolOrLane(lane.getName(), graphicInfo, scaleFactor); - } - } - - // Draw activities and their sequence-flows - for (Process process : bpmnModel.getProcesses()) { - for (FlowNode flowNode : process.findFlowElementsOfType(FlowNode.class)) { - if (!isPartOfCollapsedSubProcess(flowNode, bpmnModel)) { - drawActivity(processDiagramCanvas, bpmnModel, flowNode, highLightedActivities, highLightedFlows, scaleFactor, drawSequenceFlowNameWithNoLabelDI); - } - } - } - - // Draw artifacts - for (Process process : bpmnModel.getProcesses()) { - - for (Artifact artifact : process.getArtifacts()) { - drawArtifact(processDiagramCanvas, bpmnModel, artifact); - } - - List subProcesses = process.findFlowElementsOfType(SubProcess.class, true); - if (subProcesses != null) { - for (SubProcess subProcess : subProcesses) { - - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(subProcess.getId()); - if (graphicInfo != null && graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) { - continue; - } - - if (!isPartOfCollapsedSubProcess(subProcess, bpmnModel)) { - for (Artifact subProcessArtifact : subProcess.getArtifacts()) { - drawArtifact(processDiagramCanvas, bpmnModel, subProcessArtifact); - } - } - } - } - } - - return processDiagramCanvas; - } - - protected void prepareBpmnModel(BpmnModel bpmnModel) { - - // Need to make sure all elements have positive x and y. - // Check all graphicInfo and update the elements accordingly - - List allGraphicInfos = new ArrayList<>(); - if (bpmnModel.getLocationMap() != null) { - allGraphicInfos.addAll(bpmnModel.getLocationMap().values()); - } - if (bpmnModel.getLabelLocationMap() != null) { - allGraphicInfos.addAll(bpmnModel.getLabelLocationMap().values()); - } - if (bpmnModel.getFlowLocationMap() != null) { - for (List flowGraphicInfos : bpmnModel.getFlowLocationMap().values()) { - allGraphicInfos.addAll(flowGraphicInfos); - } - } - - if (allGraphicInfos.size() > 0) { - - boolean needsTranslationX = false; - boolean needsTranslationY = false; - - double lowestX = 0.0; - double lowestY = 0.0; - - // Collect lowest x and y - for (GraphicInfo graphicInfo : allGraphicInfos) { - - double x = graphicInfo.getX(); - double y = graphicInfo.getY(); - - if (x < lowestX) { - needsTranslationX = true; - lowestX = x; - } - if (y < lowestY) { - needsTranslationY = true; - lowestY = y; - } - - } - - // Update all graphicInfo objects - if (needsTranslationX || needsTranslationY) { - - double translationX = Math.abs(lowestX); - double translationY = Math.abs(lowestY); - - for (GraphicInfo graphicInfo : allGraphicInfos) { - if (needsTranslationX) { - graphicInfo.setX(graphicInfo.getX() + translationX); - } - if (needsTranslationY) { - graphicInfo.setY(graphicInfo.getY() + translationY); - } - } - } - - } - - } - - protected void drawActivity(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, - FlowNode flowNode, List highLightedActivities, List highLightedFlows, double scaleFactor, Boolean drawSequenceFlowNameWithNoLabelDI) { - - ActivityDrawInstruction drawInstruction = activityDrawInstructions.get(flowNode.getClass()); - if (drawInstruction != null) { - - drawInstruction.draw(processDiagramCanvas, bpmnModel, flowNode); - - // Gather info on the multi instance marker - boolean multiInstanceSequential = false; - boolean multiInstanceParallel = false; - boolean collapsed = false; - if (flowNode instanceof Activity) { - Activity activity = (Activity) flowNode; - MultiInstanceLoopCharacteristics multiInstanceLoopCharacteristics = activity.getLoopCharacteristics(); - if (multiInstanceLoopCharacteristics != null) { - multiInstanceSequential = multiInstanceLoopCharacteristics.isSequential(); - multiInstanceParallel = !multiInstanceSequential; - } - } - - // Gather info on the collapsed marker - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - if (flowNode instanceof SubProcess) { - collapsed = graphicInfo.getExpanded() != null && !graphicInfo.getExpanded(); - } else if (flowNode instanceof CallActivity) { - collapsed = true; - } - - if (scaleFactor == 1.0) { - // Actually draw the markers - processDiagramCanvas.drawActivityMarkers((int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight(), - multiInstanceSequential, multiInstanceParallel, collapsed); - } - - // Draw highlighted activities - if (highLightedActivities.contains(flowNode.getId())) { - drawHighLightRed(processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId())); - } else if (highLightedActivities.contains(Color.RED.toString() + flowNode.getId())) { - drawHighLight(processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId())); - } - - } else if (flowNode instanceof Task) { - activityDrawInstructions.get(Task.class).draw(processDiagramCanvas, bpmnModel, flowNode); - - if (highLightedActivities.contains(flowNode.getId())) { - drawHighLightRed(processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId())); - } else if (highLightedActivities.contains(Color.RED.toString() + flowNode.getId())) { - drawHighLight(processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId())); - } - } - - // Outgoing transitions of activity - for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) { - boolean highLighted = (highLightedFlows.contains(sequenceFlow.getId())); - String defaultFlow = null; - if (flowNode instanceof Activity) { - defaultFlow = ((Activity) flowNode).getDefaultFlow(); - } else if (flowNode instanceof Gateway) { - defaultFlow = ((Gateway) flowNode).getDefaultFlow(); - } - - boolean isDefault = false; - if (defaultFlow != null && defaultFlow.equalsIgnoreCase(sequenceFlow.getId())) { - isDefault = true; - } - boolean drawConditionalIndicator = sequenceFlow.getConditionExpression() != null && sequenceFlow.getConditionExpression().trim().length() > 0 && !(flowNode instanceof Gateway); - - String sourceRef = sequenceFlow.getSourceRef(); - String targetRef = sequenceFlow.getTargetRef(); - FlowElement sourceElement = bpmnModel.getFlowElement(sourceRef); - FlowElement targetElement = bpmnModel.getFlowElement(targetRef); - List graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(sequenceFlow.getId()); - if (graphicInfoList != null && graphicInfoList.size() > 0) { - graphicInfoList = connectionPerfectionizer(processDiagramCanvas, bpmnModel, sourceElement, targetElement, graphicInfoList); - int[] xPoints = new int[graphicInfoList.size()]; - int[] yPoints = new int[graphicInfoList.size()]; - - for (int i = 1; i < graphicInfoList.size(); i++) { - GraphicInfo graphicInfo = graphicInfoList.get(i); - GraphicInfo previousGraphicInfo = graphicInfoList.get(i - 1); - - if (i == 1) { - xPoints[0] = (int) previousGraphicInfo.getX(); - yPoints[0] = (int) previousGraphicInfo.getY(); - } - xPoints[i] = (int) graphicInfo.getX(); - yPoints[i] = (int) graphicInfo.getY(); - - } - - processDiagramCanvas.drawSequenceflow(xPoints, yPoints, drawConditionalIndicator, isDefault, highLighted, scaleFactor); - - // Draw sequenceflow label - GraphicInfo labelGraphicInfo = bpmnModel.getLabelGraphicInfo(sequenceFlow.getId()); - if (labelGraphicInfo != null) { - processDiagramCanvas.drawLabel(sequenceFlow.getName(), labelGraphicInfo, false); - } else { - if (drawSequenceFlowNameWithNoLabelDI) { - GraphicInfo lineCenter = getLineCenter(graphicInfoList); - processDiagramCanvas.drawLabel(sequenceFlow.getName(), lineCenter, false); - } - - } - } - } - - // Nested elements - if (flowNode instanceof FlowElementsContainer) { - for (FlowElement nestedFlowElement : ((FlowElementsContainer) flowNode).getFlowElements()) { - if (nestedFlowElement instanceof FlowNode && !isPartOfCollapsedSubProcess(nestedFlowElement, bpmnModel)) { - drawActivity(processDiagramCanvas, bpmnModel, (FlowNode) nestedFlowElement, - highLightedActivities, highLightedFlows, scaleFactor, drawSequenceFlowNameWithNoLabelDI); - } - } - } - } - - /** - * This method makes coordinates of connection flow better. - * - * @param processDiagramCanvas - * @param bpmnModel - * @param sourceElement - * @param targetElement - * @param graphicInfoList - * @return - */ - protected static List connectionPerfectionizer(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, BaseElement sourceElement, BaseElement targetElement, List graphicInfoList) { - GraphicInfo sourceGraphicInfo = bpmnModel.getGraphicInfo(sourceElement.getId()); - GraphicInfo targetGraphicInfo = bpmnModel.getGraphicInfo(targetElement.getId()); - - CustomDefaultProcessDiagramCanvas.SHAPE_TYPE sourceShapeType = getShapeType(sourceElement); - CustomDefaultProcessDiagramCanvas.SHAPE_TYPE targetShapeType = getShapeType(targetElement); - - return processDiagramCanvas.connectionPerfectionizer(sourceShapeType, targetShapeType, sourceGraphicInfo, targetGraphicInfo, graphicInfoList); - } - - /** - * This method returns shape type of base element.
- * Each element can be presented as rectangle, rhombus, or ellipse. - * - * @param baseElement - * @return CustomDefaultProcessDiagramCanvas.SHAPE_TYPE - */ - protected static CustomDefaultProcessDiagramCanvas.SHAPE_TYPE getShapeType(BaseElement baseElement) { - if (baseElement instanceof Task || baseElement instanceof Activity || baseElement instanceof TextAnnotation) { - return CustomDefaultProcessDiagramCanvas.SHAPE_TYPE.Rectangle; - } else if (baseElement instanceof Gateway) { - return CustomDefaultProcessDiagramCanvas.SHAPE_TYPE.Rhombus; - } else if (baseElement instanceof Event) { - return CustomDefaultProcessDiagramCanvas.SHAPE_TYPE.Ellipse; - } else { - // unknown source element, just do not correct coordinates - } - return null; - } - - protected static GraphicInfo getLineCenter(List graphicInfoList) { - GraphicInfo gi = new GraphicInfo(); - - int[] xPoints = new int[graphicInfoList.size()]; - int[] yPoints = new int[graphicInfoList.size()]; - - double length = 0; - double[] lengths = new double[graphicInfoList.size()]; - lengths[0] = 0; - double m; - for (int i = 1; i < graphicInfoList.size(); i++) { - GraphicInfo graphicInfo = graphicInfoList.get(i); - GraphicInfo previousGraphicInfo = graphicInfoList.get(i - 1); - - if (i == 1) { - xPoints[0] = (int) previousGraphicInfo.getX(); - yPoints[0] = (int) previousGraphicInfo.getY(); - } - xPoints[i] = (int) graphicInfo.getX(); - yPoints[i] = (int) graphicInfo.getY(); - - length += Math.sqrt( - Math.pow((int) graphicInfo.getX() - (int) previousGraphicInfo.getX(), 2) + - Math.pow((int) graphicInfo.getY() - (int) previousGraphicInfo.getY(), 2)); - lengths[i] = length; - } - m = length / 2; - int p1 = 0; - int p2 = 1; - for (int i = 1; i < lengths.length; i++) { - double len = lengths[i]; - p1 = i - 1; - p2 = i; - if (len > m) { - break; - } - } - - GraphicInfo graphicInfo1 = graphicInfoList.get(p1); - GraphicInfo graphicInfo2 = graphicInfoList.get(p2); - - double AB = (int) graphicInfo2.getX() - (int) graphicInfo1.getX(); - double OA = (int) graphicInfo2.getY() - (int) graphicInfo1.getY(); - double OB = lengths[p2] - lengths[p1]; - double ob = m - lengths[p1]; - double ab = AB * ob / OB; - double oa = OA * ob / OB; - - double mx = graphicInfo1.getX() + ab; - double my = graphicInfo1.getY() + oa; - - gi.setX(mx); - gi.setY(my); - return gi; - } - - protected void drawArtifact(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, Artifact artifact) { - - ArtifactDrawInstruction drawInstruction = artifactDrawInstructions.get(artifact.getClass()); - if (drawInstruction != null) { - drawInstruction.draw(processDiagramCanvas, bpmnModel, artifact); - } - } - - private static void drawHighLight(CustomDefaultProcessDiagramCanvas processDiagramCanvas, GraphicInfo graphicInfo) { - processDiagramCanvas.drawHighLight((int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight()); - - } - - private static void drawHighLightRed(CustomDefaultProcessDiagramCanvas processDiagramCanvas, GraphicInfo graphicInfo) { - processDiagramCanvas.drawHighLightRed((int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight()); - - } - - protected static CustomDefaultProcessDiagramCanvas initProcessDiagramCanvas(BpmnModel bpmnModel, String imageType, - String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) { - - // We need to calculate maximum values to know how big the image will be in its entirety - double minX = Double.MAX_VALUE; - double maxX = 0; - double minY = Double.MAX_VALUE; - double maxY = 0; - - for (Pool pool : bpmnModel.getPools()) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(pool.getId()); - minX = graphicInfo.getX(); - maxX = graphicInfo.getX() + graphicInfo.getWidth(); - minY = graphicInfo.getY(); - maxY = graphicInfo.getY() + graphicInfo.getHeight(); - } - - List flowNodes = gatherAllFlowNodes(bpmnModel); - for (FlowNode flowNode : flowNodes) { - - GraphicInfo flowNodeGraphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - - // width - if (flowNodeGraphicInfo.getX() + flowNodeGraphicInfo.getWidth() > maxX) { - maxX = flowNodeGraphicInfo.getX() + flowNodeGraphicInfo.getWidth(); - } - if (flowNodeGraphicInfo.getX() < minX) { - minX = flowNodeGraphicInfo.getX(); - } - // height - if (flowNodeGraphicInfo.getY() + flowNodeGraphicInfo.getHeight() > maxY) { - maxY = flowNodeGraphicInfo.getY() + flowNodeGraphicInfo.getHeight(); - } - if (flowNodeGraphicInfo.getY() < minY) { - minY = flowNodeGraphicInfo.getY(); - } - - for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) { - List graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(sequenceFlow.getId()); - if (graphicInfoList != null) { - for (GraphicInfo graphicInfo : graphicInfoList) { - // width - if (graphicInfo.getX() > maxX) { - maxX = graphicInfo.getX(); - } - if (graphicInfo.getX() < minX) { - minX = graphicInfo.getX(); - } - // height - if (graphicInfo.getY() > maxY) { - maxY = graphicInfo.getY(); - } - if (graphicInfo.getY() < minY) { - minY = graphicInfo.getY(); - } - } - } - } - } - - List artifacts = gatherAllArtifacts(bpmnModel); - for (Artifact artifact : artifacts) { - - GraphicInfo artifactGraphicInfo = bpmnModel.getGraphicInfo(artifact.getId()); - - if (artifactGraphicInfo != null) { - // width - if (artifactGraphicInfo.getX() + artifactGraphicInfo.getWidth() > maxX) { - maxX = artifactGraphicInfo.getX() + artifactGraphicInfo.getWidth(); - } - if (artifactGraphicInfo.getX() < minX) { - minX = artifactGraphicInfo.getX(); - } - // height - if (artifactGraphicInfo.getY() + artifactGraphicInfo.getHeight() > maxY) { - maxY = artifactGraphicInfo.getY() + artifactGraphicInfo.getHeight(); - } - if (artifactGraphicInfo.getY() < minY) { - minY = artifactGraphicInfo.getY(); - } - } - - List graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(artifact.getId()); - if (graphicInfoList != null) { - for (GraphicInfo graphicInfo : graphicInfoList) { - // width - if (graphicInfo.getX() > maxX) { - maxX = graphicInfo.getX(); - } - if (graphicInfo.getX() < minX) { - minX = graphicInfo.getX(); - } - // height - if (graphicInfo.getY() > maxY) { - maxY = graphicInfo.getY(); - } - if (graphicInfo.getY() < minY) { - minY = graphicInfo.getY(); - } - } - } - } - - int nrOfLanes = 0; - for (Process process : bpmnModel.getProcesses()) { - for (Lane l : process.getLanes()) { - - nrOfLanes++; - - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(l.getId()); - // // width - if (graphicInfo.getX() + graphicInfo.getWidth() > maxX) { - maxX = graphicInfo.getX() + graphicInfo.getWidth(); - } - if (graphicInfo.getX() < minX) { - minX = graphicInfo.getX(); - } - // height - if (graphicInfo.getY() + graphicInfo.getHeight() > maxY) { - maxY = graphicInfo.getY() + graphicInfo.getHeight(); - } - if (graphicInfo.getY() < minY) { - minY = graphicInfo.getY(); - } - } - } - - // Special case, see https://activiti.atlassian.net/browse/ACT-1431 - if (flowNodes.isEmpty() && bpmnModel.getPools().isEmpty() && nrOfLanes == 0) { - // Nothing to show - minX = 0; - minY = 0; - } - - return new CustomDefaultProcessDiagramCanvas((int) maxX + 10, (int) maxY + 10, (int) minX, (int) minY, - imageType, activityFontName, labelFontName, annotationFontName, customClassLoader); - } - - protected static List gatherAllArtifacts(BpmnModel bpmnModel) { - List artifacts = new ArrayList<>(); - for (Process process : bpmnModel.getProcesses()) { - artifacts.addAll(process.getArtifacts()); - } - return artifacts; - } - - protected static List gatherAllFlowNodes(BpmnModel bpmnModel) { - List flowNodes = new ArrayList<>(); - for (Process process : bpmnModel.getProcesses()) { - flowNodes.addAll(gatherAllFlowNodes(process)); - } - return flowNodes; - } - - protected static List gatherAllFlowNodes(FlowElementsContainer flowElementsContainer) { - List flowNodes = new ArrayList<>(); - for (FlowElement flowElement : flowElementsContainer.getFlowElements()) { - if (flowElement instanceof FlowNode) { - flowNodes.add((FlowNode) flowElement); - } - if (flowElement instanceof FlowElementsContainer) { - flowNodes.addAll(gatherAllFlowNodes((FlowElementsContainer) flowElement)); - } - } - return flowNodes; - } - - protected boolean isPartOfCollapsedSubProcess(FlowElement flowElement, BpmnModel model) { - SubProcess subProcess = flowElement.getSubProcess(); - if (subProcess != null) { - GraphicInfo graphicInfo = model.getGraphicInfo(subProcess.getId()); - if (graphicInfo != null && graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) { - return true; - } - - return isPartOfCollapsedSubProcess(subProcess, model); - } - - return false; - } - - public Map, ActivityDrawInstruction> getActivityDrawInstructions() { - return activityDrawInstructions; - } - - public void setActivityDrawInstructions( - Map, ActivityDrawInstruction> activityDrawInstructions) { - this.activityDrawInstructions = activityDrawInstructions; - } - - public Map, ArtifactDrawInstruction> getArtifactDrawInstructions() { - return artifactDrawInstructions; - } - - public void setArtifactDrawInstructions( - Map, ArtifactDrawInstruction> artifactDrawInstructions) { - this.artifactDrawInstructions = artifactDrawInstructions; - } - - protected interface ActivityDrawInstruction { - void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode); - } - - protected interface ArtifactDrawInstruction { - void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, Artifact artifact); - } -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/cmd/AddSequenceMultiInstanceCmd.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/cmd/AddSequenceMultiInstanceCmd.java deleted file mode 100644 index 3cdfcf4..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/cmd/AddSequenceMultiInstanceCmd.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.dromara.workflow.flowable.cmd; - -import cn.hutool.core.collection.CollUtil; -import org.flowable.common.engine.impl.interceptor.Command; -import org.flowable.common.engine.impl.interceptor.CommandContext; -import org.flowable.engine.impl.persistence.entity.ExecutionEntity; -import org.flowable.engine.impl.persistence.entity.ExecutionEntityManager; -import org.flowable.engine.impl.util.CommandContextUtil; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static org.dromara.workflow.common.constant.FlowConstant.NUMBER_OF_INSTANCES; - -/** - * 串行加签 - * - * @author may - */ -public class AddSequenceMultiInstanceCmd implements Command { - - /** - * 执行id - */ - private final String executionId; - - /** - * 会签人员集合KEY - */ - private final String assigneeList; - - /** - * 加签人员 - */ - private final List assignees; - - public AddSequenceMultiInstanceCmd(String executionId, String assigneeList, List assignees) { - this.executionId = executionId; - this.assigneeList = assigneeList; - this.assignees = assignees; - } - - @Override - public Void execute(CommandContext commandContext) { - ExecutionEntityManager executionEntityManager = CommandContextUtil.getExecutionEntityManager(); - ExecutionEntity entity = executionEntityManager.findById(executionId); - // 多实例任务总数加 assignees.size() - if (entity.getVariable(NUMBER_OF_INSTANCES) instanceof Integer nrOfInstances) { - entity.setVariable(NUMBER_OF_INSTANCES, nrOfInstances + assignees.size()); - } - // 设置流程变量 - if (entity.getVariable(assigneeList) instanceof List userIds) { - CollUtil.addAll(userIds, assignees); - Map variables = new HashMap<>(16); - variables.put(assigneeList, userIds); - entity.setVariables(variables); - } - return null; - } -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/cmd/AttachmentCmd.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/cmd/AttachmentCmd.java deleted file mode 100644 index 1b23def..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/cmd/AttachmentCmd.java +++ /dev/null @@ -1,67 +0,0 @@ -package org.dromara.workflow.flowable.cmd; - -import cn.hutool.core.collection.CollUtil; -import org.dromara.common.core.utils.StringUtils; -import org.dromara.common.satoken.utils.LoginHelper; -import org.dromara.resource.api.RemoteFileService; -import org.dromara.resource.api.domain.RemoteFile; -import org.flowable.common.engine.impl.interceptor.Command; -import org.flowable.common.engine.impl.interceptor.CommandContext; -import org.flowable.engine.impl.persistence.entity.AttachmentEntity; -import org.flowable.engine.impl.persistence.entity.AttachmentEntityManager; -import org.flowable.engine.impl.util.CommandContextUtil; - -import java.util.Date; -import java.util.List; - -/** - * 附件上传 - * - * @author may - */ -public class AttachmentCmd implements Command { - - private final String fileId; - - private final String taskId; - - private final String processInstanceId; - - private final RemoteFileService remoteFileService; - - public AttachmentCmd(String fileId, String taskId, String processInstanceId, - RemoteFileService remoteFileService) { - this.fileId = fileId; - this.taskId = taskId; - this.processInstanceId = processInstanceId; - this.remoteFileService = remoteFileService; - } - - @Override - public Boolean execute(CommandContext commandContext) { - try { - if (StringUtils.isNotBlank(fileId)) { - List ossList = remoteFileService.selectByIds(fileId); - if (CollUtil.isNotEmpty(ossList)) { - for (RemoteFile oss : ossList) { - AttachmentEntityManager attachmentEntityManager = CommandContextUtil.getAttachmentEntityManager(); - AttachmentEntity attachmentEntity = attachmentEntityManager.create(); - attachmentEntity.setRevision(1); - attachmentEntity.setUserId(LoginHelper.getUserId().toString()); - attachmentEntity.setName(oss.getOriginalName()); - attachmentEntity.setDescription(oss.getOriginalName()); - attachmentEntity.setType(oss.getFileSuffix()); - attachmentEntity.setTaskId(taskId); - attachmentEntity.setProcessInstanceId(processInstanceId); - attachmentEntity.setContentId(oss.getOssId().toString()); - attachmentEntity.setTime(new Date()); - attachmentEntityManager.insert(attachmentEntity); - } - } - } - } catch (Exception e) { - throw new RuntimeException(e); - } - return true; - } -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/cmd/DeleteExecutionCmd.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/cmd/DeleteExecutionCmd.java deleted file mode 100644 index 215d310..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/cmd/DeleteExecutionCmd.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.dromara.workflow.flowable.cmd; - -import org.flowable.common.engine.impl.interceptor.Command; -import org.flowable.common.engine.impl.interceptor.CommandContext; -import org.flowable.engine.impl.persistence.entity.ExecutionEntity; -import org.flowable.engine.impl.persistence.entity.ExecutionEntityManager; -import org.flowable.engine.impl.util.CommandContextUtil; - -import java.io.Serializable; - -/** - * 删除执行数据 - * - * @author may - */ -public class DeleteExecutionCmd implements Command, Serializable { - - /** - * 执行id - */ - private final String executionId; - - public DeleteExecutionCmd(String executionId) { - this.executionId = executionId; - } - - @Override - public Void execute(CommandContext commandContext) { - ExecutionEntityManager executionEntityManager = CommandContextUtil.getExecutionEntityManager(); - ExecutionEntity entity = executionEntityManager.findById(executionId); - if (entity != null) { - executionEntityManager.deleteExecutionAndRelatedData(entity, "", false, false); - } - return null; - } -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/cmd/DeleteSequenceMultiInstanceCmd.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/cmd/DeleteSequenceMultiInstanceCmd.java deleted file mode 100644 index a61daeb..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/cmd/DeleteSequenceMultiInstanceCmd.java +++ /dev/null @@ -1,83 +0,0 @@ -package org.dromara.workflow.flowable.cmd; - -import cn.hutool.core.util.ObjectUtil; -import lombok.AllArgsConstructor; -import org.dromara.common.core.utils.StreamUtils; -import org.flowable.common.engine.impl.interceptor.Command; -import org.flowable.common.engine.impl.interceptor.CommandContext; -import org.flowable.engine.impl.persistence.entity.ExecutionEntity; -import org.flowable.engine.impl.persistence.entity.ExecutionEntityManager; -import org.flowable.engine.impl.util.CommandContextUtil; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static org.dromara.workflow.common.constant.FlowConstant.LOOP_COUNTER; -import static org.dromara.workflow.common.constant.FlowConstant.NUMBER_OF_INSTANCES; - - -/** - * 串行减签 - * - * @author may - */ -@AllArgsConstructor -public class DeleteSequenceMultiInstanceCmd implements Command { - - /** - * 当前节点审批人员id - */ - private final String currentUserId; - - /** - * 执行id - */ - private final String executionId; - - /** - * 会签人员集合KEY - */ - private final String assigneeList; - - /** - * 减签人员 - */ - private final List assignees; - - - @Override - @SuppressWarnings("unchecked") - public Void execute(CommandContext commandContext) { - ExecutionEntityManager executionEntityManager = CommandContextUtil.getExecutionEntityManager(); - ExecutionEntity entity = executionEntityManager.findById(executionId); - // 设置流程变量 - List userIds = new ArrayList<>(); - List variable = (List) entity.getVariable(assigneeList); - for (Object o : variable) { - userIds.add(Long.valueOf(o.toString())); - } - List userIdList = new ArrayList<>(); - userIds.forEach(e -> { - Long userId = StreamUtils.findFirst(assignees, id -> ObjectUtil.equals(id, e)); - if (userId == null) { - userIdList.add(e); - } - }); - // 当前任务执行位置 - int loopCounterIndex = -1; - for (int i = 0; i < userIdList.size(); i++) { - Long userId = userIdList.get(i); - if (currentUserId.equals(userId.toString())) { - loopCounterIndex = i; - } - } - Map variables = new HashMap<>(16); - variables.put(NUMBER_OF_INSTANCES, userIdList.size()); - variables.put(assigneeList, userIdList); - variables.put(LOOP_COUNTER, loopCounterIndex); - entity.setVariables(variables); - return null; - } -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/cmd/ExecutionChildByExecutionIdCmd.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/cmd/ExecutionChildByExecutionIdCmd.java deleted file mode 100644 index 1f3088b..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/cmd/ExecutionChildByExecutionIdCmd.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.dromara.workflow.flowable.cmd; - -import org.dromara.common.core.utils.StreamUtils; -import org.flowable.common.engine.impl.interceptor.Command; -import org.flowable.common.engine.impl.interceptor.CommandContext; -import org.flowable.engine.impl.persistence.entity.ExecutionEntity; -import org.flowable.engine.impl.persistence.entity.ExecutionEntityManager; -import org.flowable.engine.impl.util.CommandContextUtil; - -import java.io.Serializable; -import java.util.List; - -/** - * 获取并行网关执行后保留的执行实例数据 - * - * @author may - */ -public class ExecutionChildByExecutionIdCmd implements Command>, Serializable { - - /** - * 当前任务执行实例id - */ - private final String executionId; - - public ExecutionChildByExecutionIdCmd(String executionId) { - this.executionId = executionId; - } - - @Override - public List execute(CommandContext commandContext) { - ExecutionEntityManager executionEntityManager = CommandContextUtil.getExecutionEntityManager(); - // 获取当前执行数据 - ExecutionEntity executionEntity = executionEntityManager.findById(executionId); - // 通过当前执行数据的父执行,查询所有子执行数据 - List allChildrenExecution = - executionEntityManager.collectChildren(executionEntity.getParent()); - return StreamUtils.filter(allChildrenExecution, e -> !e.isActive()); - } -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/cmd/UpdateBusinessStatusCmd.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/cmd/UpdateBusinessStatusCmd.java deleted file mode 100644 index 3ba120a..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/cmd/UpdateBusinessStatusCmd.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.dromara.workflow.flowable.cmd; - -import org.dromara.common.core.exception.ServiceException; -import org.flowable.common.engine.impl.interceptor.Command; -import org.flowable.common.engine.impl.interceptor.CommandContext; -import org.flowable.engine.impl.persistence.entity.HistoricProcessInstanceEntity; -import org.flowable.engine.impl.persistence.entity.HistoricProcessInstanceEntityManager; -import org.flowable.engine.impl.util.CommandContextUtil; - -/** - * 修改流程状态 - * - * @author may - */ -public class UpdateBusinessStatusCmd implements Command { - - private final String processInstanceId; - private final String status; - - public UpdateBusinessStatusCmd(String processInstanceId, String status) { - this.processInstanceId = processInstanceId; - this.status = status; - } - - @Override - public Boolean execute(CommandContext commandContext) { - try { - HistoricProcessInstanceEntityManager manager = CommandContextUtil.getHistoricProcessInstanceEntityManager(); - HistoricProcessInstanceEntity processInstance = manager.findById(processInstanceId); - processInstance.setBusinessStatus(status); - manager.update(processInstance); - return true; - } catch (Exception e) { - throw new ServiceException(e.getMessage()); - } - } -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/cmd/UpdateHiTaskInstCmd.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/cmd/UpdateHiTaskInstCmd.java deleted file mode 100644 index 42f6d1c..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/cmd/UpdateHiTaskInstCmd.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.dromara.workflow.flowable.cmd; - -import org.dromara.common.core.exception.ServiceException; -import org.flowable.common.engine.impl.interceptor.Command; -import org.flowable.common.engine.impl.interceptor.CommandContext; -import org.flowable.engine.impl.util.CommandContextUtil; -import org.flowable.task.service.HistoricTaskService; -import org.flowable.task.service.impl.persistence.entity.HistoricTaskInstanceEntity; - -import java.util.Date; -import java.util.List; - - -/** - * 修改流程历史 - * - * @author may - */ -public class UpdateHiTaskInstCmd implements Command { - - private final List taskIds; - - private final String processDefinitionId; - - private final String processInstanceId; - - public UpdateHiTaskInstCmd(List taskIds, String processDefinitionId, String processInstanceId) { - this.taskIds = taskIds; - this.processDefinitionId = processDefinitionId; - this.processInstanceId = processInstanceId; - } - - @Override - public Boolean execute(CommandContext commandContext) { - try { - HistoricTaskService historicTaskService = CommandContextUtil.getHistoricTaskService(); - for (String taskId : taskIds) { - HistoricTaskInstanceEntity historicTask = historicTaskService.getHistoricTask(taskId); - if (historicTask != null) { - historicTask.setProcessDefinitionId(processDefinitionId); - historicTask.setProcessInstanceId(processInstanceId); - historicTask.setCreateTime(new Date()); - CommandContextUtil.getHistoricTaskService().updateHistoricTask(historicTask, true); - } - } - return true; - } catch (Exception e) { - throw new ServiceException(e.getMessage()); - } - } -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/config/FlowableConfig.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/config/FlowableConfig.java deleted file mode 100644 index 1494bf3..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/config/FlowableConfig.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.dromara.workflow.flowable.config; - -import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator; -import org.dromara.workflow.flowable.handler.TaskTimeoutJobHandler; -import org.flowable.spring.SpringProcessEngineConfiguration; -import org.flowable.spring.boot.EngineConfigurationConfigurer; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Configuration; - -import java.util.Collections; - - -/** - * flowable配置 - * - * @author may - */ -@Configuration -public class FlowableConfig implements EngineConfigurationConfigurer { - - @Autowired - private GlobalFlowableListener globalFlowableListener; - @Autowired - private IdentifierGenerator identifierGenerator; - - @Override - public void configure(SpringProcessEngineConfiguration processEngineConfiguration) { - processEngineConfiguration.setIdGenerator(() -> identifierGenerator.nextId(null).toString()); - processEngineConfiguration.setEventListeners(Collections.singletonList(globalFlowableListener)); - processEngineConfiguration.addCustomJobHandler(new TaskTimeoutJobHandler()); - } -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/config/GlobalFlowableListener.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/config/GlobalFlowableListener.java deleted file mode 100644 index 9bb971a..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/config/GlobalFlowableListener.java +++ /dev/null @@ -1,139 +0,0 @@ -package org.dromara.workflow.flowable.config; - -import cn.hutool.core.collection.CollUtil; -import org.dromara.common.core.utils.StringUtils; -import org.dromara.common.tenant.helper.TenantHelper; -import org.dromara.workflow.common.enums.TaskStatusEnum; -import org.dromara.workflow.flowable.handler.TaskTimeoutJobHandler; -import org.dromara.workflow.utils.QueryUtils; -import org.flowable.bpmn.model.BoundaryEvent; -import org.flowable.bpmn.model.BpmnModel; -import org.flowable.bpmn.model.FlowElement; -import org.flowable.common.engine.api.delegate.event.*; -import org.flowable.common.engine.impl.cfg.TransactionState; -import org.flowable.engine.RepositoryService; -import org.flowable.engine.RuntimeService; -import org.flowable.engine.TaskService; -import org.flowable.engine.impl.util.CommandContextUtil; -import org.flowable.engine.runtime.Execution; -import org.flowable.engine.task.Comment; -import org.flowable.job.service.TimerJobService; -import org.flowable.job.service.impl.persistence.entity.JobEntity; -import org.flowable.job.service.impl.persistence.entity.TimerJobEntity; -import org.flowable.task.api.Task; -import org.flowable.task.service.impl.persistence.entity.TaskEntity; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Component; - -import java.util.Date; -import java.util.List; - - -/** - * 引擎调度监听 - * - * @author may - */ -@Component -public class GlobalFlowableListener implements FlowableEventListener { - - @Autowired - @Lazy - private TaskService taskService; - - @Autowired - @Lazy - private RuntimeService runtimeService; - - @Autowired - @Lazy - private RepositoryService repositoryService; - - @Value("${flowable.async-executor-activate}") - private boolean asyncExecutorActivate; - - @Override - public void onEvent(FlowableEvent flowableEvent) { - if (flowableEvent instanceof FlowableEngineEvent flowableEngineEvent) { - FlowableEngineEventType engineEventType = (FlowableEngineEventType) flowableEvent.getType(); - switch (engineEventType) { - case JOB_EXECUTION_SUCCESS -> jobExecutionSuccess((FlowableEngineEntityEvent) flowableEngineEvent); - case TASK_DUEDATE_CHANGED, TASK_CREATED -> { - FlowableEntityEvent flowableEntityEvent = (FlowableEntityEvent) flowableEngineEvent; - Object entityObject = flowableEntityEvent.getEntity(); - TaskEntity task = (TaskEntity) entityObject; - if (asyncExecutorActivate && task.getDueDate() != null && task.getDueDate().after(new Date())) { - //删除之前已经存在的定时任务 - TimerJobService timerJobService = CommandContextUtil.getTimerJobService(); - List timerJobEntityList = timerJobService.findTimerJobsByProcessInstanceId(task.getProcessInstanceId()); - if (!CollUtil.isEmpty(timerJobEntityList)) { - for (TimerJobEntity timerJobEntity : timerJobEntityList) { - String taskId = timerJobEntity.getJobHandlerConfiguration(); - if (task.getId().equals(taskId)) { - timerJobService.deleteTimerJob(timerJobEntity); - } - } - } - //创建job对象 - TimerJobEntity timer = timerJobService.createTimerJob(); - timer.setTenantId(TenantHelper.getTenantId()); - //设置job类型 - timer.setJobType(JobEntity.JOB_TYPE_TIMER); - timer.setJobHandlerType(TaskTimeoutJobHandler.TYPE); - timer.setDuedate(task.getDueDate()); - timer.setProcessInstanceId(task.getProcessInstanceId()); - //设置任务id - timer.setJobHandlerConfiguration(task.getId()); - //保存并触发事件 - timerJobService.scheduleTimerJob(timer); - } - } - } - } - } - - @Override - public boolean isFailOnException() { - return true; - } - - @Override - public boolean isFireOnTransactionLifecycleEvent() { - return false; - } - - @Override - public String getOnTransaction() { - return TransactionState.COMMITTED.name(); - } - - /** - * 处理边界定时事件自动审批记录 - * - * @param event 事件 - */ - protected void jobExecutionSuccess(FlowableEngineEntityEvent event) { - if (event != null && StringUtils.isNotBlank(event.getExecutionId())) { - Execution execution = runtimeService.createExecutionQuery().executionId(event.getExecutionId()).singleResult(); - if (execution != null) { - BpmnModel bpmnModel = repositoryService.getBpmnModel(event.getProcessDefinitionId()); - FlowElement flowElement = bpmnModel.getFlowElement(execution.getActivityId()); - if (flowElement instanceof BoundaryEvent) { - String attachedToRefId = ((BoundaryEvent) flowElement).getAttachedToRefId(); - List list = runtimeService.createExecutionQuery().activityId(attachedToRefId).list(); - for (Execution ex : list) { - Task task = QueryUtils.taskQuery().executionId(ex.getId()).singleResult(); - if (task != null) { - List taskComments = taskService.getTaskComments(task.getId()); - if (CollUtil.isEmpty(taskComments)) { - taskService.addComment(task.getId(), task.getProcessInstanceId(), TaskStatusEnum.PASS.getStatus(), "超时自动审批!"); - } - } - } - } - } - } - } -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/handler/FlowProcessEventHandler.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/handler/FlowProcessEventHandler.java deleted file mode 100644 index 94924a8..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/handler/FlowProcessEventHandler.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.dromara.workflow.flowable.handler; - -import org.dromara.common.core.utils.SpringUtils; -import org.dromara.workflow.api.domain.event.ProcessEvent; -import org.dromara.workflow.api.domain.event.ProcessTaskEvent; -import org.springframework.stereotype.Component; - -/** - * 流程监听服务 - * - * @author may - * @date 2024-06-02 - */ -@Component -public class FlowProcessEventHandler { - - /** - * 总体流程监听(例如: 提交 退回 撤销 终止 作废等) - * - * @param key 流程key - * @param businessKey 业务id - * @param status 状态 - * @param submit 当为true时为申请人节点办理 - */ - public void processHandler(String key, String businessKey, String status, boolean submit) { - ProcessEvent processEvent = new ProcessEvent(); - processEvent.setKey(key); - processEvent.setBusinessKey(businessKey); - processEvent.setStatus(status); - processEvent.setSubmit(submit); - SpringUtils.context().publishEvent(processEvent); - } - - /** - * 执行办理任务监听 - * - * @param key 流程key - * @param taskDefinitionKey 审批节点key - * @param taskId 任务id - * @param businessKey 业务id - */ - public void processTaskHandler(String key, String taskDefinitionKey, String taskId, String businessKey) { - ProcessTaskEvent processTaskEvent = new ProcessTaskEvent(); - processTaskEvent.setKey(key); - processTaskEvent.setTaskDefinitionKey(taskDefinitionKey); - processTaskEvent.setTaskId(taskId); - processTaskEvent.setBusinessKey(businessKey); - SpringUtils.context().publishEvent(processTaskEvent); - } -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/handler/TaskTimeoutJobHandler.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/handler/TaskTimeoutJobHandler.java deleted file mode 100644 index 7685423..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/flowable/handler/TaskTimeoutJobHandler.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.dromara.workflow.flowable.handler; - -import org.dromara.workflow.common.enums.TaskStatusEnum; -import org.flowable.common.engine.impl.interceptor.CommandContext; -import org.flowable.engine.TaskService; -import org.flowable.engine.impl.jobexecutor.TimerEventHandler; -import org.flowable.engine.impl.util.CommandContextUtil; -import org.flowable.job.service.JobHandler; -import org.flowable.job.service.impl.persistence.entity.JobEntity; -import org.flowable.task.api.Task; -import org.flowable.task.api.TaskQuery; -import org.flowable.variable.api.delegate.VariableScope; - -/** - * 办理超时(过期)任务 - * - * @author may - */ -public class TaskTimeoutJobHandler extends TimerEventHandler implements JobHandler { - - public static final String TYPE = "taskTimeout"; - - @Override - public String getType() { - return TYPE; - } - - @Override - public void execute(JobEntity job, String configuration, VariableScope variableScope, CommandContext commandContext) { - TaskService taskService = CommandContextUtil.getProcessEngineConfiguration(commandContext) - .getTaskService(); - Task task = taskService.createTaskQuery().taskId(configuration).singleResult(); - if (task != null) { - taskService.addComment(task.getId(), task.getProcessInstanceId(), TaskStatusEnum.TIMEOUT.getStatus(), "超时自动审批!"); - taskService.complete(configuration); - } - } -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/mapper/ActHiProcinstMapper.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/mapper/ActHiProcinstMapper.java deleted file mode 100644 index a3a41c9..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/mapper/ActHiProcinstMapper.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.dromara.workflow.mapper; - -import com.baomidou.mybatisplus.annotation.InterceptorIgnore; -import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; -import org.dromara.workflow.domain.ActHiProcinst; - -/** - * 流程实例Mapper接口 - * - * @author may - * @date 2023-07-22 - */ -@InterceptorIgnore(tenantLine = "true") -public interface ActHiProcinstMapper extends BaseMapperPlus { - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/mapper/ActHiTaskinstMapper.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/mapper/ActHiTaskinstMapper.java deleted file mode 100644 index 63b394b..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/mapper/ActHiTaskinstMapper.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.dromara.workflow.mapper; - -import com.baomidou.mybatisplus.annotation.InterceptorIgnore; -import org.dromara.workflow.domain.ActHiTaskinst; -import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; - -/** - * 流程历史任务Mapper接口 - * - * @author may - * @date 2024-03-02 - */ -@InterceptorIgnore(tenantLine = "true") -public interface ActHiTaskinstMapper extends BaseMapperPlus { - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/mapper/ActTaskMapper.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/mapper/ActTaskMapper.java deleted file mode 100644 index 63c5ecb..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/mapper/ActTaskMapper.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.dromara.workflow.mapper; - -import com.baomidou.mybatisplus.annotation.InterceptorIgnore; -import com.baomidou.mybatisplus.core.conditions.Wrapper; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.toolkit.Constants; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import org.apache.ibatis.annotations.Param; -import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; -import org.dromara.workflow.domain.vo.TaskVo; - - -/** - * 任务信息Mapper接口 - * - * @author may - * @date 2024-03-02 - */ -@InterceptorIgnore(tenantLine = "true") -public interface ActTaskMapper extends BaseMapperPlus { - /** - * 获取待办信息 - * - * @param page 分页 - * @param queryWrapper 条件 - * @return 结果 - */ - Page getTaskWaitByPage(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); - - /** - * 获取已办 - * - * @param page 分页 - * @param queryWrapper 条件 - * @return 结果 - */ - Page getTaskFinishByPage(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); - - /** - * 查询当前用户的抄送 - * - * @param page 分页 - * @param queryWrapper 条件 - * @return 结果 - */ - Page getTaskCopyByPage(@Param("page") Page page, @Param(Constants.WRAPPER) QueryWrapper queryWrapper); -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/mapper/TestLeaveMapper.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/mapper/TestLeaveMapper.java deleted file mode 100644 index cd1edba..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/mapper/TestLeaveMapper.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.dromara.workflow.mapper; - -import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; -import org.dromara.workflow.domain.TestLeave; -import org.dromara.workflow.domain.vo.TestLeaveVo; - -/** - * 请假Mapper接口 - * - * @author may - * @date 2023-07-21 - */ -public interface TestLeaveMapper extends BaseMapperPlus { - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/mapper/WfCategoryMapper.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/mapper/WfCategoryMapper.java deleted file mode 100644 index 98aea02..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/mapper/WfCategoryMapper.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.dromara.workflow.mapper; - -import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; -import org.dromara.workflow.domain.WfCategory; -import org.dromara.workflow.domain.vo.WfCategoryVo; - -/** - * 流程分类Mapper接口 - * - * @author may - * @date 2023-06-27 - */ -public interface WfCategoryMapper extends BaseMapperPlus { - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/mapper/WfDefinitionConfigMapper.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/mapper/WfDefinitionConfigMapper.java deleted file mode 100644 index ee20882..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/mapper/WfDefinitionConfigMapper.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.dromara.workflow.mapper; - -import org.dromara.workflow.domain.WfDefinitionConfig; -import org.dromara.workflow.domain.vo.WfDefinitionConfigVo; -import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; - -/** - * 流程定义配置Mapper接口 - * - * @author may - * @date 2024-03-18 - */ -public interface WfDefinitionConfigMapper extends BaseMapperPlus { - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/mapper/WfFormManageMapper.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/mapper/WfFormManageMapper.java deleted file mode 100644 index acf8111..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/mapper/WfFormManageMapper.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.dromara.workflow.mapper; - -import org.dromara.workflow.domain.WfFormManage; -import org.dromara.workflow.domain.vo.WfFormManageVo; -import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; - -/** - * 表单管理Mapper接口 - * - * @author may - * @date 2024-03-29 - */ -public interface WfFormManageMapper extends BaseMapperPlus { - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/mapper/WfNodeConfigMapper.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/mapper/WfNodeConfigMapper.java deleted file mode 100644 index d2aecac..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/mapper/WfNodeConfigMapper.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.dromara.workflow.mapper; - -import org.dromara.workflow.domain.WfNodeConfig; -import org.dromara.workflow.domain.vo.WfNodeConfigVo; -import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; - -/** - * 节点配置Mapper接口 - * - * @author may - * @date 2024-03-30 - */ -public interface WfNodeConfigMapper extends BaseMapperPlus { - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/mapper/WfTaskBackNodeMapper.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/mapper/WfTaskBackNodeMapper.java deleted file mode 100644 index 9b291fe..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/mapper/WfTaskBackNodeMapper.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.dromara.workflow.mapper; - -import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; -import org.dromara.workflow.domain.WfTaskBackNode; - -/** - * 节点驳回记录Mapper接口 - * - * @author may - * @date 2024-03-13 - */ -public interface WfTaskBackNodeMapper extends BaseMapperPlus { -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/runner/WorkflowApplicationRunner.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/runner/WorkflowApplicationRunner.java deleted file mode 100644 index 414cd69..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/runner/WorkflowApplicationRunner.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.dromara.workflow.runner; - -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.dubbo.config.annotation.DubboReference; -import org.dromara.resource.api.RemoteFileService; -import org.dromara.system.api.RemoteUserService; -import org.springframework.boot.ApplicationArguments; -import org.springframework.boot.ApplicationRunner; -import org.springframework.stereotype.Component; - -/** - * 初始化 dubbo 接口生成接口代理 不然无法直接用 SpringUtils 注入 dubbo 接口使用 - * - * @author Lion Li - */ -@Slf4j -@RequiredArgsConstructor -@Component -public class WorkflowApplicationRunner implements ApplicationRunner { - - @DubboReference - private RemoteUserService remoteUserService; - @DubboReference - private RemoteFileService remoteFileService; - - @Override - public void run(ApplicationArguments args) throws Exception { - } - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/IActHiProcinstService.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/service/IActHiProcinstService.java deleted file mode 100644 index e802c69..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/IActHiProcinstService.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.dromara.workflow.service; - - -import org.dromara.workflow.domain.ActHiProcinst; - -import java.util.List; - -/** - * 流程实例Service接口 - * - * @author may - * @date 2023-07-22 - */ -public interface IActHiProcinstService { - - /** - * 按照业务id查询 - * - * @param businessKeys 业务id - * @return 结果 - */ - List selectByBusinessKeyIn(List businessKeys); - - /** - * 按照业务id查询 - * - * @param businessKey 业务id - * @return 结果 - */ - ActHiProcinst selectByBusinessKey(String businessKey); -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/IActHiTaskinstService.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/service/IActHiTaskinstService.java deleted file mode 100644 index ad286e2..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/IActHiTaskinstService.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.dromara.workflow.service; - - -/** - * 流程历史任务Service接口 - * - * @author may - * @date 2024-03-02 - */ -public interface IActHiTaskinstService { -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/IActModelService.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/service/IActModelService.java deleted file mode 100644 index 4a6d170..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/IActModelService.java +++ /dev/null @@ -1,83 +0,0 @@ -package org.dromara.workflow.service; - -import jakarta.servlet.http.HttpServletResponse; -import org.dromara.common.mybatis.core.page.PageQuery; -import org.dromara.common.mybatis.core.page.TableDataInfo; -import org.dromara.workflow.domain.bo.ModelBo; -import org.dromara.workflow.domain.vo.ModelVo; -import org.flowable.engine.repository.Model; - -import java.util.List; - - -/** - * 模型管理 服务层 - * - * @author may - */ -public interface IActModelService { - /** - * 分页查询模型 - * - * @param modelBo 模型参数 - * @param pageQuery 参数 - * @return 返回分页列表 - */ - TableDataInfo page(ModelBo modelBo, PageQuery pageQuery); - - /** - * 新增模型 - * - * @param modelBo 模型请求对象 - * @return 结果 - */ - boolean saveNewModel(ModelBo modelBo); - - /** - * 查询模型 - * - * @param modelId 模型id - * @return 模型数据 - */ - ModelVo getInfo(String modelId); - - /** - * 修改模型信息 - * - * @param modelBo 模型数据 - * @return 结果 - */ - boolean update(ModelBo modelBo); - - /** - * 编辑模型XML - * - * @param modelBo 模型数据 - * @return 结果 - */ - boolean editModelXml(ModelBo modelBo); - - /** - * 模型部署 - * - * @param id 模型id - * @return 结果 - */ - boolean modelDeploy(String id); - - /** - * 导出模型zip压缩包 - * - * @param modelIds 模型id - * @param response 响应 - */ - void exportZip(List modelIds, HttpServletResponse response); - - /** - * 复制模型 - * - * @param modelBo 模型数据 - * @return 结果 - */ - boolean copyModel(ModelBo modelBo); -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/IActProcessDefinitionService.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/service/IActProcessDefinitionService.java deleted file mode 100644 index 5d00e41..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/IActProcessDefinitionService.java +++ /dev/null @@ -1,91 +0,0 @@ -package org.dromara.workflow.service; - -import org.dromara.common.mybatis.core.page.PageQuery; -import org.dromara.common.mybatis.core.page.TableDataInfo; -import org.dromara.workflow.domain.bo.ProcessDefinitionBo; -import org.dromara.workflow.domain.vo.ProcessDefinitionVo; -import org.springframework.web.multipart.MultipartFile; - -import java.util.List; - -/** - * 流程定义 服务层 - * - * @author may - */ -public interface IActProcessDefinitionService { - /** - * 分页查询 - * - * @param processDefinitionBo 参数 - * @param pageQuery 分页 - * @return 返回分页列表 - */ - TableDataInfo page(ProcessDefinitionBo processDefinitionBo, PageQuery pageQuery); - - /** - * 查询历史流程定义列表 - * - * @param key 流程定义key - * @return 结果 - */ - List getListByKey(String key); - - /** - * 查看流程定义图片 - * - * @param processDefinitionId 流程定义id - * @return 结果 - */ - String definitionImage(String processDefinitionId); - - /** - * 查看流程定义xml文件 - * - * @param processDefinitionId 流程定义id - * @return 结果 - */ - String definitionXml(String processDefinitionId); - - /** - * 删除流程定义 - * - * @param deploymentIds 部署id - * @param processDefinitionIds 流程定义id - * @return 结果 - */ - boolean deleteDeployment(List deploymentIds, List processDefinitionIds); - - /** - * 激活或者挂起流程定义 - * - * @param processDefinitionId 流程定义id - * @return 结果 - */ - boolean updateDefinitionState(String processDefinitionId); - - /** - * 迁移流程定义 - * - * @param currentProcessDefinitionId 当前流程定义id - * @param fromProcessDefinitionId 需要迁移到的流程定义id - * @return 结果 - */ - boolean migrationDefinition(String currentProcessDefinitionId, String fromProcessDefinitionId); - - /** - * 流程定义转换为模型 - * - * @param processDefinitionId 流程定义id - * @return 结果 - */ - boolean convertToModel(String processDefinitionId); - - /** - * 通过zip或xml部署流程定义 - * - * @param file 文件 - * @param categoryCode 分类 - */ - void deployByFile(MultipartFile file, String categoryCode); -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/IActProcessInstanceService.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/service/IActProcessInstanceService.java deleted file mode 100644 index ca3b6fb..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/IActProcessInstanceService.java +++ /dev/null @@ -1,110 +0,0 @@ -package org.dromara.workflow.service; - -import org.dromara.common.mybatis.core.page.PageQuery; -import org.dromara.common.mybatis.core.page.TableDataInfo; -import org.dromara.workflow.domain.bo.ProcessInstanceBo; -import org.dromara.workflow.domain.bo.ProcessInvalidBo; -import org.dromara.workflow.domain.bo.TaskUrgingBo; -import org.dromara.workflow.domain.vo.ActHistoryInfoVo; -import org.dromara.workflow.domain.vo.ProcessInstanceVo; - -import java.util.List; -import java.util.Map; - -/** - * 流程实例 服务层 - * - * @author may - */ -public interface IActProcessInstanceService { - /** - * 通过流程实例id获取历史流程图 - * - * @param businessKey 流程实例id - * @return 结果 - */ - String getHistoryImage(String businessKey); - - /** - * 通过业务id获取历史流程图运行中,历史等节点 - * - * @param businessKey 业务id - * @return 结果 - */ - Map getHistoryList(String businessKey); - - /** - * 分页查询正在运行的流程实例 - * - * @param processInstanceBo 参数 - * @param pageQuery 分页 - * @return 结果 - */ - TableDataInfo getPageByRunning(ProcessInstanceBo processInstanceBo, PageQuery pageQuery); - - /** - * 分页查询已结束的流程实例 - * - * @param processInstanceBo 参数 - * @param pageQuery 分页 - * @return 结果 - */ - TableDataInfo getPageByFinish(ProcessInstanceBo processInstanceBo, PageQuery pageQuery); - - /** - * 获取审批记录 - * - * @param businessKey 业务id - * @return 结果 - */ - List getHistoryRecord(String businessKey); - - /** - * 作废流程实例,不会删除历史记录(删除运行中的实例) - * - * @param processInvalidBo 参数 - * @return 结果 - */ - boolean deleteRunInstance(ProcessInvalidBo processInvalidBo); - - /** - * 运行中的实例 删除程实例,删除历史记录,删除业务与流程关联信息 - * - * @param businessKeys 业务id - * @return 结果 - */ - boolean deleteRunAndHisInstance(List businessKeys); - - /** - * 已完成的实例 删除程实例,删除历史记录,删除业务与流程关联信息 - * - * @param businessKeys 业务id - * @return 结果 - */ - boolean deleteFinishAndHisInstance(List businessKeys); - - /** - * 撤销流程申请 - * - * @param businessKey 业务id - * @return 结果 - */ - boolean cancelProcessApply(String businessKey); - - /** - * 分页查询当前登录人单据 - * - * @param processInstanceBo 参数 - * @param pageQuery 分页 - * @return 结果 - */ - TableDataInfo getPageByCurrent(ProcessInstanceBo processInstanceBo, PageQuery pageQuery); - - /** - * 任务催办(给当前任务办理人发送站内信,邮件,短信等) - * - * @param taskUrgingBo 任务催办 - * @return 结果 - */ - boolean taskUrging(TaskUrgingBo taskUrgingBo); -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/IActTaskService.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/service/IActTaskService.java deleted file mode 100644 index 8e9f763..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/IActTaskService.java +++ /dev/null @@ -1,161 +0,0 @@ -package org.dromara.workflow.service; - -import org.dromara.common.mybatis.core.page.PageQuery; -import org.dromara.common.mybatis.core.page.TableDataInfo; -import org.dromara.workflow.domain.bo.*; -import org.dromara.workflow.domain.vo.TaskVo; -import org.dromara.workflow.domain.vo.VariableVo; - -import java.util.List; -import java.util.Map; - -/** - * 任务 服务层 - * - * @author may - */ -public interface IActTaskService { - /** - * 启动任务 - * - * @param startProcessBo 启动流程参数 - * @return 结果 - */ - Map startWorkFlow(StartProcessBo startProcessBo); - - - /** - * 办理任务 - * - * @param completeTaskBo 办理任务参数 - * @return 结果 - */ - boolean completeTask(CompleteTaskBo completeTaskBo); - - /** - * 查询当前用户的待办任务 - * - * @param taskBo 参数 - * @param pageQuery 分页 - * @return 结果 - */ - TableDataInfo getPageByTaskWait(TaskBo taskBo, PageQuery pageQuery); - - /** - * 查询当前租户所有待办任务 - * - * @param taskBo 参数 - * @param pageQuery 分页 - * @return 结果 - */ - TableDataInfo getPageByAllTaskWait(TaskBo taskBo, PageQuery pageQuery); - - - /** - * 查询当前用户的已办任务 - * - * @param taskBo 参数 - * @param pageQuery 参数 - * @return 结果 - */ - TableDataInfo getPageByTaskFinish(TaskBo taskBo, PageQuery pageQuery); - - /** - * 查询当前用户的抄送 - * - * @param taskBo 参数 - * @param pageQuery 参数 - * @return 结果 - */ - TableDataInfo getPageByTaskCopy(TaskBo taskBo, PageQuery pageQuery); - - /** - * 查询当前租户所有已办任务 - * - * @param taskBo 参数 - * @param pageQuery 参数 - * @return 结果 - */ - TableDataInfo getPageByAllTaskFinish(TaskBo taskBo, PageQuery pageQuery); - - /** - * 委派任务 - * - * @param delegateBo 参数 - * @return 结果 - */ - boolean delegateTask(DelegateBo delegateBo); - - /** - * 终止任务 - * - * @param terminationBo 参数 - * @return 结果 - */ - boolean terminationTask(TerminationBo terminationBo); - - /** - * 转办任务 - * - * @param transmitBo 参数 - * @return 结果 - */ - boolean transferTask(TransmitBo transmitBo); - - /** - * 会签任务加签 - * - * @param addMultiBo 参数 - * @return 结果 - */ - boolean addMultiInstanceExecution(AddMultiBo addMultiBo); - - /** - * 会签任务减签 - * - * @param deleteMultiBo 参数 - * @return 结果 - */ - boolean deleteMultiInstanceExecution(DeleteMultiBo deleteMultiBo); - - /** - * 驳回审批 - * - * @param backProcessBo 参数 - * @return 流程实例id - */ - String backProcess(BackProcessBo backProcessBo); - - /** - * 修改任务办理人 - * - * @param taskIds 任务id - * @param userId 办理人id - * @return 结果 - */ - boolean updateAssignee(String[] taskIds, String userId); - - /** - * 查询流程变量 - * - * @param taskId 任务id - * @return 结果 - */ - List getInstanceVariable(String taskId); - - /** - * 查询工作流任务用户选择加签人员 - * - * @param taskId 任务id - * @return 结果 - */ - String getTaskUserIdsByAddMultiInstance(String taskId); - - /** - * 查询工作流选择减签人员 - * - * @param taskId 任务id - * @return 结果 - */ - List getListByDeleteMultiInstance(String taskId); -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/ITestLeaveService.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/service/ITestLeaveService.java deleted file mode 100644 index 943c919..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/ITestLeaveService.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.dromara.workflow.service; - -import org.dromara.common.mybatis.core.page.PageQuery; -import org.dromara.common.mybatis.core.page.TableDataInfo; -import org.dromara.workflow.domain.bo.TestLeaveBo; -import org.dromara.workflow.domain.vo.TestLeaveVo; - -import java.util.Collection; -import java.util.List; - -/** - * 请假Service接口 - * - * @author may - * @date 2023-07-21 - */ -public interface ITestLeaveService { - - /** - * 查询请假 - */ - TestLeaveVo queryById(Long id); - - /** - * 查询请假列表 - */ - TableDataInfo queryPageList(TestLeaveBo bo, PageQuery pageQuery); - - /** - * 查询请假列表 - */ - List queryList(TestLeaveBo bo); - - /** - * 新增请假 - */ - TestLeaveVo insertByBo(TestLeaveBo bo); - - /** - * 修改请假 - */ - TestLeaveVo updateByBo(TestLeaveBo bo); - - /** - * 校验并批量删除请假信息 - */ - Boolean deleteWithValidByIds(Collection ids); -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/IWfCategoryService.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/service/IWfCategoryService.java deleted file mode 100644 index acf0aa2..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/IWfCategoryService.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.dromara.workflow.service; - -import org.dromara.workflow.domain.WfCategory; -import org.dromara.workflow.domain.bo.WfCategoryBo; -import org.dromara.workflow.domain.vo.WfCategoryVo; - -import java.util.Collection; -import java.util.List; - -/** - * 流程分类Service接口 - * - * @author may - * @date 2023-06-28 - */ -public interface IWfCategoryService { - - /** - * 查询流程分类 - */ - WfCategoryVo queryById(Long id); - - - /** - * 查询流程分类列表 - */ - List queryList(WfCategoryBo bo); - - /** - * 新增流程分类 - */ - Boolean insertByBo(WfCategoryBo bo); - - /** - * 修改流程分类 - */ - Boolean updateByBo(WfCategoryBo bo); - - /** - * 校验并批量删除流程分类信息 - */ - Boolean deleteWithValidByIds(Collection ids, Boolean isValid); - - /** - * 按照类别编码查询 - * - * @param categoryCode 分类比吗 - * @return 结果 - */ - WfCategory queryByCategoryCode(String categoryCode); -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/IWfDefinitionConfigService.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/service/IWfDefinitionConfigService.java deleted file mode 100644 index fe5cf7a..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/IWfDefinitionConfigService.java +++ /dev/null @@ -1,83 +0,0 @@ -package org.dromara.workflow.service; - -import org.dromara.workflow.domain.vo.WfDefinitionConfigVo; -import org.dromara.workflow.domain.bo.WfDefinitionConfigBo; - -import java.util.Collection; -import java.util.List; - -/** - * 流程定义配置Service接口 - * - * @author may - * @date 2024-03-18 - */ -public interface IWfDefinitionConfigService { - - /** - * 查询流程定义配置 - * - * @param definitionId 流程定义id - * @return 结果 - */ - WfDefinitionConfigVo getByDefId(String definitionId); - - /** - * 查询流程定义配置 - * - * @param tableName 表名 - * @return 结果 - */ - WfDefinitionConfigVo getByTableNameLastVersion(String tableName); - - /** - * 查询流程定义配置 - * - * @param definitionId 流程定义id - * @param tableName 表名 - * @return 结果 - */ - WfDefinitionConfigVo getByDefIdAndTableName(String definitionId, String tableName); - - /** - * 查询流程定义配置排除当前查询的流程定义 - * - * @param definitionId 流程定义id - * @param tableName 表名 - * @return 结果 - */ - List getByTableNameNotDefId(String tableName, String definitionId); - - /** - * 查询流程定义配置列表 - * - * @param definitionIds 流程定义id - * @return 结果 - */ - List queryList(List definitionIds); - - - /** - * 新增流程定义配置 - * - * @param bo 参数 - * @return 结果 - */ - Boolean saveOrUpdate(WfDefinitionConfigBo bo); - - /** - * 删除 - * - * @param ids id - * @return 结果 - */ - Boolean deleteByIds(Collection ids); - - /** - * 按照流程定义id删除 - * - * @param ids 流程定义id - * @return 结果 - */ - Boolean deleteByDefIds(Collection ids); -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/IWfFormManageService.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/service/IWfFormManageService.java deleted file mode 100644 index 2ca2264..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/IWfFormManageService.java +++ /dev/null @@ -1,81 +0,0 @@ -package org.dromara.workflow.service; - -import org.dromara.workflow.domain.vo.WfFormManageVo; -import org.dromara.workflow.domain.bo.WfFormManageBo; -import org.dromara.common.mybatis.core.page.TableDataInfo; -import org.dromara.common.mybatis.core.page.PageQuery; - -import java.util.Collection; -import java.util.List; - -/** - * 表单管理Service接口 - * - * @author may - * @date 2024-03-29 - */ -public interface IWfFormManageService { - - /** - * 查询表单管理 - * - * @param id 主键 - * @return 结果 - */ - WfFormManageVo queryById(Long id); - - /** - * 查询表单管理 - * - * @param ids 主键 - * @return 结果 - */ - List queryByIds(List ids); - - /** - * 查询表单管理列表 - * - * @param bo 参数 - * @param pageQuery 分页 - * @return 结果 - */ - TableDataInfo queryPageList(WfFormManageBo bo, PageQuery pageQuery); - - /** - * 查询表单管理列表 - * - * @return 结果 - */ - List selectList(); - /** - * 查询表单管理列表 - * - * @param bo 参数 - * @return 结果 - */ - List queryList(WfFormManageBo bo); - - /** - * 新增表单管理 - * - * @param bo 参数 - * @return 结果 - */ - Boolean insertByBo(WfFormManageBo bo); - - /** - * 修改表单管理 - * - * @param bo 参数 - * @return 结果 - */ - Boolean updateByBo(WfFormManageBo bo); - - /** - * 批量删除表单管理信息 - * - * @param ids 主键 - * @return 结果 - */ - Boolean deleteByIds(Collection ids); -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/IWfNodeConfigService.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/service/IWfNodeConfigService.java deleted file mode 100644 index 5e64d64..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/IWfNodeConfigService.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.dromara.workflow.service; - -import org.dromara.workflow.domain.WfNodeConfig; -import org.dromara.workflow.domain.vo.WfNodeConfigVo; - -import java.util.Collection; -import java.util.List; - -/** - * 节点配置Service接口 - * - * @author may - * @date 2024-03-30 - */ -public interface IWfNodeConfigService { - - /** - * 查询节点配置 - * - * @param id 主键 - * @return 结果 - */ - WfNodeConfigVo queryById(Long id); - - /** - * 保存节点配置 - * - * @param list 参数 - * @return 结果 - */ - Boolean saveOrUpdate(List list); - - /** - * 批量删除节点配置信息 - * - * @param ids 主键 - * @return 结果 - */ - Boolean deleteByIds(Collection ids); - - /** - * 按照流程定义id删除 - * - * @param ids 流程定义id - * @return 结果 - */ - Boolean deleteByDefIds(Collection ids); - - /** - * 按照流程定义id查询 - * - * @param ids 流程定义id - * @return 结果 - */ - List selectByDefIds(Collection ids); -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/IWfTaskBackNodeService.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/service/IWfTaskBackNodeService.java deleted file mode 100644 index 97f9406..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/IWfTaskBackNodeService.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.dromara.workflow.service; - - -import org.dromara.workflow.domain.WfTaskBackNode; -import org.flowable.task.api.Task; - -import java.util.List; - -/** - * 节点驳回记录Service接口 - * - * @author may - * @date 2024-03-13 - */ -public interface IWfTaskBackNodeService { - - /** - * 记录审批节点 - * - * @param task 任务 - */ - void recordExecuteNode(Task task); - - /** - * 按流程实例id查询 - * - * @param processInstanceId 流程实例id - * @return 结果 - */ - List getListByInstanceId(String processInstanceId); - - /** - * 按照流程实例id,节点id查询 - * - * @param processInstanceId 流程实例id - * @param nodeId 节点id - * @return 结果 - */ - WfTaskBackNode getListByInstanceIdAndNodeId(String processInstanceId, String nodeId); - - /** - * 删除驳回后的节点 - * - * @param processInstanceId 流程实例id - * @param targetActivityId 节点id - * @return 结果 - */ - boolean deleteBackTaskNode(String processInstanceId, String targetActivityId); - - /** - * 按流程实例id删除 - * - * @param processInstanceId 流程实例id - * @return 结果 - */ - boolean deleteByInstanceId(String processInstanceId); - - /** - * 按流程实例id删除 - * - * @param processInstanceIds 流程实例id - * @return 结果 - */ - boolean deleteByInstanceIds(List processInstanceIds); -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/WorkflowService.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/service/WorkflowService.java deleted file mode 100644 index 0100305..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/WorkflowService.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.dromara.workflow.service; - -import java.util.List; -import java.util.Map; - -/** - * 通用 工作流服务 - * - * @author may - */ -public interface WorkflowService { - - /** - * 运行中的实例 删除程实例,删除历史记录,删除业务与流程关联信息 - * - * @param businessKeys 业务id - * @return 结果 - */ - boolean deleteRunAndHisInstance(List businessKeys); - - /** - * 获取当前流程状态 - * - * @param taskId 任务id - */ - String getBusinessStatusByTaskId(String taskId); - - /** - * 获取当前流程状态 - * - * @param businessKey 业务id - */ - String getBusinessStatus(String businessKey); - - /** - * 设置流程变量(全局变量) - * - * @param taskId 任务id - * @param variableName 变量名称 - * @param value 变量值 - */ - void setVariable(String taskId, String variableName, Object value); - - /** - * 设置流程变量(全局变量) - * - * @param taskId 任务id - * @param variables 流程变量 - */ - void setVariables(String taskId, Map variables); - - /** - * 设置流程变量(本地变量,非全局变量) - * - * @param taskId 任务id - * @param variableName 变量名称 - * @param value 变量值 - */ - void setVariableLocal(String taskId, String variableName, Object value); - - /** - * 设置流程变量(本地变量,非全局变量) - * - * @param taskId 任务id - * @param variables 流程变量 - */ - void setVariablesLocal(String taskId, Map variables); - - /** - * 按照业务id查询流程实例id - * - * @param businessKey 业务id - * @return 结果 - */ - String getInstanceIdByBusinessKey(String businessKey); -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/ActHiProcinstServiceImpl.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/ActHiProcinstServiceImpl.java deleted file mode 100644 index 06d607b..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/ActHiProcinstServiceImpl.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.dromara.workflow.service.impl; - - -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import lombok.RequiredArgsConstructor; -import org.dromara.common.tenant.helper.TenantHelper; -import org.dromara.workflow.domain.ActHiProcinst; -import org.dromara.workflow.mapper.ActHiProcinstMapper; -import org.dromara.workflow.service.IActHiProcinstService; -import org.springframework.stereotype.Service; - -import java.util.List; - - -/** - * 流程实例Service业务层处理 - * - * @author may - * @date 2023-07-22 - */ -@RequiredArgsConstructor -@Service -public class ActHiProcinstServiceImpl implements IActHiProcinstService { - - private final ActHiProcinstMapper baseMapper; - - /** - * 按照业务id查询 - * - * @param businessKeys 业务id - */ - @Override - public List selectByBusinessKeyIn(List businessKeys) { - return baseMapper.selectList(new LambdaQueryWrapper() - .in(ActHiProcinst::getBusinessKey, businessKeys) - .eq(TenantHelper.isEnable(), ActHiProcinst::getTenantId, TenantHelper.getTenantId())); - } - - /** - * 按照业务id查询 - * - * @param businessKey 业务id - */ - @Override - public ActHiProcinst selectByBusinessKey(String businessKey) { - return baseMapper.selectOne(new LambdaQueryWrapper() - .eq(ActHiProcinst::getBusinessKey, businessKey) - .eq(TenantHelper.isEnable(), ActHiProcinst::getTenantId, TenantHelper.getTenantId())); - - } -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/ActHiTaskinstServiceImpl.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/ActHiTaskinstServiceImpl.java deleted file mode 100644 index 5548f22..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/ActHiTaskinstServiceImpl.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.dromara.workflow.service.impl; - -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.dromara.workflow.service.IActHiTaskinstService; - - -/** - * 流程历史任务Service业务层处理 - * - * @author may - * @date 2024-03-02 - */ -@RequiredArgsConstructor -@Service -public class ActHiTaskinstServiceImpl implements IActHiTaskinstService { - -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/ActModelServiceImpl.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/ActModelServiceImpl.java deleted file mode 100644 index 290bb8d..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/ActModelServiceImpl.java +++ /dev/null @@ -1,428 +0,0 @@ -package org.dromara.workflow.service.impl; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.lang.Validator; -import cn.hutool.core.util.ArrayUtil; -import cn.hutool.core.util.ObjectUtil; -import cn.hutool.core.util.StrUtil; -import cn.hutool.core.util.ZipUtil; -import cn.hutool.json.JSONUtil; -import com.alibaba.excel.util.StringUtils; -import jakarta.servlet.http.HttpServletResponse; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.batik.transcoder.TranscoderInput; -import org.apache.batik.transcoder.TranscoderOutput; -import org.apache.batik.transcoder.image.PNGTranscoder; -import org.dromara.common.core.exception.ServiceException; -import org.dromara.common.mybatis.core.page.PageQuery; -import org.dromara.common.mybatis.core.page.TableDataInfo; -import org.dromara.common.tenant.helper.TenantHelper; -import org.dromara.workflow.common.constant.FlowConstant; -import org.dromara.workflow.domain.WfNodeConfig; -import org.dromara.workflow.domain.bo.ModelBo; -import org.dromara.workflow.domain.bo.WfDefinitionConfigBo; -import org.dromara.workflow.domain.vo.ModelVo; -import org.dromara.workflow.domain.vo.WfDefinitionConfigVo; -import org.dromara.workflow.service.IActModelService; -import org.dromara.workflow.service.IWfDefinitionConfigService; -import org.dromara.workflow.service.IWfNodeConfigService; -import org.dromara.workflow.utils.ModelUtils; -import org.dromara.workflow.utils.QueryUtils; -import org.flowable.bpmn.converter.BpmnXMLConverter; -import org.flowable.bpmn.model.BpmnModel; -import org.flowable.bpmn.model.Process; -import org.flowable.bpmn.model.UserTask; -import org.flowable.engine.RepositoryService; -import org.flowable.engine.repository.Deployment; -import org.flowable.engine.repository.Model; -import org.flowable.engine.repository.ModelQuery; -import org.flowable.engine.repository.ProcessDefinition; -import org.flowable.validation.ValidationError; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; - -/** - * 模型管理 服务层实现 - * - * @author may - */ -@Slf4j -@RequiredArgsConstructor -@Service -public class ActModelServiceImpl implements IActModelService { - - @Autowired(required = false) - private RepositoryService repositoryService; - private final IWfNodeConfigService wfNodeConfigService; - private final IWfDefinitionConfigService wfDefinitionConfigService; - - /** - * 分页查询模型 - * - * @param modelBo 模型参数 - * @return 返回分页列表 - */ - @Override - public TableDataInfo page(ModelBo modelBo, PageQuery pageQuery) { - ModelQuery query = QueryUtils.modelQuery(); - if (StringUtils.isNotBlank(modelBo.getName())) { - query.modelNameLike("%" + modelBo.getName() + "%"); - } - if (StringUtils.isNotBlank(modelBo.getKey())) { - query.modelKey(modelBo.getKey()); - } - if (StringUtils.isNotBlank(modelBo.getCategoryCode())) { - query.modelCategory(modelBo.getCategoryCode()); - } - query.orderByLastUpdateTime().desc(); - // 创建时间降序排列 - query.orderByCreateTime().desc(); - // 分页查询 - List modelList = query.listPage(pageQuery.getFirstNum(), pageQuery.getPageSize()); - // 总记录数 - long total = query.count(); - TableDataInfo build = TableDataInfo.build(); - build.setRows(modelList); - build.setTotal(total); - return build; - } - - /** - * 新增模型 - * - * @param modelBo 模型请求对象 - * @return 结果 - */ - @Override - @Transactional(rollbackFor = Exception.class) - public boolean saveNewModel(ModelBo modelBo) { - try { - int version = 0; - String key = modelBo.getKey(); - String name = modelBo.getName(); - String description = modelBo.getDescription(); - String categoryCode = modelBo.getCategoryCode(); - String xml = modelBo.getXml(); - Model checkModel = QueryUtils.modelQuery().modelKey(key).singleResult(); - if (ObjectUtil.isNotNull(checkModel)) { - throw new ServiceException("模型key已存在!"); - } - //初始空的模型 - Model model = repositoryService.newModel(); - model.setKey(key); - model.setName(name); - model.setVersion(version); - model.setCategory(categoryCode); - model.setMetaInfo(description); - model.setTenantId(TenantHelper.getTenantId()); - //保存初始化的模型基本信息数据 - repositoryService.saveModel(model); - repositoryService.addModelEditorSource(model.getId(), StrUtil.utf8Bytes(xml)); - return true; - } catch (Exception e) { - log.error(e.getMessage(), e); - throw new ServiceException(e.getMessage()); - } - } - - /** - * 查询模型 - * - * @param id 模型id - * @return 模型数据 - */ - @Override - public ModelVo getInfo(String id) { - ModelVo modelVo = new ModelVo(); - Model model = repositoryService.getModel(id); - if (model != null) { - try { - byte[] modelEditorSource = repositoryService.getModelEditorSource(model.getId()); - modelVo.setXml(StrUtil.utf8Str(modelEditorSource)); - modelVo.setId(model.getId()); - modelVo.setKey(model.getKey()); - modelVo.setName(model.getName()); - modelVo.setCategoryCode(model.getCategory()); - modelVo.setDescription(model.getMetaInfo()); - return modelVo; - } catch (Exception e) { - throw new ServiceException(e.getMessage()); - } - } - return modelVo; - } - - /** - * 修改模型信息 - * - * @param modelBo 模型数据 - * @return 结果 - */ - @Override - public boolean update(ModelBo modelBo) { - try { - Model model = repositoryService.getModel(modelBo.getId()); - List list = QueryUtils.modelQuery().modelKey(modelBo.getKey()).list(); - list.stream().filter(e -> !e.getId().equals(model.getId())).findFirst().ifPresent(e -> { - throw new ServiceException("模型KEY已存在!"); - }); - model.setCategory(modelBo.getCategoryCode()); - model.setMetaInfo(modelBo.getDescription()); - repositoryService.saveModel(model); - } catch (Exception e) { - throw new ServiceException(e.getMessage()); - } - return true; - } - - /** - * 编辑模型XML - * - * @param modelBo 模型数据 - * @return 结果 - */ - @Override - @Transactional(rollbackFor = Exception.class) - public boolean editModelXml(ModelBo modelBo) { - try { - String xml = modelBo.getXml(); - String svg = modelBo.getSvg(); - String modelId = modelBo.getId(); - String key = modelBo.getKey(); - String name = modelBo.getName(); - BpmnModel bpmnModel = ModelUtils.xmlToBpmnModel(xml); - ModelUtils.checkBpmnModel(bpmnModel); - Model model = repositoryService.getModel(modelId); - List list = QueryUtils.modelQuery().modelKey(key).list(); - list.stream().filter(e -> !e.getId().equals(model.getId())).findFirst().ifPresent(e -> { - throw new ServiceException("模型KEY已存在!"); - }); - // 校验key命名规范 - if (!Validator.isMatchRegex(FlowConstant.MODEL_KEY_PATTERN, key)) { - throw new ServiceException("模型标识KEY只能字符或者下划线开头!"); - } - model.setKey(key); - model.setName(name); - model.setVersion(model.getVersion() + 1); - repositoryService.saveModel(model); - repositoryService.addModelEditorSource(model.getId(), StrUtil.utf8Bytes(xml)); - // 转换图片 - InputStream svgStream = new ByteArrayInputStream(StrUtil.utf8Bytes(svg)); - TranscoderInput input = new TranscoderInput(svgStream); - - PNGTranscoder transcoder = new PNGTranscoder(); - ByteArrayOutputStream outStream = new ByteArrayOutputStream(); - TranscoderOutput output = new TranscoderOutput(outStream); - - transcoder.transcode(input, output); - final byte[] result = outStream.toByteArray(); - repositoryService.addModelEditorSourceExtra(model.getId(), result); - return true; - } catch (Exception e) { - log.error(e.getMessage(), e); - throw new ServiceException(e.getMessage()); - } - } - - /** - * 模型部署 - * - * @param id 模型id - * @return 结果 - */ - @Override - @Transactional(rollbackFor = Exception.class) - public boolean modelDeploy(String id) { - try { - // 查询流程定义模型xml - byte[] xmlBytes = repositoryService.getModelEditorSource(id); - if (ArrayUtil.isEmpty(xmlBytes)) { - throw new ServiceException("模型数据为空,请先设计流程定义模型,再进行部署!"); - } - if (JSONUtil.isTypeJSON(new String(xmlBytes, StandardCharsets.UTF_8))) { - byte[] bytes = ModelUtils.bpmnJsonToXmlBytes(xmlBytes); - if (ArrayUtil.isEmpty(bytes)) { - throw new ServiceException("模型不能为空,请至少设计一条主线流程!"); - } - } - BpmnModel bpmnModel = ModelUtils.xmlToBpmnModel(xmlBytes); - // 校验模型 - ModelUtils.checkBpmnModel(bpmnModel); - List validationErrors = repositoryService.validateProcess(bpmnModel); - if (CollUtil.isNotEmpty(validationErrors)) { - String errorMsg = validationErrors.stream().map(ValidationError::getProblem).distinct().collect(Collectors.joining(",")); - throw new ServiceException(errorMsg); - } - // 查询模型的基本信息 - Model model = repositoryService.getModel(id); - ProcessDefinition processDefinition = QueryUtils.definitionQuery().processDefinitionKey(model.getKey()).latestVersion().singleResult(); - // xml资源的名称 ,对应act_ge_bytearray表中的name_字段 - String processName = model.getName() + ".bpmn20.xml"; - // 调用部署相关的api方法进行部署流程定义 - Deployment deployment = repositoryService.createDeployment() - // 部署名称 - .name(model.getName()) - // 部署标识key - .key(model.getKey()) - // 部署流程分类 - .category(model.getCategory()) - // bpmn20.xml资源 - .addBytes(processName, xmlBytes) - // 租户id - .tenantId(TenantHelper.getTenantId()) - .deploy(); - - // 更新 部署id 到流程定义模型数据表中 - model.setDeploymentId(deployment.getId()); - repositoryService.saveModel(model); - // 更新分类 - ProcessDefinition definition = QueryUtils.definitionQuery().deploymentId(deployment.getId()).singleResult(); - repositoryService.setProcessDefinitionCategory(definition.getId(), model.getCategory()); - //更新流程定义配置 - if (processDefinition != null) { - WfDefinitionConfigVo definitionVo = wfDefinitionConfigService.getByDefId(processDefinition.getId()); - if (definitionVo != null) { - wfDefinitionConfigService.deleteByDefIds(Collections.singletonList(processDefinition.getId())); - WfDefinitionConfigBo wfFormDefinition = new WfDefinitionConfigBo(); - wfFormDefinition.setDefinitionId(definition.getId()); - wfFormDefinition.setProcessKey(definition.getKey()); - wfFormDefinition.setTableName(definitionVo.getTableName()); - wfFormDefinition.setVersion(definition.getVersion()); - wfFormDefinition.setRemark(definitionVo.getRemark()); - wfDefinitionConfigService.saveOrUpdate(wfFormDefinition); - } - } - //更新流程节点配置表单 - List userTasks = ModelUtils.getUserTaskFlowElements(definition.getId()); - UserTask applyUserTask = ModelUtils.getApplyUserTask(definition.getId()); - List wfNodeConfigList = new ArrayList<>(); - for (UserTask userTask : userTasks) { - if (StringUtils.isNotBlank(userTask.getFormKey()) && userTask.getFormKey().contains(StrUtil.COLON)) { - WfNodeConfig wfNodeConfig = new WfNodeConfig(); - wfNodeConfig.setNodeId(userTask.getId()); - wfNodeConfig.setNodeName(userTask.getName()); - wfNodeConfig.setDefinitionId(definition.getId()); - String[] split = userTask.getFormKey().split(StrUtil.COLON); - wfNodeConfig.setFormType(split[0]); - wfNodeConfig.setFormId(Long.valueOf(split[1])); - wfNodeConfig.setApplyUserTask(applyUserTask.getId().equals(userTask.getId()) ? FlowConstant.TRUE : FlowConstant.FALSE); - wfNodeConfigList.add(wfNodeConfig); - } - } - if (CollUtil.isNotEmpty(wfNodeConfigList)) { - wfNodeConfigService.saveOrUpdate(wfNodeConfigList); - } - return true; - } catch (Exception e) { - log.error(e.getMessage(), e); - throw new ServiceException(e.getMessage()); - } - } - - /** - * 导出模型zip压缩包 - * - * @param modelIds 模型id - * @param response 相应 - */ - @Override - public void exportZip(List modelIds, HttpServletResponse response) { - try (ZipOutputStream zos = ZipUtil.getZipOutputStream(response.getOutputStream(), StandardCharsets.UTF_8)) { - // 压缩包文件名 - String zipName = "模型不存在"; - // 查询模型基本信息 - for (String modelId : modelIds) { - Model model = repositoryService.getModel(modelId); - byte[] xmlBytes = repositoryService.getModelEditorSource(modelId); - if (ObjectUtil.isNotNull(model)) { - if (JSONUtil.isTypeJSON(new String(xmlBytes, StandardCharsets.UTF_8)) && ArrayUtil.isEmpty(ModelUtils.bpmnJsonToXmlBytes(xmlBytes))) { - zipName = "模型不能为空,请至少设计一条主线流程!"; - zos.putNextEntry(new ZipEntry(zipName + ".txt")); - zos.write(zipName.getBytes(StandardCharsets.UTF_8)); - } else if (ArrayUtil.isEmpty(xmlBytes)) { - zipName = "模型数据为空,请先设计流程定义模型,再进行部署!"; - zos.putNextEntry(new ZipEntry(zipName + ".txt")); - zos.write(zipName.getBytes(StandardCharsets.UTF_8)); - } else { - String fileName = model.getName() + "-" + model.getKey(); - // 压缩包文件名 - zipName = fileName + ".zip"; - // 将xml添加到压缩包中(指定xml文件名:请假流程.bpmn20.xml - zos.putNextEntry(new ZipEntry(fileName + ".bpmn20.xml")); - zos.write(xmlBytes); - } - } - } - response.setHeader("Content-Disposition", - "attachment; filename=" + URLEncoder.encode(zipName, StandardCharsets.UTF_8) + ".zip"); - response.addHeader("Access-Control-Expose-Headers", "Content-Disposition"); - // 刷出响应流 - response.flushBuffer(); - } catch (IOException e) { - log.error(e.getMessage(), e); - } - } - - /** - * 复制模型 - * - * @param modelBo 模型数据 - * @return 结果 - */ - @Override - @Transactional(rollbackFor = Exception.class) - public boolean copyModel(ModelBo modelBo) { - try { - String key = modelBo.getKey(); - if (StringUtils.isNotBlank(key)) { - // 查询模型 - Model model = repositoryService.createModelQuery().modelId(modelBo.getId()).singleResult(); - if (ObjectUtil.isNotNull(model)) { - byte[] modelEditorSource = repositoryService.getModelEditorSource(model.getId()); - List list = QueryUtils.modelQuery().modelKey(key).list(); - if (CollUtil.isNotEmpty(list)) { - throw new ServiceException("模型KEY已存在!"); - } - // 校验key命名规范 - if (!Validator.isMatchRegex(FlowConstant.MODEL_KEY_PATTERN, key)) { - throw new ServiceException("模型标识KEY只能字符或者下划线开头!"); - } - // 复制模型数据 - Model newModel = repositoryService.newModel(); - newModel.setKey(modelBo.getKey()); - newModel.setName(modelBo.getName()); - newModel.setCategory(modelBo.getCategoryCode()); - newModel.setVersion(1); - newModel.setMetaInfo(modelBo.getDescription()); - newModel.setTenantId(TenantHelper.getTenantId()); - String xml = StrUtil.utf8Str(modelEditorSource); - BpmnModel bpmnModel = ModelUtils.xmlToBpmnModel(xml); - Process mainProcess = bpmnModel.getMainProcess(); - mainProcess.setId(modelBo.getKey()); - mainProcess.setName(modelBo.getName()); - byte[] xmlBytes = new BpmnXMLConverter().convertToXML(bpmnModel); - repositoryService.saveModel(newModel); - repositoryService.addModelEditorSource(newModel.getId(), xmlBytes); - } - } - } catch (Exception e) { - throw new ServiceException(e.getMessage()); - } - return true; - } -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessDefinitionServiceImpl.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessDefinitionServiceImpl.java deleted file mode 100644 index 77fb257..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessDefinitionServiceImpl.java +++ /dev/null @@ -1,444 +0,0 @@ -package org.dromara.workflow.service.impl; - -import cn.hutool.core.bean.BeanUtil; -import cn.hutool.core.codec.Base64; -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.io.FileUtil; -import cn.hutool.core.io.IoUtil; -import cn.hutool.core.util.ObjectUtil; -import cn.hutool.core.util.StrUtil; -import lombok.RequiredArgsConstructor; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.dromara.common.core.exception.ServiceException; -import org.dromara.common.core.utils.StreamUtils; -import org.dromara.common.core.utils.StringUtils; -import org.dromara.common.mybatis.core.page.PageQuery; -import org.dromara.common.mybatis.core.page.TableDataInfo; -import org.dromara.common.tenant.helper.TenantHelper; -import org.dromara.workflow.common.constant.FlowConstant; -import org.dromara.workflow.domain.WfCategory; -import org.dromara.workflow.domain.WfDefinitionConfig; -import org.dromara.workflow.domain.WfNodeConfig; -import org.dromara.workflow.domain.bo.ProcessDefinitionBo; -import org.dromara.workflow.domain.bo.WfDefinitionConfigBo; -import org.dromara.workflow.domain.vo.ProcessDefinitionVo; -import org.dromara.workflow.domain.vo.WfDefinitionConfigVo; -import org.dromara.workflow.mapper.WfDefinitionConfigMapper; -import org.dromara.workflow.service.IActProcessDefinitionService; -import org.dromara.workflow.service.IWfCategoryService; -import org.dromara.workflow.service.IWfDefinitionConfigService; -import org.dromara.workflow.service.IWfNodeConfigService; -import org.dromara.workflow.utils.ModelUtils; -import org.dromara.workflow.utils.QueryUtils; -import org.flowable.bpmn.model.UserTask; -import org.flowable.engine.ProcessMigrationService; -import org.flowable.engine.RepositoryService; -import org.flowable.engine.history.HistoricProcessInstance; -import org.flowable.engine.impl.bpmn.deployer.ResourceNameUtil; -import org.flowable.engine.repository.*; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.multipart.MultipartFile; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; - -/** - * 流程定义 服务层实现 - * - * @author may - */ -@Slf4j -@RequiredArgsConstructor -@Service -public class ActProcessDefinitionServiceImpl implements IActProcessDefinitionService { - - @Autowired(required = false) - private RepositoryService repositoryService; - @Autowired(required = false) - private ProcessMigrationService processMigrationService; - private final IWfCategoryService wfCategoryService; - private final IWfDefinitionConfigService wfDefinitionConfigService; - private final WfDefinitionConfigMapper wfDefinitionConfigMapper; - private final IWfNodeConfigService wfNodeConfigService; - - /** - * 分页查询 - * - * @param bo 参数 - * @return 返回分页列表 - */ - @Override - public TableDataInfo page(ProcessDefinitionBo bo, PageQuery pageQuery) { - ProcessDefinitionQuery query = QueryUtils.definitionQuery(); - if (StringUtils.isNotEmpty(bo.getKey())) { - query.processDefinitionKey(bo.getKey()); - } - if (StringUtils.isNotEmpty(bo.getCategoryCode())) { - query.processDefinitionCategory(bo.getCategoryCode()); - } - if (StringUtils.isNotEmpty(bo.getName())) { - query.processDefinitionNameLike("%" + bo.getName() + "%"); - } - query.orderByDeploymentId().desc(); - // 分页查询 - List processDefinitionVoList = new ArrayList<>(); - List definitionList = query.latestVersion().listPage(pageQuery.getFirstNum(), pageQuery.getPageSize()); - List deploymentList = null; - if (CollUtil.isNotEmpty(definitionList)) { - List deploymentIds = StreamUtils.toList(definitionList, ProcessDefinition::getDeploymentId); - deploymentList = QueryUtils.deploymentQuery(deploymentIds).list(); - } - if (CollUtil.isNotEmpty(definitionList)) { - List ids = StreamUtils.toList(definitionList, ProcessDefinition::getId); - List wfDefinitionConfigVos = wfDefinitionConfigService.queryList(ids); - for (ProcessDefinition processDefinition : definitionList) { - ProcessDefinitionVo processDefinitionVo = BeanUtil.toBean(processDefinition, ProcessDefinitionVo.class); - if (CollUtil.isNotEmpty(deploymentList)) { - // 部署时间 - deploymentList.stream().filter(e -> e.getId().equals(processDefinition.getDeploymentId())).findFirst().ifPresent(e -> { - processDefinitionVo.setDeploymentTime(e.getDeploymentTime()); - }); - } - if (CollUtil.isNotEmpty(wfDefinitionConfigVos)) { - wfDefinitionConfigVos.stream().filter(e -> e.getDefinitionId().equals(processDefinition.getId())).findFirst().ifPresent(processDefinitionVo::setWfDefinitionConfigVo); - } - processDefinitionVoList.add(processDefinitionVo); - } - } - // 总记录数 - long total = query.count(); - TableDataInfo build = TableDataInfo.build(); - build.setRows(processDefinitionVoList); - build.setTotal(total); - return build; - } - - /** - * 查询历史流程定义列表 - * - * @param key 流程定义key - */ - @Override - public List getListByKey(String key) { - List processDefinitionVoList = new ArrayList<>(); - ProcessDefinitionQuery query = QueryUtils.definitionQuery(); - List definitionList = query.processDefinitionKey(key).list(); - List deploymentList = null; - if (CollUtil.isNotEmpty(definitionList)) { - List deploymentIds = StreamUtils.toList(definitionList, ProcessDefinition::getDeploymentId); - deploymentList = QueryUtils.deploymentQuery(deploymentIds).list(); - } - if (CollUtil.isNotEmpty(definitionList)) { - List ids = StreamUtils.toList(definitionList, ProcessDefinition::getId); - List wfDefinitionConfigVos = wfDefinitionConfigService.queryList(ids); - for (ProcessDefinition processDefinition : definitionList) { - ProcessDefinitionVo processDefinitionVo = BeanUtil.toBean(processDefinition, ProcessDefinitionVo.class); - if (CollUtil.isNotEmpty(deploymentList)) { - // 部署时间 - deploymentList.stream().filter(e -> e.getId().equals(processDefinition.getDeploymentId())).findFirst().ifPresent(e -> { - processDefinitionVo.setDeploymentTime(e.getDeploymentTime()); - }); - if (CollUtil.isNotEmpty(wfDefinitionConfigVos)) { - wfDefinitionConfigVos.stream().filter(e -> e.getDefinitionId().equals(processDefinition.getId())).findFirst().ifPresent(processDefinitionVo::setWfDefinitionConfigVo); - } - } - processDefinitionVoList.add(processDefinitionVo); - } - } - return CollUtil.reverse(processDefinitionVoList); - } - - /** - * 查看流程定义图片 - * - * @param processDefinitionId 流程定义id - */ - @SneakyThrows - @Override - public String definitionImage(String processDefinitionId) { - InputStream inputStream = repositoryService.getProcessDiagram(processDefinitionId); - return Base64.encode(IoUtil.readBytes(inputStream)); - } - - /** - * 查看流程定义xml文件 - * - * @param processDefinitionId 流程定义id - */ - @Override - public String definitionXml(String processDefinitionId) { - StringBuilder xml = new StringBuilder(); - ProcessDefinition processDefinition = repositoryService.getProcessDefinition(processDefinitionId); - InputStream inputStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), processDefinition.getResourceName()); - xml.append(IoUtil.read(inputStream, StandardCharsets.UTF_8)); - return xml.toString(); - } - - /** - * 删除流程定义 - * - * @param deploymentIds 部署id - * @param processDefinitionIds 流程定义id - */ - @Override - @Transactional(rollbackFor = Exception.class) - public boolean deleteDeployment(List deploymentIds, List processDefinitionIds) { - try { - List historicProcessInstances = QueryUtils.hisInstanceQuery().deploymentIdIn(deploymentIds).list(); - if (CollUtil.isNotEmpty(historicProcessInstances)) { - Set defIds = StreamUtils.toSet(historicProcessInstances, HistoricProcessInstance::getProcessDefinitionId); - List processDefinitions = QueryUtils.definitionQuery().processDefinitionIds(defIds).list(); - if (CollUtil.isNotEmpty(processDefinitions)) { - Set keys = StreamUtils.toSet(processDefinitions, ProcessDefinition::getKey); - throw new ServiceException("当前【" + String.join(",", keys) + "】流程定义已被使用不可删除!"); - } - } - //删除流程定义 - for (String deploymentId : deploymentIds) { - repositoryService.deleteDeployment(deploymentId); - } - //删除流程定义配置 - wfDefinitionConfigService.deleteByDefIds(processDefinitionIds); - //删除节点配置 - wfNodeConfigService.deleteByDefIds(processDefinitionIds); - return true; - } catch (Exception e) { - log.error(e.getMessage(), e); - throw new ServiceException(e.getMessage()); - } - } - - /** - * 激活或者挂起流程定义 - * - * @param processDefinitionId 流程定义id - */ - @Override - public boolean updateDefinitionState(String processDefinitionId) { - try { - ProcessDefinition processDefinition = QueryUtils.definitionQuery() - .processDefinitionId(processDefinitionId).singleResult(); - //将当前为挂起状态更新为激活状态 - //参数说明:参数1:流程定义id,参数2:是否激活(true是否级联对应流程实例,激活了则对应流程实例都可以审批), - //参数3:什么时候激活,如果为null则立即激活,如果为具体时间则到达此时间后激活 - if (processDefinition.isSuspended()) { - repositoryService.activateProcessDefinitionById(processDefinitionId, true, null); - } else { - repositoryService.suspendProcessDefinitionById(processDefinitionId, true, null); - } - return true; - } catch (Exception e) { - log.error(e.getMessage(), e); - throw new ServiceException("操作失败:" + e.getMessage()); - } - } - - /** - * 迁移流程定义 - * - * @param currentProcessDefinitionId 当前流程定义id - * @param fromProcessDefinitionId 需要迁移到的流程定义id - */ - - @Override - public boolean migrationDefinition(String currentProcessDefinitionId, String fromProcessDefinitionId) { - try { - // 迁移验证 - boolean migrationValid = processMigrationService.createProcessInstanceMigrationBuilder() - .migrateToProcessDefinition(currentProcessDefinitionId) - .validateMigrationOfProcessInstances(fromProcessDefinitionId) - .isMigrationValid(); - if (!migrationValid) { - throw new ServiceException("流程定义差异过大无法迁移,请修改流程图"); - } - // 已结束的流程实例不会迁移 - processMigrationService.createProcessInstanceMigrationBuilder() - .migrateToProcessDefinition(currentProcessDefinitionId) - .migrateProcessInstances(fromProcessDefinitionId); - return true; - } catch (Exception e) { - log.error(e.getMessage(), e); - throw new ServiceException(e.getMessage()); - } - } - - /** - * 流程定义转换为模型 - * - * @param processDefinitionId 流程定义id - */ - @Override - public boolean convertToModel(String processDefinitionId) { - ProcessDefinition pd = QueryUtils.definitionQuery() - .processDefinitionId(processDefinitionId).singleResult(); - InputStream inputStream = repositoryService.getResourceAsStream(pd.getDeploymentId(), pd.getResourceName()); - ModelQuery query = QueryUtils.modelQuery(); - Model model = query.modelKey(pd.getKey()).singleResult(); - try { - if (ObjectUtil.isNotNull(model)) { - repositoryService.addModelEditorSource(model.getId(), IoUtil.readBytes(inputStream)); - } else { - Model modelData = repositoryService.newModel(); - modelData.setKey(pd.getKey()); - modelData.setName(pd.getName()); - modelData.setCategory(pd.getCategory()); - modelData.setTenantId(pd.getTenantId()); - repositoryService.saveModel(modelData); - repositoryService.addModelEditorSource(modelData.getId(), IoUtil.readBytes(inputStream)); - } - return true; - } catch (Exception e) { - log.error(e.getMessage(), e); - throw new ServiceException(e.getMessage()); - } - } - - /** - * 通过zip或xml部署流程定义 - * - * @param file 文件 - * @param categoryCode 分类 - */ - @SneakyThrows - @Override - @Transactional(rollbackFor = Exception.class) - public void deployByFile(MultipartFile file, String categoryCode) { - - WfCategory wfCategory = wfCategoryService.queryByCategoryCode(categoryCode); - if (wfCategory == null) { - throw new ServiceException("流程分类不存在"); - } - // 文件后缀名 - String suffix = FileUtil.extName(file.getOriginalFilename()); - InputStream inputStream = file.getInputStream(); - if (FlowConstant.ZIP.equalsIgnoreCase(suffix)) { - ZipInputStream zipInputStream = null; - try { - zipInputStream = new ZipInputStream(inputStream); - ZipEntry zipEntry; - while ((zipEntry = zipInputStream.getNextEntry()) != null) { - String filename = zipEntry.getName(); - String[] splitFilename = filename.substring(0, filename.lastIndexOf(".")).split("-"); - //流程名称 - String processName = splitFilename[0]; - //流程key - String processKey = splitFilename[1]; - ProcessDefinition oldProcessDefinition = QueryUtils.definitionQuery().processDefinitionKey(processKey).latestVersion().singleResult(); - DeploymentBuilder builder = repositoryService.createDeployment(); - Deployment deployment = builder.addInputStream(filename, zipInputStream) - .tenantId(TenantHelper.getTenantId()) - .name(processName).key(processKey).category(categoryCode).deploy(); - ProcessDefinition definition = QueryUtils.definitionQuery().deploymentId(deployment.getId()).singleResult(); - repositoryService.setProcessDefinitionCategory(definition.getId(), categoryCode); - setWfConfig(oldProcessDefinition, definition); - zipInputStream.closeEntry(); - } - } catch (IOException e) { - throw new RuntimeException(e); - } finally { - if (zipInputStream != null) { - zipInputStream.close(); - } - } - //初始化配置数据(demo使用,不用可删除) - initWfDefConfig(); - } else { - String originalFilename = file.getOriginalFilename(); - if (StringUtils.containsAny(originalFilename, ResourceNameUtil.BPMN_RESOURCE_SUFFIXES)) { - // 文件名 = 流程名称-流程key - String[] splitFilename = originalFilename.substring(0, originalFilename.lastIndexOf(".")).split("-"); - if (splitFilename.length < 2) { - throw new ServiceException("文件名 = 流程名称-流程KEY"); - } - //流程名称 - String processName = splitFilename[0]; - //流程key - String processKey = splitFilename[1]; - ProcessDefinition oldProcessDefinition = QueryUtils.definitionQuery().processDefinitionKey(processKey).latestVersion().singleResult(); - DeploymentBuilder builder = repositoryService.createDeployment(); - Deployment deployment = builder.addInputStream(originalFilename, inputStream) - .tenantId(TenantHelper.getTenantId()) - .name(processName).key(processKey).category(categoryCode).deploy(); - // 更新分类 - ProcessDefinition definition = QueryUtils.definitionQuery().deploymentId(deployment.getId()).singleResult(); - repositoryService.setProcessDefinitionCategory(definition.getId(), categoryCode); - setWfConfig(oldProcessDefinition, definition); - } else { - throw new ServiceException("文件类型上传错误!"); - } - } - - } - - /** - * 初始化配置数据(demo使用,不用可删除) - */ - private void initWfDefConfig() { - List wfDefinitionConfigs = wfDefinitionConfigMapper.selectList(); - if (CollUtil.isEmpty(wfDefinitionConfigs)) { - ProcessDefinition processDefinition = QueryUtils.definitionQuery().processDefinitionKey("leave1").latestVersion().singleResult(); - if (processDefinition != null) { - WfDefinitionConfigBo wfDefinitionConfigBo = new WfDefinitionConfigBo(); - wfDefinitionConfigBo.setDefinitionId(processDefinition.getId()); - wfDefinitionConfigBo.setProcessKey(processDefinition.getKey()); - wfDefinitionConfigBo.setTableName("test_leave"); - wfDefinitionConfigBo.setVersion(processDefinition.getVersion()); - wfDefinitionConfigService.saveOrUpdate(wfDefinitionConfigBo); - } - } - - } - - /** - * 设置表单内容 - * - * @param oldProcessDefinition 部署前最新流程定义 - * @param definition 部署后最新流程定义 - */ - private void setWfConfig(ProcessDefinition oldProcessDefinition, ProcessDefinition definition) { - //更新流程定义表单 - if (oldProcessDefinition != null) { - WfDefinitionConfigVo definitionVo = wfDefinitionConfigService.getByDefId(oldProcessDefinition.getId()); - if (definitionVo != null) { - wfDefinitionConfigService.deleteByDefIds(Collections.singletonList(oldProcessDefinition.getId())); - WfDefinitionConfigBo wfDefinitionConfigBo = new WfDefinitionConfigBo(); - wfDefinitionConfigBo.setDefinitionId(definition.getId()); - wfDefinitionConfigBo.setProcessKey(definition.getKey()); - wfDefinitionConfigBo.setTableName(definitionVo.getTableName()); - wfDefinitionConfigBo.setVersion(definition.getVersion()); - wfDefinitionConfigBo.setRemark(definitionVo.getRemark()); - wfDefinitionConfigService.saveOrUpdate(wfDefinitionConfigBo); - } - } - //更新流程节点配置表单 - List userTasks = ModelUtils.getUserTaskFlowElements(definition.getId()); - UserTask applyUserTask = ModelUtils.getApplyUserTask(definition.getId()); - List wfNodeConfigList = new ArrayList<>(); - for (UserTask userTask : userTasks) { - if (StringUtils.isNotBlank(userTask.getFormKey()) && userTask.getFormKey().contains(StrUtil.COLON)) { - WfNodeConfig wfNodeConfig = new WfNodeConfig(); - wfNodeConfig.setNodeId(userTask.getId()); - wfNodeConfig.setNodeName(userTask.getName()); - wfNodeConfig.setDefinitionId(definition.getId()); - String[] split = userTask.getFormKey().split(StrUtil.COLON); - wfNodeConfig.setFormType(split[0]); - wfNodeConfig.setFormId(Long.valueOf(split[1])); - wfNodeConfig.setApplyUserTask(applyUserTask.getId().equals(userTask.getId()) ? FlowConstant.TRUE : FlowConstant.FALSE); - wfNodeConfigList.add(wfNodeConfig); - } - } - if (CollUtil.isNotEmpty(wfNodeConfigList)) { - wfNodeConfigService.saveOrUpdate(wfNodeConfigList); - } - } -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessInstanceServiceImpl.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessInstanceServiceImpl.java deleted file mode 100644 index af7a9a2..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessInstanceServiceImpl.java +++ /dev/null @@ -1,694 +0,0 @@ -package org.dromara.workflow.service.impl; - -import cn.hutool.core.bean.BeanUtil; -import cn.hutool.core.codec.Base64; -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.convert.Convert; -import cn.hutool.core.io.IoUtil; -import cn.hutool.core.util.ObjectUtil; -import lombok.RequiredArgsConstructor; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.apache.dubbo.config.annotation.DubboReference; -import org.dromara.common.core.exception.ServiceException; -import org.dromara.common.core.utils.StreamUtils; -import org.dromara.common.core.utils.StringUtils; -import org.dromara.common.mybatis.core.page.PageQuery; -import org.dromara.common.mybatis.core.page.TableDataInfo; -import org.dromara.common.satoken.utils.LoginHelper; -import org.dromara.system.api.RemoteUserService; -import org.dromara.workflow.common.constant.FlowConstant; -import org.dromara.common.core.enums.BusinessStatusEnum; -import org.dromara.workflow.common.enums.TaskStatusEnum; -import org.dromara.workflow.domain.ActHiProcinst; -import org.dromara.workflow.domain.bo.ProcessInstanceBo; -import org.dromara.workflow.domain.bo.ProcessInvalidBo; -import org.dromara.workflow.domain.bo.TaskUrgingBo; -import org.dromara.workflow.domain.vo.*; -import org.dromara.workflow.flowable.CustomDefaultProcessDiagramGenerator; -import org.dromara.workflow.flowable.cmd.DeleteExecutionCmd; -import org.dromara.workflow.flowable.cmd.ExecutionChildByExecutionIdCmd; -import org.dromara.workflow.flowable.handler.FlowProcessEventHandler; -import org.dromara.workflow.service.IActHiProcinstService; -import org.dromara.workflow.service.IActProcessInstanceService; -import org.dromara.workflow.service.IWfNodeConfigService; -import org.dromara.workflow.service.IWfTaskBackNodeService; -import org.dromara.workflow.utils.QueryUtils; -import org.dromara.workflow.utils.WorkflowUtils; -import org.flowable.bpmn.model.*; -import org.flowable.engine.*; -import org.flowable.engine.history.HistoricActivityInstance; -import org.flowable.engine.history.HistoricProcessInstance; -import org.flowable.engine.history.HistoricProcessInstanceQuery; -import org.flowable.engine.impl.persistence.entity.ExecutionEntity; -import org.flowable.engine.repository.ProcessDefinition; -import org.flowable.engine.runtime.ProcessInstance; -import org.flowable.engine.runtime.ProcessInstanceQuery; -import org.flowable.engine.task.Attachment; -import org.flowable.engine.task.Comment; -import org.flowable.task.api.Task; -import org.flowable.task.api.history.HistoricTaskInstance; -import org.springframework.beans.BeanUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.awt.*; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.util.List; -import java.util.*; -import java.util.stream.Collectors; - -/** - * 流程实例 服务层实现 - * - * @author may - */ -@Slf4j -@RequiredArgsConstructor -@Service -public class ActProcessInstanceServiceImpl implements IActProcessInstanceService { - - @Autowired(required = false) - private RepositoryService repositoryService; - @Autowired(required = false) - private RuntimeService runtimeService; - @Autowired(required = false) - private HistoryService historyService; - @Autowired(required = false) - private TaskService taskService; - @Autowired(required = false) - private ManagementService managementService; - private final IActHiProcinstService actHiProcinstService; - private final IWfTaskBackNodeService wfTaskBackNodeService; - private final IWfNodeConfigService wfNodeConfigService; - private final FlowProcessEventHandler flowProcessEventHandler; - @DubboReference - private final RemoteUserService remoteUserService; - - @Value("${flowable.activity-font-name}") - private String activityFontName; - - @Value("${flowable.label-font-name}") - private String labelFontName; - - @Value("${flowable.annotation-font-name}") - private String annotationFontName; - - /** - * 分页查询正在运行的流程实例 - * - * @param bo 参数 - */ - @Override - public TableDataInfo getPageByRunning(ProcessInstanceBo bo, PageQuery pageQuery) { - List list = new ArrayList<>(); - ProcessInstanceQuery query = QueryUtils.instanceQuery(); - if (StringUtils.isNotBlank(bo.getName())) { - query.processInstanceNameLikeIgnoreCase("%" + bo.getName() + "%"); - } - if (StringUtils.isNotBlank(bo.getKey())) { - query.processDefinitionKey(bo.getKey()); - } - if (StringUtils.isNotBlank(bo.getStartUserId())) { - query.startedBy(bo.getStartUserId()); - } - if (StringUtils.isNotBlank(bo.getBusinessKey())) { - query.processInstanceBusinessKey(bo.getBusinessKey()); - } - if (StringUtils.isNotBlank(bo.getCategoryCode())) { - query.processDefinitionCategory(bo.getCategoryCode()); - } - query.orderByStartTime().desc(); - List processInstances = query.listPage(pageQuery.getFirstNum(), pageQuery.getPageSize()); - for (ProcessInstance processInstance : processInstances) { - ProcessInstanceVo processInstanceVo = BeanUtil.toBean(processInstance, ProcessInstanceVo.class); - processInstanceVo.setIsSuspended(processInstance.isSuspended()); - processInstanceVo.setBusinessStatusName(BusinessStatusEnum.findByStatus(processInstance.getBusinessStatus())); - list.add(processInstanceVo); - } - if (CollUtil.isNotEmpty(list)) { - List processDefinitionIds = StreamUtils.toList(list, ProcessInstanceVo::getProcessDefinitionId); - List wfNodeConfigVoList = wfNodeConfigService.selectByDefIds(processDefinitionIds); - for (ProcessInstanceVo processInstanceVo : list) { - if (CollUtil.isNotEmpty(wfNodeConfigVoList)) { - wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(processInstanceVo.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(processInstanceVo::setWfNodeConfigVo); - } - } - } - long count = query.count(); - TableDataInfo build = TableDataInfo.build(); - build.setRows(list); - build.setTotal(count); - return build; - } - - /** - * 分页查询已结束的流程实例 - * - * @param bo 参数 - */ - @Override - public TableDataInfo getPageByFinish(ProcessInstanceBo bo, PageQuery pageQuery) { - List list = new ArrayList<>(); - HistoricProcessInstanceQuery query = QueryUtils.hisInstanceQuery() - .finished().orderByProcessInstanceEndTime().desc(); - if (StringUtils.isNotEmpty(bo.getName())) { - query.processInstanceNameLikeIgnoreCase("%" + bo.getName() + "%"); - } - if (StringUtils.isNotBlank(bo.getKey())) { - query.processDefinitionKey(bo.getKey()); - } - if (StringUtils.isNotEmpty(bo.getStartUserId())) { - query.startedBy(bo.getStartUserId()); - } - if (StringUtils.isNotBlank(bo.getBusinessKey())) { - query.processInstanceBusinessKey(bo.getBusinessKey()); - } - if (StringUtils.isNotBlank(bo.getCategoryCode())) { - query.processDefinitionCategory(bo.getCategoryCode()); - } - List historicProcessInstances = query.listPage(pageQuery.getFirstNum(), pageQuery.getPageSize()); - for (HistoricProcessInstance historicProcessInstance : historicProcessInstances) { - ProcessInstanceVo processInstanceVo = BeanUtil.toBean(historicProcessInstance, ProcessInstanceVo.class); - processInstanceVo.setBusinessStatusName(BusinessStatusEnum.findByStatus(historicProcessInstance.getBusinessStatus())); - list.add(processInstanceVo); - } - if (CollUtil.isNotEmpty(list)) { - List processDefinitionIds = StreamUtils.toList(list, ProcessInstanceVo::getProcessDefinitionId); - List wfNodeConfigVoList = wfNodeConfigService.selectByDefIds(processDefinitionIds); - for (ProcessInstanceVo processInstanceVo : list) { - if (CollUtil.isNotEmpty(wfNodeConfigVoList)) { - wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(processInstanceVo.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(processInstanceVo::setWfNodeConfigVo); - } - } - } - long count = query.count(); - TableDataInfo build = TableDataInfo.build(); - build.setRows(list); - build.setTotal(count); - return build; - } - - /** - * 通过业务id获取历史流程图 - * - * @param businessKey 业务id - */ - @SneakyThrows - @Override - public String getHistoryImage(String businessKey) { - String processDefinitionId; - // 获取当前的流程实例 - ProcessInstance processInstance = QueryUtils.businessKeyQuery(businessKey).singleResult(); - // 如果流程已经结束,则得到结束节点 - if (Objects.isNull(processInstance)) { - HistoricProcessInstance pi = QueryUtils.hisInstanceQuery().processInstanceBusinessKey(businessKey).singleResult(); - processDefinitionId = pi.getProcessDefinitionId(); - } else { - // 根据流程实例ID获得当前处于活动状态的ActivityId合集 - ProcessInstance pi = QueryUtils.instanceQuery(processInstance.getProcessInstanceId()).singleResult(); - processDefinitionId = pi.getProcessDefinitionId(); - } - - // 获得活动的节点 - List highLightedFlowList = QueryUtils.hisActivityInstanceQuery(processInstance.getProcessInstanceId()).orderByHistoricActivityInstanceStartTime().asc().list(); - - List highLightedFlows = new ArrayList<>(); - List highLightedNodes = new ArrayList<>(); - //高亮 - for (HistoricActivityInstance tempActivity : highLightedFlowList) { - if (FlowConstant.SEQUENCE_FLOW.equals(tempActivity.getActivityType())) { - //高亮线 - highLightedFlows.add(tempActivity.getActivityId()); - } else { - //高亮节点 - if (tempActivity.getEndTime() == null) { - highLightedNodes.add(Color.RED.toString() + tempActivity.getActivityId()); - } else { - highLightedNodes.add(tempActivity.getActivityId()); - } - } - } - List highLightedNodeList = new ArrayList<>(); - //运行中的节点 - List redNodeCollect = StreamUtils.filter(highLightedNodes, e -> e.contains(Color.RED.toString())); - //排除与运行中相同的节点 - for (String nodeId : highLightedNodes) { - if (!nodeId.contains(Color.RED.toString()) && !redNodeCollect.contains(Color.RED + nodeId)) { - highLightedNodeList.add(nodeId); - } - } - highLightedNodeList.addAll(redNodeCollect); - BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId); - CustomDefaultProcessDiagramGenerator diagramGenerator = new CustomDefaultProcessDiagramGenerator(); - InputStream inputStream = diagramGenerator.generateDiagram(bpmnModel, "png", highLightedNodeList, highLightedFlows, activityFontName, labelFontName, annotationFontName, null, 1.0, true); - return Base64.encode(IoUtil.readBytes(inputStream)); - } - - /** - * 通过业务id获取历史流程图运行中,历史等节点 - * - * @param businessKey 业务id - */ - @Override - public Map getHistoryList(String businessKey) { - Map map = new HashMap<>(); - List> taskList = new ArrayList<>(); - HistoricProcessInstance historicProcessInstance = QueryUtils.hisBusinessKeyQuery(businessKey).singleResult(); - String processInstanceId = historicProcessInstance.getId(); - StringBuilder xml = new StringBuilder(); - ProcessDefinition processDefinition = repositoryService.getProcessDefinition(historicProcessInstance.getProcessDefinitionId()); - // 获取节点 - List highLightedFlowList = QueryUtils.hisActivityInstanceQuery(processInstanceId).orderByHistoricActivityInstanceStartTime().asc().list(); - for (HistoricActivityInstance tempActivity : highLightedFlowList) { - Map task = new HashMap<>(); - switch (tempActivity.getActivityType()) { - case FlowConstant.SEQUENCE_FLOW, FlowConstant.PARALLEL_GATEWAY, - FlowConstant.EXCLUSIVE_GATEWAY, FlowConstant.INCLUSIVE_GATEWAY -> {} - default -> { - task.put("key", tempActivity.getActivityId()); - task.put("completed", tempActivity.getEndTime() != null); - task.put("activityType", tempActivity.getActivityType()); - taskList.add(task); - } - } - } - ProcessInstance processInstance = QueryUtils.instanceQuery(processInstanceId).singleResult(); - if (processInstance != null) { - taskList = StreamUtils.filter(taskList, e -> !e.get("activityType").equals(FlowConstant.END_EVENT)); - } - //查询出运行中节点 - List> runtimeNodeList = StreamUtils.filter(taskList, e -> !(Boolean) e.get("completed")); - if (CollUtil.isNotEmpty(runtimeNodeList)) { - Iterator> iterator = taskList.iterator(); - while (iterator.hasNext()) { - Map next = iterator.next(); - runtimeNodeList.stream().filter(t -> t.get("key").equals(next.get("key")) && (Boolean) next.get("completed")).findFirst().ifPresent(t -> iterator.remove()); - } - } - map.put("taskList", taskList); - List historyTaskList = getHistoryTaskList(processInstanceId, processDefinition.getVersion()); - map.put("historyList", historyTaskList); - InputStream inputStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), processDefinition.getResourceName()); - xml.append(IoUtil.read(inputStream, StandardCharsets.UTF_8)); - map.put("xml", xml.toString()); - return map; - } - - /** - * 获取历史任务节点信息 - * - * @param processInstanceId 流程实例id - * @param version 版本 - */ - private List getHistoryTaskList(String processInstanceId, Integer version) { - //查询任务办理记录 - List list = QueryUtils.hisTaskInstanceQuery(processInstanceId).orderByHistoricTaskInstanceEndTime().desc().list(); - list = StreamUtils.sorted(list, Comparator.comparing(HistoricTaskInstance::getEndTime, Comparator.nullsFirst(Date::compareTo)).reversed()); - List actHistoryInfoVoList = new ArrayList<>(); - for (HistoricTaskInstance historicTaskInstance : list) { - ActHistoryInfoVo actHistoryInfoVo = new ActHistoryInfoVo(); - BeanUtils.copyProperties(historicTaskInstance, actHistoryInfoVo); - actHistoryInfoVo.setStatus(actHistoryInfoVo.getEndTime() == null ? "待处理" : "已处理"); - if (ObjectUtil.isNotEmpty(historicTaskInstance.getDurationInMillis())) { - actHistoryInfoVo.setRunDuration(getDuration(historicTaskInstance.getDurationInMillis())); - } - actHistoryInfoVo.setVersion(version); - actHistoryInfoVoList.add(actHistoryInfoVo); - } - List historyInfoVoList = new ArrayList<>(); - Map> groupByKey = StreamUtils.groupByKey(actHistoryInfoVoList, ActHistoryInfoVo::getTaskDefinitionKey); - for (Map.Entry> entry : groupByKey.entrySet()) { - ActHistoryInfoVo historyInfoVo = new ActHistoryInfoVo(); - if (entry.getValue().size() > 1) { - List historyInfoVos = StreamUtils.filter(entry.getValue(), e -> StringUtils.isNotBlank(e.getAssignee())); - if (CollUtil.isNotEmpty(historyInfoVos)) { - ActHistoryInfoVo infoVo = historyInfoVos.get(0); - BeanUtils.copyProperties(infoVo, historyInfoVo); - historyInfoVo.setStatus(infoVo.getEndTime() == null ? "待处理" : "已处理"); - historyInfoVo.setStartTime(infoVo.getStartTime()); - historyInfoVo.setEndTime(infoVo.getEndTime() == null ? null : infoVo.getEndTime()); - historyInfoVo.setRunDuration(infoVo.getEndTime() == null ? null : infoVo.getRunDuration()); - if (ObjectUtil.isEmpty(infoVo.getAssignee())) { - ParticipantVo participantVo = WorkflowUtils.getCurrentTaskParticipant(infoVo.getId(), remoteUserService); - if (ObjectUtil.isNotEmpty(participantVo) && CollUtil.isNotEmpty(participantVo.getCandidate())) { - historyInfoVo.setAssignee(StreamUtils.join(participantVo.getCandidate(), Convert::toStr)); - } - } - } - } else { - actHistoryInfoVoList.stream().filter(e -> e.getTaskDefinitionKey().equals(entry.getKey())).findFirst() - .ifPresent(e -> { - BeanUtils.copyProperties(e, historyInfoVo); - historyInfoVo.setStatus(e.getEndTime() == null ? "待处理" : "已处理"); - historyInfoVo.setStartTime(e.getStartTime()); - historyInfoVo.setEndTime(e.getEndTime() == null ? null : e.getEndTime()); - historyInfoVo.setRunDuration(e.getEndTime() == null ? null : e.getRunDuration()); - if (ObjectUtil.isEmpty(e.getAssignee())) { - ParticipantVo participantVo = WorkflowUtils.getCurrentTaskParticipant(e.getId(), remoteUserService); - if (ObjectUtil.isNotEmpty(participantVo) && CollUtil.isNotEmpty(participantVo.getCandidate())) { - historyInfoVo.setAssignee(StreamUtils.join(participantVo.getCandidate(), Convert::toStr)); - } - } - }); - - } - historyInfoVoList.add(historyInfoVo); - - } - return historyInfoVoList; - } - - /** - * 获取审批记录 - * - * @param businessKey 业务id - */ - @Override - public List getHistoryRecord(String businessKey) { - // 查询任务办理记录 - List list = QueryUtils.hisTaskBusinessKeyQuery(businessKey).orderByHistoricTaskInstanceEndTime().desc().list(); - list = StreamUtils.sorted(list, Comparator.comparing(HistoricTaskInstance::getEndTime, Comparator.nullsFirst(Date::compareTo)).reversed()); - HistoricProcessInstance historicProcessInstance = QueryUtils.hisBusinessKeyQuery(businessKey).singleResult(); - String processInstanceId = historicProcessInstance.getId(); - List actHistoryInfoVoList = new ArrayList<>(); - List processInstanceComments = taskService.getProcessInstanceComments(processInstanceId); - //附件 - List attachmentList = taskService.getProcessInstanceAttachments(processInstanceId); - for (HistoricTaskInstance historicTaskInstance : list) { - ActHistoryInfoVo actHistoryInfoVo = new ActHistoryInfoVo(); - BeanUtils.copyProperties(historicTaskInstance, actHistoryInfoVo); - if (actHistoryInfoVo.getEndTime() == null) { - actHistoryInfoVo.setStatus(TaskStatusEnum.WAITING.getStatus()); - actHistoryInfoVo.setStatusName(TaskStatusEnum.WAITING.getDesc()); - } - if (CollUtil.isNotEmpty(processInstanceComments)) { - processInstanceComments.stream().filter(e -> e.getTaskId().equals(historicTaskInstance.getId())).findFirst().ifPresent(e -> { - actHistoryInfoVo.setComment(e.getFullMessage()); - actHistoryInfoVo.setStatus(e.getType()); - actHistoryInfoVo.setStatusName(TaskStatusEnum.findByStatus(e.getType())); - }); - } - if (ObjectUtil.isNotEmpty(historicTaskInstance.getDurationInMillis())) { - actHistoryInfoVo.setRunDuration(getDuration(historicTaskInstance.getDurationInMillis())); - } - //附件 - if (CollUtil.isNotEmpty(attachmentList)) { - List attachments = attachmentList.stream().filter(e -> e.getTaskId().equals(historicTaskInstance.getId())).collect(Collectors.toList()); - if (CollUtil.isNotEmpty(attachments)) { - actHistoryInfoVo.setAttachmentList(attachments); - } - } - //设置人员id - if (ObjectUtil.isEmpty(historicTaskInstance.getAssignee())) { - ParticipantVo participantVo = WorkflowUtils.getCurrentTaskParticipant(historicTaskInstance.getId(), remoteUserService); - if (ObjectUtil.isNotEmpty(participantVo) && CollUtil.isNotEmpty(participantVo.getCandidate())) { - actHistoryInfoVo.setAssignee(StreamUtils.join(participantVo.getCandidate(), Convert::toStr)); - } - } - actHistoryInfoVoList.add(actHistoryInfoVo); - } - // 审批记录 - Map> groupByKey = StreamUtils.groupByKey(actHistoryInfoVoList, ActHistoryInfoVo::getTaskDefinitionKey); - for (Map.Entry> entry : groupByKey.entrySet()) { - ActHistoryInfoVo actHistoryInfoVo = BeanUtil.toBean(entry.getValue().get(0), ActHistoryInfoVo.class); - actHistoryInfoVoList.stream().filter(e -> e.getTaskDefinitionKey().equals(entry.getKey()) && e.getEndTime() != null).findFirst() - .ifPresent(e -> { - actHistoryInfoVo.setStatus("已处理"); - actHistoryInfoVo.setStartTime(e.getStartTime()); - }); - actHistoryInfoVoList.stream().filter(e -> e.getTaskDefinitionKey().equals(entry.getKey()) && e.getEndTime() == null).findFirst() - .ifPresent(e -> { - actHistoryInfoVo.setStatus("待处理"); - actHistoryInfoVo.setStartTime(e.getStartTime()); - actHistoryInfoVo.setEndTime(null); - actHistoryInfoVo.setRunDuration(null); - }); - } - List recordList = new ArrayList<>(); - // 待办理 - recordList.addAll(StreamUtils.filter(actHistoryInfoVoList, e -> e.getEndTime() == null)); - // 已办理 - recordList.addAll(StreamUtils.filter(actHistoryInfoVoList, e -> e.getEndTime() != null)); - - return recordList; - } - - /** - * 任务完成时间处理 - * - * @param time 时间 - */ - private String getDuration(long time) { - - long day = time / (24 * 60 * 60 * 1000); - long hour = (time / (60 * 60 * 1000) - day * 24); - long minute = ((time / (60 * 1000)) - day * 24 * 60 - hour * 60); - long second = (time / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - minute * 60); - - if (day > 0) { - return day + "天" + hour + "小时" + minute + "分钟"; - } - if (hour > 0) { - return hour + "小时" + minute + "分钟"; - } - if (minute > 0) { - return minute + "分钟"; - } - if (second > 0) { - return second + "秒"; - } else { - return 0 + "秒"; - } - } - - /** - * 作废流程实例,不会删除历史记录(删除运行中的实例) - * - * @param processInvalidBo 参数 - */ - @Override - @Transactional(rollbackFor = Exception.class) - public boolean deleteRunInstance(ProcessInvalidBo processInvalidBo) { - try { - List list = QueryUtils.taskQuery().processInstanceBusinessKey(processInvalidBo.getBusinessKey()).list(); - String processInstanceId = list.get(0).getProcessInstanceId(); - List subTasks = StreamUtils.filter(list, e -> StringUtils.isNotBlank(e.getParentTaskId())); - if (CollUtil.isNotEmpty(subTasks)) { - subTasks.forEach(e -> taskService.deleteTask(e.getId())); - } - String deleteReason = LoginHelper.getLoginUser().getNickname() + "作废了当前申请!"; - if (StringUtils.isNotBlank(processInvalidBo.getDeleteReason())) { - deleteReason = LoginHelper.getLoginUser().getNickname() + "作废理由:" + processInvalidBo.getDeleteReason(); - } - for (Task task : StreamUtils.filter(list, e -> StringUtils.isBlank(e.getParentTaskId()))) { - taskService.addComment(task.getId(), task.getProcessInstanceId(), TaskStatusEnum.INVALID.getStatus(), deleteReason); - } - HistoricProcessInstance historicProcessInstance = QueryUtils.hisInstanceQuery(processInstanceId).singleResult(); - BusinessStatusEnum.checkInvalidStatus(historicProcessInstance.getBusinessStatus()); - runtimeService.updateBusinessStatus(processInstanceId, BusinessStatusEnum.INVALID.getStatus()); - runtimeService.deleteProcessInstance(processInstanceId, deleteReason); - //流程作废监听 - flowProcessEventHandler.processHandler(historicProcessInstance.getProcessDefinitionKey(), - historicProcessInstance.getBusinessKey(), BusinessStatusEnum.INVALID.getStatus(), false); - return true; - } catch (Exception e) { - log.error(e.getMessage(), e); - throw new ServiceException(e.getMessage()); - } - } - - /** - * 运行中的实例 删除程实例,删除历史记录,删除业务与流程关联信息 - * - * @param businessKeys 业务id - */ - @Override - @Transactional(rollbackFor = Exception.class) - public boolean deleteRunAndHisInstance(List businessKeys) { - try { - // 1.删除运行中流程实例 - List actHiProcinsts = actHiProcinstService.selectByBusinessKeyIn(businessKeys); - if (CollUtil.isEmpty(actHiProcinsts)) { - log.warn("当前业务ID:{}查询到流程实例为空!", businessKeys); - return false; - } - List processInstanceIds = StreamUtils.toList(actHiProcinsts, ActHiProcinst::getId); - List list = QueryUtils.taskQuery(processInstanceIds).list(); - List subTasks = StreamUtils.filter(list, e -> StringUtils.isNotBlank(e.getParentTaskId())); - if (CollUtil.isNotEmpty(subTasks)) { - subTasks.forEach(e -> taskService.deleteTask(e.getId())); - } - runtimeService.bulkDeleteProcessInstances(processInstanceIds, LoginHelper.getUserId() + "删除了当前流程申请"); - // 2.删除历史记录 - List historicProcessInstanceList = QueryUtils.hisInstanceQuery(new HashSet<>(processInstanceIds)).list(); - if (ObjectUtil.isNotEmpty(historicProcessInstanceList)) { - historyService.bulkDeleteHistoricProcessInstances(processInstanceIds); - } - wfTaskBackNodeService.deleteByInstanceIds(processInstanceIds); - return true; - } catch (Exception e) { - log.error(e.getMessage(), e); - throw new ServiceException(e.getMessage()); - } - } - - /** - * 已完成的实例 删除程实例,删除历史记录,删除业务与流程关联信息 - * - * @param businessKeys 业务id - */ - @Override - @Transactional(rollbackFor = Exception.class) - public boolean deleteFinishAndHisInstance(List businessKeys) { - try { - List actHiProcinsts = actHiProcinstService.selectByBusinessKeyIn(businessKeys); - if (CollUtil.isEmpty(actHiProcinsts)) { - log.warn("当前业务ID:{}查询到流程实例为空!", businessKeys); - return false; - } - List processInstanceIds = StreamUtils.toList(actHiProcinsts, ActHiProcinst::getId); - historyService.bulkDeleteHistoricProcessInstances(processInstanceIds); - wfTaskBackNodeService.deleteByInstanceIds(processInstanceIds); - return true; - } catch (Exception e) { - log.error(e.getMessage(), e); - throw new ServiceException(e.getMessage()); - } - } - - /** - * 撤销流程申请 - * - * @param businessKey 业务id - */ - @Override - @Transactional(rollbackFor = Exception.class) - public boolean cancelProcessApply(String businessKey) { - try { - ProcessInstance processInstance = QueryUtils.businessKeyQuery(businessKey) - .startedBy(String.valueOf(LoginHelper.getUserId())).singleResult(); - if (ObjectUtil.isNull(processInstance)) { - throw new ServiceException("您不是流程发起人,撤销失败!"); - } - if (processInstance.isSuspended()) { - throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED); - } - String processInstanceId = processInstance.getId(); - BusinessStatusEnum.checkCancelStatus(processInstance.getBusinessStatus()); - List taskList = QueryUtils.taskQuery(processInstanceId).list(); - for (Task task : taskList) { - taskService.setAssignee(task.getId(), null); - taskService.addComment(task.getId(), processInstanceId, TaskStatusEnum.CANCEL.getStatus(), LoginHelper.getLoginUser().getNickname() + ":撤销申请"); - } - HistoricTaskInstance historicTaskInstance = QueryUtils.hisTaskInstanceQuery(processInstanceId).finished().orderByHistoricTaskInstanceEndTime().asc().list().get(0); - List nodeIds = StreamUtils.toList(taskList, Task::getTaskDefinitionKey); - runtimeService.createChangeActivityStateBuilder() - .processInstanceId(processInstanceId) - .moveActivityIdsToSingleActivityId(nodeIds, historicTaskInstance.getTaskDefinitionKey()).changeState(); - Task task = QueryUtils.taskQuery(processInstanceId).list().get(0); - taskService.setAssignee(task.getId(), historicTaskInstance.getAssignee()); - //获取并行网关执行后保留的执行实例数据 - ExecutionChildByExecutionIdCmd childByExecutionIdCmd = new ExecutionChildByExecutionIdCmd(task.getExecutionId()); - List executionEntities = managementService.executeCommand(childByExecutionIdCmd); - //删除流程实例垃圾数据 - for (ExecutionEntity executionEntity : executionEntities) { - DeleteExecutionCmd deleteExecutionCmd = new DeleteExecutionCmd(executionEntity.getId()); - managementService.executeCommand(deleteExecutionCmd); - } - runtimeService.updateBusinessStatus(processInstanceId, BusinessStatusEnum.CANCEL.getStatus()); - //流程作废监听 - flowProcessEventHandler.processHandler(processInstance.getProcessDefinitionKey(), - processInstance.getBusinessKey(), BusinessStatusEnum.CANCEL.getStatus(), false); - return true; - } catch (Exception e) { - log.error(e.getMessage(), e); - throw new ServiceException("撤销失败:" + e.getMessage()); - } - } - - /** - * 分页查询当前登录人单据 - * - * @param bo 参数 - */ - @Override - public TableDataInfo getPageByCurrent(ProcessInstanceBo bo, PageQuery pageQuery) { - List list = new ArrayList<>(); - HistoricProcessInstanceQuery query = QueryUtils.hisInstanceQuery(); - query.startedBy(String.valueOf(LoginHelper.getUserId())); - if (StringUtils.isNotBlank(bo.getName())) { - query.processInstanceNameLikeIgnoreCase("%" + bo.getName() + "%"); - } - if (StringUtils.isNotBlank(bo.getKey())) { - query.processDefinitionKey(bo.getKey()); - } - if (StringUtils.isNotBlank(bo.getBusinessKey())) { - query.processInstanceBusinessKey(bo.getBusinessKey()); - } - if (StringUtils.isNotBlank(bo.getCategoryCode())) { - query.processDefinitionCategory(bo.getCategoryCode()); - } - query.orderByProcessInstanceStartTime().desc(); - List historicProcessInstanceList = query.listPage(pageQuery.getFirstNum(), pageQuery.getPageSize()); - List taskVoList = new ArrayList<>(); - if (CollUtil.isNotEmpty(historicProcessInstanceList)) { - List processInstanceIds = StreamUtils.toList(historicProcessInstanceList, HistoricProcessInstance::getId); - List taskList = QueryUtils.taskQuery(processInstanceIds).list(); - for (Task task : taskList) { - taskVoList.add(BeanUtil.toBean(task, TaskVo.class)); - } - } - for (HistoricProcessInstance processInstance : historicProcessInstanceList) { - ProcessInstanceVo processInstanceVo = BeanUtil.toBean(processInstance, ProcessInstanceVo.class); - processInstanceVo.setBusinessStatusName(BusinessStatusEnum.findByStatus(processInstance.getBusinessStatus())); - if (CollUtil.isNotEmpty(taskVoList)) { - List collect = StreamUtils.filter(taskVoList, e -> e.getProcessInstanceId().equals(processInstance.getId())); - processInstanceVo.setTaskVoList(CollUtil.isNotEmpty(collect) ? collect : Collections.emptyList()); - } - list.add(processInstanceVo); - } - if (CollUtil.isNotEmpty(list)) { - List processDefinitionIds = StreamUtils.toList(list, ProcessInstanceVo::getProcessDefinitionId); - List wfNodeConfigVoList = wfNodeConfigService.selectByDefIds(processDefinitionIds); - for (ProcessInstanceVo processInstanceVo : list) { - if (CollUtil.isNotEmpty(wfNodeConfigVoList)) { - wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(processInstanceVo.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(processInstanceVo::setWfNodeConfigVo); - } - } - } - long count = query.count(); - TableDataInfo build = TableDataInfo.build(); - build.setRows(list); - build.setTotal(count); - return build; - } - - /** - * 任务催办(给当前任务办理人发送站内信,邮件,短信等) - * - * @param taskUrgingBo 任务催办 - */ - @Override - @Transactional(rollbackFor = Exception.class) - public boolean taskUrging(TaskUrgingBo taskUrgingBo) { - try { - ProcessInstance processInstance = QueryUtils.instanceQuery(taskUrgingBo.getProcessInstanceId()).singleResult(); - if (processInstance == null) { - throw new ServiceException("任务已结束!"); - } - String message = taskUrgingBo.getMessage(); - if (StringUtils.isBlank(message)) { - message = "您的【" + processInstance.getName() + "】单据还未审批,请您及时处理。"; - } - List list = QueryUtils.taskQuery(taskUrgingBo.getProcessInstanceId()).list(); - WorkflowUtils.sendMessage(list, processInstance.getName(), taskUrgingBo.getMessageType(), message, remoteUserService); - } catch (ServiceException e) { - throw new ServiceException(e.getMessage()); - } - return true; - } -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java deleted file mode 100644 index 4a56b33..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java +++ /dev/null @@ -1,862 +0,0 @@ -package org.dromara.workflow.service.impl; - -import cn.hutool.core.bean.BeanUtil; -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.ObjectUtil; -import cn.hutool.core.util.StrUtil; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.dubbo.config.annotation.DubboReference; -import org.dromara.common.core.exception.ServiceException; -import org.dromara.common.core.utils.StreamUtils; -import org.dromara.common.core.utils.StringUtils; -import org.dromara.common.mybatis.core.page.PageQuery; -import org.dromara.common.mybatis.core.page.TableDataInfo; -import org.dromara.common.satoken.utils.LoginHelper; -import org.dromara.common.tenant.helper.TenantHelper; -import org.dromara.resource.api.RemoteFileService; -import org.dromara.system.api.RemoteUserService; -import org.dromara.system.api.domain.vo.RemoteUserVo; -import org.dromara.system.api.model.RoleDTO; -import org.dromara.workflow.common.constant.FlowConstant; -import org.dromara.common.core.enums.BusinessStatusEnum; -import org.dromara.workflow.common.enums.TaskStatusEnum; -import org.dromara.workflow.domain.ActHiTaskinst; -import org.dromara.workflow.domain.WfTaskBackNode; -import org.dromara.workflow.domain.bo.*; -import org.dromara.workflow.domain.vo.*; -import org.dromara.workflow.flowable.cmd.*; -import org.dromara.workflow.flowable.handler.FlowProcessEventHandler; -import org.dromara.workflow.mapper.ActHiTaskinstMapper; -import org.dromara.workflow.mapper.ActTaskMapper; -import org.dromara.workflow.service.IActTaskService; -import org.dromara.workflow.service.IWfDefinitionConfigService; -import org.dromara.workflow.service.IWfNodeConfigService; -import org.dromara.workflow.service.IWfTaskBackNodeService; -import org.dromara.workflow.utils.ModelUtils; -import org.dromara.workflow.utils.QueryUtils; -import org.dromara.workflow.utils.WorkflowUtils; -import org.flowable.common.engine.api.FlowableObjectNotFoundException; -import org.flowable.common.engine.impl.identity.Authentication; -import org.flowable.engine.*; -import org.flowable.engine.history.HistoricProcessInstance; -import org.flowable.engine.history.HistoricProcessInstanceQuery; -import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior; -import org.flowable.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior; -import org.flowable.engine.impl.persistence.entity.ExecutionEntity; -import org.flowable.engine.runtime.ProcessInstance; -import org.flowable.identitylink.api.history.HistoricIdentityLink; -import org.flowable.task.api.Task; -import org.flowable.task.api.TaskQuery; -import org.flowable.task.api.history.HistoricTaskInstance; -import org.flowable.task.service.impl.persistence.entity.TaskEntity; -import org.flowable.variable.api.persistence.entity.VariableInstance; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.scheduling.annotation.Async; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.*; -import java.util.stream.Collectors; - -import static org.dromara.workflow.common.constant.FlowConstant.*; - -/** - * 任务 服务层实现 - * - * @author may - */ -@Slf4j -@RequiredArgsConstructor -@Service -public class ActTaskServiceImpl implements IActTaskService { - - @Autowired(required = false) - private RuntimeService runtimeService; - @Autowired(required = false) - private TaskService taskService; - @Autowired(required = false) - private HistoryService historyService; - @Autowired(required = false) - private IdentityService identityService; - @Autowired(required = false) - private ManagementService managementService; - private final ActTaskMapper actTaskMapper; - private final IWfTaskBackNodeService wfTaskBackNodeService; - private final ActHiTaskinstMapper actHiTaskinstMapper; - private final IWfNodeConfigService wfNodeConfigService; - private final IWfDefinitionConfigService wfDefinitionConfigService; - private final FlowProcessEventHandler flowProcessEventHandler; - @DubboReference - private RemoteUserService remoteUserService; - @DubboReference - private RemoteFileService remoteFileService; - - /** - * 启动任务 - * - * @param startProcessBo 启动流程参数 - */ - @Override - @Transactional(rollbackFor = Exception.class) - public Map startWorkFlow(StartProcessBo startProcessBo) { - Map map = new HashMap<>(); - if (StringUtils.isBlank(startProcessBo.getBusinessKey())) { - throw new ServiceException("启动工作流时必须包含业务ID"); - } - // 判断当前业务是否启动过流程 - HistoricProcessInstanceQuery query = QueryUtils.hisInstanceQuery(); - HistoricProcessInstance historicProcessInstance = query.processInstanceBusinessKey(startProcessBo.getBusinessKey()).singleResult(); - if (ObjectUtil.isNotEmpty(historicProcessInstance)) { - BusinessStatusEnum.checkStartStatus(historicProcessInstance.getBusinessStatus()); - } - List taskResult = QueryUtils.taskQuery().processInstanceBusinessKey(startProcessBo.getBusinessKey()).list(); - if (CollUtil.isNotEmpty(taskResult)) { - if (CollUtil.isNotEmpty(startProcessBo.getVariables())) { - taskService.setVariables(taskResult.get(0).getId(), startProcessBo.getVariables()); - } - map.put(PROCESS_INSTANCE_ID, taskResult.get(0).getProcessInstanceId()); - map.put("taskId", taskResult.get(0).getId()); - return map; - } - WfDefinitionConfigVo wfDefinitionConfigVo = wfDefinitionConfigService.getByTableNameLastVersion(startProcessBo.getTableName()); - if (wfDefinitionConfigVo == null) { - throw new ServiceException("请到流程定义绑定业务表名与流程KEY!"); - } - // 设置启动人 - identityService.setAuthenticatedUserId(String.valueOf(LoginHelper.getUserId())); - Authentication.setAuthenticatedUserId(String.valueOf(LoginHelper.getUserId())); - // 启动流程实例(提交申请) - Map variables = startProcessBo.getVariables(); - // 启动跳过表达式 - variables.put(FLOWABLE_SKIP_EXPRESSION_ENABLED, true); - // 流程发起人 - variables.put(INITIATOR, (String.valueOf(LoginHelper.getUserId()))); - ProcessInstance pi; - try { - if (TenantHelper.isEnable()) { - pi = runtimeService.startProcessInstanceByKeyAndTenantId(wfDefinitionConfigVo.getProcessKey(), startProcessBo.getBusinessKey(), variables, TenantHelper.getTenantId()); - } else { - pi = runtimeService.startProcessInstanceByKey(wfDefinitionConfigVo.getProcessKey(), startProcessBo.getBusinessKey(), variables); - } - } catch (FlowableObjectNotFoundException e) { - throw new ServiceException("找不到当前【" + wfDefinitionConfigVo.getProcessKey() + "】流程定义!"); - } - // 将流程定义名称 作为 流程实例名称 - runtimeService.setProcessInstanceName(pi.getProcessInstanceId(), pi.getProcessDefinitionName()); - // 申请人执行流程 - List taskList = QueryUtils.taskQuery(pi.getId()).list(); - if (taskList.size() > 1) { - throw new ServiceException("请检查流程第一个环节是否为申请人!"); - } - - runtimeService.updateBusinessStatus(pi.getProcessInstanceId(), BusinessStatusEnum.DRAFT.getStatus()); - taskService.setAssignee(taskList.get(0).getId(), LoginHelper.getUserId().toString()); - taskService.setVariable(taskList.get(0).getId(), PROCESS_INSTANCE_ID, pi.getProcessInstanceId()); - taskService.setVariable(taskList.get(0).getId(), BUSINESS_KEY, pi.getBusinessKey()); - map.put("processInstanceId", pi.getProcessInstanceId()); - map.put("taskId", taskList.get(0).getId()); - return map; - } - - /** - * 办理任务 - * - * @param completeTaskBo 办理任务参数 - */ - @Override - @Transactional(rollbackFor = Exception.class) - public boolean completeTask(CompleteTaskBo completeTaskBo) { - try { - String userId = String.valueOf(LoginHelper.getUserId()); - Task task = WorkflowUtils.getTaskByCurrentUser(completeTaskBo.getTaskId()); - if (task == null) { - throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL); - } - if (task.isSuspended()) { - throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED); - } - ProcessInstance processInstance = QueryUtils.instanceQuery(task.getProcessInstanceId()).singleResult(); - //办理委托任务 - if (ObjectUtil.isNotEmpty(task.getDelegationState()) && FlowConstant.PENDING.equals(task.getDelegationState().name())) { - taskService.resolveTask(completeTaskBo.getTaskId()); - TaskEntity newTask = WorkflowUtils.createNewTask(task); - taskService.addComment(newTask.getId(), task.getProcessInstanceId(), TaskStatusEnum.PASS.getStatus(), StringUtils.isNotBlank(completeTaskBo.getMessage()) ? completeTaskBo.getMessage() : StrUtil.EMPTY); - taskService.complete(newTask.getId()); - return true; - } - //附件上传 - AttachmentCmd attachmentCmd = new AttachmentCmd(completeTaskBo.getFileId(), task.getId(), task.getProcessInstanceId(), remoteFileService); - managementService.executeCommand(attachmentCmd); - String businessStatus = WorkflowUtils.getBusinessStatus(processInstance.getBusinessKey()); - //流程提交监听 - if (BusinessStatusEnum.DRAFT.getStatus().equals(businessStatus) || BusinessStatusEnum.BACK.getStatus().equals(businessStatus) || BusinessStatusEnum.CANCEL.getStatus().equals(businessStatus)) { - flowProcessEventHandler.processHandler(processInstance.getProcessDefinitionKey(), processInstance.getBusinessKey(), businessStatus, true); - } - runtimeService.updateBusinessStatus(task.getProcessInstanceId(), BusinessStatusEnum.WAITING.getStatus()); - //办理监听 - flowProcessEventHandler.processTaskHandler(processInstance.getProcessDefinitionKey(), task.getTaskDefinitionKey(), - task.getId(), processInstance.getBusinessKey()); - //办理意见 - taskService.addComment(completeTaskBo.getTaskId(), task.getProcessInstanceId(), TaskStatusEnum.PASS.getStatus(), StringUtils.isBlank(completeTaskBo.getMessage()) ? "同意" : completeTaskBo.getMessage()); - //办理任务 - taskService.setAssignee(task.getId(), userId); - if (CollUtil.isNotEmpty(completeTaskBo.getVariables())) { - taskService.complete(completeTaskBo.getTaskId(), completeTaskBo.getVariables()); - } else { - taskService.complete(completeTaskBo.getTaskId()); - } - //记录执行过的流程任务节点 - wfTaskBackNodeService.recordExecuteNode(task); - ProcessInstance pi = QueryUtils.instanceQuery(task.getProcessInstanceId()).singleResult(); - if (pi == null) { - UpdateBusinessStatusCmd updateBusinessStatusCmd = new UpdateBusinessStatusCmd(task.getProcessInstanceId(), BusinessStatusEnum.FINISH.getStatus()); - managementService.executeCommand(updateBusinessStatusCmd); - flowProcessEventHandler.processHandler(processInstance.getProcessDefinitionKey(), processInstance.getBusinessKey(), - BusinessStatusEnum.FINISH.getStatus(), false); - } else { - List list = QueryUtils.taskQuery(task.getProcessInstanceId()).list(); - for (Task t : list) { - if (ModelUtils.isUserTask(t.getProcessDefinitionId(), t.getTaskDefinitionKey())) { - List links = historyService.getHistoricIdentityLinksForTask(t.getId()); - if (CollUtil.isEmpty(links) && StringUtils.isBlank(t.getAssignee())) { - throw new ServiceException("下一节点【" + t.getName() + "】没有办理人!"); - } - } - } - - if (CollUtil.isNotEmpty(list) && CollUtil.isNotEmpty(completeTaskBo.getWfCopyList())) { - TaskEntity newTask = WorkflowUtils.createNewTask(task); - taskService.addComment(newTask.getId(), task.getProcessInstanceId(), TaskStatusEnum.COPY.getStatus(), LoginHelper.getLoginUser().getNickname() + "【抄送】给" + String.join(",", StreamUtils.toList(completeTaskBo.getWfCopyList(), WfCopy::getUserName))); - taskService.complete(newTask.getId()); - List taskList = QueryUtils.taskQuery(task.getProcessInstanceId()).list(); - WorkflowUtils.createCopyTask(taskList, StreamUtils.toList(completeTaskBo.getWfCopyList(), WfCopy::getUserId)); - } - sendMessage(list, processInstance.getName(), completeTaskBo.getMessageType(), null); - } - return true; - } catch (Exception e) { - log.error(e.getMessage(), e); - throw new ServiceException(e.getMessage()); - } - } - - /** - * 发送消息 - * - * @param list 任务 - * @param name 流程名称 - * @param messageType 消息类型 - * @param message 消息内容,为空则发送默认配置的消息内容 - */ - @Async - public void sendMessage(List list, String name, List messageType, String message) { - WorkflowUtils.sendMessage(list, name, messageType, message, remoteUserService); - } - - /** - * 查询当前用户的待办任务 - * - * @param taskBo 参数 - */ - @Override - public TableDataInfo getPageByTaskWait(TaskBo taskBo, PageQuery pageQuery) { - QueryWrapper queryWrapper = new QueryWrapper<>(); - List roles = LoginHelper.getLoginUser().getRoles(); - List roleIds = StreamUtils.toList(roles, e -> String.valueOf(e.getRoleId())); - String userId = String.valueOf(LoginHelper.getUserId()); - queryWrapper.eq("t.business_status_", BusinessStatusEnum.WAITING.getStatus()); - queryWrapper.eq(TenantHelper.isEnable(), "t.tenant_id_", TenantHelper.getTenantId()); - String ids = StreamUtils.join(roleIds, x -> "'" + x + "'"); - queryWrapper.and(w1 -> w1.eq("t.assignee_", userId).or(w2 -> w2.isNull("t.assignee_").apply("exists ( select LINK.ID_ from ACT_RU_IDENTITYLINK LINK where LINK.TASK_ID_ = t.ID_ and LINK.TYPE_ = 'candidate' and (LINK.USER_ID_ = {0} or ( LINK.GROUP_ID_ IN (" + ids + ") ) ))", userId))); - if (StringUtils.isNotBlank(taskBo.getName())) { - queryWrapper.like("t.name_", taskBo.getName()); - } - if (StringUtils.isNotBlank(taskBo.getProcessDefinitionName())) { - queryWrapper.like("t.processDefinitionName", taskBo.getProcessDefinitionName()); - } - if (StringUtils.isNotBlank(taskBo.getProcessDefinitionKey())) { - queryWrapper.eq("t.processDefinitionKey", taskBo.getProcessDefinitionKey()); - } - queryWrapper.orderByDesc("t.CREATE_TIME_"); - Page page = actTaskMapper.getTaskWaitByPage(pageQuery.build(), queryWrapper); - - List taskList = page.getRecords(); - if (CollUtil.isNotEmpty(taskList)) { - List processDefinitionIds = StreamUtils.toList(taskList, TaskVo::getProcessDefinitionId); - List wfNodeConfigVoList = wfNodeConfigService.selectByDefIds(processDefinitionIds); - for (TaskVo task : taskList) { - task.setBusinessStatusName(BusinessStatusEnum.findByStatus(task.getBusinessStatus())); - task.setParticipantVo(WorkflowUtils.getCurrentTaskParticipant(task.getId(), remoteUserService)); - task.setMultiInstance(WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey()) != null); - if (CollUtil.isNotEmpty(wfNodeConfigVoList)) { - wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo); - wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && e.getNodeId().equals(task.getTaskDefinitionKey()) && FlowConstant.FALSE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo); - } - } - } - return TableDataInfo.build(page); - } - - /** - * 查询当前租户所有待办任务 - * - * @param taskBo 参数 - */ - @Override - public TableDataInfo getPageByAllTaskWait(TaskBo taskBo, PageQuery pageQuery) { - TaskQuery query = QueryUtils.taskQuery(); - if (StringUtils.isNotBlank(taskBo.getName())) { - query.taskNameLike("%" + taskBo.getName() + "%"); - } - if (StringUtils.isNotBlank(taskBo.getProcessDefinitionName())) { - query.processDefinitionNameLike("%" + taskBo.getProcessDefinitionName() + "%"); - } - if (StringUtils.isNotBlank(taskBo.getProcessDefinitionKey())) { - query.processDefinitionKey(taskBo.getProcessDefinitionKey()); - } - query.orderByTaskCreateTime().desc(); - List taskList = query.listPage(pageQuery.getFirstNum(), pageQuery.getPageSize()); - List processInstanceList = null; - if (CollUtil.isNotEmpty(taskList)) { - Set processInstanceIds = StreamUtils.toSet(taskList, Task::getProcessInstanceId); - processInstanceList = QueryUtils.instanceQuery(processInstanceIds).list(); - } - List list = new ArrayList<>(); - if (CollUtil.isNotEmpty(taskList)) { - List processDefinitionIds = StreamUtils.toList(taskList, Task::getProcessDefinitionId); - List wfNodeConfigVoList = wfNodeConfigService.selectByDefIds(processDefinitionIds); - for (Task task : taskList) { - TaskVo taskVo = BeanUtil.toBean(task, TaskVo.class); - if (CollUtil.isNotEmpty(processInstanceList)) { - processInstanceList.stream().filter(e -> e.getId().equals(task.getProcessInstanceId())).findFirst().ifPresent(e -> { - taskVo.setBusinessStatus(e.getBusinessStatus()); - taskVo.setBusinessStatusName(BusinessStatusEnum.findByStatus(taskVo.getBusinessStatus())); - taskVo.setProcessDefinitionKey(e.getProcessDefinitionKey()); - taskVo.setProcessDefinitionName(e.getProcessDefinitionName()); - taskVo.setProcessDefinitionVersion(e.getProcessDefinitionVersion()); - taskVo.setBusinessKey(e.getBusinessKey()); - }); - } - taskVo.setAssignee(StringUtils.isNotBlank(task.getAssignee()) ? Long.valueOf(task.getAssignee()) : null); - taskVo.setParticipantVo(WorkflowUtils.getCurrentTaskParticipant(task.getId(), remoteUserService)); - taskVo.setMultiInstance(WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey()) != null); - if (CollUtil.isNotEmpty(wfNodeConfigVoList)) { - wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(taskVo::setWfNodeConfigVo); - wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && e.getNodeId().equals(task.getTaskDefinitionKey()) && FlowConstant.FALSE.equals(e.getApplyUserTask())).findFirst().ifPresent(taskVo::setWfNodeConfigVo); - } - list.add(taskVo); - } - } - long count = query.count(); - TableDataInfo build = TableDataInfo.build(); - build.setRows(list); - build.setTotal(count); - return build; - } - - /** - * 查询当前用户的已办任务 - * - * @param taskBo 参数 - */ - @Override - public TableDataInfo getPageByTaskFinish(TaskBo taskBo, PageQuery pageQuery) { - String userId = String.valueOf(LoginHelper.getUserId()); - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.like(StringUtils.isNotBlank(taskBo.getName()), "t.name_", taskBo.getName()); - queryWrapper.like(StringUtils.isNotBlank(taskBo.getProcessDefinitionName()), "t.processDefinitionName", taskBo.getProcessDefinitionName()); - queryWrapper.eq(StringUtils.isNotBlank(taskBo.getProcessDefinitionKey()), "t.processDefinitionKey", taskBo.getProcessDefinitionKey()); - queryWrapper.eq("t.assignee_", userId); - Page page = actTaskMapper.getTaskFinishByPage(pageQuery.build(), queryWrapper); - - List taskList = page.getRecords(); - if (CollUtil.isNotEmpty(taskList)) { - List processDefinitionIds = StreamUtils.toList(taskList, TaskVo::getProcessDefinitionId); - List wfNodeConfigVoList = wfNodeConfigService.selectByDefIds(processDefinitionIds); - for (TaskVo task : taskList) { - task.setBusinessStatusName(BusinessStatusEnum.findByStatus(task.getBusinessStatus())); - if (CollUtil.isNotEmpty(wfNodeConfigVoList)) { - wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo); - wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && e.getNodeId().equals(task.getTaskDefinitionKey()) && FlowConstant.FALSE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo); - } - } - } - return TableDataInfo.build(page); - } - - /** - * 查询当前用户的抄送 - * - * @param taskBo 参数 - */ - @Override - public TableDataInfo getPageByTaskCopy(TaskBo taskBo, PageQuery pageQuery) { - QueryWrapper queryWrapper = new QueryWrapper<>(); - String userId = String.valueOf(LoginHelper.getUserId()); - if (StringUtils.isNotBlank(taskBo.getName())) { - queryWrapper.like("t.name_", taskBo.getName()); - } - if (StringUtils.isNotBlank(taskBo.getProcessDefinitionName())) { - queryWrapper.like("t.processDefinitionName", taskBo.getProcessDefinitionName()); - } - if (StringUtils.isNotBlank(taskBo.getProcessDefinitionKey())) { - queryWrapper.eq("t.processDefinitionKey", taskBo.getProcessDefinitionKey()); - } - queryWrapper.eq("t.assignee_", userId); - Page page = actTaskMapper.getTaskCopyByPage(pageQuery.build(), queryWrapper); - - List taskList = page.getRecords(); - if (CollUtil.isNotEmpty(taskList)) { - List processDefinitionIds = StreamUtils.toList(taskList, TaskVo::getProcessDefinitionId); - List wfNodeConfigVoList = wfNodeConfigService.selectByDefIds(processDefinitionIds); - for (TaskVo task : taskList) { - task.setBusinessStatusName(BusinessStatusEnum.findByStatus(task.getBusinessStatus())); - if (CollUtil.isNotEmpty(wfNodeConfigVoList)) { - wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo); - wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && e.getNodeId().equals(task.getTaskDefinitionKey()) && FlowConstant.FALSE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo); - } - } - } - return TableDataInfo.build(page); - } - - /** - * 查询当前租户所有已办任务 - * - * @param taskBo 参数 - */ - @Override - public TableDataInfo getPageByAllTaskFinish(TaskBo taskBo, PageQuery pageQuery) { - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.like(StringUtils.isNotBlank(taskBo.getName()), "t.name_", taskBo.getName()); - queryWrapper.like(StringUtils.isNotBlank(taskBo.getProcessDefinitionName()), "t.processDefinitionName", taskBo.getProcessDefinitionName()); - queryWrapper.eq(StringUtils.isNotBlank(taskBo.getProcessDefinitionKey()), "t.processDefinitionKey", taskBo.getProcessDefinitionKey()); - Page page = actTaskMapper.getTaskFinishByPage(pageQuery.build(), queryWrapper); - - List taskList = page.getRecords(); - if (CollUtil.isNotEmpty(taskList)) { - List processDefinitionIds = StreamUtils.toList(taskList, TaskVo::getProcessDefinitionId); - List wfNodeConfigVoList = wfNodeConfigService.selectByDefIds(processDefinitionIds); - for (TaskVo task : taskList) { - task.setBusinessStatusName(BusinessStatusEnum.findByStatus(task.getBusinessStatus())); - if (CollUtil.isNotEmpty(wfNodeConfigVoList)) { - wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo); - wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && e.getNodeId().equals(task.getTaskDefinitionKey()) && FlowConstant.FALSE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo); - } - } - } - return TableDataInfo.build(page); - } - - /** - * 委派任务 - * - * @param delegateBo 参数 - */ - @Override - @Transactional(rollbackFor = Exception.class) - public boolean delegateTask(DelegateBo delegateBo) { - Task task = WorkflowUtils.getTaskByCurrentUser(delegateBo.getTaskId()); - - if (ObjectUtil.isEmpty(task)) { - throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL); - } - if (task.isSuspended()) { - throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED); - } - try { - TaskEntity newTask = WorkflowUtils.createNewTask(task); - taskService.addComment(newTask.getId(), task.getProcessInstanceId(), TaskStatusEnum.PENDING.getStatus(), "【" + LoginHelper.getLoginUser().getNickname() + "】委派给【" + delegateBo.getNickName() + "】"); - //委托任务 - taskService.delegateTask(delegateBo.getTaskId(), delegateBo.getUserId()); - //办理生成的任务记录 - taskService.complete(newTask.getId()); - return true; - } catch (Exception e) { - log.error(e.getMessage(), e); - throw new ServiceException(e.getMessage()); - } - } - - /** - * 终止任务 - * - * @param terminationBo 参数 - */ - @Override - @Transactional(rollbackFor = Exception.class) - public boolean terminationTask(TerminationBo terminationBo) { - TaskQuery query = QueryUtils.taskQuery(); - Task task = query.taskId(terminationBo.getTaskId()).singleResult(); - - if (ObjectUtil.isEmpty(task)) { - throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL); - } - if (task.isSuspended()) { - throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED); - } - HistoricProcessInstance historicProcessInstance = QueryUtils.hisInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult(); - BusinessStatusEnum.checkInvalidStatus(historicProcessInstance.getBusinessStatus()); - try { - if (StringUtils.isBlank(terminationBo.getComment())) { - terminationBo.setComment(LoginHelper.getLoginUser().getNickname() + "终止了申请"); - } else { - terminationBo.setComment(LoginHelper.getLoginUser().getNickname() + "终止了申请:" + terminationBo.getComment()); - } - taskService.addComment(task.getId(), task.getProcessInstanceId(), TaskStatusEnum.TERMINATION.getStatus(), terminationBo.getComment()); - List list = QueryUtils.taskQuery(task.getProcessInstanceId()).list(); - if (CollUtil.isNotEmpty(list)) { - List subTasks = StreamUtils.filter(list, e -> StringUtils.isNotBlank(e.getParentTaskId())); - if (CollUtil.isNotEmpty(subTasks)) { - subTasks.forEach(e -> taskService.deleteTask(e.getId())); - } - runtimeService.updateBusinessStatus(task.getProcessInstanceId(), BusinessStatusEnum.TERMINATION.getStatus()); - runtimeService.deleteProcessInstance(task.getProcessInstanceId(), StrUtil.EMPTY); - } - //流程终止监听 - flowProcessEventHandler.processHandler(historicProcessInstance.getProcessDefinitionKey(), - historicProcessInstance.getBusinessKey(), BusinessStatusEnum.TERMINATION.getStatus(), false); - return true; - } catch (Exception e) { - throw new ServiceException(e.getMessage()); - } - } - - /** - * 转办任务 - * - * @param transmitBo 参数 - */ - @Override - public boolean transferTask(TransmitBo transmitBo) { - Task task = WorkflowUtils.getTaskByCurrentUser(transmitBo.getTaskId()); - if (ObjectUtil.isEmpty(task)) { - throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL); - } - if (task.isSuspended()) { - throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED); - } - try { - TaskEntity newTask = WorkflowUtils.createNewTask(task); - taskService.addComment(newTask.getId(), task.getProcessInstanceId(), TaskStatusEnum.TRANSFER.getStatus(), StringUtils.isNotBlank(transmitBo.getComment()) ? transmitBo.getComment() : LoginHelper.getUsername() + "转办了任务"); - taskService.complete(newTask.getId()); - taskService.setAssignee(task.getId(), transmitBo.getUserId()); - return true; - } catch (Exception e) { - log.error(e.getMessage(), e); - throw new ServiceException(e.getMessage()); - } - } - - /** - * 会签任务加签 - * - * @param addMultiBo 参数 - */ - @Override - public boolean addMultiInstanceExecution(AddMultiBo addMultiBo) { - TaskQuery taskQuery = QueryUtils.taskQuery(); - taskQuery.taskId(addMultiBo.getTaskId()); - if (!LoginHelper.isSuperAdmin() && !LoginHelper.isTenantAdmin()) { - taskQuery.taskCandidateOrAssigned(String.valueOf(LoginHelper.getUserId())); - } - Task task = taskQuery.singleResult(); - if (ObjectUtil.isEmpty(task)) { - throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL); - } - if (task.isSuspended()) { - throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED); - } - String taskDefinitionKey = task.getTaskDefinitionKey(); - String processInstanceId = task.getProcessInstanceId(); - String processDefinitionId = task.getProcessDefinitionId(); - - try { - MultiInstanceVo multiInstanceVo = WorkflowUtils.isMultiInstance(processDefinitionId, taskDefinitionKey); - if (multiInstanceVo == null) { - throw new ServiceException("当前环节不是会签节点"); - } - if (multiInstanceVo.getType() instanceof ParallelMultiInstanceBehavior) { - for (Long assignee : addMultiBo.getAssignees()) { - runtimeService.addMultiInstanceExecution(taskDefinitionKey, processInstanceId, Collections.singletonMap(multiInstanceVo.getAssignee(), assignee)); - } - } else if (multiInstanceVo.getType() instanceof SequentialMultiInstanceBehavior) { - AddSequenceMultiInstanceCmd addSequenceMultiInstanceCmd = new AddSequenceMultiInstanceCmd(task.getExecutionId(), multiInstanceVo.getAssigneeList(), addMultiBo.getAssignees()); - managementService.executeCommand(addSequenceMultiInstanceCmd); - } - List assigneeNames = addMultiBo.getAssigneeNames(); - String username = LoginHelper.getUsername(); - TaskEntity newTask = WorkflowUtils.createNewTask(task); - taskService.addComment(newTask.getId(), processInstanceId, TaskStatusEnum.SIGN.getStatus(), username + "加签【" + String.join(StringUtils.SEPARATOR, assigneeNames) + "】"); - taskService.complete(newTask.getId()); - return true; - } catch (Exception e) { - log.error(e.getMessage(), e); - throw new ServiceException(e.getMessage()); - } - } - - /** - * 会签任务减签 - * - * @param deleteMultiBo 参数 - */ - @Override - public boolean deleteMultiInstanceExecution(DeleteMultiBo deleteMultiBo) { - TaskQuery taskQuery = QueryUtils.taskQuery(); - taskQuery.taskId(deleteMultiBo.getTaskId()); - if (!LoginHelper.isSuperAdmin() && !LoginHelper.isTenantAdmin()) { - taskQuery.taskCandidateOrAssigned(String.valueOf(LoginHelper.getUserId())); - } - Task task = taskQuery.singleResult(); - if (ObjectUtil.isEmpty(task)) { - throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL); - } - if (task.isSuspended()) { - throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED); - } - String taskDefinitionKey = task.getTaskDefinitionKey(); - String processInstanceId = task.getProcessInstanceId(); - String processDefinitionId = task.getProcessDefinitionId(); - try { - MultiInstanceVo multiInstanceVo = WorkflowUtils.isMultiInstance(processDefinitionId, taskDefinitionKey); - if (multiInstanceVo == null) { - throw new ServiceException("当前环节不是会签节点"); - } - if (multiInstanceVo.getType() instanceof ParallelMultiInstanceBehavior) { - for (String executionId : deleteMultiBo.getExecutionIds()) { - runtimeService.deleteMultiInstanceExecution(executionId, false); - } - for (String taskId : deleteMultiBo.getTaskIds()) { - historyService.deleteHistoricTaskInstance(taskId); - } - } else if (multiInstanceVo.getType() instanceof SequentialMultiInstanceBehavior) { - DeleteSequenceMultiInstanceCmd deleteSequenceMultiInstanceCmd = new DeleteSequenceMultiInstanceCmd(task.getAssignee(), task.getExecutionId(), multiInstanceVo.getAssigneeList(), deleteMultiBo.getAssigneeIds()); - managementService.executeCommand(deleteSequenceMultiInstanceCmd); - } - List assigneeNames = deleteMultiBo.getAssigneeNames(); - String username = LoginHelper.getUsername(); - TaskEntity newTask = WorkflowUtils.createNewTask(task); - taskService.addComment(newTask.getId(), processInstanceId, TaskStatusEnum.SIGN_OFF.getStatus(), username + "减签【" + String.join(StringUtils.SEPARATOR, assigneeNames) + "】"); - taskService.complete(newTask.getId()); - return true; - } catch (Exception e) { - log.error(e.getMessage(), e); - throw new ServiceException(e.getMessage()); - } - } - - /** - * 驳回审批 - * - * @param backProcessBo 参数 - */ - @Override - @Transactional(rollbackFor = Exception.class) - public String backProcess(BackProcessBo backProcessBo) { - String userId = String.valueOf(LoginHelper.getUserId()); - Task task = WorkflowUtils.getTaskByCurrentUser(backProcessBo.getTaskId()); - - if (ObjectUtil.isEmpty(task)) { - throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL); - } - if (task.isSuspended()) { - throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED); - } - try { - String processInstanceId = task.getProcessInstanceId(); - ProcessInstance processInstance = QueryUtils.instanceQuery(task.getProcessInstanceId()).singleResult(); - //获取并行网关执行后保留的执行实例数据 - ExecutionChildByExecutionIdCmd childByExecutionIdCmd = new ExecutionChildByExecutionIdCmd(task.getExecutionId()); - List executionEntities = managementService.executeCommand(childByExecutionIdCmd); - //校验单据 - BusinessStatusEnum.checkBackStatus(processInstance.getBusinessStatus()); - //判断是否有多个任务 - List taskList = QueryUtils.taskQuery(processInstanceId).list(); - String backTaskDefinitionKey = backProcessBo.getTargetActivityId(); - taskService.addComment(task.getId(), processInstanceId, TaskStatusEnum.BACK.getStatus(), StringUtils.isNotBlank(backProcessBo.getMessage()) ? backProcessBo.getMessage() : "退回"); - if (taskList.size() > 1) { - //当前多个任务驳回到单个节点 - runtimeService.createChangeActivityStateBuilder().processInstanceId(processInstanceId).moveActivityIdsToSingleActivityId(taskList.stream().map(Task::getTaskDefinitionKey).distinct().collect(Collectors.toList()), backTaskDefinitionKey).changeState(); - ActHiTaskinst actHiTaskinst = new ActHiTaskinst(); - actHiTaskinst.setAssignee(userId); - actHiTaskinst.setId(task.getId()); - actHiTaskinstMapper.updateById(actHiTaskinst); - } else { - //当前单个节点驳回单个节点 - runtimeService.createChangeActivityStateBuilder().processInstanceId(processInstanceId).moveActivityIdTo(task.getTaskDefinitionKey(), backTaskDefinitionKey).changeState(); - } - //删除并行环节未办理记录 - MultiInstanceVo multiInstance = WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey()); - if (multiInstance == null && taskList.size() > 1) { - List tasks = StreamUtils.filter(taskList, e -> !e.getTaskDefinitionKey().equals(task.getTaskDefinitionKey())); - if (CollUtil.isNotEmpty(tasks)) { - actHiTaskinstMapper.deleteByIds(StreamUtils.toList(tasks, Task::getId)); - } - } - - - List instanceList = QueryUtils.hisTaskInstanceQuery(processInstanceId).finished().orderByHistoricTaskInstanceEndTime().desc().list(); - List list = QueryUtils.taskQuery(processInstanceId).list(); - for (Task t : list) { - instanceList.stream().filter(e -> e.getTaskDefinitionKey().equals(t.getTaskDefinitionKey())).findFirst().ifPresent(e -> { - taskService.setAssignee(t.getId(), e.getAssignee()); - }); - } - //发送消息 - String message = "您的【" + processInstance.getName() + "】单据已经被驳回,请您注意查收。"; - sendMessage(list, processInstance.getName(), backProcessBo.getMessageType(), message); - //删除流程实例垃圾数据 - for (ExecutionEntity executionEntity : executionEntities) { - DeleteExecutionCmd deleteExecutionCmd = new DeleteExecutionCmd(executionEntity.getId()); - managementService.executeCommand(deleteExecutionCmd); - } - - WfTaskBackNode wfTaskBackNode = wfTaskBackNodeService.getListByInstanceIdAndNodeId(task.getProcessInstanceId(), backProcessBo.getTargetActivityId()); - if (ObjectUtil.isNotNull(wfTaskBackNode) && wfTaskBackNode.getOrderNo() == 0) { - runtimeService.updateBusinessStatus(processInstanceId, BusinessStatusEnum.BACK.getStatus()); - flowProcessEventHandler.processHandler(processInstance.getProcessDefinitionKey(), - processInstance.getBusinessKey(), BusinessStatusEnum.BACK.getStatus(), false); - } - //删除驳回后的流程节点 - wfTaskBackNodeService.deleteBackTaskNode(processInstanceId, backProcessBo.getTargetActivityId()); - } catch (Exception e) { - log.error(e.getMessage(), e); - throw new ServiceException(e.getMessage()); - } - return task.getProcessInstanceId(); - } - - /** - * 修改任务办理人 - * - * @param taskIds 任务id - * @param userId 办理人id - */ - @Override - @Transactional(rollbackFor = Exception.class) - public boolean updateAssignee(String[] taskIds, String userId) { - try { - List list = QueryUtils.taskQuery().taskIds(Arrays.asList(taskIds)).list(); - for (Task task : list) { - taskService.setAssignee(task.getId(), userId); - } - } catch (Exception e) { - log.error(e.getMessage(), e); - throw new ServiceException("修改失败:" + e.getMessage()); - } - return true; - } - - /** - * 查询流程变量 - * - * @param taskId 任务id - */ - @Override - public List getInstanceVariable(String taskId) { - List variableVoList = new ArrayList<>(); - Map variableInstances = taskService.getVariableInstances(taskId); - if (CollUtil.isNotEmpty(variableInstances)) { - for (Map.Entry entry : variableInstances.entrySet()) { - VariableVo variableVo = new VariableVo(); - variableVo.setKey(entry.getKey()); - variableVo.setValue(entry.getValue().getValue().toString()); - variableVoList.add(variableVo); - } - } - return variableVoList; - } - - /** - * 查询工作流任务用户选择加签人员 - * - * @param taskId 任务id - * @return - */ - @Override - @SuppressWarnings("unchecked") - public String getTaskUserIdsByAddMultiInstance(String taskId) { - Task task = QueryUtils.taskQuery().taskId(taskId).singleResult(); - if (task == null) { - throw new ServiceException("任务不存在"); - } - MultiInstanceVo multiInstance = WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey()); - if (multiInstance == null) { - return ""; - } - List userIds; - if (multiInstance.getType() instanceof SequentialMultiInstanceBehavior) { - userIds = (List) runtimeService.getVariable(task.getExecutionId(), multiInstance.getAssigneeList()); - } else { - List list = QueryUtils.taskQuery(task.getProcessInstanceId()).list(); - userIds = StreamUtils.toList(list, e -> Long.valueOf(e.getAssignee())); - } - return StringUtils.join(userIds, StringUtils.SEPARATOR); - } - - /** - * 查询工作流选择减签人员 - * - * @param taskId 任务id 任务id - */ - @Override - @SuppressWarnings("unchecked") - public List getListByDeleteMultiInstance(String taskId) { - Task task = QueryUtils.taskQuery().taskId(taskId).singleResult(); - List taskList = QueryUtils.taskQuery(task.getProcessInstanceId()).list(); - MultiInstanceVo multiInstance = WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey()); - List taskListVo = new ArrayList<>(); - if (multiInstance == null) { - return List.of(); - } - List assigneeList = new ArrayList<>(); - if (multiInstance.getType() instanceof SequentialMultiInstanceBehavior) { - List variable = (List) runtimeService.getVariable(task.getExecutionId(), multiInstance.getAssigneeList()); - for (Object o : variable) { - assigneeList.add(Long.valueOf(o.toString())); - } - } - - if (multiInstance.getType() instanceof SequentialMultiInstanceBehavior) { - List userIds = StreamUtils.filter(assigneeList, e -> !String.valueOf(e).equals(task.getAssignee())); - List userList = remoteUserService.selectListByIds(userIds); - for (Long userId : userIds) { - TaskVo taskVo = new TaskVo(); - taskVo.setId("串行会签"); - taskVo.setExecutionId("串行会签"); - taskVo.setProcessInstanceId(task.getProcessInstanceId()); - taskVo.setName(task.getName()); - taskVo.setAssignee(userId); - if (CollUtil.isNotEmpty(userList)) { - userList.stream().filter(u -> u.getUserId().toString().equals(userId.toString())).findFirst().ifPresent(u -> taskVo.setAssigneeName(u.getNickName())); - } - taskListVo.add(taskVo); - } - return taskListVo; - } else if (multiInstance.getType() instanceof ParallelMultiInstanceBehavior) { - List tasks = StreamUtils.filter(taskList, e -> StringUtils.isBlank(e.getParentTaskId()) && !e.getExecutionId().equals(task.getExecutionId()) && e.getTaskDefinitionKey().equals(task.getTaskDefinitionKey())); - if (CollUtil.isNotEmpty(tasks)) { - List userIds = StreamUtils.toList(tasks, e -> Long.valueOf(e.getAssignee())); - List userList = remoteUserService.selectListByIds(userIds); - for (Task t : tasks) { - TaskVo taskVo = new TaskVo(); - taskVo.setId(t.getId()); - taskVo.setExecutionId(t.getExecutionId()); - taskVo.setProcessInstanceId(t.getProcessInstanceId()); - taskVo.setName(t.getName()); - taskVo.setAssignee(Long.valueOf(t.getAssignee())); - if (CollUtil.isNotEmpty(userList)) { - userList.stream().filter(u -> u.getUserId().toString().equals(t.getAssignee())).findFirst().ifPresent(e -> taskVo.setAssigneeName(e.getNickName())); - } - taskListVo.add(taskVo); - } - return taskListVo; - } - } - return List.of(); - } -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/TestLeaveServiceImpl.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/TestLeaveServiceImpl.java deleted file mode 100644 index 18b85ca..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/TestLeaveServiceImpl.java +++ /dev/null @@ -1,159 +0,0 @@ -package org.dromara.workflow.service.impl; - -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.toolkit.Wrappers; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.dubbo.config.annotation.DubboReference; -import org.dromara.common.core.utils.MapstructUtils; -import org.dromara.common.core.utils.StreamUtils; -import org.dromara.common.core.utils.StringUtils; -import org.dromara.common.mybatis.core.domain.BaseEntity; -import org.dromara.common.mybatis.core.page.PageQuery; -import org.dromara.common.mybatis.core.page.TableDataInfo; -import org.dromara.workflow.api.domain.RemoteWorkflowService; -import org.dromara.workflow.api.domain.event.ProcessEvent; -import org.dromara.workflow.api.domain.event.ProcessTaskEvent; -import org.dromara.common.core.enums.BusinessStatusEnum; -import org.dromara.workflow.domain.TestLeave; -import org.dromara.workflow.domain.bo.TestLeaveBo; -import org.dromara.workflow.domain.vo.TestLeaveVo; -import org.dromara.workflow.mapper.TestLeaveMapper; -import org.dromara.workflow.service.ITestLeaveService; -import org.springframework.context.event.EventListener; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.Collection; -import java.util.List; - -/** - * 请假Service业务层处理 - * - * @author may - * @date 2023-07-21 - */ -@RequiredArgsConstructor -@Service -@Slf4j -public class TestLeaveServiceImpl implements ITestLeaveService { - - private final TestLeaveMapper baseMapper; - @DubboReference - private final RemoteWorkflowService workflowService; - - /** - * 查询请假 - */ - @Override - public TestLeaveVo queryById(Long id) { - return baseMapper.selectVoById(id); - } - - /** - * 查询请假列表 - */ - @Override - public TableDataInfo queryPageList(TestLeaveBo bo, PageQuery pageQuery) { - LambdaQueryWrapper lqw = buildQueryWrapper(bo); - Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); - return TableDataInfo.build(result); - } - - /** - * 查询请假列表 - */ - @Override - public List queryList(TestLeaveBo bo) { - LambdaQueryWrapper lqw = buildQueryWrapper(bo); - return baseMapper.selectVoList(lqw); - } - - private LambdaQueryWrapper buildQueryWrapper(TestLeaveBo bo) { - LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); - lqw.eq(StringUtils.isNotBlank(bo.getLeaveType()), TestLeave::getLeaveType, bo.getLeaveType()); - lqw.ge(bo.getStartLeaveDays() != null, TestLeave::getLeaveDays, bo.getStartLeaveDays()); - lqw.le(bo.getEndLeaveDays() != null, TestLeave::getLeaveDays, bo.getEndLeaveDays()); - lqw.orderByDesc(BaseEntity::getCreateTime); - return lqw; - } - - /** - * 新增请假 - */ - @Override - public TestLeaveVo insertByBo(TestLeaveBo bo) { - TestLeave add = MapstructUtils.convert(bo, TestLeave.class); - if (StringUtils.isBlank(add.getStatus())) { - add.setStatus(BusinessStatusEnum.DRAFT.getStatus()); - } - boolean flag = baseMapper.insert(add) > 0; - if (flag) { - bo.setId(add.getId()); - } - return MapstructUtils.convert(add, TestLeaveVo.class); - } - - /** - * 修改请假 - */ - @Override - public TestLeaveVo updateByBo(TestLeaveBo bo) { - TestLeave update = MapstructUtils.convert(bo, TestLeave.class); - baseMapper.updateById(update); - return MapstructUtils.convert(update, TestLeaveVo.class); - } - - /** - * 批量删除请假 - */ - @Override - @Transactional(rollbackFor = Exception.class) - public Boolean deleteWithValidByIds(Collection ids) { - List idList = StreamUtils.toList(ids, String::valueOf); - workflowService.deleteRunAndHisInstance(idList); - return baseMapper.deleteByIds(ids) > 0; - } - - /** - * 总体流程监听(例如: 提交 退回 撤销 终止 作废等) - * 正常使用只需#processEvent.key=='leave1' - * 示例为了方便则使用startsWith匹配了全部示例key - * - * @param processEvent 参数 - */ - @EventListener(condition = "#processEvent.key.startsWith('leave')") - public void processHandler(ProcessEvent processEvent) { - log.info("当前任务执行了{}", processEvent.toString()); - TestLeave testLeave = baseMapper.selectById(Long.valueOf(processEvent.getBusinessKey())); - testLeave.setStatus(processEvent.getStatus()); - if (processEvent.isSubmit()) { - testLeave.setStatus(BusinessStatusEnum.WAITING.getStatus()); - } - baseMapper.updateById(testLeave); - } - - /** - * 执行办理任务监听 - * 示例:也可通过 @EventListener(condition = "#processTaskEvent.key=='leave1'")进行判断 - * 在方法中判断流程节点key - * if ("xxx".equals(processTaskEvent.getTaskDefinitionKey())) { - * //执行业务逻辑 - * } - * - * @param processTaskEvent 参数 - */ - @EventListener(condition = "#processTaskEvent.key.startsWith('leave')") - public void processTaskHandler(ProcessTaskEvent processTaskEvent) { - // 所有demo案例的申请人节点id - String[] ids = {"Activity_14633hx", "Activity_19b1i4j", "Activity_0uscrk3", - "Activity_0uscrk3", "Activity_0x6b71j", "Activity_0zy3g6j", "Activity_06a55t0"}; - if (StringUtils.equalsAny(processTaskEvent.getTaskDefinitionKey(), ids)) { - log.info("当前任务执行了{}", processTaskEvent.toString()); - TestLeave testLeave = baseMapper.selectById(Long.valueOf(processTaskEvent.getBusinessKey())); - testLeave.setStatus(BusinessStatusEnum.WAITING.getStatus()); - baseMapper.updateById(testLeave); - } - } -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/WfCategoryServiceImpl.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/WfCategoryServiceImpl.java deleted file mode 100644 index e562823..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/WfCategoryServiceImpl.java +++ /dev/null @@ -1,130 +0,0 @@ -package org.dromara.workflow.service.impl; - -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.toolkit.Wrappers; -import lombok.RequiredArgsConstructor; -import org.dromara.common.core.utils.MapstructUtils; -import org.dromara.common.core.utils.StringUtils; -import org.dromara.workflow.domain.WfCategory; -import org.dromara.workflow.domain.bo.WfCategoryBo; -import org.dromara.workflow.domain.vo.WfCategoryVo; -import org.dromara.workflow.mapper.WfCategoryMapper; -import org.dromara.workflow.service.IWfCategoryService; -import org.dromara.workflow.utils.QueryUtils; -import org.flowable.engine.RepositoryService; -import org.flowable.engine.repository.Deployment; -import org.flowable.engine.repository.Model; -import org.flowable.engine.repository.ProcessDefinition; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.Collection; -import java.util.List; - -/** - * 流程分类Service业务层处理 - * - * @author may - * @date 2023-06-28 - */ -@RequiredArgsConstructor -@Service -public class WfCategoryServiceImpl implements IWfCategoryService { - - private final WfCategoryMapper baseMapper; - @Autowired(required = false) - private RepositoryService repositoryService; - - /** - * 查询流程分类 - */ - @Override - public WfCategoryVo queryById(Long id) { - return baseMapper.selectVoById(id); - } - - - /** - * 查询流程分类列表 - */ - @Override - public List queryList(WfCategoryBo bo) { - LambdaQueryWrapper lqw = buildQueryWrapper(bo); - return baseMapper.selectVoList(lqw); - } - - private LambdaQueryWrapper buildQueryWrapper(WfCategoryBo bo) { - LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); - lqw.like(StringUtils.isNotBlank(bo.getCategoryName()), WfCategory::getCategoryName, bo.getCategoryName()); - lqw.eq(StringUtils.isNotBlank(bo.getCategoryCode()), WfCategory::getCategoryCode, bo.getCategoryCode()); - return lqw; - } - - /** - * 新增流程分类 - */ - @Override - public Boolean insertByBo(WfCategoryBo bo) { - WfCategory add = MapstructUtils.convert(bo, WfCategory.class); - validEntityBeforeSave(add); - boolean flag = baseMapper.insert(add) > 0; - if (flag) { - bo.setId(add.getId()); - } - return flag; - } - - /** - * 修改流程分类 - */ - @Override - @Transactional(rollbackFor = Exception.class) - public Boolean updateByBo(WfCategoryBo bo) { - WfCategory update = MapstructUtils.convert(bo, WfCategory.class); - validEntityBeforeSave(update); - WfCategoryVo wfCategoryVo = baseMapper.selectVoById(bo.getId()); - List processDefinitionList = QueryUtils.definitionQuery().processDefinitionCategory(wfCategoryVo.getCategoryCode()).list(); - for (ProcessDefinition processDefinition : processDefinitionList) { - repositoryService.setProcessDefinitionCategory(processDefinition.getId(), bo.getCategoryCode()); - } - List deploymentList = QueryUtils.deploymentQuery().deploymentCategory(wfCategoryVo.getCategoryCode()).list(); - for (Deployment deployment : deploymentList) { - repositoryService.setDeploymentCategory(deployment.getId(), bo.getCategoryCode()); - } - List modelList = QueryUtils.modelQuery().modelCategory(wfCategoryVo.getCategoryCode()).list(); - for (Model model : modelList) { - model.setCategory(bo.getCategoryCode()); - repositoryService.saveModel(model); - } - return baseMapper.updateById(update) > 0; - } - - /** - * 保存前的数据校验 - */ - private void validEntityBeforeSave(WfCategory entity) { - //TODO 做一些数据校验,如唯一约束 - } - - /** - * 批量删除流程分类 - */ - @Override - public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { - if (isValid) { - //TODO 做一些业务上的校验,判断是否需要校验 - } - return baseMapper.deleteByIds(ids) > 0; - } - - /** - * 按照类别编码查询 - * - * @param categoryCode 分类比吗 - */ - @Override - public WfCategory queryByCategoryCode(String categoryCode) { - return baseMapper.selectOne(new LambdaQueryWrapper().eq(WfCategory::getCategoryCode, categoryCode)); - } -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/WfDefinitionConfigServiceImpl.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/WfDefinitionConfigServiceImpl.java deleted file mode 100644 index b2ffb9e..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/WfDefinitionConfigServiceImpl.java +++ /dev/null @@ -1,117 +0,0 @@ -package org.dromara.workflow.service.impl; - -import cn.hutool.core.collection.CollUtil; -import org.dromara.common.core.utils.MapstructUtils; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import lombok.RequiredArgsConstructor; -import org.dromara.workflow.domain.WfDefinitionConfig; -import org.dromara.workflow.domain.bo.WfDefinitionConfigBo; -import org.dromara.workflow.domain.vo.WfDefinitionConfigVo; -import org.dromara.workflow.service.IWfDefinitionConfigService; -import org.springframework.stereotype.Service; -import org.dromara.workflow.mapper.WfDefinitionConfigMapper; -import org.springframework.transaction.annotation.Transactional; - -import java.util.List; -import java.util.Collection; - -/** - * 流程定义配置Service业务层处理 - * - * @author may - * @date 2024-03-18 - */ -@RequiredArgsConstructor -@Service -public class WfDefinitionConfigServiceImpl implements IWfDefinitionConfigService { - - private final WfDefinitionConfigMapper baseMapper; - - /** - * 查询流程定义配置 - */ - @Override - public WfDefinitionConfigVo getByDefId(String definitionId) { - return baseMapper.selectVoOne(new LambdaQueryWrapper().eq(WfDefinitionConfig::getDefinitionId, definitionId)); - } - - /** - * 查询流程定义配置 - * - * @param tableName 表名 - * @return 结果 - */ - @Override - public WfDefinitionConfigVo getByTableNameLastVersion(String tableName) { - List wfDefinitionConfigVos = baseMapper.selectVoList( - new LambdaQueryWrapper().eq(WfDefinitionConfig::getTableName, tableName).orderByDesc(WfDefinitionConfig::getVersion)); - if (CollUtil.isNotEmpty(wfDefinitionConfigVos)) { - return wfDefinitionConfigVos.get(0); - } - return null; - } - - /** - * 查询流程定义配置 - * - * @param definitionId 流程定义id - * @param tableName 表名 - * @return 结果 - */ - @Override - public WfDefinitionConfigVo getByDefIdAndTableName(String definitionId, String tableName) { - return baseMapper.selectVoOne(new LambdaQueryWrapper() - .eq(WfDefinitionConfig::getDefinitionId, definitionId) - .eq(WfDefinitionConfig::getTableName, tableName)); - } - - /** - * 查询流程定义配置排除当前查询的流程定义 - * - * @param tableName 表名 - * @param definitionId 流程定义id - */ - @Override - public List getByTableNameNotDefId(String tableName, String definitionId) { - return baseMapper.selectVoList(new LambdaQueryWrapper() - .eq(WfDefinitionConfig::getTableName, tableName) - .ne(WfDefinitionConfig::getDefinitionId, definitionId)); - } - - /** - * 查询流程定义配置列表 - */ - @Override - public List queryList(List definitionIds) { - return baseMapper.selectVoList(new LambdaQueryWrapper().in(WfDefinitionConfig::getDefinitionId, definitionIds)); - } - - /** - * 新增流程定义配置 - */ - @Override - @Transactional(rollbackFor = Exception.class) - public Boolean saveOrUpdate(WfDefinitionConfigBo bo) { - WfDefinitionConfig add = MapstructUtils.convert(bo, WfDefinitionConfig.class); - baseMapper.delete(new LambdaQueryWrapper().eq(WfDefinitionConfig::getTableName, bo.getTableName())); - add.setTableName(add.getTableName().toLowerCase()); - boolean flag = baseMapper.insertOrUpdate(add); - if (flag) { - bo.setId(add.getId()); - } - return flag; - } - - /** - * 批量删除流程定义配置 - */ - @Override - public Boolean deleteByIds(Collection ids) { - return baseMapper.deleteByIds(ids) > 0; - } - - @Override - public Boolean deleteByDefIds(Collection ids) { - return baseMapper.delete(new LambdaQueryWrapper().in(WfDefinitionConfig::getDefinitionId, ids)) > 0; - } -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/WfFormManageServiceImpl.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/WfFormManageServiceImpl.java deleted file mode 100644 index 55e4911..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/WfFormManageServiceImpl.java +++ /dev/null @@ -1,111 +0,0 @@ -package org.dromara.workflow.service.impl; - -import org.dromara.common.core.utils.MapstructUtils; -import org.dromara.common.core.utils.StringUtils; -import org.dromara.common.mybatis.core.page.TableDataInfo; -import org.dromara.common.mybatis.core.page.PageQuery; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.toolkit.Wrappers; -import lombok.RequiredArgsConstructor; -import org.dromara.workflow.common.enums.FormTypeEnum; -import org.springframework.stereotype.Service; -import org.dromara.workflow.domain.bo.WfFormManageBo; -import org.dromara.workflow.domain.vo.WfFormManageVo; -import org.dromara.workflow.domain.WfFormManage; -import org.dromara.workflow.mapper.WfFormManageMapper; -import org.dromara.workflow.service.IWfFormManageService; - -import java.util.List; -import java.util.Collection; - -/** - * 表单管理Service业务层处理 - * - * @author may - * @date 2024-03-29 - */ -@RequiredArgsConstructor -@Service -public class WfFormManageServiceImpl implements IWfFormManageService { - - private final WfFormManageMapper baseMapper; - - /** - * 查询表单管理 - */ - @Override - public WfFormManageVo queryById(Long id) { - return baseMapper.selectVoById(id); - } - - @Override - public List queryByIds(List ids) { - return baseMapper.selectVoByIds(ids); - } - - /** - * 查询表单管理列表 - */ - @Override - public TableDataInfo queryPageList(WfFormManageBo bo, PageQuery pageQuery) { - LambdaQueryWrapper lqw = buildQueryWrapper(bo); - Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); - return TableDataInfo.build(result); - } - - @Override - public List selectList() { - List wfFormManageVos = baseMapper.selectVoList(new LambdaQueryWrapper().orderByDesc(WfFormManage::getUpdateTime)); - for (WfFormManageVo wfFormManageVo : wfFormManageVos) { - wfFormManageVo.setFormTypeName(FormTypeEnum.findByType(wfFormManageVo.getFormType())); - } - return wfFormManageVos; - } - - /** - * 查询表单管理列表 - */ - @Override - public List queryList(WfFormManageBo bo) { - LambdaQueryWrapper lqw = buildQueryWrapper(bo); - return baseMapper.selectVoList(lqw); - } - - private LambdaQueryWrapper buildQueryWrapper(WfFormManageBo bo) { - LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); - lqw.like(StringUtils.isNotBlank(bo.getFormName()), WfFormManage::getFormName, bo.getFormName()); - lqw.eq(StringUtils.isNotBlank(bo.getFormType()), WfFormManage::getFormType, bo.getFormType()); - return lqw; - } - - /** - * 新增表单管理 - */ - @Override - public Boolean insertByBo(WfFormManageBo bo) { - WfFormManage add = MapstructUtils.convert(bo, WfFormManage.class); - boolean flag = baseMapper.insert(add) > 0; - if (flag) { - bo.setId(add.getId()); - } - return flag; - } - - /** - * 修改表单管理 - */ - @Override - public Boolean updateByBo(WfFormManageBo bo) { - WfFormManage update = MapstructUtils.convert(bo, WfFormManage.class); - return baseMapper.updateById(update) > 0; - } - - /** - * 批量删除表单管理 - */ - @Override - public Boolean deleteByIds(Collection ids) { - return baseMapper.deleteByIds(ids) > 0; - } -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/WfNodeConfigServiceImpl.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/WfNodeConfigServiceImpl.java deleted file mode 100644 index 2f71482..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/WfNodeConfigServiceImpl.java +++ /dev/null @@ -1,75 +0,0 @@ -package org.dromara.workflow.service.impl; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.ObjectUtil; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import lombok.RequiredArgsConstructor; -import org.dromara.common.core.utils.StreamUtils; -import org.dromara.workflow.domain.vo.WfFormManageVo; -import org.dromara.workflow.service.IWfFormManageService; -import org.springframework.stereotype.Service; -import org.dromara.workflow.domain.vo.WfNodeConfigVo; -import org.dromara.workflow.domain.WfNodeConfig; -import org.dromara.workflow.mapper.WfNodeConfigMapper; -import org.dromara.workflow.service.IWfNodeConfigService; - -import java.util.Collection; -import java.util.List; - -/** - * 节点配置Service业务层处理 - * - * @author may - * @date 2024-03-30 - */ -@RequiredArgsConstructor -@Service -public class WfNodeConfigServiceImpl implements IWfNodeConfigService { - - private final WfNodeConfigMapper baseMapper; - private final IWfFormManageService wfFormManageService; - - /** - * 查询节点配置 - */ - @Override - public WfNodeConfigVo queryById(Long id) { - return baseMapper.selectVoById(id); - } - - /** - * 保存节点配置 - */ - @Override - public Boolean saveOrUpdate(List list) { - return baseMapper.insertOrUpdateBatch(list); - } - - /** - * 批量删除节点配置 - */ - @Override - public Boolean deleteByIds(Collection ids) { - return baseMapper.deleteByIds(ids) > 0; - } - - - - @Override - public Boolean deleteByDefIds(Collection ids) { - return baseMapper.delete(new LambdaQueryWrapper().in(WfNodeConfig::getDefinitionId, ids)) > 0; - } - - @Override - public List selectByDefIds(Collection ids) { - List wfNodeConfigVos = baseMapper.selectVoList(new LambdaQueryWrapper().in(WfNodeConfig::getDefinitionId, ids)); - if (CollUtil.isNotEmpty(wfNodeConfigVos)) { - List formIds = StreamUtils.toList(wfNodeConfigVos, WfNodeConfigVo::getFormId); - List wfFormManageVos = wfFormManageService.queryByIds(formIds); - for (WfNodeConfigVo wfNodeConfigVo : wfNodeConfigVos) { - wfFormManageVos.stream().filter(e -> ObjectUtil.equals(e.getId(), wfNodeConfigVo.getFormId())).findFirst().ifPresent(wfNodeConfigVo::setWfFormManageVo); - } - } - return wfNodeConfigVos; - } -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/WfTaskBackNodeServiceImpl.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/WfTaskBackNodeServiceImpl.java deleted file mode 100644 index 6c255d3..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/WfTaskBackNodeServiceImpl.java +++ /dev/null @@ -1,144 +0,0 @@ -package org.dromara.workflow.service.impl; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.ObjectUtil; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.dromara.common.core.exception.ServiceException; -import org.dromara.common.core.utils.StreamUtils; -import org.dromara.common.core.utils.StringUtils; -import org.dromara.common.satoken.utils.LoginHelper; -import org.dromara.workflow.domain.WfTaskBackNode; -import org.dromara.workflow.domain.vo.MultiInstanceVo; -import org.dromara.workflow.mapper.WfTaskBackNodeMapper; -import org.dromara.workflow.service.IWfTaskBackNodeService; -import org.dromara.workflow.utils.WorkflowUtils; -import org.flowable.task.api.Task; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.ArrayList; -import java.util.List; - -import static org.dromara.workflow.common.constant.FlowConstant.MULTI_INSTANCE; -import static org.dromara.workflow.common.constant.FlowConstant.USER_TASK; - - -/** - * 节点驳回记录Service业务层处理 - * - * @author may - * @date 2024-03-13 - */ -@Slf4j -@RequiredArgsConstructor -@Service -public class WfTaskBackNodeServiceImpl implements IWfTaskBackNodeService { - - private final WfTaskBackNodeMapper wfTaskBackNodeMapper; - - @Override - @Transactional(rollbackFor = Exception.class) - public void recordExecuteNode(Task task) { - List list = getListByInstanceId(task.getProcessInstanceId()); - WfTaskBackNode wfTaskBackNode = new WfTaskBackNode(); - wfTaskBackNode.setNodeId(task.getTaskDefinitionKey()); - wfTaskBackNode.setNodeName(task.getName()); - wfTaskBackNode.setInstanceId(task.getProcessInstanceId()); - wfTaskBackNode.setAssignee(String.valueOf(LoginHelper.getUserId())); - MultiInstanceVo multiInstance = WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey()); - if (ObjectUtil.isNotEmpty(multiInstance)) { - wfTaskBackNode.setTaskType(MULTI_INSTANCE); - } else { - wfTaskBackNode.setTaskType(USER_TASK); - } - if (CollUtil.isEmpty(list)) { - wfTaskBackNode.setOrderNo(0); - wfTaskBackNodeMapper.insert(wfTaskBackNode); - } else { - WfTaskBackNode taskNode = StreamUtils.findFirst(list, e -> e.getNodeId().equals(wfTaskBackNode.getNodeId()) && e.getOrderNo() == 0); - if (ObjectUtil.isEmpty(taskNode)) { - wfTaskBackNode.setOrderNo(list.get(0).getOrderNo() + 1); - WfTaskBackNode node = getListByInstanceIdAndNodeId(wfTaskBackNode.getInstanceId(), wfTaskBackNode.getNodeId()); - if (ObjectUtil.isNotEmpty(node)) { - node.setAssignee(node.getAssignee() + StringUtils.SEPARATOR + LoginHelper.getUserId()); - wfTaskBackNodeMapper.updateById(node); - } else { - wfTaskBackNodeMapper.insert(wfTaskBackNode); - } - } - } - } - - @Override - public List getListByInstanceId(String processInstanceId) { - LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); - wrapper.eq(WfTaskBackNode::getInstanceId, processInstanceId); - wrapper.orderByDesc(WfTaskBackNode::getOrderNo); - return wfTaskBackNodeMapper.selectList(wrapper); - } - - @Override - public WfTaskBackNode getListByInstanceIdAndNodeId(String processInstanceId, String nodeId) { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(WfTaskBackNode::getInstanceId, processInstanceId); - queryWrapper.eq(WfTaskBackNode::getNodeId, nodeId); - return wfTaskBackNodeMapper.selectOne(queryWrapper); - } - - @Override - @Transactional(rollbackFor = Exception.class) - public boolean deleteBackTaskNode(String processInstanceId, String targetActivityId) { - try { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(WfTaskBackNode::getInstanceId, processInstanceId); - queryWrapper.eq(WfTaskBackNode::getNodeId, targetActivityId); - WfTaskBackNode actTaskNode = wfTaskBackNodeMapper.selectOne(queryWrapper); - if (ObjectUtil.isNotNull(actTaskNode)) { - Integer orderNo = actTaskNode.getOrderNo(); - List taskNodeList = getListByInstanceId(processInstanceId); - List ids = new ArrayList<>(); - if (CollUtil.isNotEmpty(taskNodeList)) { - for (WfTaskBackNode taskNode : taskNodeList) { - if (taskNode.getOrderNo() >= orderNo) { - ids.add(taskNode.getId()); - } - } - } - if (CollUtil.isNotEmpty(ids)) { - wfTaskBackNodeMapper.deleteByIds(ids); - } - } - return true; - } catch (Exception e) { - log.error(e.getMessage(), e); - throw new ServiceException("删除失败"); - } - } - - @Override - @Transactional(rollbackFor = Exception.class) - public boolean deleteByInstanceId(String processInstanceId) { - LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); - wrapper.eq(WfTaskBackNode::getInstanceId, processInstanceId); - List list = wfTaskBackNodeMapper.selectList(wrapper); - int delete = wfTaskBackNodeMapper.delete(wrapper); - if (list.size() != delete) { - throw new ServiceException("删除失败"); - } - return true; - } - - @Override - public boolean deleteByInstanceIds(List processInstanceIds) { - LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); - wrapper.in(WfTaskBackNode::getInstanceId, processInstanceIds); - List list = wfTaskBackNodeMapper.selectList(wrapper); - int delete = wfTaskBackNodeMapper.delete(wrapper); - if (list.size() != delete) { - throw new ServiceException("删除失败"); - } - return true; - } -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java deleted file mode 100644 index e12ec16..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java +++ /dev/null @@ -1,122 +0,0 @@ -package org.dromara.workflow.service.impl; - -import cn.hutool.core.util.StrUtil; -import lombok.RequiredArgsConstructor; -import org.dromara.workflow.domain.ActHiProcinst; -import org.dromara.workflow.service.IActHiProcinstService; -import org.dromara.workflow.service.IActProcessInstanceService; -import org.dromara.workflow.service.WorkflowService; -import org.dromara.workflow.utils.WorkflowUtils; -import org.flowable.engine.RuntimeService; -import org.flowable.engine.TaskService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import java.util.List; -import java.util.Map; - -/** - * 通用 工作流服务实现 - * - * @author may - */ -@RequiredArgsConstructor -@Service -public class WorkflowServiceImpl implements WorkflowService { - - @Autowired(required = false) - private TaskService taskService; - private final IActProcessInstanceService actProcessInstanceService; - private final IActHiProcinstService actHiProcinstService; - /** - * 运行中的实例 删除程实例,删除历史记录,删除业务与流程关联信息 - * - * @param businessKeys 业务id - * @return 结果 - */ - @Override - public boolean deleteRunAndHisInstance(List businessKeys) { - return actProcessInstanceService.deleteRunAndHisInstance(businessKeys); - } - - /** - * 获取当前流程状态 - * - * @param taskId 任务id - */ - @Override - public String getBusinessStatusByTaskId(String taskId) { - return WorkflowUtils.getBusinessStatusByTaskId(taskId); - } - - /** - * 获取当前流程状态 - * - * @param businessKey 业务id - */ - @Override - public String getBusinessStatus(String businessKey) { - return WorkflowUtils.getBusinessStatus(businessKey); - } - - /** - * 设置流程变量(全局变量) - * - * @param taskId 任务id - * @param variableName 变量名称 - * @param value 变量值 - */ - @Override - public void setVariable(String taskId, String variableName, Object value) { - taskService.setVariable(taskId, variableName, value); - } - - /** - * 设置流程变量(全局变量) - * - * @param taskId 任务id - * @param variables 流程变量 - */ - @Override - public void setVariables(String taskId, Map variables) { - taskService.setVariables(taskId, variables); - } - - /** - * 设置流程变量(本地变量,非全局变量) - * - * @param taskId 任务id - * @param variableName 变量名称 - * @param value 变量值 - */ - @Override - public void setVariableLocal(String taskId, String variableName, Object value) { - taskService.setVariableLocal(taskId, variableName, value); - } - - /** - * 设置流程变量(本地变量,非全局变量) - * - * @param taskId 任务id - * @param variables 流程变量 - */ - @Override - public void setVariablesLocal(String taskId, Map variables) { - taskService.setVariablesLocal(taskId, variables); - } - - /** - * 按照业务id查询流程实例id - * - * @param businessKey 业务id - * @return 结果 - */ - @Override - public String getInstanceIdByBusinessKey(String businessKey) { - ActHiProcinst actHiProcinst = actHiProcinstService.selectByBusinessKey(businessKey); - if (actHiProcinst == null) { - return StrUtil.EMPTY; - } - return actHiProcinst.getId(); - } -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/utils/ModelUtils.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/utils/ModelUtils.java deleted file mode 100644 index 7c5377e..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/utils/ModelUtils.java +++ /dev/null @@ -1,289 +0,0 @@ -package org.dromara.workflow.utils; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.collection.CollectionUtil; -import cn.hutool.core.io.IoUtil; -import cn.hutool.core.util.ObjectUtil; -import cn.hutool.core.util.StrUtil; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.AccessLevel; -import lombok.NoArgsConstructor; -import org.dromara.common.core.utils.SpringUtils; -import org.dromara.common.core.utils.StreamUtils; -import org.dromara.common.core.utils.StringUtils; -import org.dromara.common.json.utils.JsonUtils; -import org.dromara.workflow.domain.vo.MultiInstanceVo; -import org.flowable.bpmn.converter.BpmnXMLConverter; -import org.flowable.bpmn.model.*; -import org.flowable.bpmn.model.Process; -import org.flowable.editor.language.json.converter.BpmnJsonConverter; -import org.flowable.engine.ProcessEngine; - -import javax.xml.stream.XMLInputFactory; -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamReader; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.rmi.ServerException; -import java.util.*; -import java.util.stream.Collectors; - -/** - * 模型工具 - * - * @author may - */ -@NoArgsConstructor(access = AccessLevel.PRIVATE) -public class ModelUtils { - - private static final ProcessEngine PROCESS_ENGINE = SpringUtils.getBean(ProcessEngine.class); - - public static BpmnModel xmlToBpmnModel(String xml) throws IOException { - if (xml == null) { - throw new ServerException("xml不能为空"); - } - try { - InputStream inputStream = new ByteArrayInputStream(StrUtil.utf8Bytes(xml)); - XMLInputFactory factory = XMLInputFactory.newInstance(); - XMLStreamReader reader = factory.createXMLStreamReader(inputStream); - return new BpmnXMLConverter().convertToBpmnModel(reader); - } catch (XMLStreamException e) { - throw new ServerException(e.getMessage()); - } - } - - /** - * bpmnModel转为xml - * - * @param jsonBytes json - */ - public static byte[] bpmnJsonToXmlBytes(byte[] jsonBytes) throws IOException { - if (jsonBytes == null) { - return new byte[0]; - } - // 1. json字节码转成 BpmnModel 对象 - ObjectMapper objectMapper = JsonUtils.getObjectMapper(); - JsonNode jsonNode = objectMapper.readTree(jsonBytes); - BpmnModel bpmnModel = new BpmnJsonConverter().convertToBpmnModel(jsonNode); - - if (bpmnModel.getProcesses().isEmpty()) { - return new byte[0]; - } - // 2.将bpmnModel转为xml - return new BpmnXMLConverter().convertToXML(bpmnModel); - } - - /** - * xml转为bpmnModel - * - * @param xmlBytes xml - */ - public static BpmnModel xmlToBpmnModel(byte[] xmlBytes) throws XMLStreamException { - ByteArrayInputStream byteArrayInputStream = IoUtil.toStream(xmlBytes); - XMLInputFactory xif = XMLInputFactory.newInstance(); - XMLStreamReader xtr = xif.createXMLStreamReader(byteArrayInputStream); - return new BpmnXMLConverter().convertToBpmnModel(xtr); - } - - /** - * 校验模型 - * - * @param bpmnModel bpmn模型 - */ - public static void checkBpmnModel(BpmnModel bpmnModel) throws ServerException { - Collection flowElements = bpmnModel.getMainProcess().getFlowElements(); - - checkBpmnNode(flowElements, false); - - List subProcessList = flowElements.stream().filter(SubProcess.class::isInstance).map(SubProcess.class::cast).collect(Collectors.toList()); - if (!CollUtil.isEmpty(subProcessList)) { - for (SubProcess subProcess : subProcessList) { - Collection subProcessFlowElements = subProcess.getFlowElements(); - checkBpmnNode(subProcessFlowElements, true); - } - } - List multiInstanceVoList = new ArrayList<>(); - for (FlowElement flowElement : flowElements) { - if (flowElement instanceof UserTask && ObjectUtil.isNotEmpty(((UserTask) flowElement).getLoopCharacteristics()) && StringUtils.isNotBlank(((UserTask) flowElement).getLoopCharacteristics().getInputDataItem())) { - MultiInstanceVo multiInstanceVo = new MultiInstanceVo(); - multiInstanceVo.setAssigneeList(((UserTask) flowElement).getLoopCharacteristics().getInputDataItem()); - multiInstanceVoList.add(multiInstanceVo); - } - } - - if (CollectionUtil.isNotEmpty(multiInstanceVoList) && multiInstanceVoList.size() > 1) { - Map> assigneeListGroup = StreamUtils.groupByKey(multiInstanceVoList, MultiInstanceVo::getAssigneeList); - for (Map.Entry> entry : assigneeListGroup.entrySet()) { - List value = entry.getValue(); - if (CollectionUtil.isNotEmpty(value) && value.size() > 1) { - String key = entry.getKey(); - throw new ServerException("会签人员集合【" + key + "】重复,请重新设置集合KEY"); - } - } - } - } - - /** - * 校验bpmn节点是否合法 - * - * @param flowElements 节点集合 - * @param subtask 是否子流程 - */ - private static void checkBpmnNode(Collection flowElements, boolean subtask) throws ServerException { - - if (CollUtil.isEmpty(flowElements)) { - throw new ServerException(subtask ? "子流程必须存在节点" : "必须存在节点!"); - } - - List startEventList = flowElements.stream().filter(StartEvent.class::isInstance).map(StartEvent.class::cast).collect(Collectors.toList()); - if (CollUtil.isEmpty(startEventList)) { - throw new ServerException(subtask ? "子流程必须存在开始节点" : "必须存在开始节点!"); - } - - if (startEventList.size() > 1) { - throw new ServerException(subtask ? "子流程只能存在一个开始节点" : "只能存在一个开始节点!"); - } - - StartEvent startEvent = startEventList.get(0); - List outgoingFlows = startEvent.getOutgoingFlows(); - if (CollUtil.isEmpty(outgoingFlows)) { - throw new ServerException(subtask ? "子流程流程节点为空,请至少设计一条主线流程!" : "流程节点为空,请至少设计一条主线流程!"); - } - - FlowElement targetFlowElement = outgoingFlows.get(0).getTargetFlowElement(); - if (!(targetFlowElement instanceof UserTask) && !subtask) { - throw new ServerException("开始节点后第一个节点必须是用户任务!"); - } - //开始节点后第一个节点申请人节点 - if ((targetFlowElement instanceof UserTask) && !subtask) { - UserTask userTask = (UserTask) targetFlowElement; - if (StringUtils.isBlank(userTask.getFormKey())) { - throw new ServerException("申请人节点必须选择表单!"); - } - } - List endEventList = flowElements.stream().filter(EndEvent.class::isInstance).map(EndEvent.class::cast).collect(Collectors.toList()); - if (CollUtil.isEmpty(endEventList)) { - throw new ServerException(subtask ? "子流程必须存在结束节点!" : "必须存在结束节点!"); - } - } - - /** - * 获取流程全部用户节点 - * - * @param processDefinitionId 流程定义id - */ - public static List getUserTaskFlowElements(String processDefinitionId) { - BpmnModel bpmnModel = PROCESS_ENGINE.getRepositoryService().getBpmnModel(processDefinitionId); - List list = new ArrayList<>(); - List processes = bpmnModel.getProcesses(); - Collection flowElements = processes.get(0).getFlowElements(); - buildUserTaskFlowElements(flowElements, list); - return list; - } - - /** - * 递归获取所有节点 - * - * @param flowElements 节点信息 - * @param list 集合 - */ - private static void buildUserTaskFlowElements(Collection flowElements, List list) { - for (FlowElement flowElement : flowElements) { - if (flowElement instanceof SubProcess) { - Collection subFlowElements = ((SubProcess) flowElement).getFlowElements(); - buildUserTaskFlowElements(subFlowElements, list); - } else if (flowElement instanceof UserTask) { - list.add((UserTask) flowElement); - } - } - } - - /** - * 获取流程全部节点 - * - * @param processDefinitionId 流程定义id - */ - public static List getFlowElements(String processDefinitionId) { - BpmnModel bpmnModel = PROCESS_ENGINE.getRepositoryService().getBpmnModel(processDefinitionId); - List list = new ArrayList<>(); - List processes = bpmnModel.getProcesses(); - Collection flowElements = processes.get(0).getFlowElements(); - buildFlowElements(flowElements, list); - return list; - } - - /** - * 递归获取所有节点 - * - * @param flowElements 节点信息 - * @param list 集合 - */ - private static void buildFlowElements(Collection flowElements, List list) { - for (FlowElement flowElement : flowElements) { - list.add(flowElement); - if (flowElement instanceof SubProcess) { - Collection subFlowElements = ((SubProcess) flowElement).getFlowElements(); - buildFlowElements(subFlowElements, list); - } - } - } - - /** - * 获取全部扩展信息 - * - * @param processDefinitionId 流程定义id - */ - public static Map> getExtensionElements(String processDefinitionId) { - Map> map = new HashMap<>(); - List flowElements = getFlowElements(processDefinitionId); - for (FlowElement flowElement : flowElements) { - if (flowElement instanceof UserTask && CollUtil.isNotEmpty(flowElement.getExtensionElements())) { - map.putAll(flowElement.getExtensionElements()); - } - } - return map; - } - - /** - * 获取某个节点的扩展信息 - * - * @param processDefinitionId 流程定义id - * @param flowElementId 节点id - */ - public static Map> getExtensionElement(String processDefinitionId, String flowElementId) { - BpmnModel bpmnModel = PROCESS_ENGINE.getRepositoryService().getBpmnModel(processDefinitionId); - Process process = bpmnModel.getMainProcess(); - FlowElement flowElement = process.getFlowElement(flowElementId); - return flowElement.getExtensionElements(); - } - - /** - * 判断当前节点是否为用户任务 - * - * @param processDefinitionId 流程定义id - * @param taskDefinitionKey 流程定义id - */ - public static boolean isUserTask(String processDefinitionId, String taskDefinitionKey) { - BpmnModel bpmnModel = PROCESS_ENGINE.getRepositoryService().getBpmnModel(processDefinitionId); - FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(taskDefinitionKey); - return flowNode instanceof UserTask; - } - - /** - * 获取申请人节点 - * - * @param processDefinitionId 流程定义id - * @return 结果 - */ - public static UserTask getApplyUserTask(String processDefinitionId) { - BpmnModel bpmnModel = PROCESS_ENGINE.getRepositoryService().getBpmnModel(processDefinitionId); - Collection flowElements = bpmnModel.getMainProcess().getFlowElements(); - List startEventList = flowElements.stream().filter(StartEvent.class::isInstance).map(StartEvent.class::cast).collect(Collectors.toList()); - StartEvent startEvent = startEventList.get(0); - List outgoingFlows = startEvent.getOutgoingFlows(); - FlowElement targetFlowElement = outgoingFlows.get(0).getTargetFlowElement(); - return (UserTask) targetFlowElement; - } -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/utils/QueryUtils.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/utils/QueryUtils.java deleted file mode 100644 index df928dc..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/utils/QueryUtils.java +++ /dev/null @@ -1,169 +0,0 @@ -package org.dromara.workflow.utils; - -import cn.hutool.core.bean.BeanUtil; -import lombok.AccessLevel; -import lombok.NoArgsConstructor; -import org.dromara.common.core.utils.SpringUtils; -import org.dromara.common.tenant.helper.TenantHelper; -import org.dromara.workflow.domain.vo.TaskVo; -import org.flowable.engine.ProcessEngine; -import org.flowable.engine.history.HistoricActivityInstanceQuery; -import org.flowable.engine.history.HistoricProcessInstanceQuery; -import org.flowable.engine.repository.DeploymentQuery; -import org.flowable.engine.repository.ModelQuery; -import org.flowable.engine.repository.ProcessDefinitionQuery; -import org.flowable.engine.runtime.ProcessInstance; -import org.flowable.engine.runtime.ProcessInstanceQuery; -import org.flowable.task.api.Task; -import org.flowable.task.api.TaskQuery; -import org.flowable.task.api.history.HistoricTaskInstanceQuery; - -import java.util.Collection; -import java.util.List; -import java.util.Set; - -/** - * 查询工具 - * - * @author Lion Li - */ -@NoArgsConstructor(access = AccessLevel.PRIVATE) -public class QueryUtils { - - private static final ProcessEngine PROCESS_ENGINE = SpringUtils.getBean(ProcessEngine.class); - - public static ModelQuery modelQuery() { - ModelQuery query = PROCESS_ENGINE.getRepositoryService().createModelQuery(); - if (TenantHelper.isEnable()) { - query.modelTenantId(TenantHelper.getTenantId()); - } - return query; - } - - public static ProcessDefinitionQuery definitionQuery() { - ProcessDefinitionQuery query = PROCESS_ENGINE.getRepositoryService().createProcessDefinitionQuery(); - if (TenantHelper.isEnable()) { - query.processDefinitionTenantId(TenantHelper.getTenantId()); - } - return query; - } - - public static DeploymentQuery deploymentQuery() { - DeploymentQuery query = PROCESS_ENGINE.getRepositoryService().createDeploymentQuery(); - if (TenantHelper.isEnable()) { - query.deploymentTenantId(TenantHelper.getTenantId()); - } - return query; - } - - public static DeploymentQuery deploymentQuery(String deploymentId) { - return deploymentQuery().deploymentId(deploymentId); - } - - public static DeploymentQuery deploymentQuery(List deploymentIds) { - return deploymentQuery().deploymentIds(deploymentIds); - } - - public static HistoricTaskInstanceQuery hisTaskInstanceQuery() { - HistoricTaskInstanceQuery query = PROCESS_ENGINE.getHistoryService().createHistoricTaskInstanceQuery(); - if (TenantHelper.isEnable()) { - query.taskTenantId(TenantHelper.getTenantId()); - } - return query; - } - - public static HistoricTaskInstanceQuery hisTaskInstanceQuery(String processInstanceId) { - return hisTaskInstanceQuery().processInstanceId(processInstanceId); - } - - public static HistoricTaskInstanceQuery hisTaskBusinessKeyQuery(String businessKey) { - return hisTaskInstanceQuery().processInstanceBusinessKey(businessKey); - } - - public static ProcessInstanceQuery instanceQuery() { - ProcessInstanceQuery query = PROCESS_ENGINE.getRuntimeService().createProcessInstanceQuery(); - if (TenantHelper.isEnable()) { - query.processInstanceTenantId(TenantHelper.getTenantId()); - } - return query; - } - - public static ProcessInstanceQuery instanceQuery(String processInstanceId) { - return instanceQuery().processInstanceId(processInstanceId); - } - - public static ProcessInstanceQuery businessKeyQuery(String businessKey) { - return instanceQuery().processInstanceBusinessKey(businessKey); - } - - public static ProcessInstanceQuery instanceQuery(Set processInstanceIds) { - return instanceQuery().processInstanceIds(processInstanceIds); - } - - public static HistoricProcessInstanceQuery hisInstanceQuery() { - HistoricProcessInstanceQuery query = PROCESS_ENGINE.getHistoryService().createHistoricProcessInstanceQuery(); - if (TenantHelper.isEnable()) { - query.processInstanceTenantId(TenantHelper.getTenantId()); - } - return query; - } - - public static HistoricProcessInstanceQuery hisInstanceQuery(String processInstanceId) { - return hisInstanceQuery().processInstanceId(processInstanceId); - } - - public static HistoricProcessInstanceQuery hisBusinessKeyQuery(String businessKey) { - return hisInstanceQuery().processInstanceBusinessKey(businessKey); - } - - public static HistoricProcessInstanceQuery hisInstanceQuery(Set processInstanceIds) { - return hisInstanceQuery().processInstanceIds(processInstanceIds); - } - - public static HistoricActivityInstanceQuery hisActivityInstanceQuery() { - HistoricActivityInstanceQuery query = PROCESS_ENGINE.getHistoryService().createHistoricActivityInstanceQuery(); - if (TenantHelper.isEnable()) { - query.activityTenantId(TenantHelper.getTenantId()); - } - return query; - } - - public static HistoricActivityInstanceQuery hisActivityInstanceQuery(String processInstanceId) { - return hisActivityInstanceQuery().processInstanceId(processInstanceId); - } - - public static TaskQuery taskQuery() { - TaskQuery query = PROCESS_ENGINE.getTaskService().createTaskQuery(); - if (TenantHelper.isEnable()) { - query.taskTenantId(TenantHelper.getTenantId()); - } - return query; - } - - public static TaskQuery taskQuery(String processInstanceId) { - return taskQuery().processInstanceId(processInstanceId); - } - - public static TaskQuery taskQuery(Collection processInstanceIds) { - return taskQuery().processInstanceIdIn(processInstanceIds); - } - - /** - * 按照任务id查询当前任务 - * - * @param taskId 任务id - */ - public static TaskVo getTask(String taskId) { - Task task = PROCESS_ENGINE.getTaskService().createTaskQuery().taskId(taskId).singleResult(); - if (task == null) { - return null; - } - ProcessInstance processInstance = QueryUtils.instanceQuery(task.getProcessInstanceId()).singleResult(); - TaskVo taskVo = BeanUtil.toBean(task, TaskVo.class); - taskVo.setBusinessKey(processInstance.getBusinessKey()); - taskVo.setMultiInstance(WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey()) != null); - String businessStatus = WorkflowUtils.getBusinessStatus(taskVo.getBusinessKey()); - taskVo.setBusinessStatus(businessStatus); - return taskVo; - } -} diff --git a/dk-modules/workflow/src/main/java/org/dromara/workflow/utils/WorkflowUtils.java b/dk-modules/workflow/src/main/java/org/dromara/workflow/utils/WorkflowUtils.java deleted file mode 100644 index 0e77d06..0000000 --- a/dk-modules/workflow/src/main/java/org/dromara/workflow/utils/WorkflowUtils.java +++ /dev/null @@ -1,296 +0,0 @@ -package org.dromara.workflow.utils; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.ObjectUtil; -import cn.hutool.core.util.StrUtil; -import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; -import lombok.AccessLevel; -import lombok.NoArgsConstructor; -import org.dromara.common.core.utils.SpringUtils; -import org.dromara.common.core.utils.StreamUtils; -import org.dromara.common.core.utils.StringUtils; -import org.dromara.common.mail.utils.MailUtils; -import org.dromara.common.satoken.utils.LoginHelper; -import org.dromara.common.tenant.helper.TenantHelper; -import org.dromara.common.websocket.dto.WebSocketMessageDto; -import org.dromara.common.websocket.utils.WebSocketUtils; -import org.dromara.system.api.RemoteUserService; -import org.dromara.system.api.domain.vo.RemoteUserVo; -import org.dromara.system.api.model.RoleDTO; -import org.dromara.workflow.common.constant.FlowConstant; -import org.dromara.workflow.common.enums.MessageTypeEnum; -import org.dromara.workflow.common.enums.TaskStatusEnum; -import org.dromara.workflow.domain.ActHiTaskinst; -import org.dromara.workflow.domain.vo.MultiInstanceVo; -import org.dromara.workflow.domain.vo.ParticipantVo; -import org.dromara.workflow.flowable.cmd.UpdateHiTaskInstCmd; -import org.dromara.workflow.mapper.ActHiTaskinstMapper; -import org.flowable.bpmn.model.BpmnModel; -import org.flowable.bpmn.model.FlowNode; -import org.flowable.common.engine.api.delegate.Expression; -import org.flowable.engine.ProcessEngine; -import org.flowable.engine.history.HistoricProcessInstance; -import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior; -import org.flowable.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior; -import org.flowable.identitylink.api.history.HistoricIdentityLink; -import org.flowable.task.api.Task; -import org.flowable.task.api.TaskQuery; -import org.flowable.task.api.history.HistoricTaskInstance; -import org.flowable.task.service.impl.persistence.entity.TaskEntity; - -import java.util.*; - -/** - * 工作流工具 - * - * @author may - */ -@NoArgsConstructor(access = AccessLevel.PRIVATE) -public class WorkflowUtils { - - private static final ProcessEngine PROCESS_ENGINE = SpringUtils.getBean(ProcessEngine.class); - private static final ActHiTaskinstMapper ACT_HI_TASKINST_MAPPER = SpringUtils.getBean(ActHiTaskinstMapper.class); - - /** - * 创建一个新任务 - * - * @param currentTask 参数 - */ - public static TaskEntity createNewTask(Task currentTask) { - TaskEntity task = null; - if (ObjectUtil.isNotEmpty(currentTask)) { - task = (TaskEntity) PROCESS_ENGINE.getTaskService().newTask(); - task.setCategory(currentTask.getCategory()); - task.setDescription(currentTask.getDescription()); - task.setAssignee(currentTask.getAssignee()); - task.setName(currentTask.getName()); - task.setProcessDefinitionId(currentTask.getProcessDefinitionId()); - task.setProcessInstanceId(currentTask.getProcessInstanceId()); - task.setTaskDefinitionKey(currentTask.getTaskDefinitionKey()); - task.setPriority(currentTask.getPriority()); - task.setCreateTime(new Date()); - task.setTenantId(TenantHelper.getTenantId()); - PROCESS_ENGINE.getTaskService().saveTask(task); - } - if (ObjectUtil.isNotNull(task)) { - UpdateHiTaskInstCmd updateHiTaskInstCmd = new UpdateHiTaskInstCmd(Collections.singletonList(task.getId()), task.getProcessDefinitionId(), task.getProcessInstanceId()); - PROCESS_ENGINE.getManagementService().executeCommand(updateHiTaskInstCmd); - } - return task; - } - - /** - * 抄送任务 - * - * @param parentTaskList 父级任务 - * @param userIds 人员id - */ - public static void createCopyTask(List parentTaskList, List userIds) { - List list = new ArrayList<>(); - String tenantId = TenantHelper.getTenantId(); - for (Task parentTask : parentTaskList) { - for (Long userId : userIds) { - TaskEntity newTask = (TaskEntity) PROCESS_ENGINE.getTaskService().newTask(); - newTask.setParentTaskId(parentTask.getId()); - newTask.setAssignee(userId.toString()); - newTask.setName("【抄送】-" + parentTask.getName()); - newTask.setProcessDefinitionId(parentTask.getProcessDefinitionId()); - newTask.setProcessInstanceId(parentTask.getProcessInstanceId()); - newTask.setTaskDefinitionKey(parentTask.getTaskDefinitionKey()); - newTask.setTenantId(tenantId); - list.add(newTask); - } - } - PROCESS_ENGINE.getTaskService().bulkSaveTasks(list); - if (CollUtil.isNotEmpty(list) && CollUtil.isNotEmpty(parentTaskList)) { - String processInstanceId = parentTaskList.get(0).getProcessInstanceId(); - String processDefinitionId = parentTaskList.get(0).getProcessDefinitionId(); - List taskIds = StreamUtils.toList(list, Task::getId); - ActHiTaskinst actHiTaskinst = new ActHiTaskinst(); - actHiTaskinst.setProcDefId(processDefinitionId); - actHiTaskinst.setProcInstId(processInstanceId); - actHiTaskinst.setScopeType(TaskStatusEnum.COPY.getStatus()); - actHiTaskinst.setTenantId(tenantId); - LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); - updateWrapper.in(ActHiTaskinst::getId, taskIds); - ACT_HI_TASKINST_MAPPER.update(actHiTaskinst, updateWrapper); - for (Task task : list) { - PROCESS_ENGINE.getTaskService().addComment(task.getId(), task.getProcessInstanceId(), TaskStatusEnum.COPY.getStatus(), StrUtil.EMPTY); - } - } - } - - /** - * 获取当前任务参与者 - * - * @param taskId 任务id - */ - public static ParticipantVo getCurrentTaskParticipant(String taskId, RemoteUserService remoteUserService) { - ParticipantVo participantVo = new ParticipantVo(); - List linksForTask = PROCESS_ENGINE.getHistoryService().getHistoricIdentityLinksForTask(taskId); - Task task = QueryUtils.taskQuery().taskId(taskId).singleResult(); - if (task != null && CollUtil.isNotEmpty(linksForTask)) { - List groupList = StreamUtils.filter(linksForTask, e -> StringUtils.isNotBlank(e.getGroupId())); - if (CollUtil.isNotEmpty(groupList)) { - List groupIds = StreamUtils.toList(groupList, e -> Long.valueOf(e.getGroupId())); - - List userIds = remoteUserService.selectUserIdsByRoleIds(groupIds); - if (CollUtil.isNotEmpty(userIds)) { - participantVo.setGroupIds(groupIds); - List userList = remoteUserService.selectListByIds(userIds); - if (CollUtil.isNotEmpty(userList)) { - List userIdList = StreamUtils.toList(userList, RemoteUserVo::getUserId); - List nickNames = StreamUtils.toList(userList, RemoteUserVo::getNickName); - participantVo.setCandidate(userIdList); - participantVo.setCandidateName(nickNames); - participantVo.setClaim(!StringUtils.isBlank(task.getAssignee())); - } - } - } else { - List candidateList = StreamUtils.filter(linksForTask, e -> FlowConstant.CANDIDATE.equals(e.getType())); - List userIdList = new ArrayList<>(); - for (HistoricIdentityLink historicIdentityLink : linksForTask) { - try { - userIdList.add(Long.valueOf(historicIdentityLink.getUserId())); - } catch (NumberFormatException ignored) { - - } - } - List userList = remoteUserService.selectListByIds(userIdList); - if (CollUtil.isNotEmpty(userList)) { - List userIds = StreamUtils.toList(userList, RemoteUserVo::getUserId); - List nickNames = StreamUtils.toList(userList, RemoteUserVo::getNickName); - participantVo.setCandidate(userIds); - participantVo.setCandidateName(nickNames); - // 判断当前任务是否具有多个办理人 - if (CollUtil.isNotEmpty(candidateList) && candidateList.size() > 1) { - // 如果 assignee 存在,则设置当前任务已经被认领 - participantVo.setClaim(StringUtils.isNotBlank(task.getAssignee())); - } - } - } - } - return participantVo; - } - - /** - * 判断当前节点是否为会签节点 - * - * @param processDefinitionId 流程定义id - * @param taskDefinitionKey 流程定义id - */ - public static MultiInstanceVo isMultiInstance(String processDefinitionId, String taskDefinitionKey) { - BpmnModel bpmnModel = PROCESS_ENGINE.getRepositoryService().getBpmnModel(processDefinitionId); - FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(taskDefinitionKey); - MultiInstanceVo multiInstanceVo = new MultiInstanceVo(); - //判断是否为并行会签节点 - if (flowNode.getBehavior() instanceof ParallelMultiInstanceBehavior behavior && behavior.getCollectionExpression() != null) { - Expression collectionExpression = behavior.getCollectionExpression(); - String assigneeList = collectionExpression.getExpressionText(); - String assignee = behavior.getCollectionElementVariable(); - multiInstanceVo.setType(behavior); - multiInstanceVo.setAssignee(assignee); - multiInstanceVo.setAssigneeList(assigneeList); - return multiInstanceVo; - //判断是否为串行会签节点 - } else if (flowNode.getBehavior() instanceof SequentialMultiInstanceBehavior behavior && behavior.getCollectionExpression() != null) { - Expression collectionExpression = behavior.getCollectionExpression(); - String assigneeList = collectionExpression.getExpressionText(); - String assignee = behavior.getCollectionElementVariable(); - multiInstanceVo.setType(behavior); - multiInstanceVo.setAssignee(assignee); - multiInstanceVo.setAssigneeList(assigneeList); - return multiInstanceVo; - } - return null; - } - - /** - * 获取当前流程状态 - * - * @param taskId 任务id - */ - public static String getBusinessStatusByTaskId(String taskId) { - HistoricTaskInstance historicTaskInstance = QueryUtils.hisTaskInstanceQuery().taskId(taskId).singleResult(); - HistoricProcessInstance historicProcessInstance = QueryUtils.hisInstanceQuery(historicTaskInstance.getProcessInstanceId()).singleResult(); - return historicProcessInstance.getBusinessStatus(); - } - - /** - * 获取当前流程状态 - * - * @param businessKey 业务id - */ - public static String getBusinessStatus(String businessKey) { - HistoricProcessInstance historicProcessInstance = QueryUtils.hisBusinessKeyQuery(businessKey).singleResult(); - return historicProcessInstance.getBusinessStatus(); - } - - /** - * 发送消息 - * - * @param list 任务 - * @param name 流程名称 - * @param messageType 消息类型 - * @param message 消息内容,为空则发送默认配置的消息内容 - */ - public static void sendMessage(List list, String name, List messageType, String message, RemoteUserService remoteUserService) { - Set userIds = new HashSet<>(); - if (StringUtils.isBlank(message)) { - message = "有新的【" + name + "】单据已经提交至您的待办,请您及时处理。"; - } - for (Task t : list) { - ParticipantVo taskParticipant = WorkflowUtils.getCurrentTaskParticipant(t.getId(), remoteUserService); - if (CollUtil.isNotEmpty(taskParticipant.getGroupIds())) { - List userIdList = remoteUserService.selectUserIdsByRoleIds(taskParticipant.getGroupIds()); - if (CollUtil.isNotEmpty(userIdList)) { - userIds.addAll(userIdList); - } - } - List candidate = taskParticipant.getCandidate(); - if (CollUtil.isNotEmpty(candidate)) { - userIds.addAll(candidate); - } - } - if (CollUtil.isNotEmpty(userIds)) { - List userList = remoteUserService.selectListByIds(new ArrayList<>(userIds)); - for (String code : messageType) { - MessageTypeEnum messageTypeEnum = MessageTypeEnum.getByCode(code); - if (ObjectUtil.isNotEmpty(messageTypeEnum)) { - switch (messageTypeEnum) { - case SYSTEM_MESSAGE: - WebSocketMessageDto dto = new WebSocketMessageDto(); - dto.setSessionKeys(new ArrayList<>(userIds)); - dto.setMessage(message); - WebSocketUtils.publishMessage(dto); - break; - case EMAIL_MESSAGE: - MailUtils.sendText(StreamUtils.join(userList, RemoteUserVo::getEmail), "单据审批提醒", message); - break; - case SMS_MESSAGE: - //todo 短信发送 - break; - } - } - } - } - } - - /** - * 根据任务id查询 当前用户的任务,检查 当前人员 是否是该 taskId 的办理人 - * - * @param taskId 任务id - * @return 结果 - */ - public static Task getTaskByCurrentUser(String taskId) { - TaskQuery taskQuery = QueryUtils.taskQuery(); - taskQuery.taskId(taskId).taskCandidateOrAssigned(String.valueOf(LoginHelper.getUserId())); - - List roles = LoginHelper.getLoginUser().getRoles(); - if (CollUtil.isNotEmpty(roles)) { - List groupIds = StreamUtils.toList(roles, e -> String.valueOf(e.getRoleId())); - taskQuery.taskCandidateGroupIn(groupIds); - } - return taskQuery.singleResult(); - } -} diff --git a/dk-modules/workflow/src/main/resources/application.yml b/dk-modules/workflow/src/main/resources/application.yml deleted file mode 100644 index afdc1c2..0000000 --- a/dk-modules/workflow/src/main/resources/application.yml +++ /dev/null @@ -1,34 +0,0 @@ -# Tomcat -server: - port: 9205 - -# Spring -spring: - application: - # 应用名称 - name: workflow - profiles: - # 环境配置 - active: @profiles.active@ - ---- # nacos 配置 -spring: - cloud: - nacos: - # nacos 服务地址 - server-addr: @nacos.server@ - username: @nacos.username@ - password: @nacos.password@ - discovery: - # 注册组 - group: @nacos.discovery.group@ - namespace: ${spring.profiles.active} - config: - # 配置组 - group: @nacos.config.group@ - namespace: ${spring.profiles.active} - config: - import: - - optional:nacos:application-common.yml - - optional:nacos:datasource.yml - - optional:nacos:${spring.application.name}.yml diff --git a/dk-modules/workflow/src/main/resources/banner.txt b/dk-modules/workflow/src/main/resources/banner.txt deleted file mode 100644 index 29aa26c..0000000 --- a/dk-modules/workflow/src/main/resources/banner.txt +++ /dev/null @@ -1,10 +0,0 @@ -Spring Boot Version: ${spring-boot.version} -Spring Application Name: ${spring.application.name} - _ _ __ _ - (_) | | / _| | - _ __ _ _ ___ _ _ _ ________ _____ _ __| | _| |_| | _____ __ -| '__| | | |/ _ \| | | | |______\ \ /\ / / _ \| '__| |/ / _| |/ _ \ \ /\ / / -| | | |_| | (_) | |_| | | \ V V / (_) | | | <| | | | (_) \ V V / -|_| \__,_|\___/ \__, |_| \_/\_/ \___/|_| |_|\_\_| |_|\___/ \_/\_/ - __/ | - |___/ diff --git a/dk-modules/workflow/src/main/resources/logback-plus.xml b/dk-modules/workflow/src/main/resources/logback-plus.xml deleted file mode 100644 index caaa345..0000000 --- a/dk-modules/workflow/src/main/resources/logback-plus.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - ${console.log.pattern} - utf-8 - - - - - - - - - - - - - - - diff --git a/dk-modules/workflow/src/main/resources/mapper/package-info.md b/dk-modules/workflow/src/main/resources/mapper/package-info.md deleted file mode 100644 index c938b1e..0000000 --- a/dk-modules/workflow/src/main/resources/mapper/package-info.md +++ /dev/null @@ -1,3 +0,0 @@ -java包使用 `.` 分割 resource 目录使用 `/` 分割 -
-此文件目的 防止文件夹粘连找不到 `xml` 文件 \ No newline at end of file diff --git a/dk-modules/workflow/src/main/resources/mapper/workflow/ActHiProcinstMapper.xml b/dk-modules/workflow/src/main/resources/mapper/workflow/ActHiProcinstMapper.xml deleted file mode 100644 index dd05785..0000000 --- a/dk-modules/workflow/src/main/resources/mapper/workflow/ActHiProcinstMapper.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/dk-modules/workflow/src/main/resources/mapper/workflow/ActHiTaskinstMapper.xml b/dk-modules/workflow/src/main/resources/mapper/workflow/ActHiTaskinstMapper.xml deleted file mode 100644 index 7e73b60..0000000 --- a/dk-modules/workflow/src/main/resources/mapper/workflow/ActHiTaskinstMapper.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/dk-modules/workflow/src/main/resources/mapper/workflow/ActTaskMapper.xml b/dk-modules/workflow/src/main/resources/mapper/workflow/ActTaskMapper.xml deleted file mode 100644 index be27877..0000000 --- a/dk-modules/workflow/src/main/resources/mapper/workflow/ActTaskMapper.xml +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/dk-modules/workflow/src/main/resources/mapper/workflow/TestLeaveMapper.xml b/dk-modules/workflow/src/main/resources/mapper/workflow/TestLeaveMapper.xml deleted file mode 100644 index d52f6b0..0000000 --- a/dk-modules/workflow/src/main/resources/mapper/workflow/TestLeaveMapper.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/dk-modules/workflow/src/main/resources/mapper/workflow/WfCategoryMapper.xml b/dk-modules/workflow/src/main/resources/mapper/workflow/WfCategoryMapper.xml deleted file mode 100644 index 4375cb2..0000000 --- a/dk-modules/workflow/src/main/resources/mapper/workflow/WfCategoryMapper.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/dk-modules/workflow/src/main/resources/mapper/workflow/WfDefinitionConfigMapper.xml b/dk-modules/workflow/src/main/resources/mapper/workflow/WfDefinitionConfigMapper.xml deleted file mode 100644 index 8d579f7..0000000 --- a/dk-modules/workflow/src/main/resources/mapper/workflow/WfDefinitionConfigMapper.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/dk-modules/workflow/src/main/resources/mapper/workflow/WfFormManageMapper.xml b/dk-modules/workflow/src/main/resources/mapper/workflow/WfFormManageMapper.xml deleted file mode 100644 index 59221f8..0000000 --- a/dk-modules/workflow/src/main/resources/mapper/workflow/WfFormManageMapper.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/dk-modules/workflow/src/main/resources/mapper/workflow/WfNodeConfigMapper.xml b/dk-modules/workflow/src/main/resources/mapper/workflow/WfNodeConfigMapper.xml deleted file mode 100644 index b65194f..0000000 --- a/dk-modules/workflow/src/main/resources/mapper/workflow/WfNodeConfigMapper.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/dk-modules/workflow/src/main/resources/mapper/workflow/WfTaskBackNodeMapper.xml b/dk-modules/workflow/src/main/resources/mapper/workflow/WfTaskBackNodeMapper.xml deleted file mode 100644 index 4a9179b..0000000 --- a/dk-modules/workflow/src/main/resources/mapper/workflow/WfTaskBackNodeMapper.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/dk-visual/nacos/src/main/resources/application.properties b/dk-visual/nacos/src/main/resources/application.properties index 3ac148a..a1feb39 100644 --- a/dk-visual/nacos/src/main/resources/application.properties +++ b/dk-visual/nacos/src/main/resources/application.properties @@ -42,7 +42,7 @@ db.num=1 ### Connect URL of DB: db.url.0=jdbc:mysql://114.235.183.147:3306/dk_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true db.user.0=root -db.password.0=dk123456! +db.password.0=dkcy@yf ### the maximum retry times for push nacos.config.push.maxRetryTime=50